import * as child_process from 'child_process'; import * as gulp from 'gulp'; // This import lacks type definitions. const gulpClean = require('gulp-clean'); // There are no type definitions available for these imports. const resolveBin = require('resolve-bin'); /** Options that can be passed to execTask or execNodeTask. */ export interface ExecTaskOptions { // Whether STDOUT and STDERR messages should be printed. silent?: boolean; // Whether STDOUT messages should be printed. silentStdout?: boolean; // If an error happens, this will replace the standard error. errMessage?: string; // Environment variables being passed to the child process. env?: any; // Whether the task should fail if the process writes to STDERR. failOnStderr?: boolean; } /** Create a task that executes a binary as if from the command line. */ export function execTask(binPath: string, args: string[], options: ExecTaskOptions = {}) { return (done: (err?: string) => void) => { const env = Object.assign({}, process.env, options.env); const childProcess = child_process.spawn(binPath, args, {env}); const stderrData: string[] = []; if (!options.silentStdout && !options.silent) { childProcess.stdout.on('data', (data: string) => process.stdout.write(data)); } if (!options.silent || options.failOnStderr) { childProcess.stderr.on('data', (data: string) => { options.failOnStderr ? stderrData.push(data) : process.stderr.write(data); }); } childProcess.on('close', (code: number) => { if (options.failOnStderr && stderrData.length) { done(stderrData.join('\n')); } else { code != 0 ? done(options.errMessage || `Process failed with code ${code}`) : done(); } }); }; } /** * Create a task that executes an NPM Bin, by resolving the binary path then executing it. These are * binaries that are normally in the `./node_modules/.bin` directory, but their name might differ * from the package. Examples are typescript, ngc and gulp itself. */ export function execNodeTask(packageName: string, executable: string | string[], args?: string[], options: ExecTaskOptions = {}) { if (!args) { args = executable; executable = ''; } return (done: (err: any) => void) => { resolveBin(packageName, { executable: executable }, (err: any, binPath: string) => { if (err) { done(err); } else { // Execute the node binary within a new child process using spawn. // The binary needs to be `node` because on Windows the shell cannot determine the correct // interpreter from the shebang. execTask('node', [binPath].concat(args!), options)(done); } }); }; } /** Delete files. */ export function cleanTask(glob: string) { return () => gulp.src(glob, { read: false }).pipe(gulpClean(null)); }