build-mac.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #!/usr/bin/env node
  2. import fs from 'fs';
  3. import path from 'path';
  4. import { spawnSync } from 'child_process';
  5. import { fileURLToPath } from 'url';
  6. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  7. const projectRoot = path.resolve(__dirname, '..');
  8. const prepareScript = path.join(projectRoot, 'scripts', 'prepare-electron-browsers.js');
  9. const iconScript = path.join(projectRoot, 'scripts', 'build-icon.js');
  10. const electronBuilderBin = path.join(
  11. projectRoot,
  12. 'node_modules',
  13. '.bin',
  14. process.platform === 'win32' ? 'electron-builder.cmd' : 'electron-builder'
  15. );
  16. const electronVersion = JSON.parse(
  17. fs.readFileSync(path.join(projectRoot, 'node_modules', 'electron', 'package.json'), 'utf8')
  18. ).version;
  19. const electronDistDir = path.join(projectRoot, '.electron-build', 'electron-dist');
  20. const rawArgs = process.argv.slice(2);
  21. const targets = rawArgs.filter((arg) => !arg.startsWith('--'));
  22. const allArch = rawArgs.includes('--all-arch');
  23. const buildArch = process.arch === 'arm64' ? 'arm64' : 'x64';
  24. const archFlag = buildArch === 'arm64' ? '--arm64' : '--x64';
  25. const builderArgs = ['--mac', ...(targets.length ? targets : ['dmg', 'zip'])];
  26. if (!allArch) builderArgs.push(archFlag);
  27. const env = {
  28. ...process.env,
  29. CSC_IDENTITY_AUTO_DISCOVERY: 'false',
  30. };
  31. function run(command, args) {
  32. return spawnSync(command, args, {
  33. cwd: projectRoot,
  34. stdio: 'inherit',
  35. env,
  36. });
  37. }
  38. function ensureElectronDistZip(arch) {
  39. fs.mkdirSync(electronDistDir, { recursive: true });
  40. const zipName = `electron-v${electronVersion}-darwin-${arch}.zip`;
  41. const zipPath = path.join(electronDistDir, zipName);
  42. if (fs.existsSync(zipPath) && fs.statSync(zipPath).size > 50 * 1024 * 1024) {
  43. return zipPath;
  44. }
  45. const url = `https://github.com/electron/electron/releases/download/v${electronVersion}/${zipName}`;
  46. const curlArgs = [
  47. '-L',
  48. '--fail',
  49. '--retry', '5',
  50. '--retry-delay', '2',
  51. '--continue-at', '-',
  52. '--output', zipPath,
  53. url,
  54. ];
  55. const result = run('curl', curlArgs);
  56. if (result.status !== 0) {
  57. process.exit(result.status || 1);
  58. }
  59. return zipPath;
  60. }
  61. const prepare = run(process.execPath, [prepareScript]);
  62. if (prepare.status !== 0) {
  63. process.exit(prepare.status || 1);
  64. }
  65. const iconBuild = run(process.execPath, [iconScript]);
  66. if (iconBuild.status !== 0) {
  67. process.exit(iconBuild.status || 1);
  68. }
  69. if (!allArch) {
  70. const zipPath = ensureElectronDistZip(buildArch);
  71. builderArgs.push(`-c.electronDist=${zipPath}`);
  72. }
  73. for (let attempt = 1; attempt <= 2; attempt++) {
  74. if (attempt > 1) {
  75. console.log(`[build-mac] Retry ${attempt}/2...`);
  76. }
  77. const result = run(electronBuilderBin, builderArgs);
  78. if (result.status === 0) {
  79. process.exit(0);
  80. }
  81. if (attempt === 2) {
  82. process.exit(result.status || 1);
  83. }
  84. }