123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- const fs = require('fs')
- const path = require('path')
- const LRU = require('lru-cache')
- const { chalk, semver } = require('@vue/cli-shared-utils')
- // Connectors
- const cwd = require('./cwd')
- const folders = require('./folders')
- const progress = require('./progress')
- const logs = require('./logs')
- // Context
- const getContext = require('../context')
- // Utils
- const { isPlugin, resolveModule } = require('@vue/cli-shared-utils')
- const { progress: installProgress } = require('@vue/cli/lib/util/executeCommand')
- const PackageManager = require('@vue/cli/lib/util/ProjectPackageManager')
- const { resolveModuleRoot } = require('../util/resolve-path')
- const { notify } = require('../util/notification')
- const { log } = require('../util/logger')
- const PROGRESS_ID = 'dependency-installation'
- const CLI_SERVICE = '@vue/cli-service'
- // Caches
- const metadataCache = new LRU({
- max: 200,
- maxAge: 1000 * 60 * 30 // 30 min.
- })
- // Local
- let dependencies
- function list (file, context) {
- const pkg = folders.readPackage(file, context)
- dependencies = []
- dependencies = dependencies.concat(
- findDependencies(pkg.devDependencies || {}, 'devDependencies', file, context)
- )
- dependencies = dependencies.concat(
- findDependencies(pkg.dependencies || {}, 'dependencies', file, context)
- )
- return dependencies
- }
- function findOne (id, context) {
- return dependencies.find(
- p => p.id === id
- )
- }
- function findDependencies (deps, type, file, context) {
- return Object.keys(deps).filter(
- id => !isPlugin(id) && id !== CLI_SERVICE
- ).map(
- id => ({
- id,
- versionRange: deps[id],
- installed: isInstalled({ id, file }),
- website: getLink({ id, file }, context),
- type,
- baseFir: file
- })
- )
- }
- function getPath ({ id, file = cwd.get() }) {
- const filePath = resolveModule(path.join(id, 'package.json'), file)
- if (!filePath) return
- return resolveModuleRoot(filePath, id)
- }
- function isInstalled ({ id, file = cwd.get() }) {
- const resolvedPath = getPath({ id, file })
- return resolvedPath && fs.existsSync(resolvedPath)
- }
- function readPackage ({ id, file }, context) {
- try {
- return folders.readPackage(getPath({ id, file }), context)
- } catch (e) {
- console.log(e)
- }
- return {}
- }
- function invalidatePackage ({ id, file }, context) {
- return folders.invalidatePackage(getPath({ id, file }), context)
- }
- async function getMetadata (id, context) {
- let metadata = metadataCache.get(id)
- if (metadata) {
- return metadata
- }
- try {
- metadata = await (new PackageManager({ context: cwd.get() })).getMetadata(id)
- } catch (e) {
- // No connection?
- }
- if (metadata) {
- metadataCache.set(id, metadata)
- return metadata
- } else {
- log('Dependencies', chalk.yellow('Can\'t load metadata'), id)
- }
- }
- async function getVersion ({ id, installed, versionRange, baseDir }, context) {
- let current
- // Is local dep
- const localPath = getLocalPath(id, context)
- // Read module package.json
- if (installed) {
- const pkg = readPackage({ id, file: baseDir }, context)
- current = pkg.version
- } else {
- current = null
- }
- // Metadata
- let latest, wanted
- const metadata = await getMetadata(id, context)
- if (metadata) {
- latest = metadata['dist-tags'].latest
- const versions = Array.isArray(metadata.versions) ? metadata.versions : Object.keys(metadata.versions)
- wanted = semver.maxSatisfying(versions, versionRange)
- }
- if (!latest) latest = current
- if (!wanted) wanted = current
- return {
- current,
- latest,
- wanted,
- range: versionRange,
- localPath
- }
- }
- function getLocalPath (id, context) {
- const projects = require('./projects')
- const projectPkg = folders.readPackage(projects.getCurrent(context).path, context, true)
- const deps = Object.assign(
- {},
- projectPkg.dependencies || {},
- projectPkg.devDependencies || {}
- )
- const range = deps[id]
- if (range && range.match(/^file:/)) {
- const localPath = range.substr('file:'.length)
- return path.resolve(cwd.get(), localPath)
- }
- return null
- }
- async function getDescription ({ id }, context) {
- const metadata = await getMetadata(id, context)
- if (metadata) {
- return metadata.description
- }
- return null
- }
- function getLink ({ id, file }, context) {
- const pkg = readPackage({ id, file }, context)
- return pkg.homepage ||
- (pkg.repository && pkg.repository.url) ||
- `https://www.npmjs.com/package/${id.replace('/', '%2F')}`
- }
- function install ({ id, type, range }, context) {
- return progress.wrap(PROGRESS_ID, context, async setProgress => {
- setProgress({
- status: 'dependency-install',
- args: [id]
- })
- let arg
- if (range) {
- arg = `${id}@${range}`
- } else {
- arg = id
- }
- const pm = new PackageManager({ context: cwd.get() })
- await pm.add(arg, {
- tilde: !range && isPlugin(id),
- dev: type === 'devDependencies'
- })
- logs.add({
- message: `Dependency ${id} installed`,
- type: 'info'
- }, context)
- notify({
- title: 'Dependency installed',
- message: `Dependency ${id} successfully installed`,
- icon: 'done'
- })
- list(cwd.get(), context)
- return findOne(id, context)
- })
- }
- function uninstall ({ id }, context) {
- return progress.wrap(PROGRESS_ID, context, async setProgress => {
- setProgress({
- status: 'dependency-uninstall',
- args: [id]
- })
- const dep = findOne(id, context)
- const pm = new PackageManager({ context: cwd.get() })
- await pm.remove(id)
- logs.add({
- message: `Dependency ${id} uninstalled`,
- type: 'info'
- }, context)
- notify({
- title: 'Dependency uninstalled',
- message: `Dependency ${id} successfully uninstalled`,
- icon: 'done'
- })
- return dep
- })
- }
- function update ({ id }, context) {
- return progress.wrap(PROGRESS_ID, context, async setProgress => {
- setProgress({
- status: 'dependency-update',
- args: [id]
- })
- const dep = findOne(id, context)
- const { current, wanted } = await getVersion(dep, context)
- const pm = new PackageManager({ context: cwd.get() })
- await pm.upgrade(id)
- logs.add({
- message: `Dependency ${id} updated from ${current} to ${wanted}`,
- type: 'info'
- }, context)
- notify({
- title: 'Dependency updated',
- message: `Dependency ${id} was successfully updated`,
- icon: 'done'
- })
- invalidatePackage({ id }, context)
- return findOne(id)
- })
- }
- function updateAll (context) {
- return progress.wrap(PROGRESS_ID, context, async setProgress => {
- const deps = list(cwd.get(), context)
- const updatedDeps = []
- for (const dep of deps) {
- const version = await getVersion(dep, context)
- if (version.current !== version.wanted) {
- updatedDeps.push(dep)
- invalidatePackage({ id: dep.id }, context)
- }
- }
- if (!updatedDeps.length) {
- notify({
- title: 'No updates available',
- message: 'No dependency to update in the version ranges declared in package.json',
- icon: 'done'
- })
- return []
- }
- setProgress({
- status: 'dependencies-update',
- args: [updatedDeps.length]
- })
- const pm = new PackageManager({ context: cwd.get() })
- await pm.upgrade(updatedDeps.map(p => p.id).join(' '))
- notify({
- title: 'Dependencies updated',
- message: `${updatedDeps.length} dependencies were successfully updated`,
- icon: 'done'
- })
- return updatedDeps
- })
- }
- function setup (context) {
- // Package installation progress events
- installProgress.on('progress', value => {
- if (progress.get(PROGRESS_ID)) {
- progress.set({ id: PROGRESS_ID, progress: value }, context)
- }
- })
- installProgress.on('log', message => {
- if (progress.get(PROGRESS_ID)) {
- progress.set({ id: PROGRESS_ID, info: message }, context)
- }
- })
- }
- setup(getContext())
- module.exports = {
- list,
- findOne,
- getPath,
- getMetadata,
- getLink,
- getDescription,
- getVersion,
- install,
- uninstall,
- update,
- updateAll,
- invalidatePackage
- }
|