mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Compare commits
1 Commits
v0.2.0-bet
...
fix-window
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d1ba7e3f3 |
@@ -4,12 +4,16 @@ setlocal
|
||||
set "SCRIPT_DIR=%~dp0"
|
||||
set "RESOURCES_DIR=%SCRIPT_DIR%.."
|
||||
set "APP_EXECUTABLE=%RESOURCES_DIR%\..\Paseo.exe"
|
||||
set "CLI_EXECUTABLE=%RESOURCES_DIR%\..\PaseoCli.exe"
|
||||
if not exist "%APP_EXECUTABLE%" (
|
||||
echo Bundled Paseo executable not found at %APP_EXECUTABLE% 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
if not exist "%CLI_EXECUTABLE%" (
|
||||
set "CLI_EXECUTABLE=%APP_EXECUTABLE%"
|
||||
)
|
||||
|
||||
set "ELECTRON_RUN_AS_NODE=1"
|
||||
set "PASEO_NODE_ENV=production"
|
||||
"%APP_EXECUTABLE%" --disable-warning=DEP0040 "%RESOURCES_DIR%\app.asar.unpacked\dist\daemon\node-entrypoint-runner.js" node-script "%RESOURCES_DIR%\app.asar\node_modules\@getpaseo\cli\dist\index.js" %*
|
||||
"%CLI_EXECUTABLE%" --disable-warning=DEP0040 "%RESOURCES_DIR%\app.asar.unpacked\dist\daemon\node-entrypoint-runner.js" node-script "%RESOURCES_DIR%\app.asar\node_modules\@getpaseo\cli\dist\index.js" %*
|
||||
exit /b %errorlevel%
|
||||
|
||||
@@ -4,6 +4,9 @@ const path = require("path");
|
||||
const { smokePackagedDesktopApp } = require("./smoke-packaged-desktop-app.js");
|
||||
|
||||
const EXECUTABLE_NAME = "Paseo";
|
||||
const WINDOWS_CLI_EXECUTABLE_NAME = "PaseoCli";
|
||||
const IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
|
||||
const PE_SUBSYSTEM_OFFSET_FROM_PE_HEADER = 0x5c;
|
||||
|
||||
// electron-builder arch enum → Node.js arch string
|
||||
const ARCH_MAP = { 0: "ia32", 1: "x64", 2: "armv7l", 3: "arm64", 4: "universal" };
|
||||
@@ -121,12 +124,50 @@ function fmtMB(bytes) {
|
||||
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
||||
}
|
||||
|
||||
function setWindowsExecutableSubsystem(filePath, subsystem) {
|
||||
const fd = fs.openSync(filePath, "r+");
|
||||
try {
|
||||
const dosHeader = Buffer.alloc(64);
|
||||
fs.readSync(fd, dosHeader, 0, dosHeader.length, 0);
|
||||
if (dosHeader.toString("ascii", 0, 2) !== "MZ") {
|
||||
throw new Error(`Invalid Windows executable DOS header: ${filePath}`);
|
||||
}
|
||||
|
||||
const peHeaderOffset = dosHeader.readUInt32LE(0x3c);
|
||||
const peSignature = Buffer.alloc(4);
|
||||
fs.readSync(fd, peSignature, 0, peSignature.length, peHeaderOffset);
|
||||
if (peSignature.toString("ascii") !== "PE\u0000\u0000") {
|
||||
throw new Error(`Invalid Windows executable PE header: ${filePath}`);
|
||||
}
|
||||
|
||||
const subsystemOffset = peHeaderOffset + PE_SUBSYSTEM_OFFSET_FROM_PE_HEADER;
|
||||
const subsystemBuffer = Buffer.alloc(2);
|
||||
subsystemBuffer.writeUInt16LE(subsystem);
|
||||
fs.writeSync(fd, subsystemBuffer, 0, subsystemBuffer.length, subsystemOffset);
|
||||
} finally {
|
||||
fs.closeSync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
function createWindowsCliExecutable(appOutDir) {
|
||||
const appExecutable = path.join(appOutDir, `${EXECUTABLE_NAME}.exe`);
|
||||
const cliExecutable = path.join(appOutDir, `${WINDOWS_CLI_EXECUTABLE_NAME}.exe`);
|
||||
|
||||
fs.copyFileSync(appExecutable, cliExecutable);
|
||||
setWindowsExecutableSubsystem(cliExecutable, IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
||||
console.log(`Created Windows CLI executable: ${cliExecutable}`);
|
||||
}
|
||||
|
||||
exports.default = async function afterPack(context) {
|
||||
const platform = context.electronPlatformName;
|
||||
const arch = ARCH_MAP[context.arch] || process.arch;
|
||||
|
||||
pruneNativeModules(context.appOutDir, platform, arch);
|
||||
|
||||
if (platform === "win32") {
|
||||
createWindowsCliExecutable(context.appOutDir);
|
||||
}
|
||||
|
||||
if (platform === "linux" || platform === "win32") {
|
||||
if (arch !== process.arch) {
|
||||
console.log(
|
||||
@@ -147,3 +188,6 @@ async function smokeUnpackedAppIfRequested(appOutDir) {
|
||||
appPath: appOutDir,
|
||||
});
|
||||
}
|
||||
|
||||
exports.createWindowsCliExecutable = createWindowsCliExecutable;
|
||||
exports.setWindowsExecutableSubsystem = setWindowsExecutableSubsystem;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { createRequire } from "node:module";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
describe("desktop packaging", () => {
|
||||
it("unpacks server zsh shell integration files for external shells", () => {
|
||||
@@ -33,4 +36,38 @@ describe("desktop packaging", () => {
|
||||
expect(deps[required], `${required} must be declared in dependencies`).toBe("*");
|
||||
}
|
||||
});
|
||||
|
||||
it("uses a console-subsystem executable for the bundled Windows CLI shim", () => {
|
||||
const cmd = readFileSync(join(packageRoot, "bin", "paseo.cmd"), "utf8");
|
||||
|
||||
expect(cmd).toContain("PaseoCli.exe");
|
||||
expect(cmd).toContain('"%CLI_EXECUTABLE%"');
|
||||
});
|
||||
|
||||
it("can mark the Windows CLI executable as console subsystem", () => {
|
||||
const { setWindowsExecutableSubsystem } = require(
|
||||
join(packageRoot, "scripts", "after-pack.js"),
|
||||
) as {
|
||||
setWindowsExecutableSubsystem: (filePath: string, subsystem: number) => void;
|
||||
};
|
||||
const tempDir = mkdtempSync(join(tmpdir(), "paseo-pe-subsystem-"));
|
||||
const exePath = join(tempDir, "probe.exe");
|
||||
const peHeaderOffset = 0x80;
|
||||
const subsystemOffset = peHeaderOffset + 0x5c;
|
||||
const bytes = Buffer.alloc(subsystemOffset + 2);
|
||||
bytes.write("MZ", 0, "ascii");
|
||||
bytes.writeUInt32LE(peHeaderOffset, 0x3c);
|
||||
bytes.write("PE\u0000\u0000", peHeaderOffset, "ascii");
|
||||
bytes.writeUInt16LE(2, subsystemOffset);
|
||||
writeFileSync(exePath, bytes);
|
||||
|
||||
try {
|
||||
setWindowsExecutableSubsystem(exePath, 3);
|
||||
|
||||
const patched = readFileSync(exePath);
|
||||
expect(patched.readUInt16LE(subsystemOffset)).toBe(3);
|
||||
} finally {
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user