UNPKG

10.3 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.computeNodeModuleFileSets = exports.computeFileSets = exports.transformFiles = exports.copyAppFiles = exports.getDestinationPath = exports.ELECTRON_COMPILE_SHIM_FILENAME = void 0;
4const bluebird_lst_1 = require("bluebird-lst");
5const builder_util_1 = require("builder-util");
6const fs_1 = require("builder-util/out/fs");
7const promises_1 = require("fs/promises");
8const path = require("path");
9const unpackDetector_1 = require("../asar/unpackDetector");
10const core_1 = require("../core");
11const fileMatcher_1 = require("../fileMatcher");
12const fileTransformer_1 = require("../fileTransformer");
13const AppFileWalker_1 = require("./AppFileWalker");
14const NodeModuleCopyHelper_1 = require("./NodeModuleCopyHelper");
15const BOWER_COMPONENTS_PATTERN = `${path.sep}bower_components${path.sep}`;
16/** @internal */
17exports.ELECTRON_COMPILE_SHIM_FILENAME = "__shim.js";
18function getDestinationPath(file, fileSet) {
19 if (file === fileSet.src) {
20 return fileSet.destination;
21 }
22 else {
23 const src = fileSet.src;
24 const dest = fileSet.destination;
25 if (file.length > src.length && file.startsWith(src) && file[src.length] === path.sep) {
26 return dest + file.substring(src.length);
27 }
28 else {
29 // hoisted node_modules
30 // not lastIndexOf, to ensure that nested module (top-level module depends on) copied to parent node_modules, not to top-level directory
31 // project https://github.com/angexis/punchcontrol/commit/cf929aba55c40d0d8901c54df7945e1d001ce022
32 let index = file.indexOf(fileTransformer_1.NODE_MODULES_PATTERN);
33 if (index < 0 && file.endsWith(`${path.sep}node_modules`)) {
34 index = file.length - 13;
35 }
36 if (index < 0) {
37 throw new Error(`File "${file}" not under the source directory "${fileSet.src}"`);
38 }
39 return dest + file.substring(index);
40 }
41 }
42}
43exports.getDestinationPath = getDestinationPath;
44async function copyAppFiles(fileSet, packager, transformer) {
45 const metadata = fileSet.metadata;
46 // search auto unpacked dir
47 const taskManager = new builder_util_1.AsyncTaskManager(packager.cancellationToken);
48 const createdParentDirs = new Set();
49 const fileCopier = new fs_1.FileCopier(file => {
50 // https://github.com/electron-userland/electron-builder/issues/3038
51 return !(unpackDetector_1.isLibOrExe(file) || file.endsWith(".node"));
52 }, transformer);
53 const links = [];
54 for (let i = 0, n = fileSet.files.length; i < n; i++) {
55 const sourceFile = fileSet.files[i];
56 const stat = metadata.get(sourceFile);
57 if (stat == null) {
58 // dir
59 continue;
60 }
61 const destinationFile = getDestinationPath(sourceFile, fileSet);
62 if (stat.isSymbolicLink()) {
63 links.push({ file: destinationFile, link: await promises_1.readlink(sourceFile) });
64 continue;
65 }
66 const fileParent = path.dirname(destinationFile);
67 if (!createdParentDirs.has(fileParent)) {
68 createdParentDirs.add(fileParent);
69 await promises_1.mkdir(fileParent, { recursive: true });
70 }
71 taskManager.addTask(fileCopier.copy(sourceFile, destinationFile, stat));
72 if (taskManager.tasks.length > fs_1.MAX_FILE_REQUESTS) {
73 await taskManager.awaitTasks();
74 }
75 }
76 if (taskManager.tasks.length > 0) {
77 await taskManager.awaitTasks();
78 }
79 if (links.length > 0) {
80 await bluebird_lst_1.default.map(links, it => promises_1.symlink(it.link, it.file), fs_1.CONCURRENCY);
81 }
82}
83exports.copyAppFiles = copyAppFiles;
84// used only for ASAR, if no asar, file transformed on the fly
85async function transformFiles(transformer, fileSet) {
86 if (transformer == null) {
87 return;
88 }
89 let transformedFiles = fileSet.transformedFiles;
90 if (fileSet.transformedFiles == null) {
91 transformedFiles = new Map();
92 fileSet.transformedFiles = transformedFiles;
93 }
94 const metadata = fileSet.metadata;
95 await bluebird_lst_1.default.filter(fileSet.files, (it, index) => {
96 const fileStat = metadata.get(it);
97 if (fileStat == null || !fileStat.isFile()) {
98 return false;
99 }
100 const transformedValue = transformer(it);
101 if (transformedValue == null) {
102 return false;
103 }
104 if (typeof transformedValue === "object" && "then" in transformedValue) {
105 return transformedValue.then(it => {
106 if (it != null) {
107 transformedFiles.set(index, it);
108 }
109 return false;
110 });
111 }
112 transformedFiles.set(index, transformedValue);
113 return false;
114 }, fs_1.CONCURRENCY);
115}
116exports.transformFiles = transformFiles;
117async function computeFileSets(matchers, transformer, platformPackager, isElectronCompile) {
118 const fileSets = [];
119 const packager = platformPackager.info;
120 for (const matcher of matchers) {
121 const fileWalker = new AppFileWalker_1.AppFileWalker(matcher, packager);
122 const fromStat = await fs_1.statOrNull(matcher.from);
123 if (fromStat == null) {
124 builder_util_1.log.debug({ directory: matcher.from, reason: "doesn't exist" }, `skipped copying`);
125 continue;
126 }
127 const files = await fs_1.walk(matcher.from, fileWalker.filter, fileWalker);
128 const metadata = fileWalker.metadata;
129 fileSets.push(validateFileSet({ src: matcher.from, files, metadata, destination: matcher.to }));
130 }
131 if (isElectronCompile) {
132 // cache files should be first (better IO)
133 fileSets.unshift(await compileUsingElectronCompile(fileSets[0], packager));
134 }
135 return fileSets;
136}
137exports.computeFileSets = computeFileSets;
138function getNodeModuleExcludedExts(platformPackager) {
139 // do not exclude *.h files (https://github.com/electron-userland/electron-builder/issues/2852)
140 const result = [".o", ".obj"].concat(fileMatcher_1.excludedExts.split(",").map(it => `.${it}`));
141 if (platformPackager.config.includePdb !== true) {
142 result.push(".pdb");
143 }
144 if (platformPackager.platform !== core_1.Platform.WINDOWS) {
145 // https://github.com/electron-userland/electron-builder/issues/1738
146 result.push(".dll");
147 result.push(".exe");
148 }
149 return result;
150}
151function validateFileSet(fileSet) {
152 if (fileSet.src == null || fileSet.src.length === 0) {
153 throw new Error("fileset src is empty");
154 }
155 return fileSet;
156}
157/** @internal */
158async function computeNodeModuleFileSets(platformPackager, mainMatcher) {
159 const deps = await platformPackager.info.getNodeDependencyInfo(platformPackager.platform).value;
160 const nodeModuleExcludedExts = getNodeModuleExcludedExts(platformPackager);
161 // serial execution because copyNodeModules is concurrent and so, no need to increase queue/pressure
162 const result = new Array();
163 let index = 0;
164 for (const info of deps) {
165 const source = info.dir;
166 const destination = getDestinationPath(source, { src: mainMatcher.from, destination: mainMatcher.to, files: [], metadata: null });
167 // use main matcher patterns, so, user can exclude some files in such hoisted node modules
168 // source here includes node_modules, but pattern base should be without because users expect that pattern "!node_modules/loot-core/src{,/**/*}" will work
169 const matcher = new fileMatcher_1.FileMatcher(path.dirname(source), destination, mainMatcher.macroExpander, mainMatcher.patterns);
170 const copier = new NodeModuleCopyHelper_1.NodeModuleCopyHelper(matcher, platformPackager.info);
171 const files = await copier.collectNodeModules(source, info.deps.map(it => it.name), nodeModuleExcludedExts);
172 result[index++] = validateFileSet({ src: source, destination, files, metadata: copier.metadata });
173 }
174 return result;
175}
176exports.computeNodeModuleFileSets = computeNodeModuleFileSets;
177async function compileUsingElectronCompile(mainFileSet, packager) {
178 builder_util_1.log.info("compiling using electron-compile");
179 const electronCompileCache = await packager.tempDirManager.getTempDir({ prefix: "electron-compile-cache" });
180 const cacheDir = path.join(electronCompileCache, ".cache");
181 // clear and create cache dir
182 await promises_1.mkdir(cacheDir, { recursive: true });
183 const compilerHost = await fileTransformer_1.createElectronCompilerHost(mainFileSet.src, cacheDir);
184 const nextSlashIndex = mainFileSet.src.length + 1;
185 // pre-compute electron-compile to cache dir - we need to process only subdirectories, not direct files of app dir
186 await bluebird_lst_1.default.map(mainFileSet.files, file => {
187 if (file.includes(fileTransformer_1.NODE_MODULES_PATTERN) ||
188 file.includes(BOWER_COMPONENTS_PATTERN) ||
189 !file.includes(path.sep, nextSlashIndex) || // ignore not root files
190 !mainFileSet.metadata.get(file).isFile()) {
191 return null;
192 }
193 return compilerHost.compile(file).then(() => null);
194 }, fs_1.CONCURRENCY);
195 await compilerHost.saveConfiguration();
196 const metadata = new Map();
197 const cacheFiles = await fs_1.walk(cacheDir, file => !file.startsWith("."), {
198 consume: (file, fileStat) => {
199 if (fileStat.isFile()) {
200 metadata.set(file, fileStat);
201 }
202 return null;
203 },
204 });
205 // add shim
206 const shimPath = `${mainFileSet.src}${path.sep}${exports.ELECTRON_COMPILE_SHIM_FILENAME}`;
207 mainFileSet.files.push(shimPath);
208 mainFileSet.metadata.set(shimPath, { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false });
209 if (mainFileSet.transformedFiles == null) {
210 mainFileSet.transformedFiles = new Map();
211 }
212 mainFileSet.transformedFiles.set(mainFileSet.files.length - 1, `
213'use strict';
214require('electron-compile').init(__dirname, require('path').resolve(__dirname, '${packager.metadata.main || "index"}'), true);
215`);
216 return { src: electronCompileCache, files: cacheFiles, metadata, destination: mainFileSet.destination };
217}
218//# sourceMappingURL=appFileCopier.js.map
\No newline at end of file