1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.Packager = void 0;
|
4 | const builder_util_1 = require("builder-util");
|
5 | const builder_util_runtime_1 = require("builder-util-runtime");
|
6 | const promise_1 = require("builder-util/out/promise");
|
7 | const events_1 = require("events");
|
8 | const fs_extra_1 = require("fs-extra");
|
9 | const isCI = require("is-ci");
|
10 | const lazy_val_1 = require("lazy-val");
|
11 | const path = require("path");
|
12 | const arch_1 = require("builder-util/out/arch");
|
13 | const appInfo_1 = require("./appInfo");
|
14 | const asar_1 = require("./asar/asar");
|
15 | const core_1 = require("./core");
|
16 | const ElectronFramework_1 = require("./electron/ElectronFramework");
|
17 | const LibUiFramework_1 = require("./frameworks/LibUiFramework");
|
18 | const platformPackager_1 = require("./platformPackager");
|
19 | const ProtonFramework_1 = require("./ProtonFramework");
|
20 | const targetFactory_1 = require("./targets/targetFactory");
|
21 | const config_1 = require("./util/config");
|
22 | const macroExpander_1 = require("./util/macroExpander");
|
23 | const packageDependencies_1 = require("./util/packageDependencies");
|
24 | const packageMetadata_1 = require("./util/packageMetadata");
|
25 | const repositoryInfo_1 = require("./util/repositoryInfo");
|
26 | const yarn_1 = require("./util/yarn");
|
27 | const version_1 = require("./version");
|
28 | const os_1 = require("os");
|
29 | function addHandler(emitter, event, handler) {
|
30 | emitter.on(event, handler);
|
31 | }
|
32 | async function createFrameworkInfo(configuration, packager) {
|
33 | let framework = configuration.framework;
|
34 | if (framework != null) {
|
35 | framework = framework.toLowerCase();
|
36 | }
|
37 | let nodeVersion = configuration.nodeVersion;
|
38 | if (framework === "electron" || framework == null) {
|
39 | return await ElectronFramework_1.createElectronFrameworkSupport(configuration, packager);
|
40 | }
|
41 | if (nodeVersion == null || nodeVersion === "current") {
|
42 | nodeVersion = process.versions.node;
|
43 | }
|
44 | const distMacOsName = `${packager.appInfo.productFilename}.app`;
|
45 | const isUseLaunchUi = configuration.launchUiVersion !== false;
|
46 | if (framework === "proton" || framework === "proton-native") {
|
47 | return new ProtonFramework_1.ProtonFramework(nodeVersion, distMacOsName, isUseLaunchUi);
|
48 | }
|
49 | else if (framework === "libui") {
|
50 | return new LibUiFramework_1.LibUiFramework(nodeVersion, distMacOsName, isUseLaunchUi);
|
51 | }
|
52 | else {
|
53 | throw new builder_util_1.InvalidConfigurationError(`Unknown framework: ${framework}`);
|
54 | }
|
55 | }
|
56 | class Packager {
|
57 |
|
58 | constructor(options, cancellationToken = new builder_util_runtime_1.CancellationToken()) {
|
59 | this.cancellationToken = cancellationToken;
|
60 | this._metadata = null;
|
61 | this._nodeModulesHandledExternally = false;
|
62 | this._isPrepackedAppAsar = false;
|
63 | this._devMetadata = null;
|
64 | this._configuration = null;
|
65 | this.isTwoPackageJsonProjectLayoutUsed = false;
|
66 | this.eventEmitter = new events_1.EventEmitter();
|
67 | this._appInfo = null;
|
68 | this.tempDirManager = new builder_util_1.TmpDir("packager");
|
69 | this._repositoryInfo = new lazy_val_1.Lazy(() => repositoryInfo_1.getRepositoryInfo(this.projectDir, this.metadata, this.devMetadata));
|
70 | this.afterPackHandlers = [];
|
71 | this.debugLogger = new builder_util_1.DebugLogger(builder_util_1.log.isDebugEnabled);
|
72 | this.nodeDependencyInfo = new Map();
|
73 | this.stageDirPathCustomizer = (target, packager, arch) => {
|
74 | return path.join(target.outDir, `__${target.name}-${arch_1.getArtifactArchName(arch, target.name)}`);
|
75 | };
|
76 | this._buildResourcesDir = null;
|
77 | this._framework = null;
|
78 | this.toDispose = [];
|
79 | if ("devMetadata" in options) {
|
80 | throw new builder_util_1.InvalidConfigurationError("devMetadata in the options is deprecated, please use config instead");
|
81 | }
|
82 | if ("extraMetadata" in options) {
|
83 | throw new builder_util_1.InvalidConfigurationError("extraMetadata in the options is deprecated, please use config.extraMetadata instead");
|
84 | }
|
85 | const targets = options.targets || new Map();
|
86 | if (options.targets == null) {
|
87 | options.targets = targets;
|
88 | }
|
89 | function processTargets(platform, types) {
|
90 | function commonArch(currentIfNotSpecified) {
|
91 | const result = Array();
|
92 | return result.length === 0 && currentIfNotSpecified ? [builder_util_1.archFromString(process.arch)] : result;
|
93 | }
|
94 | let archToType = targets.get(platform);
|
95 | if (archToType == null) {
|
96 | archToType = new Map();
|
97 | targets.set(platform, archToType);
|
98 | }
|
99 | if (types.length === 0) {
|
100 | for (const arch of commonArch(false)) {
|
101 | archToType.set(arch, []);
|
102 | }
|
103 | return;
|
104 | }
|
105 | for (const type of types) {
|
106 | const suffixPos = type.lastIndexOf(":");
|
107 | if (suffixPos > 0) {
|
108 | builder_util_1.addValue(archToType, builder_util_1.archFromString(type.substring(suffixPos + 1)), type.substring(0, suffixPos));
|
109 | }
|
110 | else {
|
111 | for (const arch of commonArch(true)) {
|
112 | builder_util_1.addValue(archToType, arch, type);
|
113 | }
|
114 | }
|
115 | }
|
116 | }
|
117 | if (options.mac != null) {
|
118 | processTargets(core_1.Platform.MAC, options.mac);
|
119 | }
|
120 | if (options.linux != null) {
|
121 | processTargets(core_1.Platform.LINUX, options.linux);
|
122 | }
|
123 | if (options.win != null) {
|
124 | processTargets(core_1.Platform.WINDOWS, options.win);
|
125 | }
|
126 | this.projectDir = options.projectDir == null ? process.cwd() : path.resolve(options.projectDir);
|
127 | this._appDir = this.projectDir;
|
128 | this.options = {
|
129 | ...options,
|
130 | prepackaged: options.prepackaged == null ? null : path.resolve(this.projectDir, options.prepackaged),
|
131 | };
|
132 | try {
|
133 | builder_util_1.log.info({ version: version_1.PACKAGE_VERSION, os: os_1.release() }, "electron-builder");
|
134 | }
|
135 | catch (e) {
|
136 |
|
137 | if (!(e instanceof ReferenceError)) {
|
138 | throw e;
|
139 | }
|
140 | }
|
141 | }
|
142 | get appDir() {
|
143 | return this._appDir;
|
144 | }
|
145 | get metadata() {
|
146 | return this._metadata;
|
147 | }
|
148 | get areNodeModulesHandledExternally() {
|
149 | return this._nodeModulesHandledExternally;
|
150 | }
|
151 | get isPrepackedAppAsar() {
|
152 | return this._isPrepackedAppAsar;
|
153 | }
|
154 | get devMetadata() {
|
155 | return this._devMetadata;
|
156 | }
|
157 | get config() {
|
158 | return this._configuration;
|
159 | }
|
160 | get appInfo() {
|
161 | return this._appInfo;
|
162 | }
|
163 | get repositoryInfo() {
|
164 | return this._repositoryInfo.value;
|
165 | }
|
166 | getNodeDependencyInfo(platform) {
|
167 | let key = "";
|
168 | let excludedDependencies = null;
|
169 | if (platform != null && this.framework.getExcludedDependencies != null) {
|
170 | excludedDependencies = this.framework.getExcludedDependencies(platform);
|
171 | if (excludedDependencies != null) {
|
172 | key += `-${platform.name}`;
|
173 | }
|
174 | }
|
175 | let result = this.nodeDependencyInfo.get(key);
|
176 | if (result == null) {
|
177 | result = packageDependencies_1.createLazyProductionDeps(this.appDir, excludedDependencies);
|
178 | this.nodeDependencyInfo.set(key, result);
|
179 | }
|
180 | return result;
|
181 | }
|
182 | get buildResourcesDir() {
|
183 | let result = this._buildResourcesDir;
|
184 | if (result == null) {
|
185 | result = path.resolve(this.projectDir, this.relativeBuildResourcesDirname);
|
186 | this._buildResourcesDir = result;
|
187 | }
|
188 | return result;
|
189 | }
|
190 | get relativeBuildResourcesDirname() {
|
191 | return this.config.directories.buildResources;
|
192 | }
|
193 | get framework() {
|
194 | return this._framework;
|
195 | }
|
196 | disposeOnBuildFinish(disposer) {
|
197 | this.toDispose.push(disposer);
|
198 | }
|
199 | addAfterPackHandler(handler) {
|
200 | this.afterPackHandlers.push(handler);
|
201 | }
|
202 | artifactCreated(handler) {
|
203 | addHandler(this.eventEmitter, "artifactCreated", handler);
|
204 | return this;
|
205 | }
|
206 | async callArtifactBuildStarted(event, logFields) {
|
207 | builder_util_1.log.info(logFields || {
|
208 | target: event.targetPresentableName,
|
209 | arch: event.arch == null ? null : builder_util_1.Arch[event.arch],
|
210 | file: builder_util_1.log.filePath(event.file),
|
211 | }, "building");
|
212 | const handler = platformPackager_1.resolveFunction(this.config.artifactBuildStarted, "artifactBuildStarted");
|
213 | if (handler != null) {
|
214 | await Promise.resolve(handler(event));
|
215 | }
|
216 | }
|
217 | |
218 |
|
219 |
|
220 | dispatchArtifactCreated(event) {
|
221 | this.eventEmitter.emit("artifactCreated", event);
|
222 | }
|
223 | async callArtifactBuildCompleted(event) {
|
224 | this.dispatchArtifactCreated(event);
|
225 | const handler = platformPackager_1.resolveFunction(this.config.artifactBuildCompleted, "artifactBuildCompleted");
|
226 | if (handler != null) {
|
227 | await Promise.resolve(handler(event));
|
228 | }
|
229 | }
|
230 | async callAppxManifestCreated(path) {
|
231 | const handler = platformPackager_1.resolveFunction(this.config.appxManifestCreated, "appxManifestCreated");
|
232 | if (handler != null) {
|
233 | await Promise.resolve(handler(path));
|
234 | }
|
235 | }
|
236 | async callMsiProjectCreated(path) {
|
237 | const handler = platformPackager_1.resolveFunction(this.config.msiProjectCreated, "msiProjectCreated");
|
238 | if (handler != null) {
|
239 | await Promise.resolve(handler(path));
|
240 | }
|
241 | }
|
242 | async build() {
|
243 | let configPath = null;
|
244 | let configFromOptions = this.options.config;
|
245 | if (typeof configFromOptions === "string") {
|
246 |
|
247 | configPath = configFromOptions;
|
248 | configFromOptions = null;
|
249 | }
|
250 | else if (configFromOptions != null && typeof configFromOptions.extends === "string" && configFromOptions.extends.includes(".")) {
|
251 | configPath = configFromOptions.extends;
|
252 | delete configFromOptions.extends;
|
253 | }
|
254 | const projectDir = this.projectDir;
|
255 | const devPackageFile = path.join(projectDir, "package.json");
|
256 | this._devMetadata = await promise_1.orNullIfFileNotExist(packageMetadata_1.readPackageJson(devPackageFile));
|
257 | const devMetadata = this.devMetadata;
|
258 | const configuration = await config_1.getConfig(projectDir, configPath, configFromOptions, new lazy_val_1.Lazy(() => Promise.resolve(devMetadata)));
|
259 | if (builder_util_1.log.isDebugEnabled) {
|
260 | builder_util_1.log.debug({ config: getSafeEffectiveConfig(configuration) }, "effective config");
|
261 | }
|
262 | this._appDir = await config_1.computeDefaultAppDirectory(projectDir, configuration.directories.app);
|
263 | this.isTwoPackageJsonProjectLayoutUsed = this._appDir !== projectDir;
|
264 | const appPackageFile = this.isTwoPackageJsonProjectLayoutUsed ? path.join(this.appDir, "package.json") : devPackageFile;
|
265 |
|
266 | if (this.devMetadata != null && !this.isTwoPackageJsonProjectLayoutUsed) {
|
267 | this._metadata = this.devMetadata;
|
268 | }
|
269 | else {
|
270 | this._metadata = await this.readProjectMetadataIfTwoPackageStructureOrPrepacked(appPackageFile);
|
271 | }
|
272 | builder_util_1.deepAssign(this.metadata, configuration.extraMetadata);
|
273 | if (this.isTwoPackageJsonProjectLayoutUsed) {
|
274 | builder_util_1.log.debug({ devPackageFile, appPackageFile }, "two package.json structure is used");
|
275 | }
|
276 | packageMetadata_1.checkMetadata(this.metadata, this.devMetadata, appPackageFile, devPackageFile);
|
277 | return await this._build(configuration, this._metadata, this._devMetadata);
|
278 | }
|
279 |
|
280 | async _build(configuration, metadata, devMetadata, repositoryInfo) {
|
281 | await config_1.validateConfig(configuration, this.debugLogger);
|
282 | this._configuration = configuration;
|
283 | this._metadata = metadata;
|
284 | this._devMetadata = devMetadata;
|
285 | if (repositoryInfo != null) {
|
286 | this._repositoryInfo.value = Promise.resolve(repositoryInfo);
|
287 | }
|
288 | this._appInfo = new appInfo_1.AppInfo(this, null);
|
289 | this._framework = await createFrameworkInfo(this.config, this);
|
290 | const commonOutDirWithoutPossibleOsMacro = path.resolve(this.projectDir, macroExpander_1.expandMacro(configuration.directories.output, null, this._appInfo, {
|
291 | os: "",
|
292 | }));
|
293 | if (!isCI && process.stdout.isTTY) {
|
294 | const effectiveConfigFile = path.join(commonOutDirWithoutPossibleOsMacro, "builder-effective-config.yaml");
|
295 | builder_util_1.log.info({ file: builder_util_1.log.filePath(effectiveConfigFile) }, "writing effective config");
|
296 | await fs_extra_1.outputFile(effectiveConfigFile, getSafeEffectiveConfig(configuration));
|
297 | }
|
298 |
|
299 | const artifactPaths = new Set();
|
300 | this.artifactCreated(event => {
|
301 | if (event.file != null) {
|
302 | artifactPaths.add(event.file);
|
303 | }
|
304 | });
|
305 | this.disposeOnBuildFinish(() => this.tempDirManager.cleanup());
|
306 | const platformToTargets = await promise_1.executeFinally(this.doBuild(), async () => {
|
307 | if (this.debugLogger.isEnabled) {
|
308 | await this.debugLogger.save(path.join(commonOutDirWithoutPossibleOsMacro, "builder-debug.yml"));
|
309 | }
|
310 | const toDispose = this.toDispose.slice();
|
311 | this.toDispose.length = 0;
|
312 | for (const disposer of toDispose) {
|
313 | await disposer().catch(e => {
|
314 | builder_util_1.log.warn({ error: e }, "cannot dispose");
|
315 | });
|
316 | }
|
317 | });
|
318 | return {
|
319 | outDir: commonOutDirWithoutPossibleOsMacro,
|
320 | artifactPaths: Array.from(artifactPaths),
|
321 | platformToTargets,
|
322 | configuration,
|
323 | };
|
324 | }
|
325 | async readProjectMetadataIfTwoPackageStructureOrPrepacked(appPackageFile) {
|
326 | let data = await promise_1.orNullIfFileNotExist(packageMetadata_1.readPackageJson(appPackageFile));
|
327 | if (data != null) {
|
328 | return data;
|
329 | }
|
330 | data = await promise_1.orNullIfFileNotExist(asar_1.readAsarJson(path.join(this.projectDir, "app.asar"), "package.json"));
|
331 | if (data != null) {
|
332 | this._isPrepackedAppAsar = true;
|
333 | return data;
|
334 | }
|
335 | throw new Error(`Cannot find package.json in the ${path.dirname(appPackageFile)}`);
|
336 | }
|
337 | async doBuild() {
|
338 | const taskManager = new builder_util_1.AsyncTaskManager(this.cancellationToken);
|
339 | const platformToTarget = new Map();
|
340 | const createdOutDirs = new Set();
|
341 | for (const [platform, archToType] of this.options.targets) {
|
342 | if (this.cancellationToken.cancelled) {
|
343 | break;
|
344 | }
|
345 | if (platform === core_1.Platform.MAC && process.platform === core_1.Platform.WINDOWS.nodeName) {
|
346 | throw new builder_util_1.InvalidConfigurationError("Build for macOS is supported only on macOS, please see https://electron.build/multi-platform-build");
|
347 | }
|
348 | const packager = await this.createHelper(platform);
|
349 | const nameToTarget = new Map();
|
350 | platformToTarget.set(platform, nameToTarget);
|
351 | for (const [arch, targetNames] of targetFactory_1.computeArchToTargetNamesMap(archToType, packager, platform)) {
|
352 | if (this.cancellationToken.cancelled) {
|
353 | break;
|
354 | }
|
355 |
|
356 | const outDir = path.resolve(this.projectDir, packager.expandMacro(this._configuration.directories.output, builder_util_1.Arch[arch]));
|
357 | const targetList = targetFactory_1.createTargets(nameToTarget, targetNames.length === 0 ? packager.defaultTarget : targetNames, outDir, packager);
|
358 | await createOutDirIfNeed(targetList, createdOutDirs);
|
359 | await packager.pack(outDir, arch, targetList, taskManager);
|
360 | }
|
361 | if (this.cancellationToken.cancelled) {
|
362 | break;
|
363 | }
|
364 | for (const target of nameToTarget.values()) {
|
365 | taskManager.addTask(target.finishBuild());
|
366 | }
|
367 | }
|
368 | await taskManager.awaitTasks();
|
369 | return platformToTarget;
|
370 | }
|
371 | async createHelper(platform) {
|
372 | if (this.options.platformPackagerFactory != null) {
|
373 | return this.options.platformPackagerFactory(this, platform);
|
374 | }
|
375 | switch (platform) {
|
376 | case core_1.Platform.MAC: {
|
377 | const helperClass = (await Promise.resolve().then(() => require("./macPackager"))).default;
|
378 | return new helperClass(this);
|
379 | }
|
380 | case core_1.Platform.WINDOWS: {
|
381 | const helperClass = (await Promise.resolve().then(() => require("./winPackager"))).WinPackager;
|
382 | return new helperClass(this);
|
383 | }
|
384 | case core_1.Platform.LINUX:
|
385 | return new (await Promise.resolve().then(() => require("./linuxPackager"))).LinuxPackager(this);
|
386 | default:
|
387 | throw new Error(`Unknown platform: ${platform}`);
|
388 | }
|
389 | }
|
390 | async installAppDependencies(platform, arch) {
|
391 | if (this.options.prepackaged != null || !this.framework.isNpmRebuildRequired) {
|
392 | return;
|
393 | }
|
394 | const frameworkInfo = { version: this.framework.version, useCustomDist: true };
|
395 | const config = this.config;
|
396 | if (config.nodeGypRebuild === true) {
|
397 | await yarn_1.nodeGypRebuild(platform.nodeName, builder_util_1.Arch[arch], frameworkInfo);
|
398 | }
|
399 | if (config.npmRebuild === false) {
|
400 | builder_util_1.log.info({ reason: "npmRebuild is set to false" }, "skipped dependencies rebuild");
|
401 | return;
|
402 | }
|
403 | const beforeBuild = platformPackager_1.resolveFunction(config.beforeBuild, "beforeBuild");
|
404 | if (beforeBuild != null) {
|
405 | const performDependenciesInstallOrRebuild = await beforeBuild({
|
406 | appDir: this.appDir,
|
407 | electronVersion: this.config.electronVersion,
|
408 | platform,
|
409 | arch: builder_util_1.Arch[arch],
|
410 | });
|
411 |
|
412 | this._nodeModulesHandledExternally = !performDependenciesInstallOrRebuild;
|
413 | if (!performDependenciesInstallOrRebuild) {
|
414 | return;
|
415 | }
|
416 | }
|
417 | if (config.buildDependenciesFromSource === true && platform.nodeName !== process.platform) {
|
418 | builder_util_1.log.info({ reason: "platform is different and buildDependenciesFromSource is set to true" }, "skipped dependencies rebuild");
|
419 | }
|
420 | else {
|
421 | await yarn_1.installOrRebuild(config, this.appDir, {
|
422 | frameworkInfo,
|
423 | platform: platform.nodeName,
|
424 | arch: builder_util_1.Arch[arch],
|
425 | productionDeps: this.getNodeDependencyInfo(null),
|
426 | });
|
427 | }
|
428 | }
|
429 | async afterPack(context) {
|
430 | const afterPack = platformPackager_1.resolveFunction(this.config.afterPack, "afterPack");
|
431 | const handlers = this.afterPackHandlers.slice();
|
432 | if (afterPack != null) {
|
433 |
|
434 | handlers.push(afterPack);
|
435 | }
|
436 | for (const handler of handlers) {
|
437 | await Promise.resolve(handler(context));
|
438 | }
|
439 | }
|
440 | }
|
441 | exports.Packager = Packager;
|
442 | function createOutDirIfNeed(targetList, createdOutDirs) {
|
443 | const ourDirs = new Set();
|
444 | for (const target of targetList) {
|
445 |
|
446 | if (target instanceof targetFactory_1.NoOpTarget) {
|
447 | continue;
|
448 | }
|
449 | const outDir = target.outDir;
|
450 | if (!createdOutDirs.has(outDir)) {
|
451 | ourDirs.add(outDir);
|
452 | }
|
453 | }
|
454 | if (ourDirs.size === 0) {
|
455 | return Promise.resolve();
|
456 | }
|
457 | return Promise.all(Array.from(ourDirs)
|
458 | .sort()
|
459 | .map(dir => {
|
460 | return fs_extra_1.mkdirs(dir)
|
461 | .then(() => fs_extra_1.chmod(dir, 0o755) )
|
462 | .then(() => createdOutDirs.add(dir));
|
463 | }));
|
464 | }
|
465 | function getSafeEffectiveConfig(configuration) {
|
466 | const o = JSON.parse(builder_util_1.safeStringifyJson(configuration));
|
467 | if (o.cscLink != null) {
|
468 | o.cscLink = "<hidden by builder>";
|
469 | }
|
470 | return builder_util_1.serializeToYaml(o, true);
|
471 | }
|
472 |
|
\ | No newline at end of file |