UNPKG

4.77 kBJavaScriptView Raw
1'use strict'
2/* eslint-disable standard/no-callback-literal */
3
4const BB = require('bluebird')
5
6const assert = require('assert')
7const cacache = require('cacache')
8const finished = BB.promisify(require('mississippi').finished)
9const log = require('npmlog')
10const npa = require('npm-package-arg')
11const npm = require('./npm.js')
12const npmConfig = require('./config/figgy-config.js')
13const output = require('./utils/output.js')
14const pacote = require('pacote')
15const path = require('path')
16const rm = BB.promisify(require('./utils/gently-rm.js'))
17const unbuild = BB.promisify(npm.commands.unbuild)
18
19cache.usage = 'npm cache add <tarball file>' +
20 '\nnpm cache add <folder>' +
21 '\nnpm cache add <tarball url>' +
22 '\nnpm cache add <git url>' +
23 '\nnpm cache add <name>@<version>' +
24 '\nnpm cache clean' +
25 '\nnpm cache verify'
26
27cache.completion = function (opts, cb) {
28 var argv = opts.conf.argv.remain
29 if (argv.length === 2) {
30 return cb(null, ['add', 'clean'])
31 }
32
33 // TODO - eventually...
34 switch (argv[2]) {
35 case 'clean':
36 case 'add':
37 return cb(null, [])
38 }
39}
40
41exports = module.exports = cache
42function cache (args, cb) {
43 const cmd = args.shift()
44 let result
45 switch (cmd) {
46 case 'rm': case 'clear': case 'clean':
47 result = clean(args)
48 break
49 case 'add':
50 result = add(args, npm.prefix)
51 break
52 case 'verify': case 'check':
53 result = verify()
54 break
55 default: return cb('Usage: ' + cache.usage)
56 }
57 if (!result || !result.then) {
58 throw new Error(`npm cache ${cmd} handler did not return a Promise`)
59 }
60 result.then(() => cb(), cb)
61}
62
63// npm cache clean [pkg]*
64cache.clean = clean
65function clean (args) {
66 if (!args) args = []
67 if (args.length) {
68 return BB.reject(new Error('npm cache clear does not accept arguments'))
69 }
70 const cachePath = path.join(npm.cache, '_cacache')
71 if (!npm.config.get('force')) {
72 return BB.reject(new Error("As of npm@5, the npm cache self-heals from corruption issues and data extracted from the cache is guaranteed to be valid. If you want to make sure everything is consistent, use 'npm cache verify' instead. On the other hand, if you're debugging an issue with the installer, you can use `npm install --cache /tmp/empty-cache` to use a temporary cache instead of nuking the actual one.\n\nIf you're sure you want to delete the entire cache, rerun this command with --force."))
73 }
74 // TODO - remove specific packages or package versions
75 return rm(cachePath)
76}
77
78// npm cache add <tarball-url>
79// npm cache add <pkg> <ver>
80// npm cache add <tarball>
81// npm cache add <folder>
82cache.add = function (pkg, ver, where, scrub) {
83 assert(typeof pkg === 'string', 'must include name of package to install')
84 if (scrub) {
85 return clean([]).then(() => {
86 return add([pkg, ver], where)
87 })
88 }
89 return add([pkg, ver], where)
90}
91
92function add (args, where) {
93 var usage = 'Usage:\n' +
94 ' npm cache add <tarball-url>\n' +
95 ' npm cache add <pkg>@<ver>\n' +
96 ' npm cache add <tarball>\n' +
97 ' npm cache add <folder>\n'
98 var spec
99 log.silly('cache add', 'args', args)
100 if (args[1] === undefined) args[1] = null
101 // at this point the args length must ==2
102 if (args[1] !== null) {
103 spec = args[0] + '@' + args[1]
104 } else if (args.length === 2) {
105 spec = args[0]
106 }
107 log.verbose('cache add', 'spec', spec)
108 if (!spec) return BB.reject(new Error(usage))
109 log.silly('cache add', 'parsed spec', spec)
110 return finished(pacote.tarball.stream(spec, npmConfig({where})).resume())
111}
112
113cache.verify = verify
114function verify () {
115 const cache = path.join(npm.config.get('cache'), '_cacache')
116 let prefix = cache
117 if (prefix.indexOf(process.env.HOME) === 0) {
118 prefix = '~' + prefix.substr(process.env.HOME.length)
119 }
120 return cacache.verify(cache).then((stats) => {
121 output(`Cache verified and compressed (${prefix}):`)
122 output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`)
123 stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`)
124 stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`)
125 stats.missingContent && output(`Missing content: ${stats.missingContent}`)
126 output(`Index entries: ${stats.totalEntries}`)
127 output(`Finished in ${stats.runTime.total / 1000}s`)
128 })
129}
130
131cache.unpack = unpack
132function unpack (pkg, ver, unpackTarget, dmode, fmode, uid, gid) {
133 return unbuild([unpackTarget], true).then(() => {
134 const opts = npmConfig({dmode, fmode, uid, gid, offline: true})
135 return pacote.extract(npa.resolve(pkg, ver), unpackTarget, opts)
136 })
137}