diff --git a/Gulpfile.js b/Gulpfile.js index cda840dba0f..dc6b6c6e546 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -29,7 +29,7 @@ const needsUpdate = require("./scripts/build/needsUpdate"); const getDiffTool = require("./scripts/build/getDiffTool"); const baselineAccept = require("./scripts/build/baselineAccept"); const cmdLineOptions = require("./scripts/build/options"); -const { execAsync } = require("./scripts/build/exec"); +const exec = require("./scripts/build/exec"); const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests"); Error.stackTraceLimit = 1000; @@ -67,14 +67,14 @@ gulp.task( "configure-nightly", "Runs scripts/configurePrerelease.ts to prepare a build for nightly publishing", [configurePrereleaseJs], - () => execAsync(host, [configurePrereleaseJs, "dev", "package.json", "src/compiler/core.ts"])); + () => exec(host, [configurePrereleaseJs, "dev", "package.json", "src/compiler/core.ts"])); gulp.task( "publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => runSequence("clean", "useDebugMode", "runtests-parallel", - () => execAsync("npm", ["publish", "--tag", "next"]))); + () => exec("npm", ["publish", "--tag", "next"]))); const importDefinitelyTypedTestsProject = "scripts/importDefinitelyTypedTests/tsconfig.json"; const importDefinitelyTypedTestsJs = "scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.js"; @@ -85,7 +85,7 @@ gulp.task( "importDefinitelyTypedTests", "Runs scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.ts to copy DT's tests to the TS-internal RWC tests", [importDefinitelyTypedTestsJs], - () => execAsync(host, [importDefinitelyTypedTestsJs, "./", "../DefinitelyTyped"])); + () => exec(host, [importDefinitelyTypedTestsJs, "./", "../DefinitelyTyped"])); gulp.task( "lib", @@ -98,7 +98,7 @@ const diagnosticMessagesJson = "src/compiler/diagnosticMessages.json"; const diagnosticMessagesGeneratedJson = "src/compiler/diagnosticMessages.generated.json"; gulp.task(diagnosticInformationMapTs, /*help*/ false, [processDiagnosticMessagesJs], () => { if (needsUpdate(diagnosticMessagesJson, [diagnosticMessagesGeneratedJson, diagnosticInformationMapTs])) { - return execAsync(host, [processDiagnosticMessagesJs, diagnosticMessagesJson]); + return exec(host, [processDiagnosticMessagesJs, diagnosticMessagesJson]); } }); gulp.task("clean:" + diagnosticInformationMapTs, /*help*/ false, () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson])); @@ -134,7 +134,7 @@ const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt gulp.task(generatedLCGFile, /*help*/ false, [generateLocalizedDiagnosticMessagesJs, diagnosticInformationMapTs], (done) => { if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) { - return execAsync(host, [generateLocalizedDiagnosticMessagesJs, "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); + return exec(host, [generateLocalizedDiagnosticMessagesJs, "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); } }); @@ -242,7 +242,7 @@ gulp.task( // Generate Markdown spec const specMd = "doc/spec.md"; gulp.task(specMd, /*help*/ false, [word2mdJs], () => - execAsync("cscript", ["//nologo", word2mdJs, path.resolve(specMd), path.resolve("doc/TypeScript Language Specification.docx")])); + exec("cscript", ["//nologo", word2mdJs, path.resolve(specMd), path.resolve("doc/TypeScript Language Specification.docx")])); gulp.task( "generate-spec", @@ -273,7 +273,7 @@ gulp.task( throw new Error("Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + missingFiles.join("\n")); } const sizeBefore = getDirSize("lib"); - return execAsync(host, [produceLKGJs]).then(() => { + return exec(host, [produceLKGJs]).then(() => { const sizeAfter = getDirSize("lib"); if (sizeAfter > (sizeBefore * 1.10)) { throw new Error("The lib folder increased by 10% or more. This likely indicates a bug."); @@ -409,25 +409,25 @@ gulp.task( if (tests) { args.push(JSON.stringify(tests)); } - return execAsync("node", args); + return exec("node", args); })); gulp.task( "generate-code-coverage", "Generates code coverage data via istanbul", ["tests"], - () => execAsync("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", "" + cmdLineOptions.testTimeout, runJs])); + () => exec("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", "" + cmdLineOptions.testTimeout, runJs])); gulp.task( "diff", "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable", - () => execAsync(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true })); + () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true })); gulp.task( "diff-rwc", "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable", - () => execAsync(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true })); + () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true })); gulp.task( "baseline-accept", @@ -470,7 +470,7 @@ const loggedIOTs = "src/harness/loggedIO.ts"; const loggedIOJs = "built/local/loggedIO.js"; gulp.task(loggedIOJs, /*help*/ false, [], (done) => { return mkdirp("built/local/temp") - .then(() => execAsync(host, ["lib/tsc.js", "--types", "--target es5", "--lib es5", "--outdir", "built/local/temp", loggedIOTs])) + .then(() => exec(host, ["lib/tsc.js", "--types", "--target es5", "--lib es5", "--outdir", "built/local/temp", loggedIOTs])) .then(() => { fs.renameSync(path.join("built/local/temp", "/harness/loggedIO.js"), loggedIOJs); }) .then(() => del("built/local/temp")); }); @@ -484,7 +484,7 @@ gulp.task( "tsc-instrumented", "Builds an instrumented tsc.js - run with --test=[testname]", ["local", loggedIOJs, instrumenterJs, typescriptServicesJs], - () => execAsync(host, [instrumenterJs, "record", cmdLineOptions.tests || "iocapture", "built/local"])); + () => exec(host, [instrumenterJs, "record", cmdLineOptions.tests || "iocapture", "built/local"])); gulp.task( "update-sublime", diff --git a/scripts/build/exec.js b/scripts/build/exec.js index 0595b47be0b..a7839cf1cb4 100644 --- a/scripts/build/exec.js +++ b/scripts/build/exec.js @@ -1,26 +1,10 @@ // @ts-check -const { Duplex } = require("stream"); const cp = require("child_process"); -const Vinyl = require("vinyl"); const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util) const isWin = /^win/.test(process.platform); const { addColor, color } = require("./colors"); -module.exports = exports = exec; -/** - * Execute the provided command - * @param {string} cmd - * @param {(string|ExecArg)[]} args - */ -function exec(cmd, args) { - switch (getArity(args)) { - case "one": return execEach(cmd, /**@type {(string|ExecArgEach)[]}*/(args)); - case "many": return execAll(cmd, /**@type {(string|ExecArgAll)[]}*/(args)); - case "underspecified": throw new Error("Supplied arguments do not specify input file arity.") - case "overspecified": throw new Error("Supplied arguments have a conflicting arity."); - } -} -exports.exec = exec; +module.exports = exec; /** * Executes the provided command once with the supplied arguments. @@ -29,14 +13,7 @@ exports.exec = exec; * @param {object} [options] * @param {boolean} [options.ignoreExitCode] */ -function execAsync(cmd, args, options = {}) { - switch (getArity(args)) { - case "underspecified": break; - case "one": break; - case "many": - case "overspecified": throw new Error("Supplied arguments have the wrong arity."); - } - +function exec(cmd, args, options = {}) { return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => { log(addColor(`${cmd} ${args.join(" ")}`, color.gray)); // TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition @@ -54,107 +31,6 @@ function execAsync(cmd, args, options = {}) { ex.on("error", reject); })); } -exports.execAsync = execAsync; - -/** - * Execute the provided command once for each input file. - * @param {string} cmd - * @param {(string|ExecArgEach)[]} args - */ -function execEach(cmd, args) { - switch (getArity(args)) { - case "one": break; - case "underspecified": - args = [...args, each.path]; - break; - - case "many": - case "overspecified": throw new Error("Supplied arguments have the wrong arity."); - } - - const duplex = new Duplex({ - objectMode: true, - /** - * @param {string|Buffer|File} file - * @param {(err?: Error) => void} cb - */ - write(file, _, cb) { - if (!Vinyl.isVinyl(file)) throw new Error(); - execAsync(cmd, getExecArgs(args, [file])).then(() => cb(), cb); - }, - final(cb) { - duplex.push(null); - cb(); - }, - read() { - } - }); - - return duplex; -} -exports.execEach = execEach; - -/** - * Execute the provided command once for all input files. - * @param {string} cmd - * @param {(string|ExecArgAll)[]} args - */ -function execAll(cmd, args) { - switch (getArity(args)) { - case "many": break; - case "underspecified": - args = [...args, all.path]; - break; - - case "one": - case "overspecified": throw new Error("Supplied arguments have the wrong arity."); - } - - /** @type {File[]} */ - const files = []; - const duplex = new Duplex({ - objectMode: true, - /** - * @param {string|Buffer|File} file - * @param {(err?: Error) => void} cb - */ - write(file, _, cb) { - if (!Vinyl.isVinyl(file)) throw new Error(); - files.push(file); - cb(); - }, - final(cb) { - execAsync(cmd, getExecArgs(args, files)).then(() => { - duplex.push(null); - cb(); - }, cb); - }, - read() { - } - }); - - return duplex; -} -exports.execAll = execAll; - -/** - * @param {(string|ExecArg)[]} args - * @param {File[]} files - */ -function getExecArgs(args, files) { - /**@type {string[]}*/ - let execArgs = []; - for (const arg of args) { - if (typeof arg === "object" && isExecArg(arg)) { - const kind = arg.kind; - execArgs = execArgs.concat(files.map(file => file[kind])); - } - else { - execArgs.push("" + arg); - } - } - return execArgs; -} /** * @param {string} cmd @@ -162,98 +38,3 @@ function getExecArgs(args, files) { function possiblyQuote(cmd) { return cmd.indexOf(" ") >= 0 ? `"${cmd}"` : cmd; } - -class ExecArgBase { - /** - * @param {ExecArgKind} kind - */ - constructor(kind) { - this.kind = kind; - } -} - -class ExecArgEach extends ExecArgBase { - /** - * @param {ExecArgKind} kind - */ - constructor(kind) { - super(kind); - /** @type {"one"} */ - this.arity = "one"; - Object.freeze(this); - } -} - -class ExecArgAll extends ExecArgBase { - /** - * @param {ExecArgKind} kind - */ - constructor(kind) { - super(kind); - /** @type {"many"} */ - this.arity = "many"; - Object.freeze(this); - } -} - -const each = exports.each = Object.freeze({ - path: new ExecArgEach("path"), - dirname: new ExecArgEach("dirname"), - basename: new ExecArgEach("basename"), - extname: new ExecArgEach("extname"), -}); - -const all = exports.all = Object.freeze({ - path: new ExecArgAll("path"), - dirname: new ExecArgAll("dirname"), - basename: new ExecArgAll("basename"), - extname: new ExecArgAll("extname"), -}); - -/** - * @param {string|ExecArg} arg - */ -function isExecArg(arg) { - return !!arg && typeof arg === "object" && "kind" in arg; -} - -/** - * @param {string|ExecArg} arg - */ -function isExecArgOne(arg) { - return !!arg && typeof arg === "object" && "kind" in arg && arg.arity === "one"; -} - -/** - * @param {string|ExecArg} arg - */ -function isExecArgMany(arg) { - return !!arg && typeof arg === "object" && "kind" in arg && arg.arity === "many"; -} - -/** - * @param {(string | ExecArg)[]} args - */ -function getArity(args) { - let arity = /** @type {"underspecified"|"one"|"many"} */("underspecified"); - for (const arg of args) { - if (isExecArgOne(arg)) { - if (arity === "many") return "overspecified"; - arity = "one"; - } - else if (isExecArgMany(arg)) { - if (arity === "one") return "overspecified"; - arity = "many"; - } - } - return arity; -} - -/** - * @typedef {import("vinyl")} File - * - * @typedef {"path"|"dirname"|"basename"|"extname"} ExecArgKind - * - * @typedef {ExecArgEach|ExecArgAll} ExecArg - */ -void 0; \ No newline at end of file diff --git a/scripts/build/tests.js b/scripts/build/tests.js index caa17944dce..60b72e64cdd 100644 --- a/scripts/build/tests.js +++ b/scripts/build/tests.js @@ -5,7 +5,7 @@ const os = require("os"); const path = require("path"); const mkdirP = require("./mkdirp"); const cmdLineOptions = require("./options"); -const { execAsync } = require("./exec"); +const exec = require("./exec"); const runSequence = require("run-sequence"); const finished = require("./finished"); const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util) @@ -103,7 +103,7 @@ function runConsoleTests(runJs, defaultReporter, runInParallel) { args.push(runJs); } setNodeEnvToDevelopment(); - return execAsync(host, [runJs]); + return exec(host, [runJs]); }) .then(({ exitCode }) => { if (exitCode !== 0) return finish(undefined, exitCode);