utils.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const { GitProcess } = require('dugite');
  2. const fs = require('fs');
  3. const klaw = require('klaw');
  4. const os = require('os');
  5. const path = require('path');
  6. const ELECTRON_DIR = path.resolve(__dirname, '..', '..');
  7. const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
  8. require('colors');
  9. const pass = '✓'.green;
  10. const fail = '✗'.red;
  11. function getElectronExec () {
  12. const OUT_DIR = getOutDir();
  13. switch (process.platform) {
  14. case 'darwin':
  15. return `out/${OUT_DIR}/Electron.app/Contents/MacOS/Electron`;
  16. case 'win32':
  17. return `out/${OUT_DIR}/electron.exe`;
  18. case 'linux':
  19. return `out/${OUT_DIR}/electron`;
  20. default:
  21. throw new Error('Unknown platform');
  22. }
  23. }
  24. function getOutDir (options = {}) {
  25. const shouldLog = options.shouldLog || false;
  26. const presetDirs = ['Testing', 'Release', 'Default', 'Debug'];
  27. if (options.outDir || process.env.ELECTRON_OUT_DIR) {
  28. const outDir = options.outDir || process.env.ELECTRON_OUT_DIR;
  29. const outPath = path.resolve(SRC_DIR, 'out', outDir);
  30. // Check that user-set variable is a valid/existing directory
  31. if (fs.existsSync(outPath)) {
  32. if (shouldLog) console.log(`OUT_DIR is: ${outDir}`);
  33. return outDir;
  34. }
  35. // Throw error if user passed/set nonexistent directory.
  36. throw new Error(`${outDir} directory not configured on your machine.`);
  37. } else {
  38. for (const buildType of presetDirs) {
  39. const outPath = path.resolve(SRC_DIR, 'out', buildType);
  40. if (fs.existsSync(outPath)) {
  41. if (shouldLog) console.log(`OUT_DIR is: ${buildType}`);
  42. return buildType;
  43. }
  44. }
  45. }
  46. // If we got here, it means process.env.ELECTRON_OUT_DIR was not
  47. // set and none of the preset options could be found in /out, so throw
  48. throw new Error(`No valid out directory found; use one of ${presetDirs.join(',')} or set process.env.ELECTRON_OUT_DIR`);
  49. }
  50. function getAbsoluteElectronExec () {
  51. return path.resolve(SRC_DIR, getElectronExec());
  52. }
  53. async function handleGitCall (args, gitDir) {
  54. const details = await GitProcess.exec(args, gitDir);
  55. if (details.exitCode === 0) {
  56. return details.stdout.replace(/^\*|\s+|\s+$/, '');
  57. } else {
  58. const error = GitProcess.parseError(details.stderr);
  59. console.log(`${fail} couldn't parse git process call: `, error);
  60. process.exit(1);
  61. }
  62. }
  63. async function getCurrentBranch (gitDir) {
  64. const RELEASE_BRANCH_PATTERN = /^\d+-x-y$/;
  65. const MAIN_BRANCH_PATTERN = /^main$/;
  66. const ORIGIN_MAIN_BRANCH_PATTERN = /^origin\/main$/;
  67. let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir);
  68. if (!MAIN_BRANCH_PATTERN.test(branch) && !RELEASE_BRANCH_PATTERN.test(branch)) {
  69. const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir);
  70. const branches = (await handleGitCall([
  71. 'branch',
  72. '--contains',
  73. lastCommit,
  74. '--remote'
  75. ], gitDir)).split('\n');
  76. branch = branches.find(b => MAIN_BRANCH_PATTERN.test(b.trim()) || ORIGIN_MAIN_BRANCH_PATTERN.test(b.trim()) || RELEASE_BRANCH_PATTERN.test(b.trim()));
  77. if (!branch) {
  78. console.log(`${fail} no release branch exists for this ref`);
  79. process.exit(1);
  80. }
  81. if (branch.startsWith('origin/')) branch = branch.substr('origin/'.length);
  82. }
  83. return branch.trim();
  84. }
  85. function chunkFilenames (filenames, offset = 0) {
  86. // Windows has a max command line length of 2047 characters, so we can't
  87. // provide too many filenames without going over that. To work around that,
  88. // chunk up a list of filenames such that it won't go over that limit when
  89. // used as args. Other platforms may have higher limits, but 4095 might be
  90. // the limit on Linux systems according to `termios(3)`, so cap it there.
  91. const MAX_FILENAME_ARGS_LENGTH =
  92. (os.platform() === 'win32' ? 2047 : 4095) - offset;
  93. return filenames.reduce(
  94. (chunkedFilenames, filename) => {
  95. const currChunk = chunkedFilenames[chunkedFilenames.length - 1];
  96. const currChunkLength = currChunk.reduce(
  97. (totalLength, _filename) => totalLength + _filename.length + 1,
  98. 0
  99. );
  100. if (currChunkLength + filename.length + 1 > MAX_FILENAME_ARGS_LENGTH) {
  101. chunkedFilenames.push([filename]);
  102. } else {
  103. currChunk.push(filename);
  104. }
  105. return chunkedFilenames;
  106. },
  107. [[]]
  108. );
  109. }
  110. /**
  111. * @param {string} top
  112. * @param {(filename: string) => boolean} test
  113. * @returns {Promise<string[]>}
  114. */
  115. async function findMatchingFiles (top, test) {
  116. return new Promise((resolve, reject) => {
  117. const matches = [];
  118. klaw(top, {
  119. filter: f => path.basename(f) !== '.bin'
  120. })
  121. .on('end', () => resolve(matches))
  122. .on('data', item => {
  123. if (test(item.path)) {
  124. matches.push(item.path);
  125. }
  126. });
  127. });
  128. }
  129. module.exports = {
  130. chunkFilenames,
  131. findMatchingFiles,
  132. getCurrentBranch,
  133. getElectronExec,
  134. getOutDir,
  135. getAbsoluteElectronExec,
  136. handleGitCall,
  137. ELECTRON_DIR,
  138. SRC_DIR
  139. };