Skip to content

Commit 3bacf54

Browse files
committed
Parallelize signing
1 parent a5bf4d4 commit 3bacf54

File tree

3 files changed

+122
-93
lines changed

3 files changed

+122
-93
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"fs-extra": "^10.0.0",
3535
"isbinaryfile": "^4.0.8",
3636
"minimist": "^1.2.6",
37+
"p-limit": "^6.2.0",
3738
"plist": "^3.0.5"
3839
},
3940
"devDependencies": {

src/sign.ts

+120-92
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import * as os from 'os';
33
import * as path from 'path';
44
import * as plist from 'plist';
55
import compareVersion from 'compare-version';
6+
import pLimit from 'p-limit';
7+
8+
const limit = pLimit(20);
69

710
import {
811
debugLog,
@@ -199,103 +202,128 @@ async function signApplication (opts: ValidatedSignOptions, identity: Identity)
199202
return bDepth - aDepth;
200203
});
201204

202-
for (const filePath of [...children, opts.app]) {
203-
if (shouldIgnoreFilePath(filePath)) {
204-
debugLog('Skipped... ' + filePath);
205-
continue;
206-
}
205+
let filesByLength: any[] = [];
206+
for (let s of [...children, opts.app]) {
207+
let len = s.split(path.sep).length;
207208

208-
const perFileOptions = await mergeOptionsForFile(
209-
opts.optionsForFile ? opts.optionsForFile(filePath) : null,
210-
defaultOptionsForFile(filePath, opts.platform)
211-
);
209+
if (filesByLength[len] === undefined)
210+
filesByLength[len] = [];
212211

213-
// preAutoEntitlements should only be applied to the top level app bundle.
214-
// Applying it other files will cause the app to crash and be rejected by Apple.
215-
if (!filePath.includes('.app/')) {
216-
if (opts.preAutoEntitlements === false) {
217-
debugWarn('Pre-sign operation disabled for entitlements automation.');
218-
} else {
219-
debugLog(
220-
'Pre-sign operation enabled for entitlements automation with versions >= `1.1.1`:',
221-
'\n',
222-
'* Disable by setting `pre-auto-entitlements` to `false`.'
223-
);
224-
if (!opts.version || compareVersion(opts.version, '1.1.1') >= 0) {
225-
// Enable Mac App Store sandboxing without using temporary-exception, introduced in Electron v1.1.1. Relates to electron#5601
226-
const newEntitlements = await preAutoEntitlements(opts, perFileOptions, {
227-
identity,
228-
provisioningProfile: opts.provisioningProfile
229-
? await getProvisioningProfile(opts.provisioningProfile, opts.keychain)
230-
: undefined
212+
filesByLength[len].push(s);
213+
}
214+
filesByLength.reverse();
215+
216+
const signingPromises = filesByLength.map((files) => {
217+
return {
218+
files: files,
219+
run: async () => await Promise.all(
220+
files.map((filePath: string) => {
221+
return limit(async () => {
222+
if (shouldIgnoreFilePath(filePath)) {
223+
debugLog('Skipped... ' + filePath);
224+
return;
225+
}
226+
227+
const perFileOptions = await mergeOptionsForFile(
228+
opts.optionsForFile ? opts.optionsForFile(filePath) : null,
229+
defaultOptionsForFile(filePath, opts.platform)
230+
);
231+
232+
// preAutoEntitlements should only be applied to the top level app bundle.
233+
// Applying it other files will cause the app to crash and be rejected by Apple.
234+
if (!filePath.includes('.app/')) {
235+
if (opts.preAutoEntitlements === false) {
236+
debugWarn('Pre-sign operation disabled for entitlements automation.');
237+
} else {
238+
debugLog(
239+
'Pre-sign operation enabled for entitlements automation with versions >= `1.1.1`:',
240+
'\n',
241+
'* Disable by setting `pre-auto-entitlements` to `false`.'
242+
);
243+
if (!opts.version || compareVersion(opts.version, '1.1.1') >= 0) {
244+
// Enable Mac App Store sandboxing without using temporary-exception, introduced in Electron v1.1.1. Relates to electron#5601
245+
const newEntitlements = await preAutoEntitlements(opts, perFileOptions, {
246+
identity,
247+
provisioningProfile: opts.provisioningProfile
248+
? await getProvisioningProfile(opts.provisioningProfile, opts.keychain)
249+
: undefined
250+
});
251+
252+
// preAutoEntitlements may provide us new entitlements, if so we update our options
253+
// and ensure that entitlements-loginhelper has a correct default value
254+
if (newEntitlements) {
255+
perFileOptions.entitlements = newEntitlements;
256+
}
257+
}
258+
}
259+
}
260+
261+
debugLog('Signing in parallel... ' + filePath);
262+
263+
const perFileArgs = [...args];
264+
265+
if (perFileOptions.requirements) {
266+
if (perFileOptions.requirements.charAt(0) === '=') {
267+
perFileArgs.push(`-r${perFileOptions.requirements}`);
268+
} else {
269+
perFileArgs.push('--requirements', perFileOptions.requirements);
270+
}
271+
}
272+
if (perFileOptions.timestamp) {
273+
perFileArgs.push('--timestamp=' + perFileOptions.timestamp);
274+
} else {
275+
perFileArgs.push('--timestamp');
276+
}
277+
278+
let optionsArguments: string[] = [];
279+
280+
if (perFileOptions.signatureFlags) {
281+
if (Array.isArray(perFileOptions.signatureFlags)) {
282+
optionsArguments.push(...perFileOptions.signatureFlags);
283+
} else {
284+
const flags = perFileOptions.signatureFlags.split(',').map(function (flag) {
285+
return flag.trim();
286+
});
287+
optionsArguments.push(...flags);
288+
}
289+
}
290+
291+
if (perFileOptions.hardenedRuntime || optionsArguments.includes('runtime')) {
292+
// Hardened runtime since darwin 17.7.0 --> macOS 10.13.6
293+
if (compareVersion(osRelease, '17.7.0') >= 0) {
294+
optionsArguments.push('runtime');
295+
} else {
296+
// Remove runtime if passed in with --signature-flags
297+
debugLog(
298+
'Not enabling hardened runtime, current macOS version too low, requires 10.13.6 and higher'
299+
);
300+
optionsArguments = optionsArguments.filter((arg) => {
301+
return arg !== 'runtime';
302+
});
303+
}
304+
}
305+
306+
if (optionsArguments.length) {
307+
perFileArgs.push('--options', [...new Set(optionsArguments)].join(','));
308+
}
309+
310+
if (perFileOptions.additionalArguments) {
311+
perFileArgs.push(...perFileOptions.additionalArguments);
312+
}
313+
314+
await execFileAsync(
315+
'codesign',
316+
perFileArgs.concat('--entitlements', perFileOptions.entitlements, filePath)
317+
);
231318
});
232-
233-
// preAutoEntitlements may provide us new entitlements, if so we update our options
234-
// and ensure that entitlements-loginhelper has a correct default value
235-
if (newEntitlements) {
236-
perFileOptions.entitlements = newEntitlements;
237-
}
238-
}
239-
}
240-
}
241-
242-
debugLog('Signing... ' + filePath);
243-
244-
const perFileArgs = [...args];
245-
246-
if (perFileOptions.requirements) {
247-
if (perFileOptions.requirements.charAt(0) === '=') {
248-
perFileArgs.push(`-r${perFileOptions.requirements}`);
249-
} else {
250-
perFileArgs.push('--requirements', perFileOptions.requirements);
251-
}
252-
}
253-
if (perFileOptions.timestamp) {
254-
perFileArgs.push('--timestamp=' + perFileOptions.timestamp);
255-
} else {
256-
perFileArgs.push('--timestamp');
257-
}
258-
259-
let optionsArguments: string[] = [];
260-
261-
if (perFileOptions.signatureFlags) {
262-
if (Array.isArray(perFileOptions.signatureFlags)) {
263-
optionsArguments.push(...perFileOptions.signatureFlags);
264-
} else {
265-
const flags = perFileOptions.signatureFlags.split(',').map(function (flag) {
266-
return flag.trim();
267-
});
268-
optionsArguments.push(...flags);
269-
}
270-
}
271-
272-
if (perFileOptions.hardenedRuntime || optionsArguments.includes('runtime')) {
273-
// Hardened runtime since darwin 17.7.0 --> macOS 10.13.6
274-
if (compareVersion(osRelease, '17.7.0') >= 0) {
275-
optionsArguments.push('runtime');
276-
} else {
277-
// Remove runtime if passed in with --signature-flags
278-
debugLog(
279-
'Not enabling hardened runtime, current macOS version too low, requires 10.13.6 and higher'
280-
);
281-
optionsArguments = optionsArguments.filter((arg) => {
282-
return arg !== 'runtime';
283-
});
284-
}
285-
}
286-
287-
if (optionsArguments.length) {
288-
perFileArgs.push('--options', [...new Set(optionsArguments)].join(','));
289-
}
290-
291-
if (perFileOptions.additionalArguments) {
292-
perFileArgs.push(...perFileOptions.additionalArguments);
319+
})
320+
)
293321
}
322+
});
294323

295-
await execFileAsync(
296-
'codesign',
297-
perFileArgs.concat('--entitlements', perFileOptions.entitlements, filePath)
298-
);
324+
for (const idx in signingPromises) {
325+
let { run } = signingPromises[idx];
326+
await run();
299327
}
300328

301329
// Verify code sign

src/util.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export async function walkAsync (dirPath: string): Promise<string[]> {
142142
children.map(async (child) => {
143143
const filePath = path.resolve(dirPath, child);
144144

145-
const stat = await fs.stat(filePath);
145+
const stat = await fs.lstat(filePath);
146146
if (stat.isFile()) {
147147
switch (path.extname(filePath)) {
148148
case '.cstemp': // Temporary file generated from past codesign

0 commit comments

Comments
 (0)