view gui_ze/gui_ze.bzl @ 71:75de5903355c

Giagantic changes that update Dowa library to be more align with stb style array and hashmap. Updated Seobeo to be caching on server side instead of file level caching. Deleted bunch of things I don't really use.
author June Park <parkjune1995@gmail.com>
date Sun, 28 Dec 2025 20:34:22 -0800
parents a30944e5719e
children 7eb79fd91c7e
line wrap: on
line source

def _foo_impl(ctx):
  out = ctx.actions.declare_file(ctx.label.name)
  ctx.actions.write(
      output = out,
      content = "Hello!\n",
  )
  return [DefaultInfo(files = depset([out]))]

foo_binary = rule(
  implementation = _foo_impl,
)

def _bundle_impl(ctx):
  """
  bundle binary target into a folder which can later be used to make a post to github easily.
  """
  binary_target = ctx.attr.binary
  binary = binary_target[DefaultInfo].files.to_list()[0] # First files are binary
  runfiles_files = binary_target[DefaultInfo].default_runfiles.files.to_list() 

  # Name as output directory 
  out_dir = ctx.actions.declare_directory(ctx.label.name)

  copy_cmd = []
  copy_cmd.append("mkdir -p {}".format(out_dir.path))

  for f in runfiles_files:
    if f.path == binary.path:
      continue

    start = 0
    for directory in f.path.split("/"):
      if directory == binary.short_path.split("/")[0]:
        break
      print("\n\n equals: ", directory, binary.short_path.split("/")[0]);
      start += 1

    # Remove the first folder (output) and last file (actaul files that needed to be copied)
    paths = "/".join(f.path.split("/")[start:-1])
    full_path = "{}/{}".format(out_dir.path, paths)
    copy_cmd.append("mkdir -p {}".format(full_path))
    copy_cmd.append("cp {} {}".format(f.path, full_path))

  copy_cmd.append("cp {} {}".format(binary.path, out_dir.path))

  ctx.actions.run_shell(
    inputs = runfiles_files,
    outputs = [out_dir],
    command = " && ".join(copy_cmd),
    progress_message = "Bundling {}".format(ctx.label.name),
  )

  print("[INFO] See {}".format(out_dir.path))

  return [DefaultInfo(files = depset([out_dir]))]

bundle = rule(
  implementation = _bundle_impl,
  attrs = {
    "binary": attr.label(
      doc = "The cc_binary target to bundle",
      providers = [DefaultInfo],
    ),
  },
)


def _bun_binary_impl(ctx):
    out = ctx.actions.declare_file("bun")
    ctx.actions.run_shell(
      inputs = ctx.files.srcs,
      outputs = [out],
      command = """
        mkdir -p {outdir}
        unzip -j {src} {inner} -d {outdir}
        chmod +x {outdir}/bun
      """.format(
        outdir = out.dirname,
        src = ctx.files.srcs[0].path,
        inner = ctx.attr.src_folder,
        out = out.path,
      ),
    )
    return DefaultInfo(
      files = depset([out]),
      executable = out,
    )

bun_binary = rule(
    implementation = _bun_binary_impl,
    attrs = {
      "srcs": attr.label_list(allow_files=True),
      "src_folder": attr.string(),
    },
    executable = True,
)

def _bun_build_impl(ctx):
  """
  Run bun build on the folder

  This sucks because you need to either copy node module into the root folder where main.ts file
  exists or copy everything outwards. I chose to do it in this way.

  TODO: If possible, maybe create a node_module inside of the main target path and create a symlink
  TODO: Add a specific path for node_modules
  """
  out = ctx.actions.declare_file(ctx.label.name + ".js")
  inputs = [ctx.file.src] + ctx.files.data

  ctx.actions.run_shell(
    inputs = inputs,
    outputs = [out],
    tools = [ctx.executable._bun] + inputs, 
    command = """
      cp -r third_party/bun/** . \
      && cp -r {src_folder}/** .  \
      && export NODE_PATH=./node_modules && {bun_path} build {input_path} --outfile {output_path}
      """.format(
      bun_path = ctx.executable._bun.path,
      src_folder = ctx.attr.src_folder,
      input_path = ctx.file.src.path.split("/")[-1],
      output_path = out.path,
    ),
    progress_message = "Bundling {} with Bun!\n\n".format(ctx.file.src.path),
  )
  
  return [DefaultInfo(files=depset([out]))]

bun_build = rule(
  implementation = _bun_build_impl,
  attrs = {
    "src": attr.label(allow_single_file = [".ts", ".tsx", ".js", ".jsx"]),
    "_bun": attr.label(
        default = Label("//third_party/bun:bun"),
        executable = True,
        cfg = "exec",
    ),
    "data": attr.label_list(allow_files=True),
    "src_folder": attr.string(),
  },
)

def _move_files_into_dir_impl(ctx):
  srcs = ctx.files.srcs
  outs = []
  for src in srcs:
    out = ctx.actions.declare_file(ctx.attr.dest + "/" + src.basename)
    ctx.actions.run_shell(
      inputs = [src],
      outputs = [out],
      command = "cp \"$1\" \"$2\"",
      arguments = [src.path, out.path],
    )
    outs.append(out)
  return [DefaultInfo(files = depset(outs))]

