view gui_ze/gui_ze.bzl @ 152:7387eec8e7f8

[Postdog] Updated to use Seobeo_Client instead of CURL. Updated to handle websocket connection.
author June Park <parkjune1995@gmail.com>
date Sun, 11 Jan 2026 07:47:05 -0800
parents 7eb79fd91c7e
children bdcc610eeed8
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
      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),
  )
  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"],
    )