Mercurial
view gui_ze/gui_ze.bzl @ 204:e5aed6c36672
[Notes] Added icons and updated styling a bit. Probalby usable now.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 15 Feb 2026 11:02:13 -0800 |
| parents | 9f4429c49733 |
| 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 _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_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 _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, )