cacache 15.1.0 → 16.0.0
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/README.md +15 -2
- package/lib/content/read.js +12 -3
- package/lib/content/write.js +16 -6
- package/lib/entry-index.js +58 -18
- package/lib/get.js +251 -0
- package/{index.js → lib/index.js} +5 -6
- package/lib/memoization.js +1 -1
- package/{put.js → lib/put.js} +8 -5
- package/{rm.js → lib/rm.js} +5 -5
- package/lib/util/disposer.js +1 -0
- package/lib/util/fix-owner.js +3 -0
- package/lib/util/move-file.js +1 -1
- package/lib/util/tmp.js +9 -9
- package/lib/verify.js +11 -7
- package/package.json +29 -36
- package/get.js +0 -255
- package/ls.js +0 -6
- package/verify.js +0 -3
package/README.md
CHANGED
|
@@ -458,13 +458,17 @@ cacache.rm.all(cachePath).then(() => {
|
|
|
458
458
|
})
|
|
459
459
|
```
|
|
460
460
|
|
|
461
|
-
#### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key) -> Promise`
|
|
461
|
+
#### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key, [opts]) -> Promise`
|
|
462
462
|
|
|
463
463
|
Alias: `cacache.rm`
|
|
464
464
|
|
|
465
465
|
Removes the index entry for `key`. Content will still be accessible if
|
|
466
466
|
requested directly by content address ([`get.stream.byDigest`](#get-stream)).
|
|
467
467
|
|
|
468
|
+
By default, this appends a new entry to the index with an integrity of `null`.
|
|
469
|
+
If `opts.removeFully` is set to `true` then the index file itself will be
|
|
470
|
+
physically deleted rather than appending a `null`.
|
|
471
|
+
|
|
468
472
|
To remove the content itself (which might still be used by other entries), use
|
|
469
473
|
[`rm.content`](#rm-content). Or, to safely vacuum any unused content, use
|
|
470
474
|
[`verify`](#verify).
|
|
@@ -491,12 +495,21 @@ cacache.rm.content(cachePath, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
|
|
|
491
495
|
})
|
|
492
496
|
```
|
|
493
497
|
|
|
494
|
-
#### <a name="index-compact"></a> `> cacache.index.compact(cache, key, matchFn) -> Promise`
|
|
498
|
+
#### <a name="index-compact"></a> `> cacache.index.compact(cache, key, matchFn, [opts]) -> Promise`
|
|
495
499
|
|
|
496
500
|
Uses `matchFn`, which must be a synchronous function that accepts two entries
|
|
497
501
|
and returns a boolean indicating whether or not the two entries match, to
|
|
498
502
|
deduplicate all entries in the cache for the given `key`.
|
|
499
503
|
|
|
504
|
+
If `opts.validateEntry` is provided, it will be called as a function with the
|
|
505
|
+
only parameter being a single index entry. The function must return a Boolean,
|
|
506
|
+
if it returns `true` the entry is considered valid and will be kept in the index,
|
|
507
|
+
if it returns `false` the entry will be removed from the index.
|
|
508
|
+
|
|
509
|
+
If `opts.validateEntry` is not provided, however, every entry in the index will
|
|
510
|
+
be deduplicated and kept until the first `null` integrity is reached, removing
|
|
511
|
+
all entries that were written before the `null`.
|
|
512
|
+
|
|
500
513
|
The deduplicated list of entries is both written to the index, replacing the
|
|
501
514
|
existing content, and returned in the Promise.
|
|
502
515
|
|
package/lib/content/read.js
CHANGED
|
@@ -23,6 +23,7 @@ function read (cache, integrity, opts = {}) {
|
|
|
23
23
|
if (typeof size === 'number' && stat.size !== size) {
|
|
24
24
|
throw sizeError(size, stat.size)
|
|
25
25
|
}
|
|
26
|
+
|
|
26
27
|
if (stat.size > MAX_SINGLE_READ_SIZE) {
|
|
27
28
|
return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
|
|
28
29
|
}
|
|
@@ -31,6 +32,7 @@ function read (cache, integrity, opts = {}) {
|
|
|
31
32
|
if (!ssri.checkData(data, sri)) {
|
|
32
33
|
throw integrityError(sri, cpath)
|
|
33
34
|
}
|
|
35
|
+
|
|
34
36
|
return data
|
|
35
37
|
})
|
|
36
38
|
})
|
|
@@ -40,11 +42,11 @@ const readPipeline = (cpath, size, sri, stream) => {
|
|
|
40
42
|
stream.push(
|
|
41
43
|
new fsm.ReadStream(cpath, {
|
|
42
44
|
size,
|
|
43
|
-
readSize: MAX_SINGLE_READ_SIZE
|
|
45
|
+
readSize: MAX_SINGLE_READ_SIZE,
|
|
44
46
|
}),
|
|
45
47
|
ssri.integrityStream({
|
|
46
48
|
integrity: sri,
|
|
47
|
-
size
|
|
49
|
+
size,
|
|
48
50
|
})
|
|
49
51
|
)
|
|
50
52
|
return stream
|
|
@@ -81,6 +83,7 @@ function readStream (cache, integrity, opts = {}) {
|
|
|
81
83
|
if (typeof size === 'number' && size !== stat.size) {
|
|
82
84
|
return stream.emit('error', sizeError(size, stat.size))
|
|
83
85
|
}
|
|
86
|
+
|
|
84
87
|
readPipeline(cpath, stat.size, sri, stream)
|
|
85
88
|
}, er => stream.emit('error', er))
|
|
86
89
|
|
|
@@ -112,12 +115,14 @@ function hasContent (cache, integrity) {
|
|
|
112
115
|
if (!integrity) {
|
|
113
116
|
return Promise.resolve(false)
|
|
114
117
|
}
|
|
118
|
+
|
|
115
119
|
return withContentSri(cache, integrity, (cpath, sri) => {
|
|
116
120
|
return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat }))
|
|
117
121
|
}).catch((err) => {
|
|
118
122
|
if (err.code === 'ENOENT') {
|
|
119
123
|
return false
|
|
120
124
|
}
|
|
125
|
+
|
|
121
126
|
if (err.code === 'EPERM') {
|
|
122
127
|
/* istanbul ignore else */
|
|
123
128
|
if (process.platform !== 'win32') {
|
|
@@ -135,6 +140,7 @@ function hasContentSync (cache, integrity) {
|
|
|
135
140
|
if (!integrity) {
|
|
136
141
|
return false
|
|
137
142
|
}
|
|
143
|
+
|
|
138
144
|
return withContentSriSync(cache, integrity, (cpath, sri) => {
|
|
139
145
|
try {
|
|
140
146
|
const stat = fs.lstatSync(cpath)
|
|
@@ -143,6 +149,7 @@ function hasContentSync (cache, integrity) {
|
|
|
143
149
|
if (err.code === 'ENOENT') {
|
|
144
150
|
return false
|
|
145
151
|
}
|
|
152
|
+
|
|
146
153
|
if (err.code === 'EPERM') {
|
|
147
154
|
/* istanbul ignore else */
|
|
148
155
|
if (process.platform !== 'win32') {
|
|
@@ -167,7 +174,8 @@ function withContentSri (cache, integrity, fn) {
|
|
|
167
174
|
const cpath = contentPath(cache, digests[0])
|
|
168
175
|
return fn(cpath, digests[0])
|
|
169
176
|
} else {
|
|
170
|
-
// Can't use race here because a generic error can happen before
|
|
177
|
+
// Can't use race here because a generic error can happen before
|
|
178
|
+
// a ENOENT error, and can happen before a valid result
|
|
171
179
|
return Promise
|
|
172
180
|
.all(digests.map((meta) => {
|
|
173
181
|
return withContentSri(cache, meta, fn)
|
|
@@ -234,6 +242,7 @@ function withContentSriSync (cache, integrity, fn) {
|
|
|
234
242
|
}
|
|
235
243
|
|
|
236
244
|
function sizeError (expected, found) {
|
|
245
|
+
/* eslint-disable-next-line max-len */
|
|
237
246
|
const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
|
|
238
247
|
err.expected = expected
|
|
239
248
|
err.found = found
|
package/lib/content/write.js
CHANGED
|
@@ -25,9 +25,11 @@ function write (cache, data, opts = {}) {
|
|
|
25
25
|
if (algorithms && algorithms.length > 1) {
|
|
26
26
|
throw new Error('opts.algorithms only supports a single algorithm for now')
|
|
27
27
|
}
|
|
28
|
+
|
|
28
29
|
if (typeof size === 'number' && data.length !== size) {
|
|
29
30
|
return Promise.reject(sizeError(size, data.length))
|
|
30
31
|
}
|
|
32
|
+
|
|
31
33
|
const sri = ssri.fromData(data, algorithms ? { algorithms } : {})
|
|
32
34
|
if (integrity && !ssri.checkData(data, integrity, opts)) {
|
|
33
35
|
return Promise.reject(checksumError(integrity, sri))
|
|
@@ -112,13 +114,17 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
|
|
|
112
114
|
const hashStream = ssri.integrityStream({
|
|
113
115
|
integrity: opts.integrity,
|
|
114
116
|
algorithms: opts.algorithms,
|
|
115
|
-
size: opts.size
|
|
117
|
+
size: opts.size,
|
|
118
|
+
})
|
|
119
|
+
hashStream.on('integrity', i => {
|
|
120
|
+
integrity = i
|
|
121
|
+
})
|
|
122
|
+
hashStream.on('size', s => {
|
|
123
|
+
size = s
|
|
116
124
|
})
|
|
117
|
-
hashStream.on('integrity', i => { integrity = i })
|
|
118
|
-
hashStream.on('size', s => { size = s })
|
|
119
125
|
|
|
120
126
|
const outStream = new fsm.WriteStream(tmpTarget, {
|
|
121
|
-
flags: 'wx'
|
|
127
|
+
flags: 'wx',
|
|
122
128
|
})
|
|
123
129
|
|
|
124
130
|
// NB: this can throw if the hashStream has a problem with
|
|
@@ -132,14 +138,16 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
|
|
|
132
138
|
|
|
133
139
|
return pipeline.promise()
|
|
134
140
|
.then(() => ({ integrity, size }))
|
|
135
|
-
.catch(er => rimraf(tmpTarget).then(() => {
|
|
141
|
+
.catch(er => rimraf(tmpTarget).then(() => {
|
|
142
|
+
throw er
|
|
143
|
+
}))
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
function makeTmp (cache, opts) {
|
|
139
147
|
const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
|
|
140
148
|
return fixOwner.mkdirfix(cache, path.dirname(tmpTarget)).then(() => ({
|
|
141
149
|
target: tmpTarget,
|
|
142
|
-
moved: false
|
|
150
|
+
moved: false,
|
|
143
151
|
}))
|
|
144
152
|
}
|
|
145
153
|
|
|
@@ -147,6 +155,7 @@ function makeTmpDisposer (tmp) {
|
|
|
147
155
|
if (tmp.moved) {
|
|
148
156
|
return Promise.resolve()
|
|
149
157
|
}
|
|
158
|
+
|
|
150
159
|
return rimraf(tmp.target)
|
|
151
160
|
}
|
|
152
161
|
|
|
@@ -166,6 +175,7 @@ function moveToDestination (tmp, cache, sri, opts) {
|
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
function sizeError (expected, found) {
|
|
178
|
+
/* eslint-disable-next-line max-len */
|
|
169
179
|
const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
|
|
170
180
|
err.expected = expected
|
|
171
181
|
err.found = found
|
package/lib/entry-index.js
CHANGED
|
@@ -14,7 +14,9 @@ const fixOwner = require('./util/fix-owner')
|
|
|
14
14
|
const hashToSegments = require('./util/hash-to-segments')
|
|
15
15
|
const indexV = require('../package.json')['cache-version'].index
|
|
16
16
|
const moveFile = require('@npmcli/move-file')
|
|
17
|
-
const
|
|
17
|
+
const _rimraf = require('rimraf')
|
|
18
|
+
const rimraf = util.promisify(_rimraf)
|
|
19
|
+
rimraf.sync = _rimraf.sync
|
|
18
20
|
|
|
19
21
|
const appendFile = util.promisify(fs.appendFile)
|
|
20
22
|
const readFile = util.promisify(fs.readFile)
|
|
@@ -35,15 +37,32 @@ module.exports.compact = compact
|
|
|
35
37
|
async function compact (cache, key, matchFn, opts = {}) {
|
|
36
38
|
const bucket = bucketPath(cache, key)
|
|
37
39
|
const entries = await bucketEntries(bucket)
|
|
38
|
-
|
|
40
|
+
const newEntries = []
|
|
41
|
+
// we loop backwards because the bottom-most result is the newest
|
|
39
42
|
// since we add new entries with appendFile
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
for (let i = entries.length - 1; i >= 0; --i) {
|
|
44
|
+
const entry = entries[i]
|
|
45
|
+
// a null integrity could mean either a delete was appended
|
|
46
|
+
// or the user has simply stored an index that does not map
|
|
47
|
+
// to any content. we determine if the user wants to keep the
|
|
48
|
+
// null integrity based on the validateEntry function passed in options.
|
|
49
|
+
// if the integrity is null and no validateEntry is provided, we break
|
|
50
|
+
// as we consider the null integrity to be a deletion of everything
|
|
51
|
+
// that came before it.
|
|
52
|
+
if (entry.integrity === null && !opts.validateEntry) {
|
|
53
|
+
break
|
|
43
54
|
}
|
|
44
55
|
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
// if this entry is valid, and it is either the first entry or
|
|
57
|
+
// the newEntries array doesn't already include an entry that
|
|
58
|
+
// matches this one based on the provided matchFn, then we add
|
|
59
|
+
// it to the beginning of our list
|
|
60
|
+
if ((!opts.validateEntry || opts.validateEntry(entry) === true) &&
|
|
61
|
+
(newEntries.length === 0 ||
|
|
62
|
+
!newEntries.find((oldEntry) => matchFn(oldEntry, entry)))) {
|
|
63
|
+
newEntries.unshift(entry)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
47
66
|
|
|
48
67
|
const newIndex = '\n' + newEntries.map((entry) => {
|
|
49
68
|
const stringified = JSON.stringify(entry)
|
|
@@ -56,7 +75,7 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
56
75
|
await fixOwner.mkdirfix(cache, path.dirname(target))
|
|
57
76
|
return {
|
|
58
77
|
target,
|
|
59
|
-
moved: false
|
|
78
|
+
moved: false,
|
|
60
79
|
}
|
|
61
80
|
}
|
|
62
81
|
|
|
@@ -85,7 +104,12 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
85
104
|
// write the file atomically
|
|
86
105
|
await disposer(setup(), teardown, write)
|
|
87
106
|
|
|
88
|
-
|
|
107
|
+
// we reverse the list we generated such that the newest
|
|
108
|
+
// entries come first in order to make looping through them easier
|
|
109
|
+
// the true passed to formatEntry tells it to keep null
|
|
110
|
+
// integrity values, if they made it this far it's because
|
|
111
|
+
// validateEntry returned true, and as such we should return it
|
|
112
|
+
return newEntries.reverse().map((entry) => formatEntry(cache, entry, true))
|
|
89
113
|
}
|
|
90
114
|
|
|
91
115
|
module.exports.insert = insert
|
|
@@ -98,7 +122,7 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
98
122
|
integrity: integrity && ssri.stringify(integrity),
|
|
99
123
|
time: Date.now(),
|
|
100
124
|
size,
|
|
101
|
-
metadata
|
|
125
|
+
metadata,
|
|
102
126
|
}
|
|
103
127
|
return fixOwner
|
|
104
128
|
.mkdirfix(cache, path.dirname(bucket))
|
|
@@ -110,7 +134,8 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
110
134
|
// another while still preserving the string length of the JSON in
|
|
111
135
|
// question. So, we just slap the length in there and verify it on read.
|
|
112
136
|
//
|
|
113
|
-
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
137
|
+
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
138
|
+
// this.
|
|
114
139
|
return appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
115
140
|
})
|
|
116
141
|
.then(() => fixOwner.chownr(cache, bucket))
|
|
@@ -118,6 +143,7 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
118
143
|
if (err.code === 'ENOENT') {
|
|
119
144
|
return undefined
|
|
120
145
|
}
|
|
146
|
+
|
|
121
147
|
throw err
|
|
122
148
|
// There's a class of race conditions that happen when things get deleted
|
|
123
149
|
// during fixOwner, or between the two mkdirfix/chownr calls.
|
|
@@ -140,7 +166,7 @@ function insertSync (cache, key, integrity, opts = {}) {
|
|
|
140
166
|
integrity: integrity && ssri.stringify(integrity),
|
|
141
167
|
time: Date.now(),
|
|
142
168
|
size,
|
|
143
|
-
metadata
|
|
169
|
+
metadata,
|
|
144
170
|
}
|
|
145
171
|
fixOwner.mkdirfix.sync(cache, path.dirname(bucket))
|
|
146
172
|
const stringified = JSON.stringify(entry)
|
|
@@ -201,14 +227,24 @@ function findSync (cache, key) {
|
|
|
201
227
|
|
|
202
228
|
module.exports.delete = del
|
|
203
229
|
|
|
204
|
-
function del (cache, key, opts) {
|
|
205
|
-
|
|
230
|
+
function del (cache, key, opts = {}) {
|
|
231
|
+
if (!opts.removeFully) {
|
|
232
|
+
return insert(cache, key, null, opts)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const bucket = bucketPath(cache, key)
|
|
236
|
+
return rimraf(bucket)
|
|
206
237
|
}
|
|
207
238
|
|
|
208
239
|
module.exports.delete.sync = delSync
|
|
209
240
|
|
|
210
|
-
function delSync (cache, key, opts) {
|
|
211
|
-
|
|
241
|
+
function delSync (cache, key, opts = {}) {
|
|
242
|
+
if (!opts.removeFully) {
|
|
243
|
+
return insertSync(cache, key, null, opts)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const bucket = bucketPath(cache, key)
|
|
247
|
+
return rimraf.sync(bucket)
|
|
212
248
|
}
|
|
213
249
|
|
|
214
250
|
module.exports.lsStream = lsStream
|
|
@@ -244,7 +280,9 @@ function lsStream (cache) {
|
|
|
244
280
|
}
|
|
245
281
|
}
|
|
246
282
|
}).catch(err => {
|
|
247
|
-
if (err.code === 'ENOENT') {
|
|
283
|
+
if (err.code === 'ENOENT') {
|
|
284
|
+
return undefined
|
|
285
|
+
}
|
|
248
286
|
throw err
|
|
249
287
|
})
|
|
250
288
|
})
|
|
@@ -291,6 +329,7 @@ function _bucketEntries (data, filter) {
|
|
|
291
329
|
if (!entry) {
|
|
292
330
|
return
|
|
293
331
|
}
|
|
332
|
+
|
|
294
333
|
const pieces = entry.split('\t')
|
|
295
334
|
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
|
|
296
335
|
// Hash is no good! Corruption or malice? Doesn't matter!
|
|
@@ -351,13 +390,14 @@ function formatEntry (cache, entry, keepAll) {
|
|
|
351
390
|
if (!entry.integrity && !keepAll) {
|
|
352
391
|
return null
|
|
353
392
|
}
|
|
393
|
+
|
|
354
394
|
return {
|
|
355
395
|
key: entry.key,
|
|
356
396
|
integrity: entry.integrity,
|
|
357
397
|
path: entry.integrity ? contentPath(cache, entry.integrity) : undefined,
|
|
358
398
|
size: entry.size,
|
|
359
399
|
time: entry.time,
|
|
360
|
-
metadata: entry.metadata
|
|
400
|
+
metadata: entry.metadata,
|
|
361
401
|
}
|
|
362
402
|
}
|
|
363
403
|
|
package/lib/get.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Collect = require('minipass-collect')
|
|
4
|
+
const Minipass = require('minipass')
|
|
5
|
+
const Pipeline = require('minipass-pipeline')
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
const util = require('util')
|
|
8
|
+
|
|
9
|
+
const index = require('./entry-index')
|
|
10
|
+
const memo = require('./memoization')
|
|
11
|
+
const read = require('./content/read')
|
|
12
|
+
|
|
13
|
+
const writeFile = util.promisify(fs.writeFile)
|
|
14
|
+
|
|
15
|
+
function getData (cache, key, opts = {}) {
|
|
16
|
+
const { integrity, memoize, size } = opts
|
|
17
|
+
const memoized = memo.get(cache, key, opts)
|
|
18
|
+
if (memoized && memoize !== false) {
|
|
19
|
+
return Promise.resolve({
|
|
20
|
+
metadata: memoized.entry.metadata,
|
|
21
|
+
data: memoized.data,
|
|
22
|
+
integrity: memoized.entry.integrity,
|
|
23
|
+
size: memoized.entry.size,
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return index.find(cache, key, opts).then((entry) => {
|
|
28
|
+
if (!entry) {
|
|
29
|
+
throw new index.NotFoundError(cache, key)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return read(cache, entry.integrity, { integrity, size }).then((data) => {
|
|
33
|
+
if (memoize) {
|
|
34
|
+
memo.put(cache, entry, data, opts)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
data,
|
|
39
|
+
metadata: entry.metadata,
|
|
40
|
+
size: entry.size,
|
|
41
|
+
integrity: entry.integrity,
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
module.exports = getData
|
|
47
|
+
|
|
48
|
+
function getDataByDigest (cache, key, opts = {}) {
|
|
49
|
+
const { integrity, memoize, size } = opts
|
|
50
|
+
const memoized = memo.get.byDigest(cache, key, opts)
|
|
51
|
+
if (memoized && memoize !== false) {
|
|
52
|
+
return Promise.resolve(memoized)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return read(cache, key, { integrity, size }).then((res) => {
|
|
56
|
+
if (memoize) {
|
|
57
|
+
memo.put.byDigest(cache, key, res, opts)
|
|
58
|
+
}
|
|
59
|
+
return res
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
module.exports.byDigest = getDataByDigest
|
|
63
|
+
|
|
64
|
+
function getDataSync (cache, key, opts = {}) {
|
|
65
|
+
const { integrity, memoize, size } = opts
|
|
66
|
+
const memoized = memo.get(cache, key, opts)
|
|
67
|
+
|
|
68
|
+
if (memoized && memoize !== false) {
|
|
69
|
+
return {
|
|
70
|
+
metadata: memoized.entry.metadata,
|
|
71
|
+
data: memoized.data,
|
|
72
|
+
integrity: memoized.entry.integrity,
|
|
73
|
+
size: memoized.entry.size,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const entry = index.find.sync(cache, key, opts)
|
|
77
|
+
if (!entry) {
|
|
78
|
+
throw new index.NotFoundError(cache, key)
|
|
79
|
+
}
|
|
80
|
+
const data = read.sync(cache, entry.integrity, {
|
|
81
|
+
integrity: integrity,
|
|
82
|
+
size: size,
|
|
83
|
+
})
|
|
84
|
+
const res = {
|
|
85
|
+
metadata: entry.metadata,
|
|
86
|
+
data: data,
|
|
87
|
+
size: entry.size,
|
|
88
|
+
integrity: entry.integrity,
|
|
89
|
+
}
|
|
90
|
+
if (memoize) {
|
|
91
|
+
memo.put(cache, entry, res.data, opts)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return res
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports.sync = getDataSync
|
|
98
|
+
|
|
99
|
+
function getDataByDigestSync (cache, digest, opts = {}) {
|
|
100
|
+
const { integrity, memoize, size } = opts
|
|
101
|
+
const memoized = memo.get.byDigest(cache, digest, opts)
|
|
102
|
+
|
|
103
|
+
if (memoized && memoize !== false) {
|
|
104
|
+
return memoized
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const res = read.sync(cache, digest, {
|
|
108
|
+
integrity: integrity,
|
|
109
|
+
size: size,
|
|
110
|
+
})
|
|
111
|
+
if (memoize) {
|
|
112
|
+
memo.put.byDigest(cache, digest, res, opts)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return res
|
|
116
|
+
}
|
|
117
|
+
module.exports.sync.byDigest = getDataByDigestSync
|
|
118
|
+
|
|
119
|
+
const getMemoizedStream = (memoized) => {
|
|
120
|
+
const stream = new Minipass()
|
|
121
|
+
stream.on('newListener', function (ev, cb) {
|
|
122
|
+
ev === 'metadata' && cb(memoized.entry.metadata)
|
|
123
|
+
ev === 'integrity' && cb(memoized.entry.integrity)
|
|
124
|
+
ev === 'size' && cb(memoized.entry.size)
|
|
125
|
+
})
|
|
126
|
+
stream.end(memoized.data)
|
|
127
|
+
return stream
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getStream (cache, key, opts = {}) {
|
|
131
|
+
const { memoize, size } = opts
|
|
132
|
+
const memoized = memo.get(cache, key, opts)
|
|
133
|
+
if (memoized && memoize !== false) {
|
|
134
|
+
return getMemoizedStream(memoized)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const stream = new Pipeline()
|
|
138
|
+
index
|
|
139
|
+
.find(cache, key)
|
|
140
|
+
.then((entry) => {
|
|
141
|
+
if (!entry) {
|
|
142
|
+
throw new index.NotFoundError(cache, key)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
stream.emit('metadata', entry.metadata)
|
|
146
|
+
stream.emit('integrity', entry.integrity)
|
|
147
|
+
stream.emit('size', entry.size)
|
|
148
|
+
stream.on('newListener', function (ev, cb) {
|
|
149
|
+
ev === 'metadata' && cb(entry.metadata)
|
|
150
|
+
ev === 'integrity' && cb(entry.integrity)
|
|
151
|
+
ev === 'size' && cb(entry.size)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const src = read.readStream(
|
|
155
|
+
cache,
|
|
156
|
+
entry.integrity,
|
|
157
|
+
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
if (memoize) {
|
|
161
|
+
const memoStream = new Collect.PassThrough()
|
|
162
|
+
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
163
|
+
stream.unshift(memoStream)
|
|
164
|
+
}
|
|
165
|
+
stream.unshift(src)
|
|
166
|
+
})
|
|
167
|
+
.catch((err) => stream.emit('error', err))
|
|
168
|
+
|
|
169
|
+
return stream
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports.stream = getStream
|
|
173
|
+
|
|
174
|
+
function getStreamDigest (cache, integrity, opts = {}) {
|
|
175
|
+
const { memoize } = opts
|
|
176
|
+
const memoized = memo.get.byDigest(cache, integrity, opts)
|
|
177
|
+
if (memoized && memoize !== false) {
|
|
178
|
+
const stream = new Minipass()
|
|
179
|
+
stream.end(memoized)
|
|
180
|
+
return stream
|
|
181
|
+
} else {
|
|
182
|
+
const stream = read.readStream(cache, integrity, opts)
|
|
183
|
+
if (!memoize) {
|
|
184
|
+
return stream
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const memoStream = new Collect.PassThrough()
|
|
188
|
+
memoStream.on('collect', data => memo.put.byDigest(
|
|
189
|
+
cache,
|
|
190
|
+
integrity,
|
|
191
|
+
data,
|
|
192
|
+
opts
|
|
193
|
+
))
|
|
194
|
+
return new Pipeline(stream, memoStream)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module.exports.stream.byDigest = getStreamDigest
|
|
199
|
+
|
|
200
|
+
function info (cache, key, opts = {}) {
|
|
201
|
+
const { memoize } = opts
|
|
202
|
+
const memoized = memo.get(cache, key, opts)
|
|
203
|
+
if (memoized && memoize !== false) {
|
|
204
|
+
return Promise.resolve(memoized.entry)
|
|
205
|
+
} else {
|
|
206
|
+
return index.find(cache, key)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
module.exports.info = info
|
|
210
|
+
|
|
211
|
+
function copy (cache, key, dest, opts = {}) {
|
|
212
|
+
if (read.copy) {
|
|
213
|
+
return index.find(cache, key, opts).then((entry) => {
|
|
214
|
+
if (!entry) {
|
|
215
|
+
throw new index.NotFoundError(cache, key)
|
|
216
|
+
}
|
|
217
|
+
return read.copy(cache, entry.integrity, dest, opts)
|
|
218
|
+
.then(() => {
|
|
219
|
+
return {
|
|
220
|
+
metadata: entry.metadata,
|
|
221
|
+
size: entry.size,
|
|
222
|
+
integrity: entry.integrity,
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return getData(cache, key, opts).then((res) => {
|
|
229
|
+
return writeFile(dest, res.data).then(() => {
|
|
230
|
+
return {
|
|
231
|
+
metadata: res.metadata,
|
|
232
|
+
size: res.size,
|
|
233
|
+
integrity: res.integrity,
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
module.exports.copy = copy
|
|
239
|
+
|
|
240
|
+
function copyByDigest (cache, key, dest, opts = {}) {
|
|
241
|
+
if (read.copy) {
|
|
242
|
+
return read.copy(cache, key, dest, opts).then(() => key)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return getDataByDigest(cache, key, opts).then((res) => {
|
|
246
|
+
return writeFile(dest, res).then(() => key)
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
module.exports.copy.byDigest = copyByDigest
|
|
250
|
+
|
|
251
|
+
module.exports.hasContent = read.hasContent
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const ls = require('./ls.js')
|
|
4
3
|
const get = require('./get.js')
|
|
5
4
|
const put = require('./put.js')
|
|
6
5
|
const rm = require('./rm.js')
|
|
7
6
|
const verify = require('./verify.js')
|
|
8
|
-
const { clearMemoized } = require('./
|
|
9
|
-
const tmp = require('./
|
|
10
|
-
const index = require('./
|
|
7
|
+
const { clearMemoized } = require('./memoization.js')
|
|
8
|
+
const tmp = require('./util/tmp.js')
|
|
9
|
+
const index = require('./entry-index.js')
|
|
11
10
|
|
|
12
11
|
module.exports.index = {}
|
|
13
12
|
module.exports.index.compact = index.compact
|
|
14
13
|
module.exports.index.insert = index.insert
|
|
15
14
|
|
|
16
|
-
module.exports.ls = ls
|
|
17
|
-
module.exports.ls.stream =
|
|
15
|
+
module.exports.ls = index.ls
|
|
16
|
+
module.exports.ls.stream = index.lsStream
|
|
18
17
|
|
|
19
18
|
module.exports.get = get
|
|
20
19
|
module.exports.get.byDigest = get.byDigest
|
package/lib/memoization.js
CHANGED
|
@@ -8,7 +8,7 @@ const MAX_AGE = 3 * 60 * 1000
|
|
|
8
8
|
const MEMOIZED = new LRU({
|
|
9
9
|
max: MAX_SIZE,
|
|
10
10
|
maxAge: MAX_AGE,
|
|
11
|
-
length: (entry, key) => key.startsWith('key:') ? entry.data.length : entry.length
|
|
11
|
+
length: (entry, key) => key.startsWith('key:') ? entry.data.length : entry.length,
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
module.exports.clearMemoized = clearMemoized
|
package/{put.js → lib/put.js}
RENAMED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const index = require('./
|
|
4
|
-
const memo = require('./
|
|
5
|
-
const write = require('./
|
|
3
|
+
const index = require('./entry-index')
|
|
4
|
+
const memo = require('./memoization')
|
|
5
|
+
const write = require('./content/write')
|
|
6
6
|
const Flush = require('minipass-flush')
|
|
7
7
|
const { PassThrough } = require('minipass-collect')
|
|
8
8
|
const Pipeline = require('minipass-pipeline')
|
|
9
9
|
|
|
10
10
|
const putOpts = (opts) => ({
|
|
11
11
|
algorithms: ['sha512'],
|
|
12
|
-
...opts
|
|
12
|
+
...opts,
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
module.exports = putData
|
|
@@ -24,6 +24,7 @@ function putData (cache, key, data, opts = {}) {
|
|
|
24
24
|
if (memoize) {
|
|
25
25
|
memo.put(cache, entry, data, opts)
|
|
26
26
|
}
|
|
27
|
+
|
|
27
28
|
return res.integrity
|
|
28
29
|
})
|
|
29
30
|
})
|
|
@@ -70,14 +71,16 @@ function putStream (cache, key, opts = {}) {
|
|
|
70
71
|
if (memoize && memoData) {
|
|
71
72
|
memo.put(cache, entry, memoData, opts)
|
|
72
73
|
}
|
|
74
|
+
|
|
73
75
|
if (integrity) {
|
|
74
76
|
pipeline.emit('integrity', integrity)
|
|
75
77
|
}
|
|
78
|
+
|
|
76
79
|
if (size) {
|
|
77
80
|
pipeline.emit('size', size)
|
|
78
81
|
}
|
|
79
82
|
})
|
|
80
|
-
}
|
|
83
|
+
},
|
|
81
84
|
}))
|
|
82
85
|
|
|
83
86
|
return pipeline
|
package/{rm.js → lib/rm.js}
RENAMED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('util')
|
|
4
4
|
|
|
5
|
-
const index = require('./
|
|
6
|
-
const memo = require('./
|
|
5
|
+
const index = require('./entry-index')
|
|
6
|
+
const memo = require('./memoization')
|
|
7
7
|
const path = require('path')
|
|
8
8
|
const rimraf = util.promisify(require('rimraf'))
|
|
9
|
-
const rmContent = require('./
|
|
9
|
+
const rmContent = require('./content/rm')
|
|
10
10
|
|
|
11
11
|
module.exports = entry
|
|
12
12
|
module.exports.entry = entry
|
|
13
13
|
|
|
14
|
-
function entry (cache, key) {
|
|
14
|
+
function entry (cache, key, opts) {
|
|
15
15
|
memo.clearMemoized()
|
|
16
|
-
return index.delete(cache, key)
|
|
16
|
+
return index.delete(cache, key, opts)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
module.exports.content = content
|
package/lib/util/disposer.js
CHANGED
package/lib/util/fix-owner.js
CHANGED
|
@@ -62,6 +62,7 @@ function fixOwner (cache, filepath) {
|
|
|
62
62
|
if (err.code === 'ENOENT') {
|
|
63
63
|
return null
|
|
64
64
|
}
|
|
65
|
+
|
|
65
66
|
throw err
|
|
66
67
|
})
|
|
67
68
|
)
|
|
@@ -97,6 +98,7 @@ function fixOwnerSync (cache, filepath) {
|
|
|
97
98
|
if (err.code === 'ENOENT') {
|
|
98
99
|
return null
|
|
99
100
|
}
|
|
101
|
+
|
|
100
102
|
throw err
|
|
101
103
|
}
|
|
102
104
|
}
|
|
@@ -119,6 +121,7 @@ function mkdirfix (cache, p, cb) {
|
|
|
119
121
|
if (err.code === 'EEXIST') {
|
|
120
122
|
return fixOwner(cache, p).then(() => null)
|
|
121
123
|
}
|
|
124
|
+
|
|
122
125
|
throw err
|
|
123
126
|
})
|
|
124
127
|
})
|
package/lib/util/move-file.js
CHANGED
package/lib/util/tmp.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const fs = require('@npmcli/fs')
|
|
4
4
|
|
|
5
5
|
const fixOwner = require('./fix-owner')
|
|
6
6
|
const path = require('path')
|
|
7
|
-
const rimraf = util.promisify(require('rimraf'))
|
|
8
|
-
const uniqueFilename = require('unique-filename')
|
|
9
|
-
const { disposer } = require('./disposer')
|
|
10
7
|
|
|
11
8
|
module.exports.mkdir = mktmpdir
|
|
12
9
|
|
|
13
10
|
function mktmpdir (cache, opts = {}) {
|
|
14
11
|
const { tmpPrefix } = opts
|
|
15
|
-
const
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const tmpDir = path.join(cache, 'tmp')
|
|
13
|
+
return fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' })
|
|
14
|
+
.then(() => {
|
|
15
|
+
// do not use path.join(), it drops the trailing / if tmpPrefix is unset
|
|
16
|
+
const target = `${tmpDir}${path.sep}${tmpPrefix || ''}`
|
|
17
|
+
return fs.mkdtemp(target, { owner: 'inherit' })
|
|
18
|
+
})
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
module.exports.withTmp = withTmp
|
|
@@ -25,7 +25,7 @@ function withTmp (cache, opts, cb) {
|
|
|
25
25
|
cb = opts
|
|
26
26
|
opts = {}
|
|
27
27
|
}
|
|
28
|
-
return
|
|
28
|
+
return fs.withTempDir(path.join(cache, 'tmp'), cb, opts)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
module.exports.fix = fixtmpdir
|
package/lib/verify.js
CHANGED
|
@@ -24,7 +24,7 @@ const readFile = util.promisify(fs.readFile)
|
|
|
24
24
|
const verifyOpts = (opts) => ({
|
|
25
25
|
concurrency: 20,
|
|
26
26
|
log: { silly () {} },
|
|
27
|
-
...opts
|
|
27
|
+
...opts,
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
module.exports = verify
|
|
@@ -40,7 +40,7 @@ function verify (cache, opts) {
|
|
|
40
40
|
rebuildIndex,
|
|
41
41
|
cleanTmp,
|
|
42
42
|
writeVerifile,
|
|
43
|
-
markEndTime
|
|
43
|
+
markEndTime,
|
|
44
44
|
]
|
|
45
45
|
|
|
46
46
|
return steps
|
|
@@ -57,6 +57,7 @@ function verify (cache, opts) {
|
|
|
57
57
|
if (!stats.runTime) {
|
|
58
58
|
stats.runTime = {}
|
|
59
59
|
}
|
|
60
|
+
|
|
60
61
|
stats.runTime[label] = end - start
|
|
61
62
|
return Promise.resolve(stats)
|
|
62
63
|
})
|
|
@@ -111,6 +112,7 @@ function garbageCollect (cache, opts) {
|
|
|
111
112
|
if (opts.filter && !opts.filter(entry)) {
|
|
112
113
|
return
|
|
113
114
|
}
|
|
115
|
+
|
|
114
116
|
liveContent.add(entry.integrity.toString())
|
|
115
117
|
})
|
|
116
118
|
return new Promise((resolve, reject) => {
|
|
@@ -120,14 +122,14 @@ function garbageCollect (cache, opts) {
|
|
|
120
122
|
return glob(path.join(contentDir, '**'), {
|
|
121
123
|
follow: false,
|
|
122
124
|
nodir: true,
|
|
123
|
-
nosort: true
|
|
125
|
+
nosort: true,
|
|
124
126
|
}).then((files) => {
|
|
125
127
|
return Promise.resolve({
|
|
126
128
|
verifiedContent: 0,
|
|
127
129
|
reclaimedCount: 0,
|
|
128
130
|
reclaimedSize: 0,
|
|
129
131
|
badContentCount: 0,
|
|
130
|
-
keptSize: 0
|
|
132
|
+
keptSize: 0,
|
|
131
133
|
}).then((stats) =>
|
|
132
134
|
pMap(
|
|
133
135
|
files,
|
|
@@ -171,7 +173,7 @@ function verifyContent (filepath, sri) {
|
|
|
171
173
|
.then((s) => {
|
|
172
174
|
const contentInfo = {
|
|
173
175
|
size: s.size,
|
|
174
|
-
valid: true
|
|
176
|
+
valid: true,
|
|
175
177
|
}
|
|
176
178
|
return ssri
|
|
177
179
|
.checkStream(new fsm.ReadStream(filepath), sri)
|
|
@@ -179,6 +181,7 @@ function verifyContent (filepath, sri) {
|
|
|
179
181
|
if (err.code !== 'EINTEGRITY') {
|
|
180
182
|
throw err
|
|
181
183
|
}
|
|
184
|
+
|
|
182
185
|
return rimraf(filepath).then(() => {
|
|
183
186
|
contentInfo.valid = false
|
|
184
187
|
})
|
|
@@ -189,6 +192,7 @@ function verifyContent (filepath, sri) {
|
|
|
189
192
|
if (err.code === 'ENOENT') {
|
|
190
193
|
return { size: 0, valid: false }
|
|
191
194
|
}
|
|
195
|
+
|
|
192
196
|
throw err
|
|
193
197
|
})
|
|
194
198
|
}
|
|
@@ -199,7 +203,7 @@ function rebuildIndex (cache, opts) {
|
|
|
199
203
|
const stats = {
|
|
200
204
|
missingContent: 0,
|
|
201
205
|
rejectedEntries: 0,
|
|
202
|
-
totalEntries: 0
|
|
206
|
+
totalEntries: 0,
|
|
203
207
|
}
|
|
204
208
|
const buckets = {}
|
|
205
209
|
for (const k in entries) {
|
|
@@ -244,7 +248,7 @@ function rebuildBucket (cache, bucket, stats, opts) {
|
|
|
244
248
|
return index
|
|
245
249
|
.insert(cache, entry.key, entry.integrity, {
|
|
246
250
|
metadata: entry.metadata,
|
|
247
|
-
size: entry.size
|
|
251
|
+
size: entry.size,
|
|
248
252
|
})
|
|
249
253
|
.then(() => {
|
|
250
254
|
stats.totalEntries++
|
package/package.json
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cacache",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"cache-version": {
|
|
5
5
|
"content": "2",
|
|
6
6
|
"index": "5"
|
|
7
7
|
},
|
|
8
8
|
"description": "Fast, fault-tolerant, cross-platform, disk-based, data-agnostic, content-addressable cache.",
|
|
9
|
-
"main": "index.js",
|
|
9
|
+
"main": "lib/index.js",
|
|
10
10
|
"files": [
|
|
11
|
-
"
|
|
11
|
+
"bin",
|
|
12
12
|
"lib"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"benchmarks": "node test/benchmarks",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"prepublishOnly": "git push --follow-tags",
|
|
20
|
-
"prerelease": "npm t",
|
|
21
|
-
"release": "standard-version -s",
|
|
16
|
+
"preversion": "npm test",
|
|
17
|
+
"postversion": "npm publish",
|
|
18
|
+
"prepublishOnly": "git push origin --follow-tags",
|
|
22
19
|
"test": "tap",
|
|
20
|
+
"snap": "tap",
|
|
23
21
|
"coverage": "tap",
|
|
24
|
-
"test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test"
|
|
22
|
+
"test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test",
|
|
23
|
+
"lint": "eslint '**/*.js'",
|
|
24
|
+
"npmclilint": "npmcli-lint",
|
|
25
|
+
"lintfix": "npm run lint -- --fix",
|
|
26
|
+
"postsnap": "npm run lintfix --",
|
|
27
|
+
"postlint": "npm-template-check",
|
|
28
|
+
"template-copy": "npm-template-copy --force",
|
|
29
|
+
"posttest": "npm run lint"
|
|
25
30
|
},
|
|
26
31
|
"repository": "https://github.com/npm/cacache",
|
|
27
32
|
"keywords": [
|
|
@@ -39,49 +44,32 @@
|
|
|
39
44
|
"disk cache",
|
|
40
45
|
"disk storage"
|
|
41
46
|
],
|
|
42
|
-
"author": {
|
|
43
|
-
"name": "Kat Marchán",
|
|
44
|
-
"email": "kzm@sykosomatic.org",
|
|
45
|
-
"twitter": "maybekatz"
|
|
46
|
-
},
|
|
47
|
-
"contributors": [
|
|
48
|
-
{
|
|
49
|
-
"name": "Charlotte Spencer",
|
|
50
|
-
"email": "charlottelaspencer@gmail.com",
|
|
51
|
-
"twitter": "charlotteis"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"name": "Rebecca Turner",
|
|
55
|
-
"email": "me@re-becca.org",
|
|
56
|
-
"twitter": "ReBeccaOrg"
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
47
|
"license": "ISC",
|
|
60
48
|
"dependencies": {
|
|
61
|
-
"@npmcli/
|
|
49
|
+
"@npmcli/fs": "^1.0.0",
|
|
50
|
+
"@npmcli/move-file": "^1.1.2",
|
|
62
51
|
"chownr": "^2.0.0",
|
|
63
|
-
"fs-minipass": "^2.
|
|
52
|
+
"fs-minipass": "^2.1.0",
|
|
64
53
|
"glob": "^7.1.4",
|
|
65
54
|
"infer-owner": "^1.0.4",
|
|
66
55
|
"lru-cache": "^6.0.0",
|
|
67
56
|
"minipass": "^3.1.1",
|
|
68
57
|
"minipass-collect": "^1.0.2",
|
|
69
58
|
"minipass-flush": "^1.0.5",
|
|
70
|
-
"minipass-pipeline": "^1.2.
|
|
71
|
-
"mkdirp": "^1.0.
|
|
59
|
+
"minipass-pipeline": "^1.2.4",
|
|
60
|
+
"mkdirp": "^1.0.4",
|
|
72
61
|
"p-map": "^4.0.0",
|
|
73
62
|
"promise-inflight": "^1.0.1",
|
|
74
63
|
"rimraf": "^3.0.2",
|
|
75
64
|
"ssri": "^8.0.1",
|
|
76
|
-
"tar": "^6.
|
|
65
|
+
"tar": "^6.1.11",
|
|
77
66
|
"unique-filename": "^1.1.1"
|
|
78
67
|
},
|
|
79
68
|
"devDependencies": {
|
|
69
|
+
"@npmcli/template-oss": "^2.9.2",
|
|
80
70
|
"benchmark": "^2.1.4",
|
|
81
71
|
"chalk": "^4.0.0",
|
|
82
72
|
"require-inject": "^1.4.4",
|
|
83
|
-
"standard": "^14.3.1",
|
|
84
|
-
"standard-version": "^7.1.0",
|
|
85
73
|
"tacks": "^1.3.0",
|
|
86
74
|
"tap": "^15.0.9"
|
|
87
75
|
},
|
|
@@ -90,6 +78,11 @@
|
|
|
90
78
|
"test-regex": "test/[^/]*.js"
|
|
91
79
|
},
|
|
92
80
|
"engines": {
|
|
93
|
-
"node": ">=
|
|
94
|
-
}
|
|
81
|
+
"node": "^12.13.0 || ^14.15.0 || >=16"
|
|
82
|
+
},
|
|
83
|
+
"templateOSS": {
|
|
84
|
+
"windowsCI": false,
|
|
85
|
+
"version": "2.9.2"
|
|
86
|
+
},
|
|
87
|
+
"author": "GitHub Inc."
|
|
95
88
|
}
|
package/get.js
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const util = require('util')
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const index = require('./lib/entry-index')
|
|
6
|
-
const memo = require('./lib/memoization')
|
|
7
|
-
const read = require('./lib/content/read')
|
|
8
|
-
|
|
9
|
-
const Minipass = require('minipass')
|
|
10
|
-
const Collect = require('minipass-collect')
|
|
11
|
-
const Pipeline = require('minipass-pipeline')
|
|
12
|
-
|
|
13
|
-
const writeFile = util.promisify(fs.writeFile)
|
|
14
|
-
|
|
15
|
-
module.exports = function get (cache, key, opts) {
|
|
16
|
-
return getData(false, cache, key, opts)
|
|
17
|
-
}
|
|
18
|
-
module.exports.byDigest = function getByDigest (cache, digest, opts) {
|
|
19
|
-
return getData(true, cache, digest, opts)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function getData (byDigest, cache, key, opts = {}) {
|
|
23
|
-
const { integrity, memoize, size } = opts
|
|
24
|
-
const memoized = byDigest
|
|
25
|
-
? memo.get.byDigest(cache, key, opts)
|
|
26
|
-
: memo.get(cache, key, opts)
|
|
27
|
-
if (memoized && memoize !== false) {
|
|
28
|
-
return Promise.resolve(
|
|
29
|
-
byDigest
|
|
30
|
-
? memoized
|
|
31
|
-
: {
|
|
32
|
-
metadata: memoized.entry.metadata,
|
|
33
|
-
data: memoized.data,
|
|
34
|
-
integrity: memoized.entry.integrity,
|
|
35
|
-
size: memoized.entry.size
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
return (byDigest ? Promise.resolve(null) : index.find(cache, key, opts)).then(
|
|
40
|
-
(entry) => {
|
|
41
|
-
if (!entry && !byDigest) {
|
|
42
|
-
throw new index.NotFoundError(cache, key)
|
|
43
|
-
}
|
|
44
|
-
return read(cache, byDigest ? key : entry.integrity, {
|
|
45
|
-
integrity,
|
|
46
|
-
size
|
|
47
|
-
})
|
|
48
|
-
.then((data) =>
|
|
49
|
-
byDigest
|
|
50
|
-
? data
|
|
51
|
-
: {
|
|
52
|
-
data,
|
|
53
|
-
metadata: entry.metadata,
|
|
54
|
-
size: entry.size,
|
|
55
|
-
integrity: entry.integrity
|
|
56
|
-
}
|
|
57
|
-
)
|
|
58
|
-
.then((res) => {
|
|
59
|
-
if (memoize && byDigest) {
|
|
60
|
-
memo.put.byDigest(cache, key, res, opts)
|
|
61
|
-
} else if (memoize) {
|
|
62
|
-
memo.put(cache, entry, res.data, opts)
|
|
63
|
-
}
|
|
64
|
-
return res
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
module.exports.sync = function get (cache, key, opts) {
|
|
71
|
-
return getDataSync(false, cache, key, opts)
|
|
72
|
-
}
|
|
73
|
-
module.exports.sync.byDigest = function getByDigest (cache, digest, opts) {
|
|
74
|
-
return getDataSync(true, cache, digest, opts)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function getDataSync (byDigest, cache, key, opts = {}) {
|
|
78
|
-
const { integrity, memoize, size } = opts
|
|
79
|
-
const memoized = byDigest
|
|
80
|
-
? memo.get.byDigest(cache, key, opts)
|
|
81
|
-
: memo.get(cache, key, opts)
|
|
82
|
-
if (memoized && memoize !== false) {
|
|
83
|
-
return byDigest
|
|
84
|
-
? memoized
|
|
85
|
-
: {
|
|
86
|
-
metadata: memoized.entry.metadata,
|
|
87
|
-
data: memoized.data,
|
|
88
|
-
integrity: memoized.entry.integrity,
|
|
89
|
-
size: memoized.entry.size
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
const entry = !byDigest && index.find.sync(cache, key, opts)
|
|
93
|
-
if (!entry && !byDigest) {
|
|
94
|
-
throw new index.NotFoundError(cache, key)
|
|
95
|
-
}
|
|
96
|
-
const data = read.sync(cache, byDigest ? key : entry.integrity, {
|
|
97
|
-
integrity: integrity,
|
|
98
|
-
size: size
|
|
99
|
-
})
|
|
100
|
-
const res = byDigest
|
|
101
|
-
? data
|
|
102
|
-
: {
|
|
103
|
-
metadata: entry.metadata,
|
|
104
|
-
data: data,
|
|
105
|
-
size: entry.size,
|
|
106
|
-
integrity: entry.integrity
|
|
107
|
-
}
|
|
108
|
-
if (memoize && byDigest) {
|
|
109
|
-
memo.put.byDigest(cache, key, res, opts)
|
|
110
|
-
} else if (memoize) {
|
|
111
|
-
memo.put(cache, entry, res.data, opts)
|
|
112
|
-
}
|
|
113
|
-
return res
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
module.exports.stream = getStream
|
|
117
|
-
|
|
118
|
-
const getMemoizedStream = (memoized) => {
|
|
119
|
-
const stream = new Minipass()
|
|
120
|
-
stream.on('newListener', function (ev, cb) {
|
|
121
|
-
ev === 'metadata' && cb(memoized.entry.metadata)
|
|
122
|
-
ev === 'integrity' && cb(memoized.entry.integrity)
|
|
123
|
-
ev === 'size' && cb(memoized.entry.size)
|
|
124
|
-
})
|
|
125
|
-
stream.end(memoized.data)
|
|
126
|
-
return stream
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getStream (cache, key, opts = {}) {
|
|
130
|
-
const { memoize, size } = opts
|
|
131
|
-
const memoized = memo.get(cache, key, opts)
|
|
132
|
-
if (memoized && memoize !== false) {
|
|
133
|
-
return getMemoizedStream(memoized)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const stream = new Pipeline()
|
|
137
|
-
index
|
|
138
|
-
.find(cache, key)
|
|
139
|
-
.then((entry) => {
|
|
140
|
-
if (!entry) {
|
|
141
|
-
throw new index.NotFoundError(cache, key)
|
|
142
|
-
}
|
|
143
|
-
stream.emit('metadata', entry.metadata)
|
|
144
|
-
stream.emit('integrity', entry.integrity)
|
|
145
|
-
stream.emit('size', entry.size)
|
|
146
|
-
stream.on('newListener', function (ev, cb) {
|
|
147
|
-
ev === 'metadata' && cb(entry.metadata)
|
|
148
|
-
ev === 'integrity' && cb(entry.integrity)
|
|
149
|
-
ev === 'size' && cb(entry.size)
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
const src = read.readStream(
|
|
153
|
-
cache,
|
|
154
|
-
entry.integrity,
|
|
155
|
-
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
if (memoize) {
|
|
159
|
-
const memoStream = new Collect.PassThrough()
|
|
160
|
-
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
161
|
-
stream.unshift(memoStream)
|
|
162
|
-
}
|
|
163
|
-
stream.unshift(src)
|
|
164
|
-
})
|
|
165
|
-
.catch((err) => stream.emit('error', err))
|
|
166
|
-
|
|
167
|
-
return stream
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
module.exports.stream.byDigest = getStreamDigest
|
|
171
|
-
|
|
172
|
-
function getStreamDigest (cache, integrity, opts = {}) {
|
|
173
|
-
const { memoize } = opts
|
|
174
|
-
const memoized = memo.get.byDigest(cache, integrity, opts)
|
|
175
|
-
if (memoized && memoize !== false) {
|
|
176
|
-
const stream = new Minipass()
|
|
177
|
-
stream.end(memoized)
|
|
178
|
-
return stream
|
|
179
|
-
} else {
|
|
180
|
-
const stream = read.readStream(cache, integrity, opts)
|
|
181
|
-
if (!memoize) {
|
|
182
|
-
return stream
|
|
183
|
-
}
|
|
184
|
-
const memoStream = new Collect.PassThrough()
|
|
185
|
-
memoStream.on('collect', data => memo.put.byDigest(
|
|
186
|
-
cache,
|
|
187
|
-
integrity,
|
|
188
|
-
data,
|
|
189
|
-
opts
|
|
190
|
-
))
|
|
191
|
-
return new Pipeline(stream, memoStream)
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
module.exports.info = info
|
|
196
|
-
|
|
197
|
-
function info (cache, key, opts = {}) {
|
|
198
|
-
const { memoize } = opts
|
|
199
|
-
const memoized = memo.get(cache, key, opts)
|
|
200
|
-
if (memoized && memoize !== false) {
|
|
201
|
-
return Promise.resolve(memoized.entry)
|
|
202
|
-
} else {
|
|
203
|
-
return index.find(cache, key)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
module.exports.hasContent = read.hasContent
|
|
208
|
-
|
|
209
|
-
function cp (cache, key, dest, opts) {
|
|
210
|
-
return copy(false, cache, key, dest, opts)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
module.exports.copy = cp
|
|
214
|
-
|
|
215
|
-
function cpDigest (cache, digest, dest, opts) {
|
|
216
|
-
return copy(true, cache, digest, dest, opts)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
module.exports.copy.byDigest = cpDigest
|
|
220
|
-
|
|
221
|
-
function copy (byDigest, cache, key, dest, opts = {}) {
|
|
222
|
-
if (read.copy) {
|
|
223
|
-
return (byDigest
|
|
224
|
-
? Promise.resolve(null)
|
|
225
|
-
: index.find(cache, key, opts)
|
|
226
|
-
).then((entry) => {
|
|
227
|
-
if (!entry && !byDigest) {
|
|
228
|
-
throw new index.NotFoundError(cache, key)
|
|
229
|
-
}
|
|
230
|
-
return read
|
|
231
|
-
.copy(cache, byDigest ? key : entry.integrity, dest, opts)
|
|
232
|
-
.then(() => {
|
|
233
|
-
return byDigest
|
|
234
|
-
? key
|
|
235
|
-
: {
|
|
236
|
-
metadata: entry.metadata,
|
|
237
|
-
size: entry.size,
|
|
238
|
-
integrity: entry.integrity
|
|
239
|
-
}
|
|
240
|
-
})
|
|
241
|
-
})
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return getData(byDigest, cache, key, opts).then((res) => {
|
|
245
|
-
return writeFile(dest, byDigest ? res : res.data).then(() => {
|
|
246
|
-
return byDigest
|
|
247
|
-
? key
|
|
248
|
-
: {
|
|
249
|
-
metadata: res.metadata,
|
|
250
|
-
size: res.size,
|
|
251
|
-
integrity: res.integrity
|
|
252
|
-
}
|
|
253
|
-
})
|
|
254
|
-
})
|
|
255
|
-
}
|
package/ls.js
DELETED
package/verify.js
DELETED