diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2bcd3e6..703bba6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -35,9 +35,48 @@ jobs:
external-cache: true
disk-cache: ci-${{ matrix.phase8_target }}
cache-save: ${{ github.event_name != 'pull_request' }}
+ - name: Install Nix
+ if: runner.os != 'Windows'
+ uses: cachix/install-nix-action@v31
+ with:
+ extra_nix_config: |
+ experimental-features = nix-command flakes
+ - name: Restore and save Nix store cache
+ if: runner.os != 'Windows'
+ uses: nix-community/cache-nix-action@v7
+ with:
+ primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
+ restore-prefixes-first-match: nix-${{ runner.os }}-
+ - name: Install flake dependencies
+ if: runner.os != 'Windows'
+ run: nix develop --accept-flake-config -c true
+ - name: Set up Python
+ if: runner.os == 'Windows'
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ - name: Provide python3 shim
+ if: runner.os == 'Windows'
+ shell: bash
+ run: |
+ mkdir -p "$RUNNER_TEMP/bin"
+ cat >"$RUNNER_TEMP/bin/python3" <<'EOF'
+ #!/usr/bin/env bash
+ exec python "$@"
+ EOF
+ chmod +x "$RUNNER_TEMP/bin/python3"
+ echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
- name: Run tests (${{ matrix.phase8_target }})
+ if: runner.os != 'Windows'
shell: bash
run: |
echo "Phase 8 target: ${{ matrix.phase8_target }}"
- targets="$(./tests/ci_test/phase8_ci_targets.sh "${{ matrix.phase8_target }}")"
- bazel test --test_output=errors ${targets}
+ mapfile -t targets < <(./tests/ci_test/phase8_ci_targets.sh "${{ matrix.phase8_target }}")
+ nix develop --accept-flake-config -c bazel test --test_output=errors "${targets[@]}"
+ - name: Run tests (${{ matrix.phase8_target }})
+ if: runner.os == 'Windows'
+ shell: bash
+ run: |
+ echo "Phase 8 target: ${{ matrix.phase8_target }}"
+ mapfile -t targets < <(./tests/ci_test/phase8_ci_targets.sh "${{ matrix.phase8_target }}")
+ bazel test --test_output=errors "${targets[@]}"
diff --git a/README.md b/README.md
index 1e6274f..6fd86c3 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ Strict defaults are enabled by default:
- `bun_install` skips lifecycle scripts unless `ignore_scripts = False`
- `bun_build`, `bun_bundle`, `bun_compile`, and `bun_test` require `install_mode = "disable"`
-- Runtime launchers do not inherit the host `PATH` unless `inherit_host_path = True`
+- Runtime launchers stage hermetic `bun`, `bunx`, and `node` commands on `PATH` and do not inherit the host `PATH` unless `inherit_host_path = True`
To refresh generated rule docs:
@@ -218,10 +218,11 @@ bun_script(
)
```
-When `node_modules` is provided, executables from `node_modules/.bin` are added
-to the runtime `PATH`. The host `PATH` is not inherited unless
-`inherit_host_path = True`. This label typically comes from `bun_install`,
-which still produces a standard `node_modules/` directory.
+Launcher-based runtime rules stage hermetic `bun`, `bunx`, and `node`
+commands on `PATH`. When `node_modules` is provided, executables from
+`node_modules/.bin` are also added to the runtime `PATH`. The host `PATH` is
+not inherited unless `inherit_host_path = True`. This label typically comes
+from `bun_install`, which still produces a standard `node_modules/` directory.
### `bun_build` and `bun_compile`
diff --git a/docs/rules.md b/docs/rules.md
index dd0f774..b88b26b 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -12,7 +12,7 @@ Public API surface for Bun Bazel rules.
Strict defaults:
- `bun_build`, `bun_bundle`, `bun_compile`, and `bun_test` require `install_mode = "disable"`
-- Runtime launchers do not inherit the host `PATH` unless `inherit_host_path = True`
+- Runtime launchers stage hermetic `bun`, `bunx`, and `node` commands on `PATH` and do not inherit the host `PATH` unless `inherit_host_path = True`
@@ -41,7 +41,7 @@ Use this rule for non-test scripts and CLIs that should run via `bazel run`.
| entry_point | Path to the main JS/TS file to execute. | Label | required | |
| env_files | Additional environment files loaded with `--env-file`. | List of labels | optional | `[]` |
| install_mode | Whether Bun may auto-install missing packages at runtime. Non-`disable` values are runtime opt-ins and are not hermetic. | String | optional | `"disable"` |
-| inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
+| inherit_host_path | If true, appends the host PATH after the staged Bun runtime tool bin and `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | Label | optional | `None` |
| preload | Modules to preload with `--preload` before running the entry point. | List of labels | optional | `[]` |
@@ -265,7 +265,7 @@ watch/HMR plus optional full restarts on selected file changes.
| entry_point | Path to the main JS/TS file to execute in dev mode. | Label | required | |
| env_files | Additional environment files loaded with `--env-file`. | List of labels | optional | `[]` |
| install_mode | Whether Bun may auto-install missing packages in dev mode. This is a local workflow helper, not a hermetic execution surface. | String | optional | `"disable"` |
-| inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
+| inherit_host_path | If true, appends the host PATH after the staged Bun runtime tool bin and `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| no_clear_screen | If true, disables terminal clearing on Bun reloads. | Boolean | optional | `False` |
| no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | Label | optional | `None` |
@@ -295,7 +295,7 @@ Use this rule to expose existing package scripts such as `dev`, `build`, or
`check` via `bazel run` without adding wrapper shell scripts. This is a good fit
for Vite-style workflows, where scripts like `vite dev` or `vite build` are
declared in `package.json` and expect to run from the package directory with
-`node_modules/.bin` available on `PATH`.
+the staged Bun runtime tool bin and `node_modules/.bin` available on `PATH`.
**ATTRIBUTES**
@@ -309,10 +309,10 @@ declared in `package.json` and expect to run from the package directory with
| execution_mode | How Bun should execute matching workspace scripts. | String | optional | `"single"` |
| filters | Workspace package filters passed via repeated `--filter` flags. | List of strings | optional | `[]` |
| install_mode | Whether Bun may auto-install missing packages while running the script. This is a local workflow helper, not a hermetic execution surface. | String | optional | `"disable"` |
-| inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
+| inherit_host_path | If true, appends the host PATH after the staged Bun runtime tool bin and `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| no_exit_on_error | If true, Bun keeps running other workspace scripts when one fails. | Boolean | optional | `False` |
-| node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`. | Label | optional | `None` |
+| node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. The staged Bun runtime tool bin and executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`. | Label | optional | `None` |
| package_json | Label of the `package.json` file containing the named script. | Label | required | |
| preload | Modules to preload with `--preload` before running the script. | List of labels | optional | `[]` |
| run_flags | Additional raw flags forwarded to `bun run` before the script name. | List of strings | optional | `[]` |
@@ -356,7 +356,7 @@ Supports Bazel test filtering (`--test_filter`) and coverage integration.
| coverage_reporters | Repeated Bun coverage reporters such as `text` or `lcov`. | List of strings | optional | `[]` |
| env_files | Additional environment files loaded with `--env-file`. | List of labels | optional | `[]` |
| install_mode | Whether Bun may auto-install missing packages while testing. Hermetic tests require `\"disable\"`, and other values are rejected. | String | optional | `"disable"` |
-| inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
+| inherit_host_path | If true, appends the host PATH after the staged Bun runtime tool bin and `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| max_concurrency | Optional maximum number of concurrent tests. | Integer | optional | `0` |
| no_env_file | If true, disables Bun's automatic `.env` loading. | Boolean | optional | `False` |
| node_modules | Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. | Label | optional | `None` |
@@ -427,7 +427,7 @@ the provided tool with any default arguments.
| package_dir_hint | Optional package-relative directory hint when package_json is not supplied. | String | optional | `"."` |
| package_json | Optional package.json used to resolve the package working directory. | Label | optional | `None` |
| tool | Executable target to launch as the dev server. | Label | required | |
-| inherit_host_path | If true, appends the host PATH after staged `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
+| inherit_host_path | If true, appends the host PATH after the staged Bun runtime tool bin and `node_modules/.bin` entries at runtime. | Boolean | optional | `False` |
| working_dir | Working directory at runtime: Bazel runfiles workspace root or the resolved package directory. | String | optional | `"workspace"` |
diff --git a/flake.nix b/flake.nix
index 59b3764..f7961b9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -118,6 +118,8 @@
shell.packages = [
pkgs.bazel-buildtools
+ pkgs.curl
+ pkgs.python3
self.packages.${system}.release
];
@@ -128,6 +130,8 @@
runtimeInputs = [
bazel9
pkgs.bun
+ pkgs.curl
+ pkgs.python3
];
};
};
diff --git a/internal/bun_binary.bzl b/internal/bun_binary.bzl
index 24951dd..c96f404 100644
--- a/internal/bun_binary.bzl
+++ b/internal/bun_binary.bzl
@@ -114,7 +114,7 @@ _BUN_BINARY_ATTRS.update({
),
"inherit_host_path": attr.bool(
default = False,
- doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
+ doc = "If true, appends the host PATH after the staged Bun runtime tool bin and node_modules/.bin entries at runtime.",
),
})
diff --git a/internal/bun_dev.bzl b/internal/bun_dev.bzl
index 10ffbd6..079136a 100644
--- a/internal/bun_dev.bzl
+++ b/internal/bun_dev.bzl
@@ -122,7 +122,7 @@ _BUN_DEV_ATTRS.update({
),
"inherit_host_path": attr.bool(
default = False,
- doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
+ doc = "If true, appends the host PATH after the staged Bun runtime tool bin and node_modules/.bin entries at runtime.",
),
})
diff --git a/internal/bun_script.bzl b/internal/bun_script.bzl
index fce857f..00ab2bb 100644
--- a/internal/bun_script.bzl
+++ b/internal/bun_script.bzl
@@ -83,7 +83,7 @@ _BUN_SCRIPT_ATTRS.update({
doc = "Label of the `package.json` file containing the named script.",
),
"node_modules": attr.label(
- doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`.",
+ doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. The staged Bun runtime tool bin and executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`.",
),
"data": attr.label_list(
allow_files = True,
@@ -148,7 +148,7 @@ _BUN_SCRIPT_ATTRS.update({
),
"inherit_host_path": attr.bool(
default = False,
- doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
+ doc = "If true, appends the host PATH after the staged Bun runtime tool bin and node_modules/.bin entries at runtime.",
),
})
@@ -159,8 +159,9 @@ bun_script = rule(
Use this rule to expose existing package scripts such as `dev`, `build`, or
`check` via `bazel run` without adding wrapper shell scripts. This is a good fit
for Vite-style workflows, where scripts like `vite dev` or `vite build` are
-declared in `package.json` and expect to run from the package directory. This
-is a local workflow helper rather than a hermetic build rule.
+declared in `package.json` and expect to run from the package directory with
+the staged Bun runtime tool bin and `node_modules/.bin` on `PATH`. This is a
+local workflow helper rather than a hermetic build rule.
""",
attrs = _BUN_SCRIPT_ATTRS,
executable = True,
diff --git a/internal/bun_test.bzl b/internal/bun_test.bzl
index 2e8cfd0..cd7f8ad 100644
--- a/internal/bun_test.bzl
+++ b/internal/bun_test.bzl
@@ -180,7 +180,7 @@ _BUN_TEST_ATTRS.update({
),
"inherit_host_path": attr.bool(
default = False,
- doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
+ doc = "If true, appends the host PATH after the staged Bun runtime tool bin and node_modules/.bin entries at runtime.",
),
})
diff --git a/internal/js_run_devserver.bzl b/internal/js_run_devserver.bzl
index 9028bc2..3c9fb31 100644
--- a/internal/js_run_devserver.bzl
+++ b/internal/js_run_devserver.bzl
@@ -92,7 +92,7 @@ _JS_RUN_DEVSERVER_ATTRS.update({
),
"inherit_host_path": attr.bool(
default = False,
- doc = "If true, appends the host PATH after staged node_modules/.bin entries at runtime.",
+ doc = "If true, appends the host PATH after the staged Bun runtime tool bin and node_modules/.bin entries at runtime.",
),
})
diff --git a/internal/runtime_launcher.js b/internal/runtime_launcher.js
index d5bcdae..15b341b 100644
--- a/internal/runtime_launcher.js
+++ b/internal/runtime_launcher.js
@@ -489,6 +489,31 @@ function materializeTreeContents(sourceRoot, destinationRoot) {
}
}
+function stageRuntimeToolAlias(sourcePath, destinationPath, preferLinks) {
+ removePath(destinationPath);
+ ensureDir(dirname(destinationPath));
+ if (preferLinks && !IS_WINDOWS) {
+ symlinkSync(sourcePath, destinationPath);
+ return;
+ }
+ copyPath(sourcePath, destinationPath);
+}
+
+function stageRuntimeToolBin(runtimeWorkspace, bunPath, preferLinks) {
+ const runtimeToolBin = join(runtimeWorkspace, ".rules_bun", "bin");
+ ensureDir(runtimeToolBin);
+
+ const bunName = IS_WINDOWS ? "bun.exe" : "bun";
+ const stagedBunPath = join(runtimeToolBin, bunName);
+ materializePath(realpathSync(bunPath), stagedBunPath, preferLinks);
+
+ for (const aliasName of IS_WINDOWS ? ["bunx.exe", "node.exe"] : ["bunx", "node"]) {
+ stageRuntimeToolAlias(stagedBunPath, join(runtimeToolBin, aliasName), preferLinks);
+ }
+
+ return runtimeToolBin;
+}
+
function stageWorkspaceView(sourceRoot, destinationRoot, packageRelDir) {
ensureDir(destinationRoot);
const skippedEntry = firstPathComponent(packageRelDir);
@@ -765,9 +790,19 @@ function mirrorInstallRepoWorkspaceNodeModules(
}
}
-function buildRuntimePath(runtimeWorkspace, runtimePackageDir, runtimeInstallRoot, inheritHostPath) {
+function buildRuntimePath(
+ runtimeToolBin,
+ runtimeWorkspace,
+ runtimePackageDir,
+ runtimeInstallRoot,
+ inheritHostPath,
+) {
const entries = [];
+ if (existsSync(runtimeToolBin) && statSync(runtimeToolBin).isDirectory()) {
+ entries.push(runtimeToolBin);
+ }
+
const installBin = join(runtimeInstallRoot, "node_modules", ".bin");
const packageBin = join(runtimePackageDir, "node_modules", ".bin");
const workspaceBin = join(runtimeWorkspace, "node_modules", ".bin");
@@ -915,9 +950,16 @@ function createRuntime(spec, runfiles) {
materializePath(runtimeInstallNodeModules, runtimePackageNodeModules, preferLinks);
}
+ const runtimeToolBin = stageRuntimeToolBin(
+ runtimeWorkspace,
+ runfiles.rlocation(spec.bun_short_path),
+ preferLinks,
+ );
+
const env = { ...process.env };
const pathKey = pathEnvKey(env);
const runtimePath = buildRuntimePath(
+ runtimeToolBin,
runtimeWorkspace,
runtimePackageDir,
runtimeInstallRoot,
@@ -992,12 +1034,31 @@ function composeBunArgs(spec, runfiles, runtime) {
return args;
}
+function isWindowsBatchFile(command) {
+ return IS_WINDOWS && /\.(cmd|bat)$/i.test(String(command || ""));
+}
+
+function quoteForWindowsShell(command) {
+ return `"${String(command).replace(/"/g, '""')}"`;
+}
+
+function spawnChild(command, args, options) {
+ const spawnOptions = {
+ ...options,
+ stdio: "inherit",
+ };
+ if (isWindowsBatchFile(command)) {
+ return spawn(quoteForWindowsShell(command), args, {
+ ...spawnOptions,
+ shell: true,
+ });
+ }
+ return spawn(command, args, spawnOptions);
+}
+
function spawnProcess(command, args, options) {
return new Promise((resolvePromise, rejectPromise) => {
- const child = spawn(command, args, {
- ...options,
- stdio: "inherit",
- });
+ const child = spawnChild(command, args, options);
child.once("error", rejectPromise);
child.once("exit", (code, signal) => {
resolvePromise({ child, code, signal });
@@ -1077,10 +1138,9 @@ async function runDevMode(spec, runfiles, userArgs) {
currentRuntime = createRuntime(spec, runfiles);
const bunPath = runfiles.rlocation(spec.bun_short_path);
const bunArgs = [...composeBunArgs(spec, runfiles, currentRuntime), watchFlag, ...passthroughArgs];
- child = spawn(bunPath, bunArgs, {
+ child = spawnChild(bunPath, bunArgs, {
cwd: currentRuntime.runtimeExecDir,
env: currentRuntime.env,
- stdio: "inherit",
});
exitPromise = new Promise((resolvePromise, rejectPromise) => {
child.once("error", rejectPromise);
diff --git a/tests/binary_test/BUILD.bazel b/tests/binary_test/BUILD.bazel
index ca408cf..65fd462 100644
--- a/tests/binary_test/BUILD.bazel
+++ b/tests/binary_test/BUILD.bazel
@@ -44,8 +44,8 @@ sh_test(
size = "small",
srcs = ["verify_data_shape.sh"],
args = [
- "$(location //internal:bun_binary.bzl)",
- "$(location //tests/binary_test:BUILD.bazel)",
+ "$(rlocationpath //internal:bun_binary.bzl)",
+ "$(rlocationpath //tests/binary_test:BUILD.bazel)",
],
data = [
"//internal:bun_binary.bzl",
diff --git a/tests/binary_test/path_probe.ts b/tests/binary_test/path_probe.ts
index 2eef2cb..acc495b 100644
--- a/tests/binary_test/path_probe.ts
+++ b/tests/binary_test/path_probe.ts
@@ -1,5 +1,18 @@
+import { spawnSync } from "node:child_process";
+
const pathValue = process.env.PATH ?? "";
+function commandSucceeds(command: string, args: string[]): boolean {
+ const result = spawnSync(command, args, {
+ encoding: "utf8",
+ env: process.env,
+ });
+ return result.status === 0;
+}
+
console.log(JSON.stringify({
hasHostSentinel: pathValue.includes("rules_bun_host_path_sentinel"),
+ canRunBun: commandSucceeds("bun", ["-e", "process.exit(0)"]),
+ canRunBunx: commandSucceeds("bunx", ["--version"]),
+ canRunNode: commandSucceeds("node", ["-e", "process.exit(0)"]),
}));
diff --git a/tests/binary_test/run_binary.sh b/tests/binary_test/run_binary.sh
index 715af61..cb8e3a1 100755
--- a/tests/binary_test/run_binary.sh
+++ b/tests/binary_test/run_binary.sh
@@ -8,12 +8,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/binary_test/run_env_binary.sh b/tests/binary_test/run_env_binary.sh
index ef26595..959c166 100755
--- a/tests/binary_test/run_env_binary.sh
+++ b/tests/binary_test/run_env_binary.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/binary_test/run_flag_binary.sh b/tests/binary_test/run_flag_binary.sh
index 1333a30..bc92489 100755
--- a/tests/binary_test/run_flag_binary.sh
+++ b/tests/binary_test/run_flag_binary.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/binary_test/run_parent_env_binary.sh b/tests/binary_test/run_parent_env_binary.sh
index d829511..dad9c24 100755
--- a/tests/binary_test/run_parent_env_binary.sh
+++ b/tests/binary_test/run_parent_env_binary.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/binary_test/run_path_binary.sh b/tests/binary_test/run_path_binary.sh
index ef7b265..23320f7 100755
--- a/tests/binary_test/run_path_binary.sh
+++ b/tests/binary_test/run_path_binary.sh
@@ -8,12 +8,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- env PATH="rules_bun_host_path_sentinel:${PATH:-}" cmd.exe /c "${command}" | tr -d '\r'
+ env PATH="rules_bun_host_path_sentinel:${PATH:-}" cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
env PATH="rules_bun_host_path_sentinel:${PATH:-}" "${launcher}" "$@"
@@ -22,12 +17,12 @@ run_launcher() {
default_output="$(run_launcher "${default_binary}")"
inherit_output="$(run_launcher "${inherit_binary}")"
-if [[ ${default_output} != '{"hasHostSentinel":false}' ]]; then
+if [[ ${default_output} != '{"hasHostSentinel":false,"canRunBun":true,"canRunBunx":true,"canRunNode":true}' ]]; then
echo "Expected default launcher to hide host PATH, got: ${default_output}" >&2
exit 1
fi
-if [[ ${inherit_output} != '{"hasHostSentinel":true}' ]]; then
+if [[ ${inherit_output} != '{"hasHostSentinel":true,"canRunBun":true,"canRunBunx":true,"canRunNode":true}' ]]; then
echo "Expected inherit_host_path launcher to preserve host PATH, got: ${inherit_output}" >&2
exit 1
fi
diff --git a/tests/binary_test/verify_data_shape.sh b/tests/binary_test/verify_data_shape.sh
index 74d5a5a..f206340 100755
--- a/tests/binary_test/verify_data_shape.sh
+++ b/tests/binary_test/verify_data_shape.sh
@@ -1,8 +1,64 @@
#!/usr/bin/env bash
set -euo pipefail
-rule_file="$1"
-build_file="$2"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+rule_file="$(resolve_runfile "${1:-}")"
+build_file="$(resolve_runfile "${2:-}")"
grep -Eq 'extra_files = ctx\.files\.data \+ ctx\.files\.preload \+ ctx\.files\.env_files \+ \[bun_bin\]' "${rule_file}"
grep -Eq 'name = "hello_js_with_data_bin"' "${build_file}"
diff --git a/tests/bun_test_test/BUILD.bazel b/tests/bun_test_test/BUILD.bazel
index 02be55e..2cb291e 100644
--- a/tests/bun_test_test/BUILD.bazel
+++ b/tests/bun_test_test/BUILD.bazel
@@ -60,7 +60,7 @@ sh_test(
name = "bun_test_failing_suite_test",
size = "small",
srcs = ["failing_suite_shape.sh"],
- args = ["$(location //tests/bun_test_test:BUILD.bazel)"],
+ args = ["$(rlocationpath //tests/bun_test_test:BUILD.bazel)"],
data = ["//tests/bun_test_test:BUILD.bazel"],
)
diff --git a/tests/bun_test_test/failing_suite_shape.sh b/tests/bun_test_test/failing_suite_shape.sh
index d494e74..fa13bd4 100755
--- a/tests/bun_test_test/failing_suite_shape.sh
+++ b/tests/bun_test_test/failing_suite_shape.sh
@@ -1,7 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
-build_file="$1"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+build_file="$(resolve_runfile "${1:-}")"
grep -Eq 'name = "failing_suite"' "${build_file}"
if grep -Eq 'tags = \["manual"\]' "${build_file}"; then
diff --git a/tests/ci_test/BUILD.bazel b/tests/ci_test/BUILD.bazel
index aabc41d..566b13b 100644
--- a/tests/ci_test/BUILD.bazel
+++ b/tests/ci_test/BUILD.bazel
@@ -4,7 +4,7 @@ sh_test(
name = "phase8_ci_matrix_shape_test",
size = "small",
srcs = ["phase8_ci_matrix_shape_test.sh"],
- args = ["$(location //.github/workflows:ci.yml)"],
+ args = ["$(rlocationpath //.github/workflows:ci.yml)"],
data = ["//.github/workflows:ci.yml"],
)
@@ -12,7 +12,7 @@ sh_test(
name = "phase8_ci_targets_test",
size = "small",
srcs = ["phase8_ci_targets_test.sh"],
- args = ["$(location :phase8_ci_targets.sh)"],
+ args = ["$(rlocationpath :phase8_ci_targets.sh)"],
data = [":phase8_ci_targets.sh"],
)
diff --git a/tests/ci_test/phase8_ci_matrix_shape_test.sh b/tests/ci_test/phase8_ci_matrix_shape_test.sh
index 02333c2..2e679de 100755
--- a/tests/ci_test/phase8_ci_matrix_shape_test.sh
+++ b/tests/ci_test/phase8_ci_matrix_shape_test.sh
@@ -1,7 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
-workflow_file="$1"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+workflow_file="$(resolve_runfile "${1:-}")"
if [ -z "${workflow_file}" ]; then
echo "Error: workflow file path required as first argument" >&2
exit 1
diff --git a/tests/ci_test/phase8_ci_targets_test.sh b/tests/ci_test/phase8_ci_targets_test.sh
index 9be6cfe..119b8f3 100755
--- a/tests/ci_test/phase8_ci_targets_test.sh
+++ b/tests/ci_test/phase8_ci_targets_test.sh
@@ -1,7 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
-resolver="${1:-}"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+resolver="$(resolve_runfile "${1:-}")"
if [[ -z ${resolver} ]]; then
echo "Error: resolver path required as first argument" >&2
exit 1
diff --git a/tests/integration_test/examples_basic_run_e2e_test.sh b/tests/integration_test/examples_basic_run_e2e_test.sh
index 8b86842..30447a4 100755
--- a/tests/integration_test/examples_basic_run_e2e_test.sh
+++ b/tests/integration_test/examples_basic_run_e2e_test.sh
@@ -19,12 +19,7 @@ start_launcher() {
local log_target="$2"
shift 2
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" >"${log_target}" 2>&1 &
+ cmd.exe /c call "${launcher}" "$@" >"${log_target}" 2>&1 &
else
"${launcher}" "$@" >"${log_target}" 2>&1 &
fi
diff --git a/tests/integration_test/examples_vite_monorepo_e2e_test.sh b/tests/integration_test/examples_vite_monorepo_e2e_test.sh
index d555515..d4affcb 100755
--- a/tests/integration_test/examples_vite_monorepo_e2e_test.sh
+++ b/tests/integration_test/examples_vite_monorepo_e2e_test.sh
@@ -22,12 +22,7 @@ start_launcher() {
local log_target="$2"
shift 2
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" >"${log_target}" 2>&1 &
+ cmd.exe /c call "${launcher}" "$@" >"${log_target}" 2>&1 &
else
"${launcher}" "$@" >"${log_target}" 2>&1 &
fi
diff --git a/tests/js_compat_test/run_binary.sh b/tests/js_compat_test/run_binary.sh
index 8385dc0..b56e5ed 100755
--- a/tests/js_compat_test/run_binary.sh
+++ b/tests/js_compat_test/run_binary.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/js_compat_test/run_devserver.sh b/tests/js_compat_test/run_devserver.sh
index 21babc9..f49d455 100755
--- a/tests/js_compat_test/run_devserver.sh
+++ b/tests/js_compat_test/run_devserver.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/script_test/run_env_script.sh b/tests/script_test/run_env_script.sh
index dfa6743..bdf8130 100755
--- a/tests/script_test/run_env_script.sh
+++ b/tests/script_test/run_env_script.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/script_test/run_paraglide_monorepo_builds.sh b/tests/script_test/run_paraglide_monorepo_builds.sh
index 96c4f99..ad6cece 100755
--- a/tests/script_test/run_paraglide_monorepo_builds.sh
+++ b/tests/script_test/run_paraglide_monorepo_builds.sh
@@ -14,12 +14,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/script_test/run_script.sh b/tests/script_test/run_script.sh
index 715af61..cb8e3a1 100755
--- a/tests/script_test/run_script.sh
+++ b/tests/script_test/run_script.sh
@@ -8,12 +8,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/script_test/run_vite_app.sh b/tests/script_test/run_vite_app.sh
index 4419c68..7162413 100755
--- a/tests/script_test/run_vite_app.sh
+++ b/tests/script_test/run_vite_app.sh
@@ -19,12 +19,7 @@ start_launcher() {
local log_target="$2"
shift 2
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" >"${log_target}" 2>&1 &
+ cmd.exe /c call "${launcher}" "$@" >"${log_target}" 2>&1 &
else
"${launcher}" "$@" >"${log_target}" 2>&1 &
fi
diff --git a/tests/script_test/run_vite_monorepo_apps.sh b/tests/script_test/run_vite_monorepo_apps.sh
index d555515..d4affcb 100755
--- a/tests/script_test/run_vite_monorepo_apps.sh
+++ b/tests/script_test/run_vite_monorepo_apps.sh
@@ -22,12 +22,7 @@ start_launcher() {
local log_target="$2"
shift 2
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" >"${log_target}" 2>&1 &
+ cmd.exe /c call "${launcher}" "$@" >"${log_target}" 2>&1 &
else
"${launcher}" "$@" >"${log_target}" 2>&1 &
fi
diff --git a/tests/script_test/run_workspace_parallel.sh b/tests/script_test/run_workspace_parallel.sh
index 3ce3261..b9179fd 100755
--- a/tests/script_test/run_workspace_parallel.sh
+++ b/tests/script_test/run_workspace_parallel.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/script_test/run_workspace_script.sh b/tests/script_test/run_workspace_script.sh
index bc9da51..9b62341 100755
--- a/tests/script_test/run_workspace_script.sh
+++ b/tests/script_test/run_workspace_script.sh
@@ -7,12 +7,7 @@ run_launcher() {
local launcher="$1"
shift
if [[ ${launcher} == *.cmd ]]; then
- local command
- printf -v command '"%s"' "${launcher}"
- for arg in "$@"; do
- printf -v command '%s "%s"' "${command}" "${arg}"
- done
- cmd.exe /c "${command}" | tr -d '\r'
+ cmd.exe /c call "${launcher}" "$@" | tr -d '\r'
return 0
fi
"${launcher}" "$@"
diff --git a/tests/toolchain_test/BUILD.bazel b/tests/toolchain_test/BUILD.bazel
index 9c7a684..2768c4b 100644
--- a/tests/toolchain_test/BUILD.bazel
+++ b/tests/toolchain_test/BUILD.bazel
@@ -45,12 +45,12 @@ sh_test(
size = "small",
srcs = ["toolchain_version.sh"],
args = select({
- ":linux_x86_64": ["$(location @bun_linux_x64//:bun)"],
- ":linux_aarch64": ["$(location @bun_linux_aarch64//:bun)"],
- ":darwin_x86_64": ["$(location @bun_darwin_x64//:bun)"],
- ":darwin_aarch64": ["$(location @bun_darwin_aarch64//:bun)"],
- ":windows_x86_64": ["$(location @bun_windows_x64//:bun)"],
- "//conditions:default": ["$(location @bun_linux_x64//:bun)"],
+ ":linux_x86_64": ["$(rlocationpath @bun_linux_x64//:bun)"],
+ ":linux_aarch64": ["$(rlocationpath @bun_linux_aarch64//:bun)"],
+ ":darwin_x86_64": ["$(rlocationpath @bun_darwin_x64//:bun)"],
+ ":darwin_aarch64": ["$(rlocationpath @bun_darwin_aarch64//:bun)"],
+ ":windows_x86_64": ["$(rlocationpath @bun_windows_x64//:bun)"],
+ "//conditions:default": ["$(rlocationpath @bun_linux_x64//:bun)"],
}),
data = select({
":linux_x86_64": ["@bun_linux_x64//:bun"],
@@ -66,6 +66,6 @@ sh_test(
name = "toolchain_resolution_matrix_test",
size = "small",
srcs = ["toolchain_resolution_matrix.sh"],
- args = ["$(location //tests/toolchain_test:BUILD.bazel)"],
+ args = ["$(rlocationpath //tests/toolchain_test:BUILD.bazel)"],
data = ["//tests/toolchain_test:BUILD.bazel"],
)
diff --git a/tests/toolchain_test/toolchain_resolution_matrix.sh b/tests/toolchain_test/toolchain_resolution_matrix.sh
index 3ec8da9..577ab80 100755
--- a/tests/toolchain_test/toolchain_resolution_matrix.sh
+++ b/tests/toolchain_test/toolchain_resolution_matrix.sh
@@ -1,7 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
-build_file="$1"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+build_file="$(resolve_runfile "${1:-}")"
grep -Eq 'name = "linux_x86_64"' "${build_file}"
grep -Eq 'name = "linux_aarch64"' "${build_file}"
diff --git a/tests/toolchain_test/toolchain_version.sh b/tests/toolchain_test/toolchain_version.sh
index 73e1387..4b0be73 100755
--- a/tests/toolchain_test/toolchain_version.sh
+++ b/tests/toolchain_test/toolchain_version.sh
@@ -1,8 +1,64 @@
#!/usr/bin/env bash
set -euo pipefail
-bun_path="$1"
-version="$(${bun_path} --version)"
+if [[ -z ${RUNFILES_DIR:-} && -n ${TEST_SRCDIR:-} && -d ${TEST_SRCDIR} ]]; then
+ RUNFILES_DIR="${TEST_SRCDIR}"
+fi
+if [[ -z ${RUNFILES_DIR:-} && -z ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ if [[ -d "$0.runfiles" ]]; then
+ RUNFILES_DIR="$0.runfiles"
+ elif [[ -f "$0.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.exe.runfiles_manifest" ]]; then
+ RUNFILES_MANIFEST_FILE="$0.exe.runfiles_manifest"
+ fi
+fi
+
+resolve_runfile() {
+ local path="${1:-}"
+ local candidate
+ local resolved
+
+ if [[ -z ${path} ]]; then
+ echo "Error: missing runfile path" >&2
+ exit 1
+ fi
+ if [[ ${path} == /* || ${path} =~ ^[A-Za-z]:[\\/] ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+ if [[ -e ${path} ]]; then
+ printf '%s\n' "${path}"
+ return 0
+ fi
+
+ for candidate in \
+ "${path}" \
+ "${TEST_WORKSPACE:-}/${path}" \
+ "_main/${path}"; do
+ [[ -z ${candidate} ]] && continue
+ if [[ -n ${RUNFILES_DIR:-} && -e "${RUNFILES_DIR}/${candidate}" ]]; then
+ printf '%s\n' "${RUNFILES_DIR}/${candidate}"
+ return 0
+ fi
+ if [[ -n ${RUNFILES_MANIFEST_FILE:-} ]]; then
+ resolved="$(
+ awk -v key="${candidate}" 'index($0, key " ") == 1 { print substr($0, length(key) + 2); exit }' \
+ "${RUNFILES_MANIFEST_FILE}"
+ )"
+ if [[ -n ${resolved} ]]; then
+ printf '%s\n' "${resolved}"
+ return 0
+ fi
+ fi
+ done
+
+ echo "Error: unable to resolve runfile: ${path}" >&2
+ exit 1
+}
+
+bun_path="$(resolve_runfile "${1:-}")"
+version="$("${bun_path}" --version)"
if [[ ! ${version} =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "Unexpected bun version output: ${version}" >&2