mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-26 04:25:46 +02:00
fix(desktop): exclude dist/** from multi-arch package contents
Merging after independent reviews confirmed the fix and all CI checks passed.
This commit is contained in:
@@ -8,6 +8,20 @@ files:
|
||||
- "!electron.vite.config.*"
|
||||
- "!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}"
|
||||
- "!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}"
|
||||
# Never repack the electron-builder output directory into the app.
|
||||
# Multi-arch release builds (scripts/package.mjs) run each target in the
|
||||
# same apps/desktop dir with per-arch output at dist/<platform>-<arch>.
|
||||
# electron-builder only auto-excludes the *current* target's output dir,
|
||||
# so the earlier arch's dist/ (its full .app + DMG + ZIP) would otherwise
|
||||
# be pulled into the next arch's app.asar. That inflated v0.4.3/v0.4.4's
|
||||
# Intel (x64) DMG until the HFS volume was full and the real
|
||||
# `Electron Framework/Versions/A/Electron Framework` binary was dropped,
|
||||
# so Intel Macs crashed on launch with a dyld missing-library error
|
||||
# (github.com/multica-ai/multica/issues/5595). Excluding all of dist/**
|
||||
# fixes it regardless of build order; a pre-build clean alone does not,
|
||||
# because the first arch writes into dist/ mid-run before the second is
|
||||
# packaged.
|
||||
- "!dist/**"
|
||||
protocols:
|
||||
- name: Multica
|
||||
schemes:
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
// real `git describe` invocation against a throwaway repo.
|
||||
|
||||
import { execFileSync, spawnSync } from "node:child_process";
|
||||
import { rmSync } from "node:fs";
|
||||
import { delimiter, dirname, resolve } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
|
||||
@@ -365,6 +366,17 @@ function main() {
|
||||
`[package] build matrix → ${buildMatrix.map(formatTarget).join(", ")}`,
|
||||
);
|
||||
|
||||
// Step 0: start every release from an empty output directory. Stale
|
||||
// artifacts from a prior run would otherwise be repacked into this run's
|
||||
// app.asar (see the `!dist/**` note in electron-builder.yml). This clean
|
||||
// is belt-and-braces only — it does NOT by itself prevent the same-run
|
||||
// cross-arch contamination that broke the Intel DMG, because the first
|
||||
// arch writes into dist/ mid-run before the next arch is packaged; the
|
||||
// `!dist/**` files exclusion is what actually guarantees isolation.
|
||||
const distDir = resolve(desktopRoot, "dist");
|
||||
rmSync(distDir, { recursive: true, force: true });
|
||||
console.log(`[package] cleaned output dir → ${distDir}`);
|
||||
|
||||
// Step 1: build the Electron main/preload/renderer bundles. Without
|
||||
// this step electron-builder silently packages whatever is already in
|
||||
// out/, which on a fresh checkout (or after a partial build) ships an
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { delimiter, join, resolve } from "node:path";
|
||||
import { afterEach, describe, it, expect } from "vitest";
|
||||
@@ -431,3 +431,49 @@ describe("envWithLocalBins", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("electron-builder.yml packaging config", () => {
|
||||
// Regression guard for github.com/multica-ai/multica/issues/5595. The
|
||||
// multi-arch release build writes each target's output to
|
||||
// dist/<platform>-<arch> in the same apps/desktop dir; electron-builder
|
||||
// only auto-excludes the *current* target's output dir, so without an
|
||||
// explicit `!dist/**` the earlier arch's dist/ was repacked into the next
|
||||
// arch's app.asar. That inflated the Intel (x64) DMG until its Electron
|
||||
// Framework binary was dropped and Intel Macs crashed on launch. Keep the
|
||||
// exclusion pinned so a future edit to the files list cannot drop it
|
||||
// unnoticed.
|
||||
// Resolve electron-builder.yml relative to cwd, tolerating vitest running
|
||||
// from either the desktop package dir or the repo root — import.meta.url is
|
||||
// not a file:// URL under the test transform, so avoid fileURLToPath here.
|
||||
const configPath = [
|
||||
resolve(process.cwd(), "electron-builder.yml"),
|
||||
resolve(process.cwd(), "apps/desktop/electron-builder.yml"),
|
||||
].find((candidate) => existsSync(candidate));
|
||||
|
||||
// Extract the entries of the top-level `files:` block sequence without a
|
||||
// YAML dependency: collect the ` - "…"` items that follow `files:` up to
|
||||
// the next top-level key. Commented (`#`) lines are ignored, so a
|
||||
// commented-out exclusion would (correctly) not count.
|
||||
function readFilesBlock(raw) {
|
||||
const lines = raw.split("\n");
|
||||
const start = lines.findIndex((l) => /^files:\s*$/.test(l));
|
||||
if (start === -1) return [];
|
||||
const entries = [];
|
||||
for (let i = start + 1; i < lines.length; i += 1) {
|
||||
const line = lines[i];
|
||||
if (/^\S/.test(line)) break; // next top-level key ends the block
|
||||
const trimmed = line.trim();
|
||||
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
||||
const m = trimmed.match(/^-\s*"?(.*?)"?\s*$/);
|
||||
if (m) entries.push(m[1]);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
it("excludes the dist output directory from the packaged files", () => {
|
||||
expect(configPath, "electron-builder.yml not found").toBeTruthy();
|
||||
const entries = readFilesBlock(readFileSync(configPath, "utf-8"));
|
||||
expect(entries.length).toBeGreaterThan(0);
|
||||
expect(entries).toContain("!dist/**");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user