cacache 12.0.2 → 13.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/util/tmp.js CHANGED
@@ -1,18 +1,20 @@
1
1
  'use strict'
2
2
 
3
- const BB = require('bluebird')
3
+ const util = require('util')
4
4
 
5
5
  const figgyPudding = require('figgy-pudding')
6
6
  const fixOwner = require('./fix-owner')
7
7
  const path = require('path')
8
- const rimraf = BB.promisify(require('rimraf'))
8
+ const rimraf = util.promisify(require('rimraf'))
9
9
  const uniqueFilename = require('unique-filename')
10
+ const { disposer } = require('./disposer')
10
11
 
11
12
  const TmpOpts = figgyPudding({
12
13
  tmpPrefix: {}
13
14
  })
14
15
 
15
16
  module.exports.mkdir = mktmpdir
17
+
16
18
  function mktmpdir (cache, opts) {
17
19
  opts = TmpOpts(opts)
18
20
  const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
@@ -22,16 +24,19 @@ function mktmpdir (cache, opts) {
22
24
  }
23
25
 
24
26
  module.exports.withTmp = withTmp
27
+
25
28
  function withTmp (cache, opts, cb) {
26
29
  if (!cb) {
27
30
  cb = opts
28
31
  opts = null
29
32
  }
30
33
  opts = TmpOpts(opts)
31
- return BB.using(mktmpdir(cache, opts).disposer(rimraf), cb)
34
+
35
+ return disposer(mktmpdir(cache, opts), rimraf, cb)
32
36
  }
33
37
 
34
38
  module.exports.fix = fixtmpdir
39
+
35
40
  function fixtmpdir (cache) {
36
41
  return fixOwner(cache, path.join(cache, 'tmp'))
37
42
  }
package/lib/verify.js CHANGED
@@ -1,19 +1,26 @@
1
1
  'use strict'
2
2
 
3
- const BB = require('bluebird')
3
+ const util = require('util')
4
4
 
5
+ const pMap = require('p-map')
5
6
  const contentPath = require('./content/path')
6
7
  const figgyPudding = require('figgy-pudding')
7
- const finished = BB.promisify(require('mississippi').finished)
8
8
  const fixOwner = require('./util/fix-owner')
9
9
  const fs = require('graceful-fs')
10
- const glob = BB.promisify(require('glob'))
10
+ const fsm = require('fs-minipass')
11
+ const glob = util.promisify(require('glob'))
11
12
  const index = require('./entry-index')
12
13
  const path = require('path')
13
- const rimraf = BB.promisify(require('rimraf'))
14
+ const rimraf = util.promisify(require('rimraf'))
14
15
  const ssri = require('ssri')
15
16
 
16
- BB.promisifyAll(fs)
17
+ const hasOwnProperty = (obj, key) =>
18
+ Object.prototype.hasOwnProperty.call(obj, key)
19
+
20
+ const stat = util.promisify(fs.stat)
21
+ const truncate = util.promisify(fs.truncate)
22
+ const writeFile = util.promisify(fs.writeFile)
23
+ const readFile = util.promisify(fs.readFile)
17
24
 
18
25
  const VerifyOpts = figgyPudding({
19
26
  concurrency: {
@@ -26,10 +33,12 @@ const VerifyOpts = figgyPudding({
26
33
  })
27
34
 
28
35
  module.exports = verify
36
+
29
37
  function verify (cache, opts) {
30
38
  opts = VerifyOpts(opts)
31
39
  opts.log.silly('verify', 'verifying cache at', cache)
32
- return BB.reduce([
40
+
41
+ const steps = [
33
42
  markStartTime,
34
43
  fixPerms,
35
44
  garbageCollect,
@@ -37,38 +46,57 @@ function verify (cache, opts) {
37
46
  cleanTmp,
38
47
  writeVerifile,
39
48
  markEndTime
40
- ], (stats, step, i) => {
41
- const label = step.name || `step #${i}`
42
- const start = new Date()
43
- return BB.resolve(step(cache, opts)).then(s => {
44
- s && Object.keys(s).forEach(k => {
45
- stats[k] = s[k]
49
+ ]
50
+
51
+ return steps
52
+ .reduce((promise, step, i) => {
53
+ const label = step.name || `step #${i}`
54
+ const start = new Date()
55
+ return promise.then((stats) => {
56
+ return step(cache, opts).then((s) => {
57
+ s &&
58
+ Object.keys(s).forEach((k) => {
59
+ stats[k] = s[k]
60
+ })
61
+ const end = new Date()
62
+ if (!stats.runTime) {
63
+ stats.runTime = {}
64
+ }
65
+ stats.runTime[label] = end - start
66
+ return Promise.resolve(stats)
67
+ })
46
68
  })
47
- const end = new Date()
48
- if (!stats.runTime) { stats.runTime = {} }
49
- stats.runTime[label] = end - start
69
+ }, Promise.resolve({}))
70
+ .then((stats) => {
71
+ stats.runTime.total = stats.endTime - stats.startTime
72
+ opts.log.silly(
73
+ 'verify',
74
+ 'verification finished for',
75
+ cache,
76
+ 'in',
77
+ `${stats.runTime.total}ms`
78
+ )
50
79
  return stats
51
80
  })
52
- }, {}).tap(stats => {
53
- stats.runTime.total = stats.endTime - stats.startTime
54
- opts.log.silly('verify', 'verification finished for', cache, 'in', `${stats.runTime.total}ms`)
55
- })
56
81
  }
57
82
 
58
83
  function markStartTime (cache, opts) {
59
- return { startTime: new Date() }
84
+ return Promise.resolve({ startTime: new Date() })
60
85
  }
61
86
 
62
87
  function markEndTime (cache, opts) {
63
- return { endTime: new Date() }
88
+ return Promise.resolve({ endTime: new Date() })
64
89
  }
65
90
 
66
91
  function fixPerms (cache, opts) {
67
92
  opts.log.silly('verify', 'fixing cache permissions')
68
- return fixOwner.mkdirfix(cache, cache).then(() => {
69
- // TODO - fix file permissions too
70
- return fixOwner.chownr(cache, cache)
71
- }).then(() => null)
93
+ return fixOwner
94
+ .mkdirfix(cache, cache)
95
+ .then(() => {
96
+ // TODO - fix file permissions too
97
+ return fixOwner.chownr(cache, cache)
98
+ })
99
+ .then(() => null)
72
100
  }
73
101
 
74
102
  // Implements a naive mark-and-sweep tracing garbage collector.
@@ -84,85 +112,104 @@ function garbageCollect (cache, opts) {
84
112
  opts.log.silly('verify', 'garbage collecting content')
85
113
  const indexStream = index.lsStream(cache)
86
114
  const liveContent = new Set()
87
- indexStream.on('data', entry => {
88
- if (opts.filter && !opts.filter(entry)) { return }
115
+ indexStream.on('data', (entry) => {
116
+ if (opts.filter && !opts.filter(entry)) {
117
+ return
118
+ }
89
119
  liveContent.add(entry.integrity.toString())
90
120
  })
91
- return finished(indexStream).then(() => {
92
- const contentDir = contentPath._contentDir(cache)
121
+ return new Promise((resolve, reject) => {
122
+ indexStream.on('end', resolve).on('error', reject)
123
+ }).then(() => {
124
+ const contentDir = contentPath.contentDir(cache)
93
125
  return glob(path.join(contentDir, '**'), {
94
126
  follow: false,
95
127
  nodir: true,
96
128
  nosort: true
97
- }).then(files => {
98
- return BB.resolve({
129
+ }).then((files) => {
130
+ return Promise.resolve({
99
131
  verifiedContent: 0,
100
132
  reclaimedCount: 0,
101
133
  reclaimedSize: 0,
102
134
  badContentCount: 0,
103
135
  keptSize: 0
104
- }).tap((stats) => BB.map(files, (f) => {
105
- const split = f.split(/[/\\]/)
106
- const digest = split.slice(split.length - 3).join('')
107
- const algo = split[split.length - 4]
108
- const integrity = ssri.fromHex(digest, algo)
109
- if (liveContent.has(integrity.toString())) {
110
- return verifyContent(f, integrity).then(info => {
111
- if (!info.valid) {
112
- stats.reclaimedCount++
113
- stats.badContentCount++
114
- stats.reclaimedSize += info.size
136
+ }).then((stats) =>
137
+ pMap(
138
+ files,
139
+ (f) => {
140
+ const split = f.split(/[/\\]/)
141
+ const digest = split.slice(split.length - 3).join('')
142
+ const algo = split[split.length - 4]
143
+ const integrity = ssri.fromHex(digest, algo)
144
+ if (liveContent.has(integrity.toString())) {
145
+ return verifyContent(f, integrity).then((info) => {
146
+ if (!info.valid) {
147
+ stats.reclaimedCount++
148
+ stats.badContentCount++
149
+ stats.reclaimedSize += info.size
150
+ } else {
151
+ stats.verifiedContent++
152
+ stats.keptSize += info.size
153
+ }
154
+ return stats
155
+ })
115
156
  } else {
116
- stats.verifiedContent++
117
- stats.keptSize += info.size
157
+ // No entries refer to this content. We can delete.
158
+ stats.reclaimedCount++
159
+ return stat(f).then((s) => {
160
+ return rimraf(f).then(() => {
161
+ stats.reclaimedSize += s.size
162
+ return stats
163
+ })
164
+ })
118
165
  }
119
- return stats
120
- })
121
- } else {
122
- // No entries refer to this content. We can delete.
123
- stats.reclaimedCount++
124
- return fs.statAsync(f).then(s => {
125
- return rimraf(f).then(() => {
126
- stats.reclaimedSize += s.size
127
- return stats
128
- })
129
- })
130
- }
131
- }, { concurrency: opts.concurrency }))
166
+ },
167
+ { concurrency: opts.concurrency }
168
+ ).then(() => stats)
169
+ )
132
170
  })
133
171
  })
134
172
  }
135
173
 
136
174
  function verifyContent (filepath, sri) {
137
- return fs.statAsync(filepath).then(stat => {
138
- const contentInfo = {
139
- size: stat.size,
140
- valid: true
141
- }
142
- return ssri.checkStream(
143
- fs.createReadStream(filepath),
144
- sri
145
- ).catch(err => {
146
- if (err.code !== 'EINTEGRITY') { throw err }
147
- return rimraf(filepath).then(() => {
148
- contentInfo.valid = false
149
- })
150
- }).then(() => contentInfo)
151
- }).catch({ code: 'ENOENT' }, () => ({ size: 0, valid: false }))
175
+ return stat(filepath)
176
+ .then((s) => {
177
+ const contentInfo = {
178
+ size: s.size,
179
+ valid: true
180
+ }
181
+ return ssri
182
+ .checkStream(new fsm.ReadStream(filepath), sri)
183
+ .catch((err) => {
184
+ if (err.code !== 'EINTEGRITY') {
185
+ throw err
186
+ }
187
+ return rimraf(filepath).then(() => {
188
+ contentInfo.valid = false
189
+ })
190
+ })
191
+ .then(() => contentInfo)
192
+ })
193
+ .catch((err) => {
194
+ if (err.code === 'ENOENT') {
195
+ return { size: 0, valid: false }
196
+ }
197
+ throw err
198
+ })
152
199
  }
153
200
 
154
201
  function rebuildIndex (cache, opts) {
155
202
  opts.log.silly('verify', 'rebuilding index')
156
- return index.ls(cache).then(entries => {
203
+ return index.ls(cache).then((entries) => {
157
204
  const stats = {
158
205
  missingContent: 0,
159
206
  rejectedEntries: 0,
160
207
  totalEntries: 0
161
208
  }
162
209
  const buckets = {}
163
- for (let k in entries) {
164
- if (entries.hasOwnProperty(k)) {
165
- const hashed = index._hashKey(k)
210
+ for (const k in entries) {
211
+ if (hasOwnProperty(entries, k)) {
212
+ const hashed = index.hashKey(k)
166
213
  const entry = entries[k]
167
214
  const excluded = opts.filter && !opts.filter(entry)
168
215
  excluded && stats.rejectedEntries++
@@ -172,35 +219,51 @@ function rebuildIndex (cache, opts) {
172
219
  // skip
173
220
  } else if (excluded) {
174
221
  buckets[hashed] = []
175
- buckets[hashed]._path = index._bucketPath(cache, k)
222
+ buckets[hashed]._path = index.bucketPath(cache, k)
176
223
  } else {
177
224
  buckets[hashed] = [entry]
178
- buckets[hashed]._path = index._bucketPath(cache, k)
225
+ buckets[hashed]._path = index.bucketPath(cache, k)
179
226
  }
180
227
  }
181
228
  }
182
- return BB.map(Object.keys(buckets), key => {
183
- return rebuildBucket(cache, buckets[key], stats, opts)
184
- }, { concurrency: opts.concurrency }).then(() => stats)
229
+ return pMap(
230
+ Object.keys(buckets),
231
+ (key) => {
232
+ return rebuildBucket(cache, buckets[key], stats, opts)
233
+ },
234
+ { concurrency: opts.concurrency }
235
+ ).then(() => stats)
185
236
  })
186
237
  }
187
238
 
188
239
  function rebuildBucket (cache, bucket, stats, opts) {
189
- return fs.truncateAsync(bucket._path).then(() => {
240
+ return truncate(bucket._path).then(() => {
190
241
  // This needs to be serialized because cacache explicitly
191
242
  // lets very racy bucket conflicts clobber each other.
192
- return BB.mapSeries(bucket, entry => {
193
- const content = contentPath(cache, entry.integrity)
194
- return fs.statAsync(content).then(() => {
195
- return index.insert(cache, entry.key, entry.integrity, {
196
- metadata: entry.metadata,
197
- size: entry.size
198
- }).then(() => { stats.totalEntries++ })
199
- }).catch({ code: 'ENOENT' }, () => {
200
- stats.rejectedEntries++
201
- stats.missingContent++
243
+ return bucket.reduce((promise, entry) => {
244
+ return promise.then(() => {
245
+ const content = contentPath(cache, entry.integrity)
246
+ return stat(content)
247
+ .then(() => {
248
+ return index
249
+ .insert(cache, entry.key, entry.integrity, {
250
+ metadata: entry.metadata,
251
+ size: entry.size
252
+ })
253
+ .then(() => {
254
+ stats.totalEntries++
255
+ })
256
+ })
257
+ .catch((err) => {
258
+ if (err.code === 'ENOENT') {
259
+ stats.rejectedEntries++
260
+ stats.missingContent++
261
+ return
262
+ }
263
+ throw err
264
+ })
202
265
  })
203
- })
266
+ }, Promise.resolve())
204
267
  })
205
268
  }
206
269
 
@@ -213,15 +276,16 @@ function writeVerifile (cache, opts) {
213
276
  const verifile = path.join(cache, '_lastverified')
214
277
  opts.log.silly('verify', 'writing verifile to ' + verifile)
215
278
  try {
216
- return fs.writeFileAsync(verifile, '' + (+(new Date())))
279
+ return writeFile(verifile, '' + +new Date())
217
280
  } finally {
218
281
  fixOwner.chownr.sync(cache, verifile)
219
282
  }
220
283
  }
221
284
 
222
285
  module.exports.lastRun = lastRun
286
+
223
287
  function lastRun (cache) {
224
- return fs.readFileAsync(
225
- path.join(cache, '_lastverified'), 'utf8'
226
- ).then(data => new Date(+data))
288
+ return readFile(path.join(cache, '_lastverified'), 'utf8').then(
289
+ (data) => new Date(+data)
290
+ )
227
291
  }
package/ls.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- var index = require('./lib/entry-index')
3
+ const index = require('./lib/entry-index')
4
4
 
5
5
  module.exports = index.ls
6
6
  module.exports.stream = index.lsStream
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cacache",
3
- "version": "12.0.2",
3
+ "version": "13.0.1",
4
4
  "cache-version": {
5
5
  "content": "2",
6
6
  "index": "5"
@@ -18,7 +18,7 @@
18
18
  "postrelease": "npm publish && git push --follow-tags",
19
19
  "pretest": "standard",
20
20
  "release": "standard-version -s",
21
- "test": "cross-env CACACHE_UPDATE_LOCALE_FILES=true tap --coverage --nyc-arg=--all -J test/*.js",
21
+ "test": "tap test/*.js",
22
22
  "test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test",
23
23
  "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'",
24
24
  "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'"
@@ -58,40 +58,38 @@
58
58
  ],
59
59
  "license": "ISC",
60
60
  "dependencies": {
61
- "bluebird": "^3.5.5",
62
- "chownr": "^1.1.1",
61
+ "chownr": "^1.1.2",
63
62
  "figgy-pudding": "^3.5.1",
63
+ "fs-minipass": "^2.0.0",
64
64
  "glob": "^7.1.4",
65
- "graceful-fs": "^4.1.15",
66
- "infer-owner": "^1.0.3",
65
+ "graceful-fs": "^4.2.2",
66
+ "infer-owner": "^1.0.4",
67
67
  "lru-cache": "^5.1.1",
68
- "mississippi": "^3.0.0",
68
+ "minipass": "^3.0.0",
69
+ "minipass-collect": "^1.0.2",
70
+ "minipass-flush": "^1.0.5",
71
+ "minipass-pipeline": "^1.2.2",
69
72
  "mkdirp": "^0.5.1",
70
73
  "move-concurrently": "^1.0.1",
74
+ "p-map": "^3.0.0",
71
75
  "promise-inflight": "^1.0.1",
72
- "rimraf": "^2.6.3",
73
- "ssri": "^6.0.1",
74
- "unique-filename": "^1.1.1",
75
- "y18n": "^4.0.0"
76
+ "rimraf": "^2.7.1",
77
+ "ssri": "^7.0.0",
78
+ "unique-filename": "^1.1.1"
76
79
  },
77
80
  "devDependencies": {
78
81
  "benchmark": "^2.1.4",
79
82
  "chalk": "^2.4.2",
80
- "cross-env": "^5.1.4",
83
+ "cross-env": "^5.2.1",
81
84
  "require-inject": "^1.4.4",
82
- "standard": "^12.0.1",
83
- "standard-version": "^6.0.1",
85
+ "standard": "^14.3.0",
86
+ "standard-version": "^7.0.0",
84
87
  "tacks": "^1.3.0",
85
- "tap": "^12.7.0",
88
+ "tap": "^14.6.9",
86
89
  "weallbehave": "^1.2.0",
87
90
  "weallcontribute": "^1.0.9"
88
91
  },
89
- "config": {
90
- "nyc": {
91
- "exclude": [
92
- "node_modules/**",
93
- "test/**"
94
- ]
95
- }
92
+ "engines": {
93
+ "node": ">= 8"
96
94
  }
97
95
  }
package/put.js CHANGED
@@ -4,7 +4,9 @@ const figgyPudding = require('figgy-pudding')
4
4
  const index = require('./lib/entry-index')
5
5
  const memo = require('./lib/memoization')
6
6
  const write = require('./lib/content/write')
7
- const to = require('mississippi').to
7
+ const Flush = require('minipass-flush')
8
+ const { PassThrough } = require('minipass-collect')
9
+ const Pipeline = require('minipass-pipeline')
8
10
 
9
11
  const PutOpts = figgyPudding({
10
12
  algorithms: {
@@ -23,64 +25,70 @@ const PutOpts = figgyPudding({
23
25
  })
24
26
 
25
27
  module.exports = putData
28
+
26
29
  function putData (cache, key, data, opts) {
27
30
  opts = PutOpts(opts)
28
- return write(cache, data, opts).then(res => {
29
- return index.insert(
30
- cache, key, res.integrity, opts.concat({ size: res.size })
31
- ).then(entry => {
32
- if (opts.memoize) {
33
- memo.put(cache, entry, data, opts)
34
- }
35
- return res.integrity
36
- })
31
+ return write(cache, data, opts).then((res) => {
32
+ return index
33
+ .insert(cache, key, res.integrity, opts.concat({ size: res.size }))
34
+ .then((entry) => {
35
+ if (opts.memoize) {
36
+ memo.put(cache, entry, data, opts)
37
+ }
38
+ return res.integrity
39
+ })
37
40
  })
38
41
  }
39
42
 
40
43
  module.exports.stream = putStream
44
+
41
45
  function putStream (cache, key, opts) {
42
46
  opts = PutOpts(opts)
43
47
  let integrity
44
48
  let size
45
- const contentStream = write.stream(
46
- cache, opts
47
- ).on('integrity', int => {
48
- integrity = int
49
- }).on('size', s => {
50
- size = s
51
- })
49
+
52
50
  let memoData
53
- let memoTotal = 0
54
- const stream = to((chunk, enc, cb) => {
55
- contentStream.write(chunk, enc, () => {
56
- if (opts.memoize) {
57
- if (!memoData) { memoData = [] }
58
- memoData.push(chunk)
59
- memoTotal += chunk.length
60
- }
61
- cb()
51
+ const pipeline = new Pipeline()
52
+ // first item in the pipeline is the memoizer, because we need
53
+ // that to end first and get the collected data.
54
+ if (opts.memoize) {
55
+ const memoizer = new PassThrough().on('collect', data => {
56
+ memoData = data
62
57
  })
63
- }, cb => {
64
- contentStream.end(() => {
65
- index.insert(cache, key, integrity, opts.concat({ size })).then(entry => {
66
- if (opts.memoize) {
67
- memo.put(cache, entry, Buffer.concat(memoData, memoTotal), opts)
68
- }
69
- stream.emit('integrity', integrity)
70
- cb()
71
- })
58
+ pipeline.push(memoizer)
59
+ }
60
+
61
+ // contentStream is a write-only, not a passthrough
62
+ // no data comes out of it.
63
+ const contentStream = write.stream(cache, opts)
64
+ .on('integrity', (int) => {
65
+ integrity = int
72
66
  })
73
- })
74
- let erred = false
75
- stream.once('error', err => {
76
- if (erred) { return }
77
- erred = true
78
- contentStream.emit('error', err)
79
- })
80
- contentStream.once('error', err => {
81
- if (erred) { return }
82
- erred = true
83
- stream.emit('error', err)
84
- })
85
- return stream
67
+ .on('size', (s) => {
68
+ size = s
69
+ })
70
+
71
+ pipeline.push(contentStream)
72
+
73
+ // last but not least, we write the index and emit hash and size,
74
+ // and memoize if we're doing that
75
+ pipeline.push(new Flush({
76
+ flush () {
77
+ return index
78
+ .insert(cache, key, integrity, opts.concat({ size }))
79
+ .then((entry) => {
80
+ if (opts.memoize && memoData) {
81
+ memo.put(cache, entry, memoData, opts)
82
+ }
83
+ if (integrity) {
84
+ pipeline.emit('integrity', integrity)
85
+ }
86
+ if (size) {
87
+ pipeline.emit('size', size)
88
+ }
89
+ })
90
+ }
91
+ }))
92
+
93
+ return pipeline
86
94
  }
package/rm.js CHANGED
@@ -1,27 +1,30 @@
1
1
  'use strict'
2
2
 
3
- const BB = require('bluebird')
3
+ const util = require('util')
4
4
 
5
5
  const index = require('./lib/entry-index')
6
6
  const memo = require('./lib/memoization')
7
7
  const path = require('path')
8
- const rimraf = BB.promisify(require('rimraf'))
8
+ const rimraf = util.promisify(require('rimraf'))
9
9
  const rmContent = require('./lib/content/rm')
10
10
 
11
11
  module.exports = entry
12
12
  module.exports.entry = entry
13
+
13
14
  function entry (cache, key) {
14
15
  memo.clearMemoized()
15
16
  return index.delete(cache, key)
16
17
  }
17
18
 
18
19
  module.exports.content = content
20
+
19
21
  function content (cache, integrity) {
20
22
  memo.clearMemoized()
21
23
  return rmContent(cache, integrity)
22
24
  }
23
25
 
24
26
  module.exports.all = all
27
+
25
28
  function all (cache) {
26
29
  memo.clearMemoized()
27
30
  return rimraf(path.join(cache, '*(content-*|index-*)'))