From 3423bf22559030edb714e83b60822e0e7d84b0e7 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 00:05:46 +0800 Subject: [PATCH 1/6] refactor: unify package manager related logic --- .../apollo-server/connectors/dependencies.js | 32 +- .../apollo-server/connectors/plugins.js | 24 +- .../apollo-server/connectors/projects.js | 2 +- packages/@vue/cli/lib/Creator.js | 7 +- packages/@vue/cli/lib/add.js | 10 +- packages/@vue/cli/lib/invoke.js | 11 +- packages/@vue/cli/lib/upgrade.js | 359 +++++++++--------- packages/@vue/cli/lib/util/PackageManager.js | 194 ++++++++++ .../{installDeps.js => executeCommand.js} | 115 +----- .../@vue/cli/lib/util/getInstalledVersion.js | 14 - .../@vue/cli/lib/util/getPackageVersion.js | 16 - packages/@vue/cli/lib/util/getVersions.js | 14 +- packages/@vue/cli/lib/util/linkBin.js | 9 - packages/@vue/cli/lib/util/packageManager.js | 102 ----- 14 files changed, 421 insertions(+), 488 deletions(-) create mode 100644 packages/@vue/cli/lib/util/PackageManager.js rename packages/@vue/cli/lib/util/{installDeps.js => executeCommand.js} (57%) delete mode 100644 packages/@vue/cli/lib/util/getInstalledVersion.js delete mode 100644 packages/@vue/cli/lib/util/getPackageVersion.js delete mode 100644 packages/@vue/cli/lib/util/packageManager.js diff --git a/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js b/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js index d8190c1b10..8174ba4214 100644 --- a/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js +++ b/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js @@ -13,14 +13,8 @@ const logs = require('./logs') const getContext = require('../context') // Utils const { isPlugin, hasYarn, resolveModule } = require('@vue/cli-shared-utils') -const getPackageVersion = require('@vue/cli/lib/util/getPackageVersion') -const { - progress: installProgress, - installPackage, - uninstallPackage, - updatePackage -} = require('@vue/cli/lib/util/installDeps') -const { getCommand } = require('../util/command') +const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand') +const PackageManager = require('@vue/cli/lib/util/PackageManager') const { resolveModuleRoot } = require('../util/resolve-path') const { notify } = require('../util/notification') const { log } = require('../util/logger') @@ -113,10 +107,7 @@ async function getMetadata (id, context) { if (!metadata) { try { - const res = await getPackageVersion(id) - if (res.statusCode === 200) { - metadata = res.body - } + metadata = await (new PackageManager({ context: cwd.get() })).getMetadata() } catch (e) { // No connection? } @@ -126,7 +117,7 @@ async function getMetadata (id, context) { metadataCache.set(id, metadata) return metadata } else { - log('Dpendencies', chalk.yellow(`Can't load metadata`), id) + log('Dependencies', chalk.yellow(`Can't load metadata`), id) } } @@ -211,7 +202,8 @@ function install ({ id, type, range }, context) { arg = id } - await installPackage(cwd.get(), getCommand(cwd.get()), arg, type === 'devDependencies') + const pm = new PackageManager({ context: cwd.get() }) + await pm.add(arg, type === 'devDependencies') logs.add({ message: `Dependency ${id} installed`, @@ -239,7 +231,8 @@ function uninstall ({ id }, context) { const dep = findOne(id, context) - await uninstallPackage(cwd.get(), getCommand(cwd.get()), id) + const pm = new PackageManager({ context: cwd.get() }) + await pm.remove(id) logs.add({ message: `Dependency ${id} uninstalled`, @@ -265,7 +258,9 @@ function update ({ id }, context) { const dep = findOne(id, context) const { current, wanted } = await getVersion(dep, context) - await updatePackage(cwd.get(), getCommand(cwd.get()), id) + + const pm = new PackageManager({ context: cwd.get() }) + await pm.upgrade(id) logs.add({ message: `Dependency ${id} updated from ${current} to ${wanted}`, @@ -310,9 +305,8 @@ function updateAll (context) { args: [updatedDeps.length] }) - await updatePackage(cwd.get(), getCommand(cwd.get()), updatedDeps.map( - p => p.id - ).join(' ')) + const pm = new PackageManager({ context: cwd.get() }) + await pm.upgrade(updatedDeps.map(p => p.id).join(' ')) notify({ title: `Dependencies updated`, diff --git a/packages/@vue/cli-ui/apollo-server/connectors/plugins.js b/packages/@vue/cli-ui/apollo-server/connectors/plugins.js index 72a8a21cae..b13925af25 100644 --- a/packages/@vue/cli-ui/apollo-server/connectors/plugins.js +++ b/packages/@vue/cli-ui/apollo-server/connectors/plugins.js @@ -30,13 +30,9 @@ const { clearModule, execa } = require('@vue/cli-shared-utils') -const { - progress: installProgress, - installPackage, - uninstallPackage, - updatePackage -} = require('@vue/cli/lib/util/installDeps') -const { getCommand } = require('../util/command') +const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand') +const PackageManager = require('@vue/cli/lib/util/PackageManager') + const ipc = require('../util/ipc') const { log } = require('../util/logger') const { notify } = require('../util/notification') @@ -334,7 +330,8 @@ function install (id, context) { if (process.env.VUE_CLI_DEBUG && isOfficialPlugin(id)) { mockInstall(id, context) } else { - await installPackage(cwd.get(), getCommand(cwd.get()), id) + const pm = new PackageManager({ context: cwd.get() }) + await pm.add(id) } await initPrompts(id, context) installationStep = 'config' @@ -412,7 +409,8 @@ function uninstall (id, context) { if (process.env.VUE_CLI_DEBUG && isOfficialPlugin(id)) { mockUninstall(id, context) } else { - await uninstallPackage(cwd.get(), getCommand(cwd.get()), id) + const pm = new PackageManager({ context: cwd.get() }) + await pm.remove(id) } currentPluginId = null installationStep = null @@ -520,7 +518,8 @@ function update ({ id, full }, context) { if (localPath) { await updateLocalPackage({ cwd: cwd.get(), id, localPath, full }, context) } else { - await updatePackage(cwd.get(), getCommand(cwd.get()), id) + const pm = new PackageManager({ context: cwd.get() }) + await pm.upgrade(id) } logs.add({ @@ -583,9 +582,8 @@ async function updateAll (context) { args: [updatedPlugins.length] }) - await updatePackage(cwd.get(), getCommand(cwd.get()), updatedPlugins.map( - p => p.id - ).join(' ')) + const pm = new PackageManager({ context: cwd.get() }) + await pm.upgrade(updatedPlugins.map(p => p.id).join(' ')) notify({ title: `Plugins updated`, diff --git a/packages/@vue/cli-ui/apollo-server/connectors/projects.js b/packages/@vue/cli-ui/apollo-server/connectors/projects.js index 5ed8b02c9c..6496ed4369 100644 --- a/packages/@vue/cli-ui/apollo-server/connectors/projects.js +++ b/packages/@vue/cli-ui/apollo-server/connectors/projects.js @@ -6,7 +6,7 @@ const { getPromptModules } = require('@vue/cli/lib/util/createTools') const { getFeatures } = require('@vue/cli/lib/util/features') const { defaults } = require('@vue/cli/lib/options') const { toShortPluginId, execa } = require('@vue/cli-shared-utils') -const { progress: installProgress } = require('@vue/cli/lib/util/installDeps') +const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand') const parseGitConfig = require('parse-git-config') // Connectors const progress = require('./progress') diff --git a/packages/@vue/cli/lib/Creator.js b/packages/@vue/cli/lib/Creator.js index b03f37d31a..6e2725e974 100644 --- a/packages/@vue/cli/lib/Creator.js +++ b/packages/@vue/cli/lib/Creator.js @@ -9,7 +9,7 @@ const Generator = require('./Generator') const cloneDeep = require('lodash.clonedeep') const sortObject = require('./util/sortObject') const getVersions = require('./util/getVersions') -const { installDeps } = require('./util/installDeps') +const PackageManager = require('./util/PackageManager') const { clearConsole } = require('./util/clearConsole') const PromptModuleAPI = require('./PromptModuleAPI') const writeFileTree = require('./util/writeFileTree') @@ -117,6 +117,7 @@ module.exports = class Creator extends EventEmitter { (hasYarn() ? 'yarn' : null) || (hasPnpm3OrLater() ? 'pnpm' : 'npm') ) + const pm = new PackageManager({ context, forcePackageManager: packageManager }) await clearConsole() logWithSpinner(`✨`, `Creating project in ${chalk.yellow(context)}.`) @@ -176,7 +177,7 @@ module.exports = class Creator extends EventEmitter { // in development, avoid installation process await require('./util/setupDevProject')(context) } else { - await installDeps(context, packageManager) + await pm.install() } // run generator @@ -197,7 +198,7 @@ module.exports = class Creator extends EventEmitter { this.emit('creation', { event: 'deps-install' }) log() if (!isTestOrDebug) { - await installDeps(context, packageManager) + await pm.install() } // run complete cbs if any (injected by generators) diff --git a/packages/@vue/cli/lib/add.js b/packages/@vue/cli/lib/add.js index 8f6b989c63..859c936fef 100644 --- a/packages/@vue/cli/lib/add.js +++ b/packages/@vue/cli/lib/add.js @@ -1,12 +1,10 @@ const chalk = require('chalk') const invoke = require('./invoke') -const { loadOptions } = require('./options') -const { installPackage } = require('./util/installDeps') + +const PackageManager = require('./util/PackageManager') const { log, error, - hasProjectYarn, - hasProjectPnpm, resolvePluginId, resolveModule } = require('@vue/cli-shared-utils') @@ -18,8 +16,8 @@ async function add (pluginName, options = {}, context = process.cwd()) { log(`📦 Installing ${chalk.cyan(packageName)}...`) log() - const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : hasProjectPnpm(context) ? 'pnpm' : 'npm') - await installPackage(context, packageManager, packageName) + const pm = new PackageManager({ context }) + await pm.add(packageName) log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`) log() diff --git a/packages/@vue/cli/lib/invoke.js b/packages/@vue/cli/lib/invoke.js index e9120e8ae1..aedf76a35d 100644 --- a/packages/@vue/cli/lib/invoke.js +++ b/packages/@vue/cli/lib/invoke.js @@ -6,9 +6,7 @@ const inquirer = require('inquirer') const { log, error, - hasProjectYarn, hasProjectGit, - hasProjectPnpm, logWithSpinner, stopSpinner, resolvePluginId, @@ -16,9 +14,9 @@ const { } = require('@vue/cli-shared-utils') const Generator = require('./Generator') -const { loadOptions } = require('./options') -const { installDeps } = require('./util/installDeps') + const readFiles = require('./util/readFiles') +const PackageManager = require('./util/PackageManager') function getPkg (context) { const pkgPath = path.resolve(context, 'package.json') @@ -125,9 +123,8 @@ async function runGenerator (context, plugin, pkg = getPkg(context)) { if (!isTestOrDebug && depsChanged) { log(`📦 Installing additional dependencies...`) log() - const packageManager = - loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : hasProjectPnpm(context) ? 'pnpm' : 'npm') - await installDeps(context, packageManager) + const pm = new PackageManager({ context }) + await pm.install() } if (createCompleteCbs.length) { diff --git a/packages/@vue/cli/lib/upgrade.js b/packages/@vue/cli/lib/upgrade.js index 19447a758b..a01984cd33 100644 --- a/packages/@vue/cli/lib/upgrade.js +++ b/packages/@vue/cli/lib/upgrade.js @@ -18,233 +18,230 @@ const { } = require('@vue/cli-shared-utils') const Migrator = require('./Migrator') - -const { getCommand, getVersion } = require('./util/packageManager') -const { installDeps, updatePackage } = require('./util/installDeps') -const { linkPackage } = require('./util/linkBin') - -const getPackageJson = require('./util/getPackageJson') -const getInstalledVersion = require('./util/getInstalledVersion') const tryGetNewerRange = require('./util/tryGetNewerRange') const readFiles = require('./util/readFiles') -const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG +const getPackageJson = require('./util/getPackageJson') +const PackageManager = require('./util/PackageManager') -async function runMigrator (packageName, options, context) { - const pluginMigrator = loadModule(`${packageName}/migrator`, context) - if (!pluginMigrator) { return } +const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG - const plugin = { - id: packageName, - apply: pluginMigrator, - installed: options.installed +class Upgrader { + constructor (context = process.cwd()) { + this.context = context + this.pkg = getPackageJson(this.context) + this.pm = new PackageManager({ context }) } - const pkg = getPackageJson(context) - const createCompleteCbs = [] - const migrator = new Migrator(context, { - plugin: plugin, + async upgradeAll () { + // TODO: should confirm for major version upgrades + // for patch & minor versions, upgrade directly + // for major versions, prompt before upgrading + const upgradable = await this.getUpgradable() - pkg, - files: await readFiles(context), - completeCbs: createCompleteCbs, - invoking: true - }) + if (!upgradable.length) { + done('Seems all plugins are up to date. Good work!') + return + } - log(`🚀 Running migrator of ${packageName}`) - await migrator.generate({ - extractConfigFiles: true, - checkExisting: true - }) + for (const p of upgradable) { + await this.upgrade(p.name, { to: p.latest }) + } - const newDeps = migrator.pkg.dependencies - const newDevDeps = migrator.pkg.devDependencies - const depsChanged = - JSON.stringify(newDeps) !== JSON.stringify(pkg.dependencies) || - JSON.stringify(newDevDeps) !== JSON.stringify(pkg.devDependencies) - - if (!isTestOrDebug && depsChanged) { - log(`📦 Installing additional dependencies...`) - log() - const packageManager = getCommand(context) - await installDeps(context, packageManager) + done('All plugins are up to date!') } - if (createCompleteCbs.length) { - logWithSpinner('⚓', `Running completion hooks...`) - for (const cb of createCompleteCbs) { - await cb() - } - stopSpinner() - log() - } + async upgrade (pluginId, options) { + const packageName = resolvePluginId(pluginId) - log(`${chalk.green('✔')} Successfully invoked migrator for plugin: ${chalk.cyan(plugin.id)}`) - if (!process.env.VUE_CLI_TEST && hasProjectGit(context)) { - const { stdout } = await execa('git', [ - 'ls-files', - '--exclude-standard', - '--modified', - '--others' - ], { - cwd: context - }) - if (stdout.trim()) { - log(` The following files have been updated / added:\n`) - log( - chalk.red( - stdout - .split(/\r?\n/g) - .map(line => ` ${line}`) - .join('\n') - ) - ) - log() - log( - ` You should review these changes with ${chalk.cyan( - `git diff` - )} and commit them.` - ) - log() + let depEntry, required + for (const depType of ['dependencies', 'devDependencies', 'optionalDependencies']) { + if (this.pkg[depType] && this.pkg[depType][packageName]) { + depEntry = depType + required = this.pkg[depType][packageName] + break + } + } + if (!required) { + throw new Error(`Can't find ${chalk.yellow(packageName)} in ${chalk.yellow('package.json')}`) } - } - - migrator.printExitLogs() -} -async function upgradeSinglePackage (pluginId, options, context) { - const packageName = resolvePluginId(pluginId) - const pkg = getPackageJson(context) + let targetVersion = options.to || 'latest' + // if the targetVersion is not an exact version + if (!/\d+\.\d+\.\d+/.test(targetVersion)) { + if (targetVersion === 'latest') { + logWithSpinner(`Getting latest version of ${packageName}`) + } else { + logWithSpinner(`Getting max satisfying version of ${packageName}@${options.to}`) + } - let depEntry, required - for (const depType of ['dependencies', 'devDependencies', 'optionalDependencies']) { - if (pkg[depType] && pkg[depType][packageName]) { - depEntry = depType - required = pkg[depType][packageName] - break + targetVersion = await this.pm.getRemoteVersion(packageName, targetVersion) + stopSpinner() } - } - if (!required) { - throw new Error(`Can't find ${chalk.yellow(packageName)} in ${chalk.yellow('package.json')}`) - } - const installed = getInstalledVersion(packageName) - let targetVersion = options.to || 'latest' + const installed = this.pm.getInstalledVersion(packageName) + if (targetVersion === installed) { + log(`Already installed ${packageName}@${targetVersion}`) - // if the targetVersion is not an exact version - if (!/\d+\.\d+\.\d+/.test(targetVersion)) { - if (targetVersion === 'latest') { - logWithSpinner(`Getting latest version of ${packageName}`) - } else { - logWithSpinner(`Getting max satisfying version of ${packageName}@${options.to}`) + const newRange = tryGetNewerRange(`^${targetVersion}`, required) + if (newRange !== required) { + this.pkg[depEntry][packageName] = newRange + fs.writeFileSync(path.resolve(this.context, 'package.json'), JSON.stringify(this.pkg, null, 2)) + log(`${chalk.green('✔')} Updated version range in ${chalk.yellow('package.json')}`) + } + return } - targetVersion = await getVersion(packageName, targetVersion, context) - stopSpinner() + log(`Upgrading ${packageName} from ${installed} to ${targetVersion}`) + await this.pm.upgrade(`${packageName}@^${targetVersion}`) + + await this.runMigrator(packageName, { installed }) } - if (targetVersion === installed) { - log(`Already installed ${packageName}@${targetVersion}`) + async runMigrator (packageName, options) { + const pluginMigrator = loadModule(`${packageName}/migrator`, this.context) + if (!pluginMigrator) { return } - const newRange = tryGetNewerRange(`^${targetVersion}`, required) - if (newRange !== required) { - pkg[depEntry][packageName] = newRange - fs.writeFileSync(path.resolve(context, 'package.json'), JSON.stringify(pkg, null, 2)) - log(`${chalk.green('✔')} Updated version range in ${chalk.yellow('package.json')}`) + const plugin = { + id: packageName, + apply: pluginMigrator, + installed: options.installed } - return - } - log(`Upgrading ${packageName} from ${installed} to ${targetVersion}`) + const createCompleteCbs = [] + const migrator = new Migrator(this.context, { + plugin: plugin, - if (isTestOrDebug) { - // link packages in current repo for test - await linkPackage(path.resolve(__dirname, `../../../${packageName}`), path.join(context, 'node_modules', packageName)) - } else { - await updatePackage(context, getCommand(context), `${packageName}@^${targetVersion}`) - } + pkg: this.pkg, + files: await readFiles(this.context), + completeCbs: createCompleteCbs, + invoking: true + }) - await runMigrator(packageName, { installed }, context) -} + log(`🚀 Running migrator of ${packageName}`) + await migrator.generate({ + extractConfigFiles: true, + checkExisting: true + }) -async function getUpgradable (context) { - // get current deps - // filter @vue/cli-service, @vue/cli-plugin-* & vue-cli-plugin-* - const pkg = getPackageJson(context) - const upgradable = [] + const newDeps = migrator.pkg.dependencies + const newDevDeps = migrator.pkg.devDependencies + const depsChanged = + JSON.stringify(newDeps) !== JSON.stringify(this.pkg.dependencies) || + JSON.stringify(newDevDeps) !== JSON.stringify(this.pkg.devDependencies) - for (const depType of ['dependencies', 'devDependencies', 'optionalDependencies']) { - for (const [name, range] of Object.entries(pkg[depType] || {})) { - if (name !== '@vue/cli-service' && !isPlugin(name)) { - continue - } + if (!isTestOrDebug && depsChanged) { + log(`📦 Installing additional dependencies...`) + log() + await this.pm.install() + } - const installed = await getInstalledVersion(name) - const wanted = await getVersion(name, range, context) - const latest = await getVersion(name, 'latest', context) + if (createCompleteCbs.length) { + logWithSpinner('⚓', `Running completion hooks...`) + for (const cb of createCompleteCbs) { + await cb() + } + stopSpinner() + log() + } - if (installed !== latest) { - upgradable.push({ name, installed, wanted, latest }) + log(`${chalk.green('✔')} Successfully invoked migrator for plugin: ${chalk.cyan(plugin.id)}`) + if (!process.env.VUE_CLI_TEST && hasProjectGit(this.context)) { + const { stdout } = await execa('git', [ + 'ls-files', + '--exclude-standard', + '--modified', + '--others' + ], { + cwd: this.context + }) + if (stdout.trim()) { + log(` The following files have been updated / added:\n`) + log( + chalk.red( + stdout + .split(/\r?\n/g) + .map(line => ` ${line}`) + .join('\n') + ) + ) + log() + log( + ` You should review these changes with ${chalk.cyan( + `git diff` + )} and commit them.` + ) + log() } } + + migrator.printExitLogs() } - return upgradable -} + async getUpgradable () { + const upgradable = [] -async function checkForUpdates (context) { - logWithSpinner('Gathering package information...') - const upgradable = await getUpgradable(context) - stopSpinner() + // get current deps + // filter @vue/cli-service, @vue/cli-plugin-* & vue-cli-plugin-* + for (const depType of ['dependencies', 'devDependencies', 'optionalDependencies']) { + for (const [name, range] of Object.entries(this.pkg[depType] || {})) { + if (name !== '@vue/cli-service' && !isPlugin(name)) { + continue + } - if (!upgradable.length) { - done('Seems all plugins are up to date. Good work!') - return - } + const installed = await this.pm.getInstalledVersion(name) + const wanted = await this.pm.getRemoteVersion(name, range) - // format the output - // adapted from @angular/cli - const names = upgradable.map(dep => dep.name) - let namePad = Math.max(...names.map(x => x.length)) + 2 - if (!Number.isFinite(namePad)) { - namePad = 30 - } - const pads = [namePad, 12, 12, 12, 0] - console.log( - ' ' + - ['Name', 'Installed', 'Wanted', 'Latest', 'Command to upgrade'].map( - (x, i) => chalk.underline(x.padEnd(pads[i])) - ).join('') - ) - for (const p of upgradable) { - const fields = [p.name, p.installed, p.wanted, p.latest, `vue upgrade ${p.name}`] - console.log(' ' + fields.map((x, i) => x.padEnd(pads[i])).join('')) + const latest = await this.pm.getRemoteVersion(name) + + if (installed !== latest) { + upgradable.push({ name, installed, wanted, latest }) + } + } + } + + return upgradable } - console.log(`Run ${chalk.yellow('vue upgrade --all')} to upgrade all the above plugins`) + async checkForUpdates () { + logWithSpinner('Gathering pacakage information...') + const upgradable = await this.getUpgradable() + stopSpinner() - return upgradable -} + if (!upgradable.length) { + done('Seems all plugins are up to date. Good work!') + return + } -async function upgradeAll (context) { - // TODO: should confirm for major version upgrades - // for patch & minor versions, upgrade directly - // for major versions, prompt before upgrading - const upgradable = await getUpgradable(context) + // format the output + // adapted from @angular/cli + const names = upgradable.map(dep => dep.name) + let namePad = Math.max(...names.map(x => x.length)) + 2 + if (!Number.isFinite(namePad)) { + namePad = 30 + } + const pads = [namePad, 12, 12, 12, 0] + console.log( + ' ' + + ['Name', 'Installed', 'Wanted', 'Latest', 'Command to upgrade'].map( + (x, i) => chalk.underline(x.padEnd(pads[i])) + ).join('') + ) + for (const p of upgradable) { + const fields = [p.name, p.installed, p.wanted, p.latest, `vue upgrade ${p.name}`] + // TODO: highlight the diff part, like in `yarn outdated` + console.log(' ' + fields.map((x, i) => x.padEnd(pads[i])).join('')) + } - if (!upgradable.length) { - done('Seems all plugins are up to date. Good work!') - return - } + console.log(`Run ${chalk.yellow('vue upgrade --all')} to upgrade all the above plugins`) - for (const p of upgradable) { - await upgradeSinglePackage(p.name, { to: p.latest }, context) + return upgradable } - - done('All plugins are up to date!') } async function upgrade (packageName, options, context = process.cwd()) { + const upgrader = new Upgrader(context) + if (!packageName) { if (options.to) { error(`Must specify a package name to upgrade to ${options.to}`) @@ -252,13 +249,13 @@ async function upgrade (packageName, options, context = process.cwd()) { } if (options.all) { - return upgradeAll(context) + return upgrader.upgradeAll() } - return checkForUpdates(context) + return upgrader.checkForUpdates() } - return upgradeSinglePackage(packageName, options, context) + return upgrader.upgrade(packageName, options) } module.exports = (...args) => { diff --git a/packages/@vue/cli/lib/util/PackageManager.js b/packages/@vue/cli/lib/util/PackageManager.js new file mode 100644 index 0000000000..098ab71060 --- /dev/null +++ b/packages/@vue/cli/lib/util/PackageManager.js @@ -0,0 +1,194 @@ +const fs = require('fs') +const path = require('path') + +const execa = require('execa') +const minimist = require('minimist') +const semver = require('semver') +const LRU = require('lru-cache') + +const { + hasYarn, + hasProjectYarn, + hasPnpm3OrLater, + hasProjectPnpm +} = require('@vue/cli-shared-utils/lib/env') +const { isOfficialPlugin } = require('@vue/cli-shared-utils/lib/pluginResolution') + +const { loadOptions } = require('../options') +const getPackageJson = require('./getPackageJson') +const executeCommand = require('./executeCommand') + +const registries = require('./registries') +const shouldUseTaobao = require('./shouldUseTaobao') + +const metadataCache = new LRU({ + max: 200, + maxAge: 1000 * 60 * 30 // 30 min. +}) + +const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG + +const TAOBAO_DIST_URL = 'https://npm.taobao.org/dist' +const SUPPORTED_PACKAGE_MANAGERS = ['yarn', 'pnpm', 'npm'] +const PACKAGE_MANAGER_CONFIG = { + npm: { + install: ['install', '--loglevel', 'error'], + add: ['install', '--loglevel', 'error'], + upgrade: ['update', '--loglevel', 'error'], + remove: ['uninstall', '--loglevel', 'error'] + }, + pnpm: { + install: ['install', '--loglevel', 'error', '--shamefully-flatten'], + add: ['install', '--loglevel', 'error', '--shamefully-flatten'], + upgrade: ['update', '--loglevel', 'error'], + remove: ['uninstall', '--loglevel', 'error'] + }, + yarn: { + install: [], + add: ['add'], + upgrade: ['upgrade'], + remove: ['remove'] + } +} + +class PackageManager { + constructor ({ context, forcePackageManager } = {}) { + this.context = context + + if (forcePackageManager) { + this.bin = forcePackageManager + } else if (context) { + this.bin = hasProjectYarn(context) ? 'yarn' : hasProjectPnpm(context) ? 'pnpm' : 'npm' + } else { + this.bin = loadOptions().packageManager || (hasYarn() ? 'yarn' : hasPnpm3OrLater() ? 'pnpm' : 'npm') + } + + if (!SUPPORTED_PACKAGE_MANAGERS.includes(this.bin)) { + throw new Error(`Unknown package manager: ${this.bin}`) + } + } + + // Any command that implemented registry-related feature should support + // `-r` / `--registry` option + async getRegistry () { + if (this._registry) { + return this._registry + } + + const args = minimist(process.argv, { + alias: { + r: 'registry' + } + }) + + if (args.registry) { + this._registry = args.registry + } else if (await shouldUseTaobao(this.bin)) { + this._registry = registries.taobao + } else { + const { stdout } = await execa(this.bin, ['config', 'get', 'registry']) + this._registry = stdout + } + + return this._registry + } + + async addRegistryToArgs (args) { + const registry = await this.getRegistry() + args.push(`--registry=${registry}`) + + if (registry === registries.taobao) { + args.push(`--disturl=${TAOBAO_DIST_URL}`) + } + + return args + } + + async getMetadata (packageName, { field = '' } = {}) { + const registry = await this.getRegistry() + + const metadataKey = `${this.bin}-${registry}-${packageName}` + let metadata = metadataCache.get(metadataKey) + + if (metadata) { + return metadata + } + + const args = await this.addRegistryToArgs(['info', packageName, field, '--json']) + const { stdout } = await execa(this.bin, args) + + metadata = JSON.parse(stdout) + if (this.bin === 'yarn') { + // `yarn info` outputs messages in the form of `{"type": "inspect", data: {}}` + metadata = metadata.data + } + + metadataCache.set(metadataKey, metadata) + return metadata + } + + async getRemoteVersion (packageName, versionRange = 'latest') { + const metadata = await this.getMetadata(packageName) + if (Object.keys(metadata['dist-tags']).includes(versionRange)) { + return metadata['dist-tags'][versionRange] + } + const versions = Array.isArray(metadata.versions) ? metadata.versions : Object.keys(metadata.versions) + return semver.maxSatisfying(versions, versionRange) + } + + getInstalledVersion (packageName) { + // for first level deps, read package.json directly is way faster than `npm list` + try { + const packageJson = getPackageJson( + path.resolve(this.context, 'node_modules', packageName) + ) + return packageJson.version + } catch (e) { + return 'N/A' + } + } + + async install () { + const args = await this.addRegistryToArgs(PACKAGE_MANAGER_CONFIG[this.bin].install) + return executeCommand(this.bin, args, this.context) + } + + async add (packageName, isDev = true) { + const args = await this.addRegistryToArgs([ + ...PACKAGE_MANAGER_CONFIG[this.bin].add, + packageName, + ...(isDev ? ['-D'] : []) + ]) + return executeCommand(this.bin, args, this.context) + } + + async upgrade (packageName) { + if ( + isTestOrDebug && + (packageName === '@vue/cli-service' || isOfficialPlugin(packageName)) + ) { + // link packages in current repo for test + const src = path.resolve(__dirname, `../../../${packageName}`) + const dest = path.join(this.context, 'node_modules', packageName) + await fs.remove(dest) + await fs.symlink(src, dest, 'dir') + return + } + + const args = await this.addRegistryToArgs([ + ...PACKAGE_MANAGER_CONFIG[this.bin].add, + packageName + ]) + return executeCommand(this.bin, args, this.context) + } + + async remove (packageName) { + const args = [ + ...PACKAGE_MANAGER_CONFIG[this.bin].remove, + packageName + ] + return executeCommand(this.bin, args, this.context) + } +} + +module.exports = PackageManager diff --git a/packages/@vue/cli/lib/util/installDeps.js b/packages/@vue/cli/lib/util/executeCommand.js similarity index 57% rename from packages/@vue/cli/lib/util/installDeps.js rename to packages/@vue/cli/lib/util/executeCommand.js index 887dae4c30..0d4c2d306a 100644 --- a/packages/@vue/cli/lib/util/installDeps.js +++ b/packages/@vue/cli/lib/util/executeCommand.js @@ -1,39 +1,10 @@ -const EventEmitter = require('events') const chalk = require('chalk') +const EventEmitter = require('events') const execa = require('execa') const readline = require('readline') -const registries = require('./registries') -const { getRegistry } = require('./packageManager') const debug = require('debug')('vue-cli:install') -const taobaoDistURL = 'https://npm.taobao.org/dist' - -const supportPackageManagerList = ['npm', 'yarn', 'pnpm'] - -const packageManagerConfig = { - npm: { - installDeps: ['install', '--loglevel', 'error'], - installPackage: ['install', '--loglevel', 'error'], - uninstallPackage: ['uninstall', '--loglevel', 'error'], - updatePackage: ['update', '--loglevel', 'error'] - }, - - pnpm: { - installDeps: ['install', '--loglevel', 'error', '--shamefully-flatten'], - installPackage: ['install', '--loglevel', 'error'], - uninstallPackage: ['uninstall', '--loglevel', 'error'], - updatePackage: ['update', '--loglevel', 'error'] - }, - - yarn: { - installDeps: [], - installPackage: ['add'], - uninstallPackage: ['remove'], - updatePackage: ['upgrade'] - } -} - class InstallProgress extends EventEmitter { constructor () { super() @@ -63,8 +34,6 @@ class InstallProgress extends EventEmitter { } } -const progress = exports.progress = new InstallProgress() - function toStartOfLine (stream) { if (!chalk.supportsColor) { stream.write('\r') @@ -73,12 +42,6 @@ function toStartOfLine (stream) { readline.cursorTo(stream, 0) } -function checkPackageManagerIsSupported (command) { - if (supportPackageManagerList.indexOf(command) === -1) { - throw new Error(`Unknown package manager: ${command}`) - } -} - function renderProgressBar (curr, total) { const ratio = Math.min(Math.max(curr / total, 0), 1) const bar = ` ${curr}/${total}` @@ -91,18 +54,10 @@ function renderProgressBar (curr, total) { process.stderr.write(`[${complete}${incomplete}]${bar}`) } -async function addRegistryToArgs (command, args) { - const altRegistry = await getRegistry({ packageManager: command }) - - if (altRegistry) { - args.push(`--registry=${altRegistry}`) - if (altRegistry === registries.taobao) { - args.push(`--disturl=${taobaoDistURL}`) - } - } -} +module.exports = function executeCommand (command, args, cwd) { + debug(`command: `, command) + debug(`args: `, args) -function executeCommand (command, args, targetDir) { return new Promise((resolve, reject) => { const apiMode = process.env.VUE_CLI_API_MODE @@ -117,7 +72,7 @@ function executeCommand (command, args, targetDir) { } const child = execa(command, args, { - cwd: targetDir, + cwd, stdio: ['inherit', apiMode ? 'pipe' : 'inherit', !apiMode && command === 'yarn' ? 'pipe' : 'inherit'] }) @@ -188,62 +143,4 @@ function executeCommand (command, args, targetDir) { }) } -exports.installDeps = async function installDeps (targetDir, command) { - checkPackageManagerIsSupported(command) - - const args = packageManagerConfig[command].installDeps - - await addRegistryToArgs(command, args) - - debug(`command: `, command) - debug(`args: `, args) - - await executeCommand(command, args, targetDir) -} - -exports.installPackage = async function (targetDir, command, packageName, dev = true) { - checkPackageManagerIsSupported(command) - - const args = packageManagerConfig[command].installPackage - - if (dev) args.push('-D') - - await addRegistryToArgs(command, args) - - args.push(packageName) - - debug(`command: `, command) - debug(`args: `, args) - - await executeCommand(command, args, targetDir) -} - -exports.uninstallPackage = async function (targetDir, command, packageName) { - checkPackageManagerIsSupported(command) - - const args = packageManagerConfig[command].uninstallPackage - - await addRegistryToArgs(command, args) - - args.push(packageName) - - debug(`command: `, command) - debug(`args: `, args) - - await executeCommand(command, args, targetDir) -} - -exports.updatePackage = async function (targetDir, command, packageName) { - checkPackageManagerIsSupported(command) - - const args = packageManagerConfig[command].updatePackage - - await addRegistryToArgs(command, args) - - packageName.split(' ').forEach(name => args.push(name)) - - debug(`command: `, command) - debug(`args: `, args) - - await executeCommand(command, args, targetDir) -} +const progress = exports.progress = new InstallProgress() diff --git a/packages/@vue/cli/lib/util/getInstalledVersion.js b/packages/@vue/cli/lib/util/getInstalledVersion.js deleted file mode 100644 index 68741c00a4..0000000000 --- a/packages/@vue/cli/lib/util/getInstalledVersion.js +++ /dev/null @@ -1,14 +0,0 @@ -const path = require('path') -const getPackageJson = require('./getPackageJson') - -module.exports = function getInstalledVersion (packageName) { - // for first level deps, read package.json directly is way faster than `npm list` - try { - const packageJson = getPackageJson( - path.resolve(process.cwd(), 'node_modules', packageName) - ) - return packageJson.version - } catch (e) { - return 'N/A' - } -} diff --git a/packages/@vue/cli/lib/util/getPackageVersion.js b/packages/@vue/cli/lib/util/getPackageVersion.js deleted file mode 100644 index 1a7c58c44e..0000000000 --- a/packages/@vue/cli/lib/util/getPackageVersion.js +++ /dev/null @@ -1,16 +0,0 @@ -const { request } = require('@vue/cli-shared-utils') -const { getRegistry } = require('./packageManager') - -module.exports = async function getPackageVersion (id, range = '', registry) { - if (!registry) { - registry = await getRegistry() - } - - let result - try { - result = await request.get(`${registry}/${encodeURIComponent(id).replace(/^%40/, '@')}/${range}`) - } catch (e) { - return e - } - return result -} diff --git a/packages/@vue/cli/lib/util/getVersions.js b/packages/@vue/cli/lib/util/getVersions.js index 7e842e33aa..8483faec32 100644 --- a/packages/@vue/cli/lib/util/getVersions.js +++ b/packages/@vue/cli/lib/util/getVersions.js @@ -1,7 +1,9 @@ const semver = require('semver') +const PackageManager = require('./PackageManager') const { loadOptions, saveOptions } = require('../options') let sessionCached +const pm = new PackageManager() module.exports = async function getVersions () { if (sessionCached) { @@ -41,14 +43,10 @@ module.exports = async function getVersions () { // fetch the latest version and save it on disk // so that it is available immediately next time async function getAndCacheLatestVersion (cached) { - const getPackageVersion = require('./getPackageVersion') - const res = await getPackageVersion('vue-cli-version-marker', 'latest') - if (res.statusCode === 200) { - const { version } = res.body - if (semver.valid(version) && version !== cached) { - saveOptions({ latestVersion: version, lastChecked: Date.now() }) - return version - } + const version = await pm.getRemoteVersion('vue-cli-version-marker', 'latest') + if (semver.valid(version) && version !== cached) { + saveOptions({ latestVersion: version, lastChecked: Date.now() }) + return version } return cached } diff --git a/packages/@vue/cli/lib/util/linkBin.js b/packages/@vue/cli/lib/util/linkBin.js index d038ac551c..31c7c2bab6 100644 --- a/packages/@vue/cli/lib/util/linkBin.js +++ b/packages/@vue/cli/lib/util/linkBin.js @@ -19,12 +19,3 @@ exports.linkBin = async (src, dest) => { await fs.chmod(dest, '755') } } - -exports.linkPackage = async (src, dest) => { - if (!process.env.VUE_CLI_TEST && !process.env.VUE_CLI_DEBUG) { - throw new Error(`linkPackage should only be used during tests or debugging.`) - } - - await fs.remove(dest) - await fs.symlink(src, dest, 'dir') -} diff --git a/packages/@vue/cli/lib/util/packageManager.js b/packages/@vue/cli/lib/util/packageManager.js deleted file mode 100644 index 34eb1832a8..0000000000 --- a/packages/@vue/cli/lib/util/packageManager.js +++ /dev/null @@ -1,102 +0,0 @@ -const execa = require('execa') -const minimist = require('minimist') -const semver = require('semver') -const LRU = require('lru-cache') - -const { - hasYarn, - hasProjectYarn, - hasPnpm3OrLater, - hasProjectPnpm -} = require('@vue/cli-shared-utils') - -const { loadOptions } = require('../options') -const registries = require('./registries') -const shouldUseTaobao = require('./shouldUseTaobao') - -function getCommand (cwd) { - if (!cwd) { - return loadOptions().packageManager || (hasYarn() ? 'yarn' : hasPnpm3OrLater() ? 'pnpm' : 'npm') - } - return hasProjectYarn(cwd) ? 'yarn' : hasProjectPnpm(cwd) ? 'pnpm' : 'npm' -} - -// Any command that implemented registry-related feature should support -// `-r` / `--registry` option -async function getRegistry ({ cwd, packageManager } = {}) { - const args = minimist(process.argv, { - alias: { - r: 'registry' - } - }) - - if (args.registry) { - return args.registry - } - - if (await shouldUseTaobao()) { - return registries.taobao - } - - if (!packageManager) { - packageManager = getCommand(cwd) - } - const { stdout } = await execa(packageManager, ['config', 'get', 'registry']) - return stdout -} - -const metadataCache = new LRU({ - max: 200, - maxAge: 1000 * 60 * 30 // 30 min. -}) - -async function getMetadata (packageName, { field = '', packageManager, cwd } = {}) { - if (!packageManager) { - packageManager = getCommand(cwd) - } - const registry = await getRegistry({ cwd, packageManager }) - - const metadataKey = `${packageManager}-${registry}-${packageName}` - let metadata = metadataCache.get(metadataKey) - - if (metadata) { - return metadata - } - - const { stdout } = await execa( - packageManager, - [ - 'info', - packageName, - field, - '--json', - '--registry', - registry - ] - ) - - metadata = JSON.parse(stdout) - if (packageManager === 'yarn') { - // `yarn info` outputs messages in the form of `{"type": "inspect", data: {}}` - metadata = metadata.data - } - - metadataCache.set(metadataKey, metadata) - return metadata -} - -async function getVersion (packageName, versionRange, cwd) { - const metadata = await getMetadata(packageName, { cwd }) - if (Object.keys(metadata['dist-tags']).includes(versionRange)) { - return metadata['dist-tags'][versionRange] - } - const versions = Array.isArray(metadata.versions) ? metadata.versions : Object.keys(metadata.versions) - return semver.maxSatisfying(versions, versionRange) -} - -module.exports = { - getCommand, - getRegistry, - getMetadata, - getVersion -} From 727af184cbab3706741d9516c36c8ffc76399baf Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 00:25:07 +0800 Subject: [PATCH 2/6] chore: rename file to circumvent git case sensitivity caveats --- packages/@vue/cli-ui/apollo-server/connectors/dependencies.js | 2 +- packages/@vue/cli-ui/apollo-server/connectors/plugins.js | 2 +- packages/@vue/cli/lib/Creator.js | 2 +- packages/@vue/cli/lib/add.js | 2 +- packages/@vue/cli/lib/invoke.js | 2 +- packages/@vue/cli/lib/upgrade.js | 2 +- .../lib/util/{PackageManager.js => ProjectPackageManager.js} | 0 packages/@vue/cli/lib/util/getVersions.js | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename packages/@vue/cli/lib/util/{PackageManager.js => ProjectPackageManager.js} (100%) diff --git a/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js b/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js index 8174ba4214..63421484de 100644 --- a/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js +++ b/packages/@vue/cli-ui/apollo-server/connectors/dependencies.js @@ -14,7 +14,7 @@ const getContext = require('../context') // Utils const { isPlugin, hasYarn, resolveModule } = require('@vue/cli-shared-utils') const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand') -const PackageManager = require('@vue/cli/lib/util/PackageManager') +const PackageManager = require('@vue/cli/lib/util/ProjectPackageManager') const { resolveModuleRoot } = require('../util/resolve-path') const { notify } = require('../util/notification') const { log } = require('../util/logger') diff --git a/packages/@vue/cli-ui/apollo-server/connectors/plugins.js b/packages/@vue/cli-ui/apollo-server/connectors/plugins.js index b13925af25..2ec05454a0 100644 --- a/packages/@vue/cli-ui/apollo-server/connectors/plugins.js +++ b/packages/@vue/cli-ui/apollo-server/connectors/plugins.js @@ -31,7 +31,7 @@ const { execa } = require('@vue/cli-shared-utils') const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand') -const PackageManager = require('@vue/cli/lib/util/PackageManager') +const PackageManager = require('@vue/cli/lib/util/ProjectPackageManager') const ipc = require('../util/ipc') const { log } = require('../util/logger') diff --git a/packages/@vue/cli/lib/Creator.js b/packages/@vue/cli/lib/Creator.js index 6e2725e974..9a0cd6d906 100644 --- a/packages/@vue/cli/lib/Creator.js +++ b/packages/@vue/cli/lib/Creator.js @@ -9,7 +9,7 @@ const Generator = require('./Generator') const cloneDeep = require('lodash.clonedeep') const sortObject = require('./util/sortObject') const getVersions = require('./util/getVersions') -const PackageManager = require('./util/PackageManager') +const PackageManager = require('./util/ProjectPackageManager') const { clearConsole } = require('./util/clearConsole') const PromptModuleAPI = require('./PromptModuleAPI') const writeFileTree = require('./util/writeFileTree') diff --git a/packages/@vue/cli/lib/add.js b/packages/@vue/cli/lib/add.js index 859c936fef..32e5e7fde9 100644 --- a/packages/@vue/cli/lib/add.js +++ b/packages/@vue/cli/lib/add.js @@ -1,7 +1,7 @@ const chalk = require('chalk') const invoke = require('./invoke') -const PackageManager = require('./util/PackageManager') +const PackageManager = require('./util/ProjectPackageManager') const { log, error, diff --git a/packages/@vue/cli/lib/invoke.js b/packages/@vue/cli/lib/invoke.js index aedf76a35d..bf105c2152 100644 --- a/packages/@vue/cli/lib/invoke.js +++ b/packages/@vue/cli/lib/invoke.js @@ -16,7 +16,7 @@ const { const Generator = require('./Generator') const readFiles = require('./util/readFiles') -const PackageManager = require('./util/PackageManager') +const PackageManager = require('./util/ProjectPackageManager') function getPkg (context) { const pkgPath = path.resolve(context, 'package.json') diff --git a/packages/@vue/cli/lib/upgrade.js b/packages/@vue/cli/lib/upgrade.js index a01984cd33..b995701d67 100644 --- a/packages/@vue/cli/lib/upgrade.js +++ b/packages/@vue/cli/lib/upgrade.js @@ -22,7 +22,7 @@ const tryGetNewerRange = require('./util/tryGetNewerRange') const readFiles = require('./util/readFiles') const getPackageJson = require('./util/getPackageJson') -const PackageManager = require('./util/PackageManager') +const PackageManager = require('./util/ProjectPackageManager') const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG diff --git a/packages/@vue/cli/lib/util/PackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js similarity index 100% rename from packages/@vue/cli/lib/util/PackageManager.js rename to packages/@vue/cli/lib/util/ProjectPackageManager.js diff --git a/packages/@vue/cli/lib/util/getVersions.js b/packages/@vue/cli/lib/util/getVersions.js index 8483faec32..d66aede5f5 100644 --- a/packages/@vue/cli/lib/util/getVersions.js +++ b/packages/@vue/cli/lib/util/getVersions.js @@ -1,5 +1,5 @@ const semver = require('semver') -const PackageManager = require('./PackageManager') +const PackageManager = require('./ProjectPackageManager') const { loadOptions, saveOptions } = require('../options') let sessionCached From ab89df23376c19258053faf1908b6604675ce581 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 00:49:18 +0800 Subject: [PATCH 3/6] fix: fix InstallProgress --- packages/@vue/cli/lib/util/executeCommand.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@vue/cli/lib/util/executeCommand.js b/packages/@vue/cli/lib/util/executeCommand.js index 0d4c2d306a..4a259dde1f 100644 --- a/packages/@vue/cli/lib/util/executeCommand.js +++ b/packages/@vue/cli/lib/util/executeCommand.js @@ -54,6 +54,7 @@ function renderProgressBar (curr, total) { process.stderr.write(`[${complete}${incomplete}]${bar}`) } +const progress = new InstallProgress() module.exports = function executeCommand (command, args, cwd) { debug(`command: `, command) debug(`args: `, args) @@ -143,4 +144,4 @@ module.exports = function executeCommand (command, args, cwd) { }) } -const progress = exports.progress = new InstallProgress() +exports.progress = progress From a729b67e08d1d2361bf556a7be650fe33a4d6d5a Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 01:01:18 +0800 Subject: [PATCH 4/6] fix: fix resolve plugin id before test if it's official plugin --- packages/@vue/cli/lib/util/ProjectPackageManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index 098ab71060..e36ebe4104 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -12,7 +12,7 @@ const { hasPnpm3OrLater, hasProjectPnpm } = require('@vue/cli-shared-utils/lib/env') -const { isOfficialPlugin } = require('@vue/cli-shared-utils/lib/pluginResolution') +const { isOfficialPlugin, resolvePluginId } = require('@vue/cli-shared-utils/lib/pluginResolution') const { loadOptions } = require('../options') const getPackageJson = require('./getPackageJson') @@ -165,7 +165,7 @@ class PackageManager { async upgrade (packageName) { if ( isTestOrDebug && - (packageName === '@vue/cli-service' || isOfficialPlugin(packageName)) + (packageName === '@vue/cli-service' || isOfficialPlugin(resolvePluginId(packageName))) ) { // link packages in current repo for test const src = path.resolve(__dirname, `../../../${packageName}`) From 02bc3d146912b137a631762eaebf4075f6b78361 Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 01:43:56 +0800 Subject: [PATCH 5/6] fix: fix symlink utility in test environment --- .../cli/lib/util/ProjectPackageManager.js | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index e36ebe4104..ea7ca35d24 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -1,4 +1,4 @@ -const fs = require('fs') +const fs = require('fs-extra') const path = require('path') const execa = require('execa') @@ -51,6 +51,18 @@ const PACKAGE_MANAGER_CONFIG = { } } +// extract the package name 'xx' from the format 'xx@1.1' +function stripVersion (packageName) { + const nameRegExp = /^(@?[^@]+)(@.*)?$/ + const result = packageName.match(nameRegExp) + + if (!result) { + throw new Error(`Invalid package name ${packageName}`) + } + + return result[1] +} + class PackageManager { constructor ({ context, forcePackageManager } = {}) { this.context = context @@ -163,13 +175,15 @@ class PackageManager { } async upgrade (packageName) { + const realname = stripVersion(packageName) if ( isTestOrDebug && - (packageName === '@vue/cli-service' || isOfficialPlugin(resolvePluginId(packageName))) + (packageName === '@vue/cli-service' || isOfficialPlugin(resolvePluginId(realname))) ) { // link packages in current repo for test - const src = path.resolve(__dirname, `../../../${packageName}`) - const dest = path.join(this.context, 'node_modules', packageName) + const src = path.resolve(__dirname, `../../../../${realname}`) + const dest = path.join(this.context, 'node_modules', realname) + fs.writeFileSync('./aaa', `${src}, ${dest}`) await fs.remove(dest) await fs.symlink(src, dest, 'dir') return From e4424bd19c22688941c44bdf8ee1506bf1e5b35c Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Wed, 10 Jul 2019 01:50:35 +0800 Subject: [PATCH 6/6] fix: fix progress --- packages/@vue/cli/lib/util/ProjectPackageManager.js | 2 +- packages/@vue/cli/lib/util/executeCommand.js | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/@vue/cli/lib/util/ProjectPackageManager.js b/packages/@vue/cli/lib/util/ProjectPackageManager.js index ea7ca35d24..153f585b62 100644 --- a/packages/@vue/cli/lib/util/ProjectPackageManager.js +++ b/packages/@vue/cli/lib/util/ProjectPackageManager.js @@ -16,7 +16,7 @@ const { isOfficialPlugin, resolvePluginId } = require('@vue/cli-shared-utils/lib const { loadOptions } = require('../options') const getPackageJson = require('./getPackageJson') -const executeCommand = require('./executeCommand') +const { executeCommand } = require('./executeCommand') const registries = require('./registries') const shouldUseTaobao = require('./shouldUseTaobao') diff --git a/packages/@vue/cli/lib/util/executeCommand.js b/packages/@vue/cli/lib/util/executeCommand.js index 4a259dde1f..154ba2bf8d 100644 --- a/packages/@vue/cli/lib/util/executeCommand.js +++ b/packages/@vue/cli/lib/util/executeCommand.js @@ -54,8 +54,8 @@ function renderProgressBar (curr, total) { process.stderr.write(`[${complete}${incomplete}]${bar}`) } -const progress = new InstallProgress() -module.exports = function executeCommand (command, args, cwd) { +const progress = exports.progress = new InstallProgress() +exports.executeCommand = function executeCommand (command, args, cwd) { debug(`command: `, command) debug(`args: `, args) @@ -143,5 +143,3 @@ module.exports = function executeCommand (command, args, cwd) { }) }) } - -exports.progress = progress