fix(brew): unbreak the generated homebrew formula install
Render Formula/omp.rb with two changes so the formula actually installs: - Stamp `using: :nounzip` on every per-platform `url` stanza so Homebrew leaves the downloaded bare Mach-O/ELF asset in the staging CWD; the default `CurlDownloadStrategy` was routing through `UnpackStrategy::Uncompressed#extract_nestedly`, nesting the file outside CWD so `Dir["omp-*"].first` returned `nil` and `bin.install nil => "omp"` raised. - Wrap `generate_completions_from_executable` in `with_env(HOME: buildpath)` so the popened binary's `os.homedir()` resolves into the writable staging dir instead of the real `/Users/<user>/.omp`, which Homebrew's sandbox profile denies read access to. Also export `renderFormula` (gated by `import.meta.main`) and add a unit test that pins the rendered stanza shape for future regressions. Fixes #2398
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### Fixed
|
||||
|
||||
- Collab links now dot-join the room secret (`<roomId>.<key>`, `host/r/<roomId>.<key>`) instead of using a second `#`: RFC 3986 forbids a raw `#` inside a URL fragment, so macOS Foundation (behind terminal click-to-open) percent-encoded the browser deep link's second `#` to `%23` and the web client rejected the session. `/join`, `omp join`, and the web client still accept legacy `#`-joined links and leniently decode `%23`-mangled ones
|
||||
- Fixed `brew install can1357/tap/omp` failing on macOS with `sandbox-exec … exited with 1`: the generated `Formula/omp.rb` (rendered by `scripts/ci-update-brew-formula.ts`) now stamps `using: :nounzip` on every per-platform `url` so Homebrew leaves the bare Mach-O/ELF asset in the staging CWD (the previous `Dir["omp-*"].first` returned `nil` because `UnpackStrategy::Uncompressed#extract_nestedly` nested the file outside it), and wraps `generate_completions_from_executable` in `with_env(HOME: buildpath)` so the popened binary's `~/.omp` lookup goes to the writable staging dir instead of the sandbox-denied real home ([#2398](https://github.com/can1357/oh-my-pi/issues/2398))
|
||||
|
||||
## [15.12.1] - 2026-06-12
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { renderFormula } from "./ci-update-brew-formula";
|
||||
|
||||
const SUMS = {
|
||||
"omp-darwin-arm64": "darwin_arm64_sha",
|
||||
"omp-darwin-x64": "darwin_x64_sha",
|
||||
"omp-linux-arm64": "linux_arm64_sha",
|
||||
"omp-linux-x64": "linux_x64_sha",
|
||||
};
|
||||
|
||||
describe("renderFormula", () => {
|
||||
const formula = renderFormula("15.12.1", SUMS);
|
||||
|
||||
// Regression: bare-binary URLs must opt out of Homebrew's UnpackStrategy.
|
||||
// Without `using: :nounzip` the default CurlDownloadStrategy nests the file
|
||||
// outside the staging CWD, `Dir["omp-*"].first` returns `nil`, and
|
||||
// `bin.install nil => "omp"` raises (issue #2398).
|
||||
it("attaches `using: :nounzip` to every per-platform url stanza", () => {
|
||||
const matches = formula.match(/using: :nounzip/g) ?? [];
|
||||
expect(matches).toHaveLength(4);
|
||||
for (const arch of ["omp-darwin-arm64", "omp-darwin-x64", "omp-linux-arm64", "omp-linux-x64"]) {
|
||||
expect(formula).toMatch(
|
||||
new RegExp(
|
||||
`url "https://github\\.com/[^"]+/${arch}",\\s+using: :nounzip\\s+sha256 "${SUMS[arch as keyof typeof SUMS]}"`,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Regression: completions generation must run with HOME redirected so the
|
||||
// popened binary doesn't touch the real `~/.omp` (denied by Homebrew's
|
||||
// sandbox profile) during the build (issue #2398).
|
||||
it("wraps `generate_completions_from_executable` with a HOME redirect to buildpath", () => {
|
||||
expect(formula).toMatch(
|
||||
/with_env\(HOME: buildpath\) do\n\s+generate_completions_from_executable\(bin\/"omp", "completions", shells: \[:bash, :zsh, :fish\]\)\n\s+end/,
|
||||
);
|
||||
// And the bare form (which is what failed in the sandbox) must not appear
|
||||
// outside the `with_env` block.
|
||||
const blockless = formula.replace(/with_env\(HOME: buildpath\) do[\s\S]*?end/, "");
|
||||
expect(blockless).not.toMatch(/generate_completions_from_executable/);
|
||||
});
|
||||
|
||||
it("emits the expected per-asset sha256 next to each url", () => {
|
||||
for (const name in SUMS) {
|
||||
const sha = SUMS[name as keyof typeof SUMS];
|
||||
expect(formula).toContain(`/${name}",`);
|
||||
expect(formula).toContain(`sha256 "${sha}"`);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -54,7 +54,17 @@ function sha256For(assets: readonly ReleaseAsset[], name: string): string {
|
||||
|
||||
// `${...}` is JS interpolation; the literal `#{version}` / `#{bin}` below are
|
||||
// Ruby interpolations Homebrew resolves when it evaluates the formula.
|
||||
function renderFormula(version: string, sums: Record<string, string>): string {
|
||||
export function renderFormula(version: string, sums: Record<string, string>): string {
|
||||
// Each `url` carries `using: :nounzip` because the release assets are bare
|
||||
// Mach-O/ELF executables, not archives. Without it Homebrew's default
|
||||
// CurlDownloadStrategy routes through UnpackStrategy::Uncompressed#extract_nestedly,
|
||||
// which nests the file outside the staging CWD; `Dir["omp-*"].first` then
|
||||
// returns `nil` and `bin.install nil => "omp"` raises.
|
||||
//
|
||||
// `with_env(HOME: buildpath)` redirects the CLI's `os.homedir()` lookup to
|
||||
// the writable staging dir so `generate_completions_from_executable` does
|
||||
// not touch the real `/Users/<user>/.omp` (denied by Homebrew's sandbox
|
||||
// profile, which would otherwise fail the popen).
|
||||
return `class Omp < Formula
|
||||
desc "${DESC}"
|
||||
homepage "${HOMEPAGE}"
|
||||
@@ -63,22 +73,26 @@ function renderFormula(version: string, sums: Record<string, string>): string {
|
||||
|
||||
on_macos do
|
||||
on_arm do
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-darwin-arm64"
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-darwin-arm64",
|
||||
using: :nounzip
|
||||
sha256 "${sums["omp-darwin-arm64"]}"
|
||||
end
|
||||
on_intel do
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-darwin-x64"
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-darwin-x64",
|
||||
using: :nounzip
|
||||
sha256 "${sums["omp-darwin-x64"]}"
|
||||
end
|
||||
end
|
||||
|
||||
on_linux do
|
||||
on_arm do
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-linux-arm64"
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-linux-arm64",
|
||||
using: :nounzip
|
||||
sha256 "${sums["omp-linux-arm64"]}"
|
||||
end
|
||||
on_intel do
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-linux-x64"
|
||||
url "https://github.com/${REPO}/releases/download/v#{version}/omp-linux-x64",
|
||||
using: :nounzip
|
||||
sha256 "${sums["omp-linux-x64"]}"
|
||||
end
|
||||
end
|
||||
@@ -86,8 +100,10 @@ function renderFormula(version: string, sums: Record<string, string>): string {
|
||||
def install
|
||||
bin.install Dir["omp-*"].first => "omp"
|
||||
(bin/"omp").chmod 0555
|
||||
with_env(HOME: buildpath) do
|
||||
generate_completions_from_executable(bin/"omp", "completions", shells: [:bash, :zsh, :fish])
|
||||
end
|
||||
end
|
||||
|
||||
test do
|
||||
assert_match version.to_s, shell_output("#{bin}/omp --version")
|
||||
@@ -114,4 +130,6 @@ async function main(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
await main();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user