From 8ba9e67cbd5044ffa02ae042baa9609fc706c108 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 2 Feb 2022 12:46:13 -0500 Subject: [PATCH] feat: detect alternative package managers based on lockfile If a package manager is not explicitly set in config.json or passed-in via argv/env, NodeBB will now check for the presence of alternative package managers' lockfiles and adjust the package manager to-be-used accordingly. If the standard npm lockfile exists, npm will always be used. --- src/cli/package-install.js | 41 ++++++++++++++++++++++++++++++++------ src/cli/upgrade-plugins.js | 9 +++------ src/plugins/install.js | 5 ++--- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/cli/package-install.js b/src/cli/package-install.js index 1fce27b591..3ae74e1c27 100644 --- a/src/cli/package-install.js +++ b/src/cli/package-install.js @@ -53,15 +53,44 @@ pkgInstall.supportedPackageManager = [ ]; pkgInstall.getPackageManager = () => { - // Use this method if you can't reliably require('nconf') directly try { - // Quick & dirty nconf setup fs.accessSync(path.join(paths.nodeModules, 'nconf/package.json'), fs.constants.R_OK); const nconf = require('nconf'); - const configFile = path.resolve(__dirname, '../../', nconf.any(['config', 'CONFIG']) || 'config.json'); - nconf.env().file({ // not sure why adding .argv() causes the process to terminate - file: configFile, - }); + if (!Object.keys(nconf.stores).length) { + // Quick & dirty nconf setup for when you cannot rely on nconf having been required already + const configFile = path.resolve(__dirname, '../../', nconf.any(['config', 'CONFIG']) || 'config.json'); + nconf.env().file({ // not sure why adding .argv() causes the process to terminate + file: configFile, + }); + } + + if (nconf.get('package_manager') && !pkgInstall.supportedPackageManager.includes(nconf.get('package_manager'))) { + nconf.clear('package_manager'); + } + + if (!nconf.get('package_manager')) { + // Best guess based on lockfile detection + try { + // use npm if lockfile present + fs.accessSync(path.resolve(__dirname, '../../package-lock.json'), fs.constants.R_OK); + } catch (e) { + nconf.set('package_manager', [ + // no cnpm detection as it uses same lockfile as npm + 'yarn.lock', 'pnpm-lock.yaml', + ].reduce((result, cur) => { + if (result) { + return result; + } + + try { + fs.accessSync(path.resolve(__dirname, `../../${cur}`), fs.constants.R_OK); + return cur.slice(0, 4); + } catch (e) { + return result; + } + }, undefined)); + } + } return nconf.get('package_manager') || 'npm'; } catch (e) { diff --git a/src/cli/upgrade-plugins.js b/src/cli/upgrade-plugins.js index 863c31dd5d..082a4e1a35 100644 --- a/src/cli/upgrade-plugins.js +++ b/src/cli/upgrade-plugins.js @@ -6,16 +6,13 @@ const cproc = require('child_process'); const semver = require('semver'); const fs = require('fs'); const path = require('path'); -const nconf = require('nconf'); const chalk = require('chalk'); const { paths, pluginNamePattern } = require('../constants'); +const pkgInstall = require('./package-install'); -const packageManager = nconf.get('package_manager'); - -const supportedPackageManagerList = require('./package-install').supportedPackageManager; // load config from src/cli/package-install.js - -let packageManagerExecutable = supportedPackageManagerList.indexOf(packageManager) >= 0 ? packageManager : 'npm'; +const packageManager = pkgInstall.getPackageManager(); +let packageManagerExecutable = packageManager; const packageManagerInstallArgs = packageManager === 'yarn' ? ['add'] : ['install', '--save']; if (process.platform === 'win32') { diff --git a/src/plugins/install.js b/src/plugins/install.js index dcfd7a8c16..05aca08e89 100644 --- a/src/plugins/install.js +++ b/src/plugins/install.js @@ -13,10 +13,9 @@ const db = require('../database'); const meta = require('../meta'); const pubsub = require('../pubsub'); const { paths } = require('../constants'); +const pkgInstall = require('../cli/package-install'); -const supportedPackageManagerList = require('../cli/package-install').supportedPackageManager; -// load config from src/cli/package-install.js -const packageManager = supportedPackageManagerList.indexOf(nconf.get('package_manager')) >= 0 ? nconf.get('package_manager') : 'npm'; +const packageManager = pkgInstall.getPackageManager(); let packageManagerExecutable = packageManager; const packageManagerCommands = { yarn: {