Files
electron/script/lib/utils.js
David Sanders 70a321634c build: don't use //third_party/depot_tools in gn build scripts (#50922)
build: don't use //third_party/depot_tools in gn build scripts (#50858)
2026-04-11 09:46:52 +02:00

225 lines
6.4 KiB
JavaScript

const chalk = require('chalk');
const childProcess = require('node:child_process');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const ELECTRON_DIR = path.resolve(__dirname, '..', '..');
const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const pass = chalk.green('✓');
const fail = chalk.red('✗');
function getElectronExec () {
const OUT_DIR = getOutDir();
switch (process.platform) {
case 'darwin':
return `out/${OUT_DIR}/Electron.app/Contents/MacOS/Electron`;
case 'win32':
return `out/${OUT_DIR}/electron.exe`;
case 'linux':
return `out/${OUT_DIR}/electron`;
default:
throw new Error('Unknown platform');
}
}
function getOutDir (options = {}) {
const shouldLog = options.shouldLog || false;
const presetDirs = ['Testing', 'Release', 'Default', 'Debug'];
if (options.outDir || process.env.ELECTRON_OUT_DIR) {
const outDir = options.outDir || process.env.ELECTRON_OUT_DIR;
const outPath = path.resolve(SRC_DIR, 'out', outDir);
// Check that user-set variable is a valid/existing directory
if (fs.existsSync(outPath)) {
if (shouldLog) console.log(`OUT_DIR is: ${outDir}`);
return outDir;
}
// Throw error if user passed/set nonexistent directory.
throw new Error(`${outDir} directory not configured on your machine.`);
} else {
for (const buildType of presetDirs) {
const outPath = path.resolve(SRC_DIR, 'out', buildType);
if (fs.existsSync(outPath)) {
if (shouldLog) console.log(`OUT_DIR is: ${buildType}`);
return buildType;
}
}
}
// If we got here, it means process.env.ELECTRON_OUT_DIR was not
// set and none of the preset options could be found in /out, so throw
throw new Error(`No valid out directory found; use one of ${presetDirs.join(',')} or set process.env.ELECTRON_OUT_DIR`);
}
function getAbsoluteElectronExec () {
return path.resolve(SRC_DIR, getElectronExec());
}
function handleGitCall (args, gitDir) {
const result = childProcess.spawnSync('git', args, {
cwd: gitDir,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (result.status === 0) {
return result.stdout.replace(/^\*|\s+|\s+$/, '');
} else {
console.log(`${fail} couldn't parse git process call: `, result.stderr);
process.exit(1);
}
}
async function getCurrentBranch (gitDir) {
const RELEASE_BRANCH_PATTERN = /^\d+-x-y$/;
const MAIN_BRANCH_PATTERN = /^main$/;
const ORIGIN_MAIN_BRANCH_PATTERN = /^origin\/main$/;
let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir);
if (!MAIN_BRANCH_PATTERN.test(branch) && !RELEASE_BRANCH_PATTERN.test(branch)) {
const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir);
const branches = (await handleGitCall([
'branch',
'--contains',
lastCommit,
'--remote'
], gitDir)).split('\n');
branch = branches.find(b => MAIN_BRANCH_PATTERN.test(b.trim()) || ORIGIN_MAIN_BRANCH_PATTERN.test(b.trim()) || RELEASE_BRANCH_PATTERN.test(b.trim()));
if (!branch) {
console.log(`${fail} no release branch exists for this ref`);
process.exit(1);
}
if (branch.startsWith('origin/')) branch = branch.substr('origin/'.length);
}
return branch.trim();
}
function chunkFilenames (filenames, offset = 0) {
// Windows has a max command line length of 2047 characters, so we can't
// provide too many filenames without going over that. To work around that,
// chunk up a list of filenames such that it won't go over that limit when
// used as args. Other platforms may have higher limits, but 4095 might be
// the limit on Linux systems according to `termios(3)`, so cap it there.
const MAX_FILENAME_ARGS_LENGTH =
(os.platform() === 'win32' ? 2047 : 4095) - offset;
return filenames.reduce(
(chunkedFilenames, filename) => {
const currChunk = chunkedFilenames[chunkedFilenames.length - 1];
const currChunkLength = currChunk.reduce(
(totalLength, _filename) => totalLength + _filename.length + 1,
0
);
if (currChunkLength + filename.length + 1 > MAX_FILENAME_ARGS_LENGTH) {
chunkedFilenames.push([filename]);
} else {
currChunk.push(filename);
}
return chunkedFilenames;
},
[[]]
);
}
/**
* @param {string} top
* @param {(filename: string) => boolean} test
* @returns {Promise<string[]>}
*/
async function findMatchingFiles (top, test) {
return fs.promises.readdir(top, { encoding: 'utf8', recursive: true })
.then(files => {
return files
.filter(name => path.basename(name) !== '.bin')
.filter(name => test(name))
.map(name => path.join(top, name));
});
}
function compareVersions (v1, v2) {
const [split1, split2] = [v1.split('.'), v2.split('.')];
if (split1.length !== split2.length) {
throw new Error(
`Expected version strings to have same number of sections: ${split1} and ${split2}`
);
}
for (let i = 0; i < split1.length; i++) {
const p1 = parseInt(split1[i], 10);
const p2 = parseInt(split2[i], 10);
if (p1 > p2) return 1;
else if (p1 < p2) return -1;
// Continue checking the value if this portion is equal
}
return 0;
}
function getDepotToolsEnv () {
let depotToolsEnv;
const findDepotToolsOnPath = () => {
const result = childProcess.spawnSync(
os.platform() === 'win32' ? 'where' : 'which',
['gclient']
);
if (result.status === 0) {
return process.env;
}
};
const checkForBuildTools = () => {
const result = childProcess.spawnSync(
'electron-build-tools',
['show', 'env', '--json'],
{ shell: true }
);
if (result.status === 0) {
return {
...process.env,
...JSON.parse(result.stdout.toString().trim())
};
}
};
try {
depotToolsEnv = checkForBuildTools();
if (!depotToolsEnv) depotToolsEnv = findDepotToolsOnPath();
} catch {}
if (!depotToolsEnv) {
throw new Error("Couldn't find depot_tools, ensure it's on your PATH");
}
if (!('CHROMIUM_BUILDTOOLS_PATH' in depotToolsEnv)) {
throw new Error(
'CHROMIUM_BUILDTOOLS_PATH environment variable must be set'
);
}
return depotToolsEnv;
}
module.exports = {
chunkFilenames,
compareVersions,
findMatchingFiles,
getCurrentBranch,
getDepotToolsEnv,
getElectronExec,
getOutDir,
getAbsoluteElectronExec,
handleGitCall,
ELECTRON_DIR,
SRC_DIR
};