mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(macos): package apps from paths with glob characters (#123751)
* fix(macos): handle metacharacters in framework paths * fix(ci): round boundary artifact refresh mtimes
This commit is contained in:
committed by
GitHub
parent
f9d9b9da2b
commit
b9cf0bb96f
@@ -350,7 +350,7 @@ merge_framework_machos() {
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
if /usr/bin/file "$file" | /usr/bin/grep -q "Mach-O"; then
|
||||
local rel="${file#$primary/}"
|
||||
local rel="${file#"$primary"/}"
|
||||
local primary_archs
|
||||
primary_archs=$(archs_for "$file")
|
||||
IFS=' ' read -r -a primary_arch_array <<< "$primary_archs"
|
||||
@@ -371,7 +371,7 @@ merge_framework_machos() {
|
||||
IFS=' ' read -r -a other_arch_array <<< "$other_archs"
|
||||
for arch in "${other_arch_array[@]}"; do
|
||||
if ! arch_in_list "$arch" "${primary_arch_array[@]}"; then
|
||||
local thin_file="$tmp_dir/$(echo "$rel" | tr '/' '_')-$arch"
|
||||
local thin_file="$tmp_dir/${rel//\//_}-$arch"
|
||||
/usr/bin/lipo -thin "$arch" "$other_file" -output "$thin_file"
|
||||
missing_files+=("$thin_file")
|
||||
primary_arch_array+=("$arch")
|
||||
|
||||
@@ -552,7 +552,7 @@ export function isArtifactSetFresh(params: ArtifactFreshParams) {
|
||||
}
|
||||
// Repair the mtime fast path so later invocations in this checkout skip
|
||||
// without re-reading every input byte.
|
||||
const now = new Date();
|
||||
const now = new Date(Math.max(Date.now(), Math.ceil(newestInputMtimeMs)));
|
||||
for (const relativePath of params.outputPaths) {
|
||||
const outputPath = resolve(rootDir, relativePath);
|
||||
if (fs.existsSync(outputPath)) {
|
||||
|
||||
@@ -47,6 +47,17 @@ function getPackageManagerHelperBlock(): string {
|
||||
return script.slice(start, end);
|
||||
}
|
||||
|
||||
function getMergeFrameworkMachOsBlock(): string {
|
||||
const script = readFileSync(scriptPath, "utf8");
|
||||
const start = script.indexOf("merge_framework_machos()");
|
||||
const end = script.indexOf('PEEKABOO_SOURCE_COMMIT="$(resolve_peekaboo_source_commit)"');
|
||||
|
||||
expect(start).toBeGreaterThanOrEqual(0);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
|
||||
return script.slice(start, end);
|
||||
}
|
||||
|
||||
function getSwiftToolchainBlock(): string {
|
||||
const script = readFileSync("scripts/lib/swift-toolchain.sh", "utf8");
|
||||
const start = script.indexOf("REQUIRED_SWIFT_TOOLS_MAJOR=");
|
||||
@@ -749,6 +760,57 @@ describe("package-mac-app plist stamping", () => {
|
||||
expect(helperCopy).toContain('chmod +x "$APP_ROOT/Contents/MacOS/$MLX_TTS_HELPER_PRODUCT"');
|
||||
});
|
||||
|
||||
it.runIf(process.platform === "darwin")(
|
||||
"merges framework Mach-O binaries when the checkout path contains glob metacharacters",
|
||||
() => {
|
||||
const root = tempDirs.make("openclaw-package-framework-[fixture]-");
|
||||
const primary = path.join(root, "Primary.framework");
|
||||
const secondary = path.join(root, "Secondary.framework");
|
||||
const destination = path.join(root, "Destination.framework");
|
||||
const relativeBinary = path.join("Versions", "A", "OpenClawFixture");
|
||||
|
||||
for (const framework of [primary, secondary, destination]) {
|
||||
mkdirSync(path.dirname(path.join(framework, relativeBinary)), { recursive: true });
|
||||
}
|
||||
|
||||
const fixtureBinary = "/bin/ls";
|
||||
const fixtureArchitectures = spawnSync("/usr/bin/lipo", ["-archs", fixtureBinary], {
|
||||
encoding: "utf8",
|
||||
})
|
||||
.stdout.trim()
|
||||
.split(/\s+/u);
|
||||
const [primaryArchitecture, secondaryArchitecture] = fixtureArchitectures;
|
||||
if (!primaryArchitecture || !secondaryArchitecture) {
|
||||
throw new Error(`${fixtureBinary} must contain at least two architectures`);
|
||||
}
|
||||
const primaryBinary = path.join(primary, relativeBinary);
|
||||
const secondaryBinary = path.join(secondary, relativeBinary);
|
||||
const destinationBinary = path.join(destination, relativeBinary);
|
||||
expect(
|
||||
spawnSync("/usr/bin/lipo", [
|
||||
"-thin",
|
||||
primaryArchitecture,
|
||||
fixtureBinary,
|
||||
"-output",
|
||||
primaryBinary,
|
||||
]).status,
|
||||
).toBe(0);
|
||||
expect(spawnSync("/bin/cp", [fixtureBinary, secondaryBinary]).status).toBe(0);
|
||||
writeFileSync(destinationBinary, readFileSync(primaryBinary));
|
||||
|
||||
const result = runHelper(`
|
||||
set -euo pipefail
|
||||
${getMergeFrameworkMachOsBlock()}
|
||||
merge_framework_machos ${JSON.stringify(primary)} ${JSON.stringify(destination)} ${JSON.stringify(secondary)}
|
||||
/usr/bin/lipo -info ${JSON.stringify(destinationBinary)}
|
||||
`);
|
||||
|
||||
expect(result.status, result.stderr).toBe(0);
|
||||
expect(result.stdout).toContain(primaryArchitecture);
|
||||
expect(result.stdout).toContain(secondaryArchitecture);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ title: "keeps the default backend when Xcode's Metal shim works", shimExit: 0, xcrunExit: 0 },
|
||||
{
|
||||
|
||||
@@ -583,6 +583,8 @@ describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
// Simulate checkout: inputs newer than restored outputs, bytes unchanged.
|
||||
fs.utimesSync(stampPath, new Date(1_000), new Date(1_000));
|
||||
fs.utimesSync(outputPath, new Date(1_000), new Date(1_000));
|
||||
const repairTimeMs = Date.now();
|
||||
fs.utimesSync(inputPath, repairTimeMs / 1_000, (repairTimeMs + 0.5) / 1_000);
|
||||
const freshParams = {
|
||||
rootDir,
|
||||
inputPaths: ["src"],
|
||||
@@ -590,9 +592,17 @@ describe("prepare-extension-package-boundary-artifacts", () => {
|
||||
hashStampPath: "dist/.demo.stamp",
|
||||
};
|
||||
|
||||
expect(isArtifactSetFresh(freshParams)).toBe(true);
|
||||
// The hash match repairs output mtimes so the next check takes the fast path.
|
||||
expect(fs.statSync(outputPath).mtimeMs).toBeGreaterThanOrEqual(fs.statSync(inputPath).mtimeMs);
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(repairTimeMs);
|
||||
try {
|
||||
expect(isArtifactSetFresh(freshParams)).toBe(true);
|
||||
// Round past fractional filesystem precision so the next check takes the fast path.
|
||||
expect(fs.statSync(outputPath).mtimeMs).toBeGreaterThanOrEqual(
|
||||
fs.statSync(inputPath).mtimeMs,
|
||||
);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
|
||||
fs.appendFileSync(inputPath, "export const demoTwo = 2;\n", "utf8");
|
||||
fs.utimesSync(outputPath, new Date(1_000), new Date(1_000));
|
||||
|
||||
Reference in New Issue
Block a user