UNPKG

11.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const builder_util_1 = require("builder-util");
4const fs_1 = require("builder-util/out/fs");
5const fs_extra_1 = require("fs-extra");
6const promises_1 = require("fs/promises");
7const path = require("path");
8const appInfo_1 = require("../appInfo");
9const core_1 = require("../core");
10const errorMessages = require("../errorMessages");
11const appBuilder_1 = require("../util/appBuilder");
12const bundledTool_1 = require("../util/bundledTool");
13const macosVersion_1 = require("../util/macosVersion");
14const pathManager_1 = require("../util/pathManager");
15const LinuxTargetHelper_1 = require("./LinuxTargetHelper");
16const tools_1 = require("./tools");
17const hash_1 = require("../util/hash");
18const PublishManager_1 = require("../publish/PublishManager");
19const builder_util_2 = require("builder-util");
20class FpmTarget extends core_1.Target {
21 constructor(name, packager, helper, outDir) {
22 super(name, false);
23 this.packager = packager;
24 this.helper = helper;
25 this.outDir = outDir;
26 this.options = { ...this.packager.platformSpecificBuildOptions, ...this.packager.config[this.name] };
27 this.scriptFiles = this.createScripts();
28 }
29 async createScripts() {
30 const defaultTemplatesDir = (0, pathManager_1.getTemplatePath)("linux");
31 const packager = this.packager;
32 const templateOptions = {
33 // old API compatibility
34 executable: packager.executableName,
35 sanitizedProductName: packager.appInfo.sanitizedProductName,
36 productFilename: packager.appInfo.productFilename,
37 ...packager.platformSpecificBuildOptions,
38 };
39 function getResource(value, defaultFile) {
40 if (value == null) {
41 return path.join(defaultTemplatesDir, defaultFile);
42 }
43 return path.resolve(packager.projectDir, value);
44 }
45 return await Promise.all([
46 writeConfigFile(packager.info.tempDirManager, getResource(this.options.afterInstall, "after-install.tpl"), templateOptions),
47 writeConfigFile(packager.info.tempDirManager, getResource(this.options.afterRemove, "after-remove.tpl"), templateOptions),
48 ]);
49 }
50 checkOptions() {
51 return this.computeFpmMetaInfoOptions();
52 }
53 async computeFpmMetaInfoOptions() {
54 var _a;
55 const packager = this.packager;
56 const projectUrl = await packager.appInfo.computePackageUrl();
57 const errors = [];
58 if (projectUrl == null) {
59 errors.push("Please specify project homepage, see https://electron.build/configuration/configuration#Metadata-homepage");
60 }
61 const options = this.options;
62 let author = options.maintainer;
63 if (author == null) {
64 const a = packager.info.metadata.author;
65 if (a == null || a.email == null) {
66 errors.push(errorMessages.authorEmailIsMissed);
67 }
68 else {
69 author = `${a.name} <${a.email}>`;
70 }
71 }
72 if (errors.length > 0) {
73 throw new Error(errors.join("\n\n"));
74 }
75 return {
76 name: (_a = options.packageName) !== null && _a !== void 0 ? _a : this.packager.appInfo.linuxPackageName,
77 maintainer: author,
78 url: projectUrl,
79 vendor: options.vendor || author,
80 };
81 }
82 async build(appOutDir, arch) {
83 var _a;
84 const target = this.name;
85 // tslint:disable:no-invalid-template-strings
86 let nameFormat = "${name}-${version}-${arch}.${ext}";
87 let isUseArchIfX64 = false;
88 if (target === "deb") {
89 nameFormat = "${name}_${version}_${arch}.${ext}";
90 isUseArchIfX64 = true;
91 }
92 else if (target === "rpm") {
93 nameFormat = "${name}-${version}.${arch}.${ext}";
94 isUseArchIfX64 = true;
95 }
96 const packager = this.packager;
97 const artifactName = packager.expandArtifactNamePattern(this.options, target, arch, nameFormat, !isUseArchIfX64);
98 const artifactPath = path.join(this.outDir, artifactName);
99 await packager.info.callArtifactBuildStarted({
100 targetPresentableName: target,
101 file: artifactPath,
102 arch,
103 });
104 await (0, fs_1.unlinkIfExists)(artifactPath);
105 if (packager.packagerOptions.prepackaged != null) {
106 await (0, promises_1.mkdir)(this.outDir, { recursive: true });
107 }
108 const publishConfig = this.supportsAutoUpdate(target)
109 ? await (0, PublishManager_1.getAppUpdatePublishConfiguration)(packager, arch, false /* in any case validation will be done on publish */)
110 : null;
111 if (publishConfig != null) {
112 const linuxDistType = this.packager.packagerOptions.prepackaged || path.join(this.outDir, `linux${(0, builder_util_1.getArchSuffix)(arch)}-unpacked`);
113 const resourceDir = packager.getResourcesDir(linuxDistType);
114 builder_util_1.log.info({ resourceDir }, `adding autoupdate files for: ${target}. (Beta feature)`);
115 await (0, fs_extra_1.outputFile)(path.join(resourceDir, "app-update.yml"), (0, builder_util_1.serializeToYaml)(publishConfig));
116 // Extra file needed for auto-updater to detect installation method
117 await (0, fs_extra_1.outputFile)(path.join(resourceDir, "package-type"), target);
118 }
119 const scripts = await this.scriptFiles;
120 const appInfo = packager.appInfo;
121 const options = this.options;
122 const synopsis = options.synopsis;
123 const args = [
124 "--architecture",
125 (0, builder_util_1.toLinuxArchString)(arch, target),
126 "--after-install",
127 scripts[0],
128 "--after-remove",
129 scripts[1],
130 "--description",
131 (0, appInfo_1.smarten)(target === "rpm" ? this.helper.getDescription(options) : `${synopsis || ""}\n ${this.helper.getDescription(options)}`),
132 "--version",
133 this.helper.getSanitizedVersion(target),
134 "--package",
135 artifactPath,
136 ];
137 (0, appBuilder_1.objectToArgs)(args, (await this.computeFpmMetaInfoOptions()));
138 const packageCategory = options.packageCategory;
139 if (packageCategory != null) {
140 args.push("--category", packageCategory);
141 }
142 if (target === "deb") {
143 args.push("--deb-priority", (_a = options.priority) !== null && _a !== void 0 ? _a : "optional");
144 }
145 else if (target === "rpm") {
146 if (synopsis != null) {
147 args.push("--rpm-summary", (0, appInfo_1.smarten)(synopsis));
148 }
149 }
150 const fpmConfiguration = {
151 args,
152 target,
153 };
154 if (options.compression != null) {
155 fpmConfiguration.compression = options.compression;
156 }
157 // noinspection JSDeprecatedSymbols
158 const depends = options.depends;
159 if (depends != null) {
160 if (Array.isArray(depends)) {
161 fpmConfiguration.customDepends = depends;
162 }
163 else {
164 // noinspection SuspiciousTypeOfGuard
165 if (typeof depends === "string") {
166 fpmConfiguration.customDepends = [depends];
167 }
168 else {
169 throw new Error(`depends must be Array or String, but specified as: ${depends}`);
170 }
171 }
172 }
173 if (target === "deb") {
174 const recommends = options.recommends;
175 if (recommends) {
176 fpmConfiguration.customRecommends = (0, builder_util_1.asArray)(recommends);
177 }
178 }
179 (0, builder_util_1.use)(packager.info.metadata.license, it => args.push("--license", it));
180 (0, builder_util_1.use)(appInfo.buildNumber, it => args.push("--iteration",
181 // dashes are not supported for iteration in older versions of fpm
182 // https://github.com/jordansissel/fpm/issues/1833
183 it.split("-").join("_")));
184 (0, builder_util_1.use)(options.fpm, it => args.push(...it));
185 args.push(`${appOutDir}/=${LinuxTargetHelper_1.installPrefix}/${appInfo.sanitizedProductName}`);
186 for (const icon of await this.helper.icons) {
187 const extWithDot = path.extname(icon.file);
188 const sizeName = extWithDot === ".svg" ? "scalable" : `${icon.size}x${icon.size}`;
189 args.push(`${icon.file}=/usr/share/icons/hicolor/${sizeName}/apps/${packager.executableName}${extWithDot}`);
190 }
191 const mimeTypeFilePath = await this.helper.mimeTypeFiles;
192 if (mimeTypeFilePath != null) {
193 args.push(`${mimeTypeFilePath}=/usr/share/mime/packages/${packager.executableName}.xml`);
194 }
195 const desktopFilePath = await this.helper.writeDesktopEntry(this.options);
196 args.push(`${desktopFilePath}=/usr/share/applications/${packager.executableName}.desktop`);
197 if (packager.packagerOptions.effectiveOptionComputed != null && (await packager.packagerOptions.effectiveOptionComputed([args, desktopFilePath]))) {
198 return;
199 }
200 const env = {
201 ...process.env,
202 SZA_PATH: await (0, builder_util_2.getPath7za)(),
203 SZA_COMPRESSION_LEVEL: packager.compression === "store" ? "0" : "9",
204 };
205 // rpmbuild wants directory rpm with some default config files. Even if we can use dylibbundler, path to such config files are not changed (we need to replace in the binary)
206 // so, for now, brew install rpm is still required.
207 if (target !== "rpm" && (await (0, macosVersion_1.isMacOsSierra)())) {
208 const linuxToolsPath = await (0, tools_1.getLinuxToolsPath)();
209 Object.assign(env, {
210 PATH: (0, bundledTool_1.computeEnv)(process.env.PATH, [path.join(linuxToolsPath, "bin")]),
211 DYLD_LIBRARY_PATH: (0, bundledTool_1.computeEnv)(process.env.DYLD_LIBRARY_PATH, [path.join(linuxToolsPath, "lib")]),
212 });
213 }
214 await (0, builder_util_1.executeAppBuilder)(["fpm", "--configuration", JSON.stringify(fpmConfiguration)], undefined, { env });
215 let info = {
216 file: artifactPath,
217 target: this,
218 arch,
219 packager,
220 };
221 if (publishConfig != null) {
222 info = {
223 ...info,
224 safeArtifactName: packager.computeSafeArtifactName(artifactName, target, arch, !isUseArchIfX64),
225 isWriteUpdateInfo: true,
226 updateInfo: {
227 sha512: await (0, hash_1.hashFile)(artifactPath),
228 size: (await (0, fs_extra_1.stat)(artifactPath)).size,
229 },
230 };
231 }
232 await packager.info.callArtifactBuildCompleted(info);
233 }
234 supportsAutoUpdate(target) {
235 return ["deb", "rpm"].includes(target);
236 }
237}
238exports.default = FpmTarget;
239async function writeConfigFile(tmpDir, templatePath, options) {
240 //noinspection JSUnusedLocalSymbols
241 function replacer(match, p1) {
242 if (p1 in options) {
243 return options[p1];
244 }
245 else {
246 throw new Error(`Macro ${p1} is not defined`);
247 }
248 }
249 const config = (await (0, promises_1.readFile)(templatePath, "utf8")).replace(/\${([a-zA-Z]+)}/g, replacer).replace(/<%=([a-zA-Z]+)%>/g, (match, p1) => {
250 builder_util_1.log.warn("<%= varName %> is deprecated, please use ${varName} instead");
251 return replacer(match, p1.trim());
252 });
253 const outputPath = await tmpDir.getTempFile({ suffix: path.basename(templatePath, ".tpl") });
254 await (0, fs_extra_1.outputFile)(outputPath, config);
255 return outputPath;
256}
257//# sourceMappingURL=FpmTarget.js.map
\No newline at end of file