mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
Adds a new `--to zip` (and `--to all`) tools-pack Windows build target that produces a portable `.zip` from the cached `win-unpacked` tree using the bundled 7z. The zip lays files at the archive root so users can extract it anywhere and launch `Open Design.exe` without going through the NSIS installer, addressing the no-install download request. Release plumbing is updated to publish the portable zip and its sha256 beside the existing installer on R2 for beta, preview, and stable channels (default on, gated by `WINDOWS_INCLUDE_ZIP`/`WIN_INCLUDE_ZIP`). The electron-updater `latest.yml` feed continues to point only at the installer; the zip is a manual-download convenience and is intentionally excluded from the in-app updater. Closes #1121 Generated-By: looper 0.0.0-dev (runner=worker, agent=claude-code) Co-authored-by: libertecode <libertecode@proton.me>
237 lines
8.2 KiB
TypeScript
237 lines
8.2 KiB
TypeScript
import { cac } from "cac";
|
|
import type { CAC } from "cac";
|
|
|
|
import { resolveToolPackConfig, type ToolPackCliOptions, type ToolPackPlatform } from "./config.js";
|
|
import {
|
|
cleanupPackedMacNamespace,
|
|
installPackedMacDmg,
|
|
inspectPackedMacApp,
|
|
packMac,
|
|
readPackedMacLogs,
|
|
startPackedMacApp,
|
|
stopPackedMacApp,
|
|
uninstallPackedMacApp,
|
|
} from "./mac/index.js";
|
|
import {
|
|
cleanupPackedWinNamespace,
|
|
installPackedWinApp,
|
|
inspectPackedWinApp,
|
|
listPackedWinNamespaces,
|
|
packWin,
|
|
readPackedWinLogs,
|
|
resetPackedWinNamespaces,
|
|
startPackedWinApp,
|
|
stopPackedWinApp,
|
|
uninstallPackedWinApp,
|
|
} from "./win/index.js";
|
|
import {
|
|
cleanupPackedLinuxNamespace,
|
|
installPackedLinuxApp,
|
|
installPackedLinuxHeadless,
|
|
inspectPackedLinuxApp,
|
|
packLinux,
|
|
readPackedLinuxLogs,
|
|
resolveLinuxLifecycleMode,
|
|
startPackedLinuxApp,
|
|
startPackedLinuxHeadless,
|
|
stopPackedLinuxApp,
|
|
stopPackedLinuxHeadless,
|
|
uninstallPackedLinuxApp,
|
|
uninstallPackedLinuxHeadless,
|
|
} from "./linux.js";
|
|
|
|
type CliOptions = ToolPackCliOptions;
|
|
|
|
function printJson(payload: unknown): void {
|
|
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
}
|
|
|
|
function printLogs(result: { logs: Record<string, { lines: string[]; logPath: string }>; namespace: string }, options: CliOptions): void {
|
|
if (options.json === true) {
|
|
printJson(result);
|
|
return;
|
|
}
|
|
|
|
for (const [app, entry] of Object.entries(result.logs)) {
|
|
process.stdout.write(`[${app}] ${entry.logPath}\n`);
|
|
process.stdout.write(entry.lines.length > 0 ? `${entry.lines.join("\n")}\n` : "(no log lines)\n");
|
|
}
|
|
}
|
|
|
|
type CacCommand = ReturnType<CAC["command"]>;
|
|
|
|
function addSharedOptions(command: CacCommand) {
|
|
return command
|
|
.option("--cache-dir <path>", "tools-pack cache directory")
|
|
.option("--dir <path>", "tools-pack root directory")
|
|
.option("--json", "print JSON")
|
|
.option("--namespace <name>", "runtime namespace")
|
|
.option("--expr <expression>", "desktop inspect eval expression")
|
|
.option("--path <path>", "desktop inspect screenshot path")
|
|
.option("--update-action <action>", "desktop update action: status|check|download|install");
|
|
}
|
|
|
|
// Per-platform `--to` help text mirroring resolveToolPackBuildOutput in
|
|
// config.ts. Keep these in sync: the resolver throws on any value not listed
|
|
// here for the given platform.
|
|
const TO_HELP_BY_PLATFORM: Record<ToolPackPlatform, string> = {
|
|
linux: "build target: all|appimage|dir (default: all)",
|
|
mac: "build target: all|app|dmg|zip (default: all)",
|
|
win: "build target: all|dir|nsis|zip (default: nsis). `zip` produces a portable zip from the unpacked build; `all` produces dir+nsis+zip.",
|
|
};
|
|
|
|
function addBuildOptions(command: CacCommand, platform: ToolPackPlatform) {
|
|
return command
|
|
.option("--app-version <version>", "override packaged app version for release artifacts")
|
|
.option("--portable", "do not bake local tools-pack runtime roots into the packaged config")
|
|
.option("--signed", "build a signed/notarized mac artifact")
|
|
.option("--to <target>", TO_HELP_BY_PLATFORM[platform]);
|
|
}
|
|
|
|
function addMacBuildOptions(command: CacCommand) {
|
|
return addBuildOptions(command, "mac")
|
|
.option("--mac-compression <mode>", "mac artifact compression: normal|maximum|store (default: normal)");
|
|
}
|
|
|
|
function addWinLifecycleOptions(command: CacCommand) {
|
|
return command
|
|
.option("--remove-data", "remove packaged data during uninstall/reset/cleanup")
|
|
.option("--remove-logs", "remove packaged logs during uninstall/reset/cleanup")
|
|
.option("--remove-product-user-data", "remove the public Electron app userData root during Windows uninstall/reset/cleanup")
|
|
.option("--remove-sidecars", "remove packaged sidecar runtime during uninstall/reset/cleanup")
|
|
.option("--silent", "run installer/uninstaller silently", { default: true });
|
|
}
|
|
|
|
const cli = cac("tools-pack");
|
|
|
|
addMacBuildOptions(addSharedOptions(cli.command("mac <action>", "Mac packaging commands: build|install|start|stop|logs|uninstall|cleanup|inspect"))).action(
|
|
async (action: string, options: CliOptions) => {
|
|
const config = resolveToolPackConfig("mac", options);
|
|
switch (action) {
|
|
case "build":
|
|
printJson(await packMac(config));
|
|
return;
|
|
case "install":
|
|
printJson(await installPackedMacDmg(config));
|
|
return;
|
|
case "start":
|
|
printJson(await startPackedMacApp(config));
|
|
return;
|
|
case "stop":
|
|
printJson(await stopPackedMacApp(config));
|
|
return;
|
|
case "logs":
|
|
printLogs(await readPackedMacLogs(config), options);
|
|
return;
|
|
case "inspect":
|
|
printJson(await inspectPackedMacApp(config, options));
|
|
return;
|
|
case "uninstall":
|
|
printJson(await uninstallPackedMacApp(config));
|
|
return;
|
|
case "cleanup":
|
|
printJson(await cleanupPackedMacNamespace(config));
|
|
return;
|
|
default:
|
|
throw new Error(`unsupported mac action: ${action}`);
|
|
}
|
|
},
|
|
);
|
|
|
|
addWinLifecycleOptions(
|
|
addBuildOptions(
|
|
addSharedOptions(
|
|
cli.command(
|
|
"win <action>",
|
|
"Windows packaging commands: build|install|start|stop|logs|uninstall|cleanup|list|reset|inspect",
|
|
),
|
|
),
|
|
"win",
|
|
),
|
|
).action(async (action: string, options: CliOptions) => {
|
|
const config = resolveToolPackConfig("win", options);
|
|
switch (action) {
|
|
case "build":
|
|
printJson(await packWin(config));
|
|
return;
|
|
case "install":
|
|
printJson(await installPackedWinApp(config));
|
|
return;
|
|
case "start":
|
|
printJson(await startPackedWinApp(config));
|
|
return;
|
|
case "stop":
|
|
printJson(await stopPackedWinApp(config));
|
|
return;
|
|
case "logs":
|
|
printLogs(await readPackedWinLogs(config), options);
|
|
return;
|
|
case "uninstall":
|
|
printJson(await uninstallPackedWinApp(config));
|
|
return;
|
|
case "cleanup":
|
|
printJson(await cleanupPackedWinNamespace(config));
|
|
return;
|
|
case "list":
|
|
printJson(await listPackedWinNamespaces(config));
|
|
return;
|
|
case "reset":
|
|
printJson(await resetPackedWinNamespaces(config));
|
|
return;
|
|
case "inspect":
|
|
printJson(await inspectPackedWinApp(config, options));
|
|
return;
|
|
default:
|
|
throw new Error(`unsupported win action: ${action}`);
|
|
}
|
|
});
|
|
|
|
addBuildOptions(addSharedOptions(cli.command("linux <action>", "Linux packaging commands: build|install|start|stop|logs|uninstall|cleanup|inspect")), "linux")
|
|
.option("--containerized", "build inside electronuserland/builder Docker for wider glibc compatibility")
|
|
.option("--headless", "install/start/stop/uninstall/cleanup the headless entry; inspect returns status only")
|
|
.action(async (action: string, options: CliOptions) => {
|
|
const config = resolveToolPackConfig("linux", options);
|
|
switch (action) {
|
|
case "build":
|
|
printJson(await packLinux(config));
|
|
return;
|
|
case "install": {
|
|
const mode = resolveLinuxLifecycleMode(options, "install");
|
|
printJson(await (mode === "headless" ? installPackedLinuxHeadless(config) : installPackedLinuxApp(config)));
|
|
return;
|
|
}
|
|
case "start": {
|
|
const mode = resolveLinuxLifecycleMode(options, "start");
|
|
printJson(await (mode === "headless" ? startPackedLinuxHeadless(config) : startPackedLinuxApp(config)));
|
|
return;
|
|
}
|
|
case "stop": {
|
|
const mode = resolveLinuxLifecycleMode(options, "stop");
|
|
printJson(await (mode === "headless" ? stopPackedLinuxHeadless(config) : stopPackedLinuxApp(config)));
|
|
return;
|
|
}
|
|
case "logs":
|
|
printLogs(await readPackedLinuxLogs(config), options);
|
|
return;
|
|
case "inspect":
|
|
printJson(await inspectPackedLinuxApp(config, {
|
|
expr: options.expr,
|
|
headless: options.headless === true,
|
|
path: options.path,
|
|
}));
|
|
return;
|
|
case "uninstall": {
|
|
const mode = resolveLinuxLifecycleMode(options, "uninstall");
|
|
printJson(await (mode === "headless" ? uninstallPackedLinuxHeadless(config) : uninstallPackedLinuxApp(config)));
|
|
return;
|
|
}
|
|
case "cleanup":
|
|
printJson(await cleanupPackedLinuxNamespace(config, options));
|
|
return;
|
|
default:
|
|
throw new Error(`unsupported linux action: ${action}`);
|
|
}
|
|
});
|
|
|
|
cli.help();
|
|
cli.parse();
|