move_files_into_dir = rule(
  implementation = _move_files_into_dir_impl,
  attrs = {
    "srcs": attr.label_list(allow_files=True),
    "dest": attr.string(),
  },
)

def _move_to_directory_impl(ctx):
  srcs = ctx.files.data
  res = []
  for src in srcs:
    true = "/".join(src.path.split("/")[2:])
    path = ctx.attr.dest + "/" + true if ctx.attr.dest != "" else true
    out = ctx.actions.declare_file(
      path 
    );
    ctx.actions.symlink(
      output = out,
      target_file = src,
    )
    res.append(out)
  return [DefaultInfo(files = depset(res))]

move_to_directory = rule(
  implementation = _move_to_directory_impl,
  attrs = {
    "data": attr.label_list(allow_files=True),
    "dest": attr.string(),
  },
)


def _macos_app_impl(ctx):
    """Implementation for creating a macOS .app bundle from a binary."""
    binary = ctx.file.binary
    app_name = ctx.attr.app_name
    bundle_id = ctx.attr.bundle_id

    # Declare the .app directory as output
    app_dir = ctx.actions.declare_directory(app_name + ".app")

    ctx.actions.run_shell(
        inputs = [binary],
        outputs = [app_dir],
        command = """
        set -e

        APPDIR="{app_dir}"

        rm -rf "$APPDIR"
        mkdir -p "$APPDIR/Contents/MacOS"
        mkdir -p "$APPDIR/Contents/Resources"

        cp {binary} "$APPDIR/Contents/MacOS/{app_name}"
        chmod +x "$APPDIR/Contents/MacOS/{app_name}"

        cat > "$APPDIR/Contents/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleExecutable</key>
  <string>{app_name}</string>
  <key>CFBundleIdentifier</key>
  <string>{bundle_id}</string>
  <key>CFBundleName</key>
  <string>{app_name}</string>
  <key>CFBundleVersion</key>
  <string>1.0</string>
</dict>
</plist>
EOF
        """.format(
            app_dir = app_dir.path,
            binary = binary.path,
            app_name = app_name,
            bundle_id = bundle_id,
        ),
        progress_message = "Creating macOS app bundle for {}".format(app_name),
    )

    return [DefaultInfo(files = depset([app_dir]))]

_macos_app = rule(
    implementation = _macos_app_impl,
    attrs = {
        "binary": attr.label(
            allow_single_file = True,
            mandatory = True,
            doc = "The binary to bundle into a .app",
        ),
        "app_name": attr.string(
            mandatory = True,
            doc = "Name of the application",
        ),
        "bundle_id": attr.string(
            mandatory = True,
            doc = "Bundle identifier (e.g., com.example.app)",
        ),
    },
)

def _macos_signed_app_impl(ctx):
    """Implementation for signing a macOS .app bundle."""
    app_dir = ctx.file.app
    app_name = ctx.attr.app_name

    # Declare the signed .app directory as output
    signed_app_dir = ctx.actions.declare_directory(app_name + "_signed.app")

    ctx.actions.run_shell(
        inputs = [app_dir],
        outputs = [signed_app_dir],
        command = """
        set -e

        APPDIR="{app_dir}"
        SIGNEDDIR="{signed_dir}"

        rm -rf "$SIGNEDDIR"
        # Use -L to dereference symlinks, as codesign doesn't work with symlinks
        cp -RL "$APPDIR" "$SIGNEDDIR"

        codesign --deep --force --sign - "$SIGNEDDIR"
        """.format(
            app_dir = app_dir.path,
            signed_dir = signed_app_dir.path,
        ),
        progress_message = "Signing macOS app bundle {}".format(app_name),
    )

    return [DefaultInfo(files = depset([signed_app_dir]))]

_macos_signed_app = rule(
    implementation = _macos_signed_app_impl,
    attrs = {
        "app": attr.label(
            allow_single_file = True,
            mandatory = True,
            doc = "The .app directory to sign",
        ),
        "app_name": attr.string(
            mandatory = True,
            doc = "Name of the application",
        ),
    },
)

def macos_app_and_dmg(name, binary, bundle_id = "com.example.app"):
    """
    Creates a macOS .app bundle, signs it, and packages it into a DMG.

    Args:
        name: Base name for the generated targets
        binary: Label of the binary target to bundle
        bundle_id: Bundle identifier for the app (default: com.example.app)

    Generates:
        {name}_app: The .app bundle
        {name}_signed_app: The signed .app bundle
        {name}_dmg: The final DMG file
    """
    # 1. Build the .app bundle
    _macos_app(
        name = name + "_app",
        binary = binary,
        app_name = name,
        bundle_id = bundle_id,
    )

    # 2. Sign the .app
    _macos_signed_app(
        name = name + "_signed_app",
        app = ":" + name + "_app",
        app_name = name,
    )

    # 3. Create the DMG
    native.genrule(
        name = name + "_dmg",
        srcs = [":" + name + "_signed_app"],
        outs = [name + ".dmg"],
        cmd = """
        set -e

        SIGNEDDIR="$(location :{name}_signed_app)"

        hdiutil create \
            -volname {name} \
            -srcfolder "$$SIGNEDDIR" \
            -ov -format UDZO "$@"
        """.format(name = name),
        local = 1,  # Disable sandboxing for hdiutil
        tags = ["no-sandbox"],
    )