Dependency acquisition during packaging left native wheels and packager inputs outside the pre-build cache save. Compose PM and existing providers into a preparation phase, then require builds to consume admitted inputs. Share native preparation with PM Bundle. Keep path-bound environments and signing outputs separate from reusable caches. Use read-only cache tokens for commit builds and preserve the one-command local build path. Verify pinned tools through PM, probe PTYs under the prepared Electron, and supply dmgbuild through a build-only PM package. Resolve bundled tool stores from their payload manifest so relocation preserves discovery. Validation: focused Python and JS tests, checkJs, Ruff, Windows checks, anti-slop, cache relocation, and network-denied Linux AppImage builds. Relocated runtime smoke passed with NixOS host libraries supplied. Native Windows/macOS signing and live GitHub cache behavior remain untested.
82 lines
4.1 KiB
JavaScript
82 lines
4.1 KiB
JavaScript
// Standalone bundle jobs need the same tools as electron-builder, even when
|
|
// GitHub evicts the build cache before the publishing job starts.
|
|
import fs from 'node:fs'
|
|
import { createRequire } from 'node:module'
|
|
import path from 'node:path'
|
|
import { pathToFileURL } from 'node:url'
|
|
|
|
import { readPackagingInputs, preparationRequired } from './prepared-packaging.mjs'
|
|
|
|
const require = createRequire(import.meta.url)
|
|
|
|
/** @typedef {{ makeappx: string, signtool: string, dlib: string | null, dotnetRoot: string | null }} WindowsBundleTools */
|
|
/** @typedef {{ WIN_CODESIGN_LATEST: string, getWindowsKitsBundle: (options: {winCodeSign?: NonNullable<import('app-builder-lib').Configuration['toolsets']>['winCodeSign'], resourcesDir: string}) => Promise<{kit: string}>, getAtsBundleDir: (version: string) => Promise<string>, getDotnetRuntimeDir: (version: string) => Promise<string> }} BuilderWindowsTools */
|
|
|
|
/** @returns {Promise<BuilderWindowsTools>} */
|
|
async function loadBuilderTools() {
|
|
// app-builder-lib exports only its entry and ./internal. Resolve the
|
|
// installed, lock-pinned package before loading its toolset implementation.
|
|
const entry = pathToFileURL(require.resolve('app-builder-lib'))
|
|
return import(new URL('./toolsets/winCodeSign.js', entry).href)
|
|
}
|
|
|
|
/** @param {import("app-builder-lib").Configuration} config @returns {string} */
|
|
function defaultResourcesDir(config) {
|
|
return path.resolve(import.meta.dirname, "..", config.directories?.buildResources || "build")
|
|
}
|
|
|
|
/** @param {string} manifest @param {string} source @param {boolean} signing @param {string | undefined} target @returns {WindowsBundleTools} */
|
|
function consumeWindowsBundleTools(manifest, source, signing, target) {
|
|
const result = readPackagingInputs(manifest, source, target).windows
|
|
if (!result || (signing && (!result.dlib || !result.dotnetRoot))) throw preparationRequired('Missing prepared Windows signing tools')
|
|
for (const file of [result.makeappx, result.signtool, ...(signing ? [result.dlib] : [])]) {
|
|
if (!file || !fs.statSync(file).isFile()) throw preparationRequired(`Missing prepared Windows tool: ${file}`)
|
|
}
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* @param {{ signing?: boolean, config?: import('app-builder-lib').Configuration, resourcesDir?: string, load?: () => Promise<BuilderWindowsTools>, prepared?: string | null, source?: string, target?: string }} [options]
|
|
* @returns {Promise<WindowsBundleTools>}
|
|
*/
|
|
export async function ensureWindowsBundleTools({
|
|
signing = false,
|
|
config = require('../electron-builder.config.cjs'),
|
|
resourcesDir = defaultResourcesDir(config),
|
|
load = loadBuilderTools,
|
|
prepared = process.env.HERMES_PREPARED_PACKAGING,
|
|
source = path.resolve(import.meta.dirname, '../../..'),
|
|
target = process.env.HERMES_PREPARED_TARGET,
|
|
} = {}) {
|
|
if (prepared) return consumeWindowsBundleTools(prepared, source, signing, target)
|
|
const builder = await load()
|
|
const configured = config.toolsets?.winCodeSign
|
|
const { kit } = await builder.getWindowsKitsBundle({ winCodeSign: configured, resourcesDir })
|
|
/** @type {WindowsBundleTools} */
|
|
const result = {
|
|
makeappx: path.join(kit, 'makeappx.exe'),
|
|
signtool: path.join(kit, 'signtool.exe'),
|
|
dlib: null,
|
|
dotnetRoot: null,
|
|
}
|
|
if (signing) {
|
|
if (configured != null && typeof configured === 'object') {
|
|
// This is electron-builder's custom-toolset contract: the owner
|
|
// provides the dlib alongside the kit and manages its runtime.
|
|
result.dlib = path.join(kit, 'Azure.CodeSigning.Dlib.dll')
|
|
} else {
|
|
const version = configured == null || configured === 'latest' ? builder.WIN_CODESIGN_LATEST : configured
|
|
const ats = await builder.getAtsBundleDir(version)
|
|
result.dlib = path.join(ats, path.basename(kit), 'Azure.CodeSigning.Dlib.dll')
|
|
result.dotnetRoot = await builder.getDotnetRuntimeDir(version)
|
|
}
|
|
}
|
|
const files = [result.makeappx, result.signtool]
|
|
if (result.dlib) files.push(result.dlib)
|
|
if (result.dotnetRoot) files.push(path.join(result.dotnetRoot, 'dotnet.exe'))
|
|
for (const file of files) {
|
|
if (!fs.statSync(file).isFile()) throw new Error(`Windows bundle tool is not a file: ${file}`)
|
|
}
|
|
return result
|
|
}
|