From c177bdc406828cee66c07e83488f7a1adb54152c Mon Sep 17 00:00:00 2001 From: Kinland <16787581+kinland@users.noreply.github.com> Date: Thu, 28 Sep 2023 22:08:09 -0700 Subject: [PATCH] Add support for pnpm (#117) --- lib/run-task.js | 31 +++++++++++++++++++++++++++---- lib/spawn-posix.js | 18 +++++++++++++++++- lib/spawn-win32.js | 18 +++++++++++++++++- package.json | 2 +- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/lib/run-task.js b/lib/run-task.js index 5a12931..53770bb 100644 --- a/lib/run-task.js +++ b/lib/run-task.js @@ -10,6 +10,7 @@ // Requirements // ------------------------------------------------------------------------------ +const fs = require('fs') const path = require('path') const parseArgs = require('shell-quote').parse const createHeader = require('./create-header') @@ -128,6 +129,9 @@ function cleanTaskArg (arg) { * An array of options which are inserted before the task name. * @param {object} options.labelState - A state object for printing labels. * @param {boolean} options.printName - The flag to print task names before running each task. + * @param {object} options.packageInfo - A package.json's information. + * @param {object} options.packageInfo.body - A package.json's JSON object. + * @param {string} options.packageInfo.path - A package.json's file path. * @returns {Promise} * A promise object which becomes fullfilled when the npm-script is completed. * This promise object has an extra method: `abort()`. @@ -156,12 +160,29 @@ module.exports = function runTask (task, options) { } // Execute. - const npmPath = options.npmPath || path.basename(process.env.npm_execpath).startsWith('npx') // eslint-disable-line no-process-env - ? path.join(path.dirname(process.env.npm_execpath), path.basename(process.env.npm_execpath).replace('npx', 'npm')) // eslint-disable-line no-process-env - : process.env.npm_execpath // eslint-disable-line no-process-env + let npmPath = options.npmPath + if (!npmPath && process.env.npm_execpath) { + npmPath = path.basename(process.env.npm_execpath).startsWith('npx') // eslint-disable-line no-process-env + ? path.join(path.dirname(process.env.npm_execpath), path.basename(process.env.npm_execpath).replace('npx', 'npm')) // eslint-disable-line no-process-env + : process.env.npm_execpath // eslint-disable-line no-process-env + } const npmPathIsJs = typeof npmPath === 'string' && /\.m?js/.test(path.extname(npmPath)) - const execPath = (npmPathIsJs ? process.execPath : npmPath || 'npm') + const npmExecPath = (npmPathIsJs ? process.execPath : npmPath || 'npm') + + let isPnpm = false + let pnpmExecPath + if (npmPath === undefined) { + const projectRoot = path.dirname(options.packageInfo.path) + const hasPnpmLockfile = fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml')) + const { status: pnpmFound, output } = spawn.sync('which', 'pnpm', { silent: true }) + isPnpm = hasPnpmLockfile && __dirname.split(path.delimiter).includes('.pnpm') && pnpmFound + if (isPnpm) { + pnpmExecPath = output + } + } + const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.startsWith('yarn') // eslint-disable-line no-process-env + const spawnArgs = ['run'] if (npmPathIsJs) { @@ -174,6 +195,8 @@ module.exports = function runTask (task, options) { } Array.prototype.push.apply(spawnArgs, parseArgs(task).map(cleanTaskArg)) + const execPath = !isPnpm ? npmExecPath : pnpmExecPath + cp = spawn(execPath, spawnArgs, spawnOptions) // Piping stdio. diff --git a/lib/spawn-posix.js b/lib/spawn-posix.js index 6d63549..ca5a851 100644 --- a/lib/spawn-posix.js +++ b/lib/spawn-posix.js @@ -55,9 +55,25 @@ function kill () { * @returns {ChildProcess} A ChildProcess instance of new process. * @private */ -module.exports = function spawn (command, args, options) { +function spawn (command, args, options) { const child = crossSpawn(command, args, options) child.kill = kill return child } + +/** + * Launches a new process synchronously with the given command. + * This is almost same as `child_process.spawnSync`. + * + * This returns a `SpawnSyncReturns` object. + * + * @param {string} command - The command to run. + * @param {string[]} args - List of string arguments. + * @param {object} options - Options. + * @returns {SpawnSyncReturns} A ChildProcess instance of new process. + * @private + */ +spawn.sync = crossSpawn.sync + +module.exports = spawn diff --git a/lib/spawn-win32.js b/lib/spawn-win32.js index 1198d98..4cc26b5 100644 --- a/lib/spawn-win32.js +++ b/lib/spawn-win32.js @@ -42,9 +42,25 @@ function kill () { * @returns {ChildProcess} A ChildProcess instance of new process. * @private */ -module.exports = function spawn (command, args, options) { +function spawn (command, args, options) { const child = crossSpawn(command, args, options) child.kill = kill return child } + +/** + * Launches a new process synchronously with the given command. + * This is almost same as `child_process.spawnSync`. + * + * This returns a `SpawnSyncReturns` object. + * + * @param {string} command - The command to run. + * @param {string[]} args - List of string arguments. + * @param {object} options - Options. + * @returns {SpawnSyncReturns} A ChildProcess instance of new process. + * @private + */ +spawn.sync = crossSpawn.sync + +module.exports = spawn diff --git a/package.json b/package.json index 404562d..628632b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "npm-run-all2", - "version": "6.0.6", + "version": "6.0.7", "description": "A CLI tool to run multiple npm-scripts in parallel or sequential. (Maintainence fork)", "bin": { "run-p": "bin/run-p/index.js",