Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,41 @@ jobs:
fi
hunk --help | grep 'Usage: hunk'

prebuilt-npm:
name: Verify prebuilt npm package (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Stage prebuilt npm packages
run: bun run build:prebuilt:npm

- name: Verify staged prebuilt packs
run: bun run check:prebuilt-pack

- name: Smoke test prebuilt global install
run: bun run smoke:prebuilt-install

build-bin:
name: Build compiled binary
runs-on: ubuntu-latest
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,14 @@ bun run build:npm
bun run check:pack
```

Stage the prototype prebuilt npm packages for the current host and smoke test the install path without Bun on `PATH`:

```bash
bun run build:prebuilt:npm
bun run check:prebuilt-pack
bun run smoke:prebuilt-install
```

## License

[MIT](LICENSE)
111 changes: 91 additions & 20 deletions bin/hunk.cjs
Original file line number Diff line number Diff line change
@@ -1,32 +1,103 @@
#!/usr/bin/env node

const { spawnSync } = require("node:child_process");
const childProcess = require("node:child_process");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");

const entrypoint = path.join(__dirname, "..", "dist", "npm", "main.js");
function run(target, args) {
const result = childProcess.spawnSync(target, args, {
stdio: "inherit",
env: process.env,
});

let bunBinary;
if (result.error) {
console.error(result.error.message);
process.exit(1);
}

process.exit(typeof result.status === "number" ? result.status : 1);
}

function hostCandidates() {
const platformMap = {
darwin: "darwin",
linux: "linux",
win32: "windows",
};
const archMap = {
x64: "x64",
arm64: "arm64",
};

const platform = platformMap[os.platform()] || os.platform();
const arch = archMap[os.arch()] || os.arch();
const binary = platform === "windows" ? "hunk.exe" : "hunk";

try {
bunBinary = require.resolve("bun/bin/bun.exe");
} catch (error) {
console.error(
"Failed to resolve the bundled Bun runtime. Try reinstalling hunkdiff.",
);
if (error && error.message) {
console.error(error.message);
if (platform === "darwin") {
if (arch === "arm64") return [{ packageName: "hunkdiff-darwin-arm64", binary }];
if (arch === "x64") return [{ packageName: "hunkdiff-darwin-x64", binary }];
}
process.exit(1);

if (platform === "linux") {
if (arch === "arm64") return [{ packageName: "hunkdiff-linux-arm64", binary }];
if (arch === "x64") return [{ packageName: "hunkdiff-linux-x64", binary }];
}

return [];
}

const result = spawnSync(bunBinary, [entrypoint, ...process.argv.slice(2)], {
stdio: "inherit",
env: process.env,
});
function findInstalledBinary(startDir) {
let current = startDir;

for (;;) {
const modulesDir = path.join(current, "node_modules");
if (fs.existsSync(modulesDir)) {
for (const candidate of hostCandidates()) {
const resolved = path.join(modulesDir, candidate.packageName, "bin", candidate.binary);
if (fs.existsSync(resolved)) {
return resolved;
}
}
}

const parent = path.dirname(current);
if (parent === current) {
return null;
}
current = parent;
}
}

function bundledBunRuntime() {
try {
return require.resolve("bun/bin/bun.exe");
} catch {
return null;
}
}

const overrideBinary = process.env.HUNK_BIN_PATH;
if (overrideBinary) {
run(overrideBinary, process.argv.slice(2));
}

const scriptDir = path.dirname(fs.realpathSync(__filename));
const prebuiltBinary = findInstalledBinary(scriptDir);
if (prebuiltBinary) {
run(prebuiltBinary, process.argv.slice(2));
}

if (result.error) {
console.error(result.error.message);
process.exit(1);
const bunBinary = bundledBunRuntime();
if (bunBinary) {
const entrypoint = path.join(__dirname, "..", "dist", "npm", "main.js");
run(bunBinary, [entrypoint, ...process.argv.slice(2)]);
}

process.exit(typeof result.status === "number" ? result.status : 1);
const printablePackages = hostCandidates().map((candidate) => `"${candidate.packageName}"`).join(" or ");
console.error(
printablePackages.length > 0
? `Failed to locate a matching prebuilt Hunk binary. Try reinstalling hunkdiff or manually installing ${printablePackages}.`
: `Unsupported platform for prebuilt Hunk binaries: ${os.platform()} ${os.arch()}`,
);
process.exit(1);
Loading
Loading