UNPKG

15 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.DmgTarget = void 0;
7
8function _appBuilderLib() {
9 const data = require("app-builder-lib");
10
11 _appBuilderLib = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function _macCodeSign() {
19 const data = require("app-builder-lib/out/codeSign/macCodeSign");
20
21 _macCodeSign = function () {
22 return data;
23 };
24
25 return data;
26}
27
28function _differentialUpdateInfoBuilder() {
29 const data = require("app-builder-lib/out/targets/differentialUpdateInfoBuilder");
30
31 _differentialUpdateInfoBuilder = function () {
32 return data;
33 };
34
35 return data;
36}
37
38function _appBuilder() {
39 const data = require("app-builder-lib/out/util/appBuilder");
40
41 _appBuilder = function () {
42 return data;
43 };
44
45 return data;
46}
47
48function _builderUtil() {
49 const data = require("builder-util");
50
51 _builderUtil = function () {
52 return data;
53 };
54
55 return data;
56}
57
58function _fs() {
59 const data = require("builder-util/out/fs");
60
61 _fs = function () {
62 return data;
63 };
64
65 return data;
66}
67
68function _fsExtra() {
69 const data = require("fs-extra");
70
71 _fsExtra = function () {
72 return data;
73 };
74
75 return data;
76}
77
78var path = _interopRequireWildcard(require("path"));
79
80function _sanitizeFilename() {
81 const data = _interopRequireDefault(require("sanitize-filename"));
82
83 _sanitizeFilename = function () {
84 return data;
85 };
86
87 return data;
88}
89
90function _dmgLicense() {
91 const data = require("./dmgLicense");
92
93 _dmgLicense = function () {
94 return data;
95 };
96
97 return data;
98}
99
100function _dmgUtil() {
101 const data = require("./dmgUtil");
102
103 _dmgUtil = function () {
104 return data;
105 };
106
107 return data;
108}
109
110function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
111
112function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
113
114function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
115
116class DmgTarget extends _appBuilderLib().Target {
117 constructor(packager, outDir) {
118 super("dmg");
119 this.packager = packager;
120 this.outDir = outDir;
121 this.options = this.packager.config.dmg || Object.create(null);
122 }
123
124 async build(appPath, arch) {
125 const packager = this.packager; // tslint:disable-next-line:no-invalid-template-strings
126
127 const artifactName = packager.expandArtifactNamePattern(packager.config.dmg, "dmg", null, "${productName}-" + (packager.platformSpecificBuildOptions.bundleShortVersion || "${version}") + ".${ext}");
128 const artifactPath = path.join(this.outDir, artifactName);
129 await packager.info.callArtifactBuildStarted({
130 targetPresentableName: "DMG",
131 file: artifactPath,
132 arch
133 });
134 const volumeName = (0, _sanitizeFilename().default)(this.computeVolumeName(this.options.title));
135 const tempDmg = await createStageDmg((await packager.getTempFile(".dmg")), appPath, volumeName);
136 const specification = await this.computeDmgOptions(); // https://github.com/electron-userland/electron-builder/issues/2115
137
138 const backgroundFile = specification.background == null ? null : await transformBackgroundFileIfNeed(specification.background, packager.info.tempDirManager);
139 const finalSize = await computeAssetSize(packager.info.cancellationToken, tempDmg, specification, backgroundFile);
140 const expandingFinalSize = finalSize * 0.1 + finalSize;
141 await (0, _builderUtil().exec)("hdiutil", ["resize", "-size", expandingFinalSize.toString(), tempDmg]);
142 const volumePath = path.join("/Volumes", volumeName);
143
144 if (await (0, _fs().exists)(volumePath)) {
145 _builderUtil().log.debug({
146 volumePath
147 }, "unmounting previous disk image");
148
149 await (0, _dmgUtil().detach)(volumePath);
150 }
151
152 if (!(await (0, _dmgUtil().attachAndExecute)(tempDmg, true, () => customizeDmg(volumePath, specification, packager, backgroundFile)))) {
153 return;
154 } // dmg file must not exist otherwise hdiutil failed (https://github.com/electron-userland/electron-builder/issues/1308#issuecomment-282847594), so, -ov must be specified
155
156
157 const args = ["convert", tempDmg, "-ov", "-format", specification.format, "-o", artifactPath];
158
159 if (specification.format === "UDZO") {
160 args.push("-imagekey", `zlib-level=${process.env.ELECTRON_BUILDER_COMPRESSION_LEVEL || "9"}`);
161 }
162
163 await (0, _builderUtil().spawn)("hdiutil", addLogLevel(args));
164
165 if (this.options.internetEnabled && parseInt(require("os").split(".")[0], 10) < 19) {
166 await (0, _builderUtil().exec)("hdiutil", addLogLevel(["internet-enable"]).concat(artifactPath));
167 }
168
169 const licenseData = await (0, _dmgLicense().addLicenseToDmg)(packager, artifactPath);
170
171 if (packager.packagerOptions.effectiveOptionComputed != null) {
172 await packager.packagerOptions.effectiveOptionComputed({
173 licenseData
174 });
175 }
176
177 if (this.options.sign === true) {
178 await this.signDmg(artifactPath);
179 }
180
181 const safeArtifactName = packager.computeSafeArtifactName(artifactName, "dmg");
182 const updateInfo = this.options.writeUpdateInfo === false ? null : await (0, _differentialUpdateInfoBuilder().createBlockmap)(artifactPath, this, packager, safeArtifactName);
183 await packager.info.callArtifactBuildCompleted({
184 file: artifactPath,
185 safeArtifactName,
186 target: this,
187 arch,
188 packager,
189 isWriteUpdateInfo: updateInfo != null,
190 updateInfo
191 });
192 }
193
194 async signDmg(artifactPath) {
195 if (!(0, _macCodeSign().isSignAllowed)(false)) {
196 return;
197 }
198
199 const packager = this.packager;
200 const qualifier = packager.platformSpecificBuildOptions.identity; // explicitly disabled if set to null
201
202 if (qualifier === null) {
203 // macPackager already somehow handle this situation, so, here just return
204 return;
205 }
206
207 const keychainFile = (await packager.codeSigningInfo.value).keychainFile;
208 const certificateType = "Developer ID Application";
209 let identity = await (0, _macCodeSign().findIdentity)(certificateType, qualifier, keychainFile);
210
211 if (identity == null) {
212 identity = await (0, _macCodeSign().findIdentity)("Mac Developer", qualifier, keychainFile);
213
214 if (identity == null) {
215 return;
216 }
217 }
218
219 const args = ["--sign", identity.hash];
220
221 if (keychainFile != null) {
222 args.push("--keychain", keychainFile);
223 }
224
225 args.push(artifactPath);
226 await (0, _builderUtil().exec)("codesign", args);
227 }
228
229 computeVolumeName(custom) {
230 const appInfo = this.packager.appInfo;
231 const shortVersion = this.packager.platformSpecificBuildOptions.bundleShortVersion || appInfo.version;
232
233 if (custom == null) {
234 return `${appInfo.productFilename} ${shortVersion}`;
235 }
236
237 return custom.replace(/\${shortVersion}/g, shortVersion).replace(/\${version}/g, appInfo.version).replace(/\${name}/g, appInfo.name).replace(/\${productName}/g, appInfo.productName);
238 } // public to test
239
240
241 async computeDmgOptions() {
242 const packager = this.packager;
243 const specification = Object.assign({}, this.options);
244
245 if (specification.icon == null && specification.icon !== null) {
246 specification.icon = await packager.getIconPath();
247 }
248
249 if (specification.icon != null && (0, _builderUtil().isEmptyOrSpaces)(specification.icon)) {
250 throw new (_builderUtil().InvalidConfigurationError)("dmg.icon cannot be specified as empty string");
251 }
252
253 const background = specification.background;
254
255 if (specification.backgroundColor != null) {
256 if (background != null) {
257 throw new (_builderUtil().InvalidConfigurationError)("Both dmg.backgroundColor and dmg.background are specified — please set the only one");
258 }
259 } else if (background == null) {
260 specification.background = await (0, _dmgUtil().computeBackground)(packager);
261 } else {
262 specification.background = path.resolve(packager.info.projectDir, background);
263 }
264
265 if (specification.format == null) {
266 if (process.env.ELECTRON_BUILDER_COMPRESSION_LEVEL != null) {
267 specification.format = "UDZO";
268 } else if (packager.compression === "store") {
269 specification.format = "UDRO";
270 } else {
271 specification.format = packager.compression === "maximum" ? "UDBZ" : "UDZO";
272 }
273 }
274
275 if (specification.contents == null) {
276 specification.contents = [{
277 x: 130,
278 y: 220
279 }, {
280 x: 410,
281 y: 220,
282 type: "link",
283 path: "/Applications"
284 }];
285 }
286
287 return specification;
288 }
289
290}
291
292exports.DmgTarget = DmgTarget;
293
294async function createStageDmg(tempDmg, appPath, volumeName) {
295 //noinspection SpellCheckingInspection
296 const imageArgs = addLogLevel(["create", "-srcfolder", appPath, "-volname", volumeName, "-anyowners", "-nospotlight", "-format", "UDRW"]);
297 imageArgs.push("-fs", "HFS+", "-fsargs", "-c c=64,a=16,e=16");
298 imageArgs.push(tempDmg);
299 await (0, _builderUtil().spawn)("hdiutil", imageArgs);
300 return tempDmg;
301}
302
303function addLogLevel(args) {
304 args.push(process.env.DEBUG_DMG === "true" ? "-verbose" : "-quiet");
305 return args;
306}
307
308async function computeAssetSize(cancellationToken, dmgFile, specification, backgroundFile) {
309 const asyncTaskManager = new (_builderUtil().AsyncTaskManager)(cancellationToken);
310 asyncTaskManager.addTask((0, _fsExtra().stat)(dmgFile));
311
312 if (specification.icon != null) {
313 asyncTaskManager.addTask((0, _fs().statOrNull)(specification.icon));
314 }
315
316 if (backgroundFile != null) {
317 asyncTaskManager.addTask((0, _fsExtra().stat)(backgroundFile));
318 }
319
320 let result = 32 * 1024;
321
322 for (const stat of await asyncTaskManager.awaitTasks()) {
323 if (stat != null) {
324 result += stat.size;
325 }
326 }
327
328 return result;
329}
330
331async function customizeDmg(volumePath, specification, packager, backgroundFile) {
332 const window = specification.window;
333 const env = Object.assign(Object.assign({}, process.env), {
334 volumePath,
335 appFileName: `${packager.appInfo.productFilename}.app`,
336 iconSize: specification.iconSize || 80,
337 iconTextSize: specification.iconTextSize || 12,
338 PYTHONIOENCODING: "utf8"
339 });
340
341 if (specification.backgroundColor != null || specification.background == null) {
342 env.backgroundColor = specification.backgroundColor || "#ffffff";
343
344 if (window != null) {
345 env.windowX = (window.x == null ? 100 : window.x).toString();
346 env.windowY = (window.y == null ? 400 : window.y).toString();
347 env.windowWidth = (window.width || 540).toString();
348 env.windowHeight = (window.height || 380).toString();
349 }
350 } else {
351 delete env.backgroundColor;
352 }
353
354 const args = ["dmg", "--volume", volumePath];
355
356 if (specification.icon != null) {
357 args.push("--icon", (await packager.getResource(specification.icon)));
358 }
359
360 if (backgroundFile != null) {
361 args.push("--background", backgroundFile);
362 }
363
364 const data = await (0, _appBuilder().executeAppBuilderAsJson)(args);
365
366 if (data.backgroundWidth != null) {
367 env.windowWidth = window == null ? null : window.width;
368 env.windowHeight = window == null ? null : window.height;
369
370 if (env.windowWidth == null) {
371 env.windowWidth = data.backgroundWidth.toString();
372 }
373
374 if (env.windowHeight == null) {
375 env.windowHeight = data.backgroundHeight.toString();
376 }
377
378 if (env.windowX == null) {
379 env.windowX = 400;
380 }
381
382 if (env.windowY == null) {
383 env.windowY = Math.round((1440 - env.windowHeight) / 2).toString();
384 }
385 }
386
387 Object.assign(env, data);
388 const asyncTaskManager = new (_builderUtil().AsyncTaskManager)(packager.info.cancellationToken);
389 env.iconLocations = await computeDmgEntries(specification, volumePath, packager, asyncTaskManager);
390 await asyncTaskManager.awaitTasks();
391 await (0, _builderUtil().exec)("/usr/bin/python", [path.join((0, _dmgUtil().getDmgVendorPath)(), "dmgbuild/core.py")], {
392 cwd: (0, _dmgUtil().getDmgVendorPath)(),
393 env
394 });
395 return packager.packagerOptions.effectiveOptionComputed == null || !(await packager.packagerOptions.effectiveOptionComputed({
396 volumePath,
397 specification,
398 packager
399 }));
400}
401
402async function computeDmgEntries(specification, volumePath, packager, asyncTaskManager) {
403 let result = "";
404
405 for (const c of specification.contents) {
406 if (c.path != null && c.path.endsWith(".app") && c.type !== "link") {
407 _builderUtil().log.warn({
408 path: c.path,
409 reason: "actual path to app will be used instead"
410 }, "do not specify path for application");
411 }
412
413 const entryPath = c.path || `${packager.appInfo.productFilename}.app`;
414 const entryName = c.name || path.basename(entryPath);
415
416 if (result.length !== 0) {
417 result += ",\n";
418 }
419
420 result += `'${entryName}': (${c.x}, ${c.y})`;
421
422 if (c.type === "link") {
423 asyncTaskManager.addTask((0, _builderUtil().exec)("ln", ["-s", `/${entryPath.startsWith("/") ? entryPath.substring(1) : entryPath}`, `${volumePath}/${entryName}`]));
424 } // use c.path instead of entryPath (to be sure that this logic is not applied to .app bundle) https://github.com/electron-userland/electron-builder/issues/2147
425 else if (!(0, _builderUtil().isEmptyOrSpaces)(c.path) && (c.type === "file" || c.type === "dir")) {
426 const source = await packager.getResource(c.path);
427
428 if (source == null) {
429 _builderUtil().log.warn({
430 entryPath,
431 reason: "doesn't exist"
432 }, "skipped DMG item copying");
433
434 continue;
435 }
436
437 const destination = `${volumePath}/${entryName}`;
438 asyncTaskManager.addTask(c.type === "dir" || (await (0, _fsExtra().stat)(source)).isDirectory() ? (0, _fs().copyDir)(source, destination) : (0, _fs().copyFile)(source, destination));
439 }
440 }
441
442 return result;
443}
444
445async function transformBackgroundFileIfNeed(file, tmpDir) {
446 if (file.endsWith(".tiff") || file.endsWith(".TIFF")) {
447 return file;
448 }
449
450 const retinaFile = file.replace(/\.([a-z]+)$/, "@2x.$1");
451
452 if (await (0, _fs().exists)(retinaFile)) {
453 const tiffFile = await tmpDir.getTempFile({
454 suffix: ".tiff"
455 });
456 await (0, _builderUtil().exec)("tiffutil", ["-cathidpicheck", file, retinaFile, "-out", tiffFile]);
457 return tiffFile;
458 }
459
460 return file;
461}
462// __ts-babel@6.0.4
463//# sourceMappingURL=dmg.js.map
\No newline at end of file