Previously we used gulp to run our formatter, currently clang-format, across our repository. This new tool within ng-dev allows us to migrate away from our gulp based solution as our gulp solution had issue with memory pressure and would cause OOM errors with too large of change sets. PR Close #36726
78 lines
2.8 KiB
TypeScript
78 lines
2.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Bar} from 'cli-progress';
|
|
import {cpus} from 'os';
|
|
import {exec} from 'shelljs';
|
|
|
|
const AVAILABLE_THREADS = Math.max(cpus().length - 1, 1);
|
|
|
|
type CallbackFunction = (file: string, code?: number, stdout?: string, stderr?: string) => void;
|
|
|
|
/**
|
|
* Run the provided commands in parallel for each provided file.
|
|
*
|
|
* A promise is returned, completed when the command has completed running for each file.
|
|
*/
|
|
export function runInParallel(providedFiles: string[], cmd: string, callback: CallbackFunction) {
|
|
return new Promise<void>((resolve) => {
|
|
if (providedFiles.length === 0) {
|
|
return resolve();
|
|
}
|
|
// The progress bar instance to use for progress tracking.
|
|
const progressBar =
|
|
new Bar({format: `[{bar}] ETA: {eta}s | {value}/{total} files`, clearOnComplete: true});
|
|
// A local copy of the files to run the command on.
|
|
const files = providedFiles.slice();
|
|
// An array to represent the current usage state of each of the threads for parallelization.
|
|
const threads = new Array<boolean>(AVAILABLE_THREADS).fill(false);
|
|
|
|
// Recursively run the command on the next available file from the list using the provided
|
|
// thread.
|
|
function runCommandInThread(thread: number) {
|
|
// Get the next file.
|
|
const file = files.pop();
|
|
// If no file was pulled from the array, return as there are no more files to run against.
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
exec(
|
|
`${cmd} ${file}`,
|
|
{async: true, silent: true},
|
|
(code, stdout, stderr) => {
|
|
// Run the provided callback function.
|
|
callback(file, code, stdout, stderr);
|
|
// Note in the progress bar another file being completed.
|
|
progressBar.increment(1);
|
|
// If more files exist in the list, run again to work on the next file,
|
|
// using the same slot.
|
|
if (files.length) {
|
|
return runCommandInThread(thread);
|
|
}
|
|
// If not more files are available, mark the thread as unused.
|
|
threads[thread] = false;
|
|
// If all of the threads are false, as they are unused, mark the progress bar
|
|
// completed and resolve the promise.
|
|
if (threads.every(active => !active)) {
|
|
progressBar.stop();
|
|
resolve();
|
|
}
|
|
},
|
|
);
|
|
// Mark the thread as in use as the command execution has been started.
|
|
threads[thread] = true;
|
|
}
|
|
|
|
// Start the progress bar
|
|
progressBar.start(files.length, 0);
|
|
// Start running the command on files from the least in each available thread.
|
|
threads.forEach((_, idx) => runCommandInThread(idx));
|
|
});
|
|
}
|