@invarn/cibuild 2.4.3 → 2.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +52 -30
- package/dist/src/yaml/steps/render-post-processor.d.ts +8 -4
- package/dist/src/yaml/steps/render-post-processor.d.ts.map +1 -1
- package/dist/src/yaml/steps/render-post-processor.js +49 -26
- package/dist/src/yaml/steps/render-post-processor.test.js +47 -23
- package/package.json +1 -1
|
@@ -73,14 +73,18 @@ export interface PostProcessorInternals {
|
|
|
73
73
|
/**
|
|
74
74
|
* Evaluates the embedded trim-stage source and returns its pure helpers, so
|
|
75
75
|
* unit tests exercise exactly the code that ships inside the runtime script
|
|
76
|
-
* (mirrors getRenderScriptInternals in ui-fidelity-render.ts). `cp`
|
|
77
|
-
* `
|
|
78
|
-
*
|
|
79
|
-
*
|
|
76
|
+
* (mirrors getRenderScriptInternals in ui-fidelity-render.ts). `cp`, `process`,
|
|
77
|
+
* `fs`, `os` and `path` are injectable so the invocation/spawn/copy seams are
|
|
78
|
+
* testable; at runtime the stage is spliced into the generated script where
|
|
79
|
+
* those names are `require`d globals. Uninjected deps only matter for branches
|
|
80
|
+
* that dereference them (the pkg copy path), so existing callers can omit them.
|
|
80
81
|
*/
|
|
81
82
|
export declare function getPostProcessorInternals(overrides?: {
|
|
82
83
|
cp?: unknown;
|
|
83
84
|
processRef?: unknown;
|
|
85
|
+
fs?: unknown;
|
|
86
|
+
os?: unknown;
|
|
87
|
+
path?: unknown;
|
|
84
88
|
}): PostProcessorInternals;
|
|
85
89
|
/**
|
|
86
90
|
* Resolves the on-disk JS entrypoint of this cibuild installation's CLI
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-post-processor.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/render-post-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-post-processor.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/render-post-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAuJtC,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5C,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAAC;IAC3D,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE;IACpD,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,sBAAsB,CAkBzB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAqBhD"}
|
|
@@ -72,19 +72,44 @@ function parseTrimDims(stdout) {
|
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
// Lazily copy the pkg ci binary to a scratch path so the trim can invoke it
|
|
76
|
+
// WITHOUT re-executing process.execPath. Under pkg the generated render script
|
|
77
|
+
// runs as an app-mode child of the ci binary, so process.execPath IS the ci
|
|
78
|
+
// binary -- but pkg refuses to let a binary re-invoke ITSELF as a subcommand:
|
|
79
|
+
// spawning process.execPath forces the child into Node-emulation, where
|
|
80
|
+
// 'fidelity-trim' is treated as a main-module script path ("Cannot find module
|
|
81
|
+
// '<cwd>/fidelity-trim'") and the subcommand dispatch never runs, so the trim
|
|
82
|
+
// silently no-ops and untrimmed renders ship. A COPY of the binary at a
|
|
83
|
+
// different path is NOT seen as a self-exec, so it runs the baked cli entrypoint
|
|
84
|
+
// normally (with the bundled pngjs). Copied once per run; returns null if the
|
|
85
|
+
// copy can't be made, and the caller then degrades to a best-effort no-op trim.
|
|
86
|
+
// Verified on the runner: a copy-spawn dispatches and emits TRIMDIMS, while an
|
|
87
|
+
// execPath self-exec crashes with the module-not-found above.
|
|
88
|
+
var ciTrimBinCopy;
|
|
89
|
+
function ciBinaryCopyForTrim() {
|
|
90
|
+
if (typeof ciTrimBinCopy !== 'undefined') return ciTrimBinCopy;
|
|
91
|
+
try {
|
|
92
|
+
var dest = path.join(os.tmpdir(), 'ci-fidelity-trim-bin');
|
|
93
|
+
if (!fs.existsSync(dest)) {
|
|
94
|
+
fs.copyFileSync(process.execPath, dest);
|
|
95
|
+
fs.chmodSync(dest, 493); // 0o755
|
|
96
|
+
}
|
|
97
|
+
ciTrimBinCopy = dest;
|
|
98
|
+
} catch (copyErr) {
|
|
99
|
+
ciTrimBinCopy = null;
|
|
100
|
+
}
|
|
101
|
+
return ciTrimBinCopy;
|
|
102
|
+
}
|
|
103
|
+
|
|
75
104
|
// Resolve how to reach the ci CLI's fidelity-trim helper from inside this
|
|
76
105
|
// generated script. Three homes, in order:
|
|
77
106
|
// 1. CIBUILD_CLI_JS -- an explicit JS entrypoint (preview harnesses, tests),
|
|
78
107
|
// run under the same node executing this script.
|
|
79
|
-
// 2.
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// 3. A ci on PATH (brew/npm installs)
|
|
84
|
-
// precisely because process.pkg is undefined under Node-emulation.
|
|
85
|
-
// Whichever home resolves, runTrimHelper strips PKG_EXECPATH from the child env
|
|
86
|
-
// so the spawned pkg binary dispatches the subcommand instead of re-entering
|
|
87
|
-
// Node-emulation. See runTrimHelper.
|
|
108
|
+
// 2. Under pkg (the production runner path) process.execPath IS the ci binary,
|
|
109
|
+
// but pkg won't let it re-invoke itself as a subcommand, so spawn a COPY of
|
|
110
|
+
// it (see ciBinaryCopyForTrim). Fall back to the (best-effort) self-exec if
|
|
111
|
+
// the copy can't be made.
|
|
112
|
+
// 3. A ci on PATH (brew/npm installs) when not running under pkg.
|
|
88
113
|
function trimHelperInvocation(args) {
|
|
89
114
|
if (process.env.CIBUILD_CLI_JS) {
|
|
90
115
|
return {
|
|
@@ -93,7 +118,11 @@ function trimHelperInvocation(args) {
|
|
|
93
118
|
};
|
|
94
119
|
}
|
|
95
120
|
if (process.pkg) {
|
|
96
|
-
|
|
121
|
+
var copy = ciBinaryCopyForTrim();
|
|
122
|
+
return {
|
|
123
|
+
cmd: copy === null ? process.execPath : copy,
|
|
124
|
+
args: ['fidelity-trim'].concat(args),
|
|
125
|
+
};
|
|
97
126
|
}
|
|
98
127
|
return { cmd: 'ci', args: ['fidelity-trim'].concat(args) };
|
|
99
128
|
}
|
|
@@ -102,16 +131,9 @@ function trimHelperInvocation(args) {
|
|
|
102
131
|
// stdout line, and exit codes are the retired CoreGraphics helper's contract).
|
|
103
132
|
function runTrimHelper(args) {
|
|
104
133
|
var invocation = trimHelperInvocation(args);
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// or a 'ci' resolved on PATH); a child that inherits PKG_EXECPATH re-enters
|
|
109
|
-
// Node-emulation and treats 'fidelity-trim' as a main-module script path
|
|
110
|
-
// ("Cannot find module '<cwd>/fidelity-trim'") instead of dispatching the
|
|
111
|
-
// subcommand -- so the trim silently no-ops and untrimmed renders ship. Strip
|
|
112
|
-
// PKG_EXECPATH from the child env so the binary runs its baked cli entrypoint
|
|
113
|
-
// (verified: 'env -u PKG_EXECPATH ci fidelity-trim' dispatches; inheriting
|
|
114
|
-
// PKG_INVOKE_NODEJS reproduces the crash).
|
|
134
|
+
// Strip pkg's node-invoke sentinel (PKG_EXECPATH) from the child env as a
|
|
135
|
+
// belt-and-suspenders alongside the copy-binary indirection above, so the
|
|
136
|
+
// spawned ci runs its baked cli entrypoint and dispatches the subcommand.
|
|
115
137
|
var childEnv = Object.assign({}, process.env);
|
|
116
138
|
delete childEnv.PKG_EXECPATH;
|
|
117
139
|
var result = cp.spawnSync(invocation.cmd, invocation.args, {
|
|
@@ -174,16 +196,17 @@ function trimRenderedImage(entry, renderedPath) {
|
|
|
174
196
|
/**
|
|
175
197
|
* Evaluates the embedded trim-stage source and returns its pure helpers, so
|
|
176
198
|
* unit tests exercise exactly the code that ships inside the runtime script
|
|
177
|
-
* (mirrors getRenderScriptInternals in ui-fidelity-render.ts). `cp`
|
|
178
|
-
* `
|
|
179
|
-
*
|
|
180
|
-
*
|
|
199
|
+
* (mirrors getRenderScriptInternals in ui-fidelity-render.ts). `cp`, `process`,
|
|
200
|
+
* `fs`, `os` and `path` are injectable so the invocation/spawn/copy seams are
|
|
201
|
+
* testable; at runtime the stage is spliced into the generated script where
|
|
202
|
+
* those names are `require`d globals. Uninjected deps only matter for branches
|
|
203
|
+
* that dereference them (the pkg copy path), so existing callers can omit them.
|
|
181
204
|
*/
|
|
182
205
|
export function getPostProcessorInternals(overrides) {
|
|
183
|
-
const factory = new Function('cp', 'process', RENDER_SCRIPT_TRIM_STAGE +
|
|
206
|
+
const factory = new Function('cp', 'process', 'fs', 'os', 'path', RENDER_SCRIPT_TRIM_STAGE +
|
|
184
207
|
'\nreturn { parseTrimDims: parseTrimDims, roundTwo: roundTwo, ' +
|
|
185
208
|
'trimHelperInvocation: trimHelperInvocation, runTrimHelper: runTrimHelper };');
|
|
186
|
-
return factory(overrides?.cp, overrides?.processRef ?? process);
|
|
209
|
+
return factory(overrides?.cp, overrides?.processRef ?? process, overrides?.fs, overrides?.os, overrides?.path);
|
|
187
210
|
}
|
|
188
211
|
/**
|
|
189
212
|
* Resolves the on-disk JS entrypoint of this cibuild installation's CLI
|
|
@@ -76,18 +76,52 @@ describe('trim stage — helper invocation resolution', () => {
|
|
|
76
76
|
args: ['/opt/cibuild/cli.cjs', 'fidelity-trim', 'in.png', 'out.png'],
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
// Under pkg (the production runner path — process.pkg IS set, verified on the
|
|
80
|
+
// runner), process.execPath IS the ci binary, and pkg REFUSES to let a binary
|
|
81
|
+
// re-invoke itself as a subcommand: spawning process.execPath forces the child
|
|
82
|
+
// into Node-emulation, where 'fidelity-trim' becomes a main-module script path
|
|
83
|
+
// ("Cannot find module '<cwd>/fidelity-trim'") and the dispatch never runs —
|
|
84
|
+
// the trim silently no-ops and untrimmed renders ship. A COPY of the binary at
|
|
85
|
+
// a different path is not a self-exec, so it runs the baked cli entrypoint.
|
|
86
|
+
// (Verified on the runner: copy-spawn dispatches + emits TRIMDIMS.)
|
|
87
|
+
function pkgInternals(opts) {
|
|
88
|
+
const copyCalls = [];
|
|
89
|
+
const fakeFs = {
|
|
90
|
+
existsSync: () => false,
|
|
91
|
+
copyFileSync: (src, dest) => {
|
|
92
|
+
copyCalls.push([src, dest]);
|
|
93
|
+
if (opts?.copyThrows)
|
|
94
|
+
throw new Error('EACCES');
|
|
95
|
+
},
|
|
96
|
+
chmodSync: () => { },
|
|
97
|
+
};
|
|
98
|
+
const fakeOs = { tmpdir: () => '/scratch' };
|
|
99
|
+
const fakePath = { join: (...parts) => parts.join('/') };
|
|
100
|
+
const internals = getPostProcessorInternals({
|
|
101
|
+
processRef: { env: {}, pkg: {}, execPath: '/opt/homebrew/bin/ci' },
|
|
102
|
+
fs: fakeFs,
|
|
103
|
+
os: fakeOs,
|
|
104
|
+
path: fakePath,
|
|
84
105
|
});
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
return { internals, copyCalls };
|
|
107
|
+
}
|
|
108
|
+
test('under pkg it spawns a COPY of the binary (not process.execPath)', () => {
|
|
109
|
+
const { internals, copyCalls } = pkgInternals();
|
|
110
|
+
expect(internals.trimHelperInvocation(['in.png', 'out.png', 'aligned.png', 'ref.png'])).toEqual({
|
|
111
|
+
cmd: '/scratch/ci-fidelity-trim-bin',
|
|
87
112
|
args: ['fidelity-trim', 'in.png', 'out.png', 'aligned.png', 'ref.png'],
|
|
88
113
|
});
|
|
114
|
+
// The copy is made once, from process.execPath.
|
|
115
|
+
expect(copyCalls).toEqual([['/opt/homebrew/bin/ci', '/scratch/ci-fidelity-trim-bin']]);
|
|
116
|
+
});
|
|
117
|
+
test('under pkg it degrades to process.execPath when the binary copy fails', () => {
|
|
118
|
+
const { internals } = pkgInternals({ copyThrows: true });
|
|
119
|
+
expect(internals.trimHelperInvocation(['in.png', 'out.png'])).toEqual({
|
|
120
|
+
cmd: '/opt/homebrew/bin/ci',
|
|
121
|
+
args: ['fidelity-trim', 'in.png', 'out.png'],
|
|
122
|
+
});
|
|
89
123
|
});
|
|
90
|
-
test('falls back to a ci on PATH', () => {
|
|
124
|
+
test('falls back to a ci on PATH when not running under pkg', () => {
|
|
91
125
|
const { trimHelperInvocation } = internalsWith({
|
|
92
126
|
env: {},
|
|
93
127
|
execPath: '/usr/local/bin/node',
|
|
@@ -97,21 +131,11 @@ describe('trim stage — helper invocation resolution', () => {
|
|
|
97
131
|
args: ['fidelity-trim', 'in.png', 'out.png'],
|
|
98
132
|
});
|
|
99
133
|
});
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
// node-invoke sentinel (PKG_EXECPATH=PKG_INVOKE_NODEJS); whichever home is
|
|
106
|
-
// spawned is the pkg binary, and a child that inherits PKG_EXECPATH re-enters
|
|
107
|
-
// Node-emulation and treats 'fidelity-trim' as a main-module script path
|
|
108
|
-
// ("Cannot find module '<cwd>/fidelity-trim'") instead of dispatching the
|
|
109
|
-
// subcommand — the exact production failure, which silently ships untrimmed
|
|
110
|
-
// renders. runTrimHelper must strip PKG_EXECPATH from the child env
|
|
111
|
-
// regardless of which home resolved, so the binary runs its baked cli
|
|
112
|
-
// entrypoint. (Verified out-of-band: `env -u PKG_EXECPATH ci fidelity-trim`
|
|
113
|
-
// dispatches; inheriting PKG_INVOKE_NODEJS reproduces the crash.)
|
|
114
|
-
test('runTrimHelper strips PKG_EXECPATH from the child env so the ci re-exec dispatches', () => {
|
|
134
|
+
// runTrimHelper strips pkg's node-invoke sentinel (PKG_EXECPATH) from the child
|
|
135
|
+
// env as belt-and-suspenders alongside the copy-binary indirection, so the
|
|
136
|
+
// spawned ci runs its baked cli entrypoint rather than re-entering
|
|
137
|
+
// Node-emulation. (Exercised here via the non-pkg `ci` home for a simple seam.)
|
|
138
|
+
test('runTrimHelper strips PKG_EXECPATH from the child env', () => {
|
|
115
139
|
const calls = [];
|
|
116
140
|
const fakeCp = {
|
|
117
141
|
spawnSync: (...args) => {
|