view gui_ze/gui_ze.bzl @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 1f9877b637e9
children
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 _shell_quote(value):
  return "'{}'".format(value.replace("'", "'\"'\"'"))

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)
  manifest = ctx.actions.declare_file(ctx.label.name + ".runfiles_manifest")
  manifest_lines = []

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

    short_path = f.short_path
    if f.short_path.startswith("../"):
      short_path = short_path[3:]
    paths = "/".join(short_path.split("/")[:-1])
    full_path = "{}/{}".format(out_dir.path, paths)
    manifest_lines.append("{}\t{}\n".format(f.path, full_path))

  ctx.actions.write(
      output = manifest,
      content = "".join(manifest_lines),
  )

  ctx.actions.run_shell(
    inputs = runfiles_files + [manifest],
    outputs = [out_dir],
    command = """
set -eu
mkdir -p {out_dir}
while IFS=$'\\t' read -r source destination; do
  mkdir -p "$destination"
  cp -rL "$source" "$destination"
done < {manifest}
cp {binary} {out_dir}
""".format(
        binary = _shell_quote(binary.path),
        manifest = _shell_quote(manifest.path),
        out_dir = _shell_quote(out_dir.path),
    ),
    progress_message = "Bundling {}".format(ctx.label.name),
  )
  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_bundle_impl(ctx):
  """
  Bundle TypeScript/JavaScript with Bun, resolving imports from bazel root.

  Copies all dependencies (dereferencing symlinks) to create a flat structure
  where imports can resolve correctly relative to the bazel workspace root.
  """
  out = ctx.actions.declare_file(ctx.label.name + ".js")

  inputs = depset(
    direct = [ctx.file.src],
    transitive = [dep[DefaultInfo].files for dep in ctx.attr.deps]
  )

  # Get the source file's package directory (e.g., "hg-web" from "hg-web/src/main.tsx")
  src_package = ctx.file.src.path.split("/")[0]

  # Collect unique root directories to copy (deduped), excluding src_package (handled separately)
  dirs_to_copy = {}
  for f in ctx.files.deps:
    # Find the root directory path by locating where short_path starts in full path
    short_path_suffix = "/".join(f.short_path.split("/")[1:])
    pos = f.path.find(short_path_suffix)
    if pos > 0:
      root_dir = f.path[:pos].rstrip("/")
      # Skip src_package - it's a symlink that needs special handling
      if not root_dir.endswith(src_package):
        dirs_to_copy[root_dir] = True

  # Build copy commands for each unique directory
  copy_commands = ["cp -rL {dir} .".format(dir = d) for d in dirs_to_copy.keys()]

  ctx.actions.run_shell(
    inputs = inputs,
    outputs = [out],
    tools = [ctx.executable._bun] + [ctx.file.src] + ctx.files.deps + ctx.files.node_modules,
    command = """
cp -rL {src_package} {src_package}_tmp && rm -rf {src_package} && mv {src_package}_tmp {src_package}
{copy_commands}
export NODE_PATH=./third_party/bun/node_modules
cp ./third_party/bun/tsconfig.json .
{bun} build {entry} --outfile {output} --target browser 
""".format(
      copy_commands = "\n".join(copy_commands),
      src_package = src_package,
      bun = ctx.executable._bun.path,
      entry = ctx.file.src.path,
      output = out.path,
    ),
    progress_message = "Bundling %s with Bun" % ctx.file.src.short_path,
  )

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

bun_bundle = rule(
  implementation = _bun_bundle_impl,
  attrs = {
    "src": attr.label(
      allow_single_file = [".ts", ".tsx", ".js", ".jsx"],
      doc = "Entry point file to bundle",
    ),
    "deps": attr.label_list(
      allow_files = True,
      doc = "Source files and other dependencies to include",
    ),
    "node_modules": attr.label_list(
      allow_files = True,
      default = [Label("//third_party/bun:bun_files")],
      doc = "Node modules for bundling (defaults to //third_party/bun:bun_files)",
    ),
    "_bun": attr.label(
      default = Label("//third_party/bun:bun"),
      executable = True,
      cfg = "exec",
    ),
  },
  doc = "Bundle TypeScript/JavaScript using Bun with bazel root imports",
)



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}/** .  \
      && cp -r ./bazel-out/k8-fastbuild/bin/hg-web/src/** src \
      && ls src \
      && pwd \
      && export NODE_PATH=./node_modules && {bun_path} build {input_path} --outfile {output_path} --target browser
      """.format(
      bun_path = ctx.executable._bun.path,
      src_folder = ctx.attr.src_folder,
      # Fix this lol
      input_path = "/".join(ctx.file.src.path.split("/")[-2:]),
      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 _bun_run_impl(ctx):
    actual_exe = ctx.actions.declare_file(ctx.label.name)
    
    # 1. Get the workspace name (crucial for runfiles paths)
    workspace_name = ctx.workspace_name

    # 2. Define the paths relative to the runfiles root
    bun_path = ctx.executable._bun.short_path
    src_path = ctx.file.src.short_path

    # 3. Create the launcher script
    # We use a template to handle the environment and pathing
    script_content = """#!/bin/bash
# Find the runfiles directory
if [[ -z "$RUNFILES_DIR" ]]; then
  if [[ -d "$0.runfiles" ]]; then
    RUNFILES_DIR="$0.runfiles"
  fi
fi

# Navigate to the workspace root inside runfiles
cd "$RUNFILES_DIR/{workspace}"
pwd
# Execute bun with the src file and any extra arguments
exec "./{bun_bin}" run "./{src_file}" "$@"
""".format(
        workspace = workspace_name,
        bun_bin = bun_path,
        src_file = src_path
    )

    ctx.actions.write(
        output = actual_exe,
        content = script_content,
        is_executable = True,
    )

    return [
        DefaultInfo(
            executable = actual_exe,
            runfiles = ctx.runfiles(
                files = [ctx.file.src] + ctx.files.data + ctx.files._bun_files
            ).merge(ctx.attr._bun[DefaultInfo].default_runfiles),
        ),
    ]

# TODO: Fix the rules so that it can do relative import.
bun_run = rule(
  implementation = _bun_run_impl,
  executable = True,
  attrs = {
    "src": attr.label(allow_single_file = True, mandatory = True),
    "data": attr.label_list(allow_files = True),
    "_bun": attr.label(
      default = Label("//third_party/bun:bun"), 
      executable = True, 
      cfg = "exec"
    ),
    "_bun_files": attr.label(default = Label("//third_party/bun:bun_files")),
  },
)


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 -r \"$1\" \"$2\"",
      arguments = [src.path, out.path],
    )
    outs.append(out)
  return [DefaultInfo(files = depset(outs), runfiles = ctx.runfiles(files = outs))]

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

def webp_image(name, src, out, quality = 90, lossless = False):
  """Convert one image to WebP as a Bazel build action."""
  native.genrule(
    name = name,
    srcs = [src],
    outs = [out],
    tools = ["@libwebp_linux_x86_64//:bin/cwebp"],
    cmd = "$(location @libwebp_linux_x86_64//:bin/cwebp) -quiet -m 6 {} -q {} $(location {}) -o $@".format(
      "-lossless" if lossless else "",
      quality,
      src,
    ),
  )

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
    """
    macos_constraint = ["@platforms//os:macos"]

    # 1. Build the .app bundle
    _macos_app(
        name = name + "_app",
        binary = binary,
        app_name = name,
        bundle_id = bundle_id,
        target_compatible_with = macos_constraint,
    )

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

    # 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"],
        target_compatible_with = macos_constraint,
    )