Some checks failed
farmcontrol/farmcontrol-server/pipeline/head There was a failure building this commit
- Updated electrobun.config.ts to include a new postWrap script for expanding macOS bundles. - Introduced expand-macos-bundle.mjs script to handle the extraction and setup of macOS application bundles, including metadata validation and resource management. - Enhanced error handling and logging for better visibility during the expansion process.
139 lines
4.2 KiB
JavaScript
139 lines
4.2 KiB
JavaScript
import {
|
|
cpSync,
|
|
existsSync,
|
|
mkdirSync,
|
|
readFileSync,
|
|
readdirSync,
|
|
rmSync,
|
|
} from "node:fs";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { tmpdir } from "node:os";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "dev";
|
|
const targetOs = process.env.ELECTROBUN_OS || "macos";
|
|
const wrapperPath = process.env.ELECTROBUN_WRAPPER_BUNDLE_PATH;
|
|
|
|
if (buildEnv === "dev" || targetOs !== "macos") {
|
|
console.log("expand-macos-bundle: skipping (dev or non-macOS build)");
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!wrapperPath || !existsSync(wrapperPath)) {
|
|
console.error("expand-macos-bundle: ELECTROBUN_WRAPPER_BUNDLE_PATH not set or missing");
|
|
process.exit(1);
|
|
}
|
|
|
|
const resolvedWrapperPath = path.resolve(wrapperPath);
|
|
const contentsPath = path.join(resolvedWrapperPath, "Contents");
|
|
const resourcesPath = path.join(contentsPath, "Resources");
|
|
const metadataPath = path.join(resourcesPath, "metadata.json");
|
|
|
|
if (!existsSync(metadataPath)) {
|
|
console.log("expand-macos-bundle: no extractor metadata, assuming already expanded");
|
|
process.exit(0);
|
|
}
|
|
|
|
const metadata = JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
const hash = metadata.hash;
|
|
const appName = metadata.name || "Farm Control Server";
|
|
const tarZstPath = path.resolve(resourcesPath, `${hash}.tar.zst`);
|
|
|
|
if (!existsSync(tarZstPath)) {
|
|
console.log(`expand-macos-bundle: ${hash}.tar.zst not found, skipping`);
|
|
process.exit(0);
|
|
}
|
|
|
|
function findZstd() {
|
|
const fromPath = spawnSync("zstd", ["--version"], { encoding: "utf8" });
|
|
if (fromPath.status === 0) {
|
|
return "zstd";
|
|
}
|
|
|
|
const hostArch = process.arch === "arm64" ? "arm64" : "x64";
|
|
const electrobunZstd = path.join(
|
|
rootDir,
|
|
"node_modules/electrobun/dist-macos-" + hostArch,
|
|
"zig-zstd",
|
|
);
|
|
if (existsSync(electrobunZstd)) {
|
|
return electrobunZstd;
|
|
}
|
|
|
|
throw new Error(
|
|
"expand-macos-bundle: zstd not found (install zstd or use electrobun dist binaries)",
|
|
);
|
|
}
|
|
|
|
const workDir = path.join(tmpdir(), `farmcontrol-server-expand-${hash}`);
|
|
const tarPath = path.join(workDir, `${hash}.tar`);
|
|
rmSync(workDir, { recursive: true, force: true });
|
|
mkdirSync(workDir, { recursive: true });
|
|
|
|
const zstd = findZstd();
|
|
const decompress = spawnSync(zstd, ["-d", "-f", "-o", tarPath, tarZstPath], {
|
|
stdio: "inherit",
|
|
});
|
|
|
|
if (decompress.status !== 0) {
|
|
console.error("expand-macos-bundle: zstd decompression failed");
|
|
process.exit(decompress.status ?? 1);
|
|
}
|
|
|
|
const extractTar = spawnSync("tar", ["-xf", tarPath, "-C", workDir], {
|
|
stdio: "inherit",
|
|
});
|
|
|
|
if (extractTar.status !== 0) {
|
|
console.error("expand-macos-bundle: tar extraction failed");
|
|
process.exit(extractTar.status ?? 1);
|
|
}
|
|
|
|
const innerAppPath = path.join(workDir, `${appName}.app`);
|
|
if (!existsSync(innerAppPath)) {
|
|
const appBundle = readdirSync(workDir).find((entry) => entry.endsWith(".app"));
|
|
if (!appBundle) {
|
|
console.error("expand-macos-bundle: extracted app bundle not found");
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
const resolvedInnerApp = existsSync(innerAppPath)
|
|
? innerAppPath
|
|
: path.join(workDir, readdirSync(workDir).find((e) => e.endsWith(".app")));
|
|
const innerContentsPath = path.join(resolvedInnerApp, "Contents");
|
|
|
|
function replaceDirectory(sourceDir, destinationDir) {
|
|
rmSync(destinationDir, { recursive: true, force: true });
|
|
cpSync(sourceDir, destinationDir, { recursive: true, dereference: true });
|
|
}
|
|
|
|
replaceDirectory(
|
|
path.join(innerContentsPath, "MacOS"),
|
|
path.join(contentsPath, "MacOS"),
|
|
);
|
|
|
|
rmSync(resourcesPath, { recursive: true, force: true });
|
|
cpSync(path.join(innerContentsPath, "Resources"), resourcesPath, {
|
|
recursive: true,
|
|
dereference: true,
|
|
});
|
|
|
|
const innerFrameworks = path.join(innerContentsPath, "Frameworks");
|
|
const wrapperFrameworks = path.join(contentsPath, "Frameworks");
|
|
if (existsSync(innerFrameworks)) {
|
|
replaceDirectory(innerFrameworks, wrapperFrameworks);
|
|
}
|
|
|
|
cpSync(path.join(innerContentsPath, "Info.plist"), path.join(contentsPath, "Info.plist"));
|
|
|
|
rmSync(workDir, { recursive: true, force: true });
|
|
|
|
if (process.platform === "darwin") {
|
|
spawnSync("xattr", ["-cr", resolvedWrapperPath], { stdio: "inherit" });
|
|
}
|
|
|
|
console.log(`expand-macos-bundle: pre-expanded ${resolvedWrapperPath}`);
|