cacache 15.1.0 → 15.2.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/get.js +27 -29
- package/lib/content/read.js +27 -33
- package/lib/content/rm.js +2 -3
- package/lib/content/write.js +19 -14
- package/lib/entry-index.js +72 -50
- package/lib/memoization.js +5 -6
- package/lib/util/disposer.js +2 -2
- package/lib/util/fix-owner.js +9 -12
- package/lib/util/move-file.js +3 -5
- package/lib/verify.js +17 -17
- package/package.json +11 -27
- package/put.js +9 -10
- package/rm.js +2 -2
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/get.js
CHANGED
|
@@ -32,18 +32,18 @@ function getData (byDigest, cache, key, opts = {}) {
|
|
|
32
32
|
metadata: memoized.entry.metadata,
|
|
33
33
|
data: memoized.data,
|
|
34
34
|
integrity: memoized.entry.integrity,
|
|
35
|
-
size: memoized.entry.size
|
|
35
|
+
size: memoized.entry.size,
|
|
36
36
|
}
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
return (byDigest ? Promise.resolve(null) : index.find(cache, key, opts)).then(
|
|
40
40
|
(entry) => {
|
|
41
|
-
if (!entry && !byDigest)
|
|
41
|
+
if (!entry && !byDigest)
|
|
42
42
|
throw new index.NotFoundError(cache, key)
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
return read(cache, byDigest ? key : entry.integrity, {
|
|
45
45
|
integrity,
|
|
46
|
-
size
|
|
46
|
+
size,
|
|
47
47
|
})
|
|
48
48
|
.then((data) =>
|
|
49
49
|
byDigest
|
|
@@ -52,15 +52,15 @@ function getData (byDigest, cache, key, opts = {}) {
|
|
|
52
52
|
data,
|
|
53
53
|
metadata: entry.metadata,
|
|
54
54
|
size: entry.size,
|
|
55
|
-
integrity: entry.integrity
|
|
55
|
+
integrity: entry.integrity,
|
|
56
56
|
}
|
|
57
57
|
)
|
|
58
58
|
.then((res) => {
|
|
59
|
-
if (memoize && byDigest)
|
|
59
|
+
if (memoize && byDigest)
|
|
60
60
|
memo.put.byDigest(cache, key, res, opts)
|
|
61
|
-
|
|
61
|
+
else if (memoize)
|
|
62
62
|
memo.put(cache, entry, res.data, opts)
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
return res
|
|
65
65
|
})
|
|
66
66
|
}
|
|
@@ -86,16 +86,16 @@ function getDataSync (byDigest, cache, key, opts = {}) {
|
|
|
86
86
|
metadata: memoized.entry.metadata,
|
|
87
87
|
data: memoized.data,
|
|
88
88
|
integrity: memoized.entry.integrity,
|
|
89
|
-
size: memoized.entry.size
|
|
89
|
+
size: memoized.entry.size,
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
const entry = !byDigest && index.find.sync(cache, key, opts)
|
|
93
|
-
if (!entry && !byDigest)
|
|
93
|
+
if (!entry && !byDigest)
|
|
94
94
|
throw new index.NotFoundError(cache, key)
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
const data = read.sync(cache, byDigest ? key : entry.integrity, {
|
|
97
97
|
integrity: integrity,
|
|
98
|
-
size: size
|
|
98
|
+
size: size,
|
|
99
99
|
})
|
|
100
100
|
const res = byDigest
|
|
101
101
|
? data
|
|
@@ -103,13 +103,13 @@ function getDataSync (byDigest, cache, key, opts = {}) {
|
|
|
103
103
|
metadata: entry.metadata,
|
|
104
104
|
data: data,
|
|
105
105
|
size: entry.size,
|
|
106
|
-
integrity: entry.integrity
|
|
106
|
+
integrity: entry.integrity,
|
|
107
107
|
}
|
|
108
|
-
if (memoize && byDigest)
|
|
108
|
+
if (memoize && byDigest)
|
|
109
109
|
memo.put.byDigest(cache, key, res, opts)
|
|
110
|
-
|
|
110
|
+
else if (memoize)
|
|
111
111
|
memo.put(cache, entry, res.data, opts)
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
return res
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -129,17 +129,16 @@ const getMemoizedStream = (memoized) => {
|
|
|
129
129
|
function getStream (cache, key, opts = {}) {
|
|
130
130
|
const { memoize, size } = opts
|
|
131
131
|
const memoized = memo.get(cache, key, opts)
|
|
132
|
-
if (memoized && memoize !== false)
|
|
132
|
+
if (memoized && memoize !== false)
|
|
133
133
|
return getMemoizedStream(memoized)
|
|
134
|
-
}
|
|
135
134
|
|
|
136
135
|
const stream = new Pipeline()
|
|
137
136
|
index
|
|
138
137
|
.find(cache, key)
|
|
139
138
|
.then((entry) => {
|
|
140
|
-
if (!entry)
|
|
139
|
+
if (!entry)
|
|
141
140
|
throw new index.NotFoundError(cache, key)
|
|
142
|
-
|
|
141
|
+
|
|
143
142
|
stream.emit('metadata', entry.metadata)
|
|
144
143
|
stream.emit('integrity', entry.integrity)
|
|
145
144
|
stream.emit('size', entry.size)
|
|
@@ -178,9 +177,9 @@ function getStreamDigest (cache, integrity, opts = {}) {
|
|
|
178
177
|
return stream
|
|
179
178
|
} else {
|
|
180
179
|
const stream = read.readStream(cache, integrity, opts)
|
|
181
|
-
if (!memoize)
|
|
180
|
+
if (!memoize)
|
|
182
181
|
return stream
|
|
183
|
-
|
|
182
|
+
|
|
184
183
|
const memoStream = new Collect.PassThrough()
|
|
185
184
|
memoStream.on('collect', data => memo.put.byDigest(
|
|
186
185
|
cache,
|
|
@@ -197,11 +196,10 @@ module.exports.info = info
|
|
|
197
196
|
function info (cache, key, opts = {}) {
|
|
198
197
|
const { memoize } = opts
|
|
199
198
|
const memoized = memo.get(cache, key, opts)
|
|
200
|
-
if (memoized && memoize !== false)
|
|
199
|
+
if (memoized && memoize !== false)
|
|
201
200
|
return Promise.resolve(memoized.entry)
|
|
202
|
-
|
|
201
|
+
else
|
|
203
202
|
return index.find(cache, key)
|
|
204
|
-
}
|
|
205
203
|
}
|
|
206
204
|
|
|
207
205
|
module.exports.hasContent = read.hasContent
|
|
@@ -224,9 +222,9 @@ function copy (byDigest, cache, key, dest, opts = {}) {
|
|
|
224
222
|
? Promise.resolve(null)
|
|
225
223
|
: index.find(cache, key, opts)
|
|
226
224
|
).then((entry) => {
|
|
227
|
-
if (!entry && !byDigest)
|
|
225
|
+
if (!entry && !byDigest)
|
|
228
226
|
throw new index.NotFoundError(cache, key)
|
|
229
|
-
|
|
227
|
+
|
|
230
228
|
return read
|
|
231
229
|
.copy(cache, byDigest ? key : entry.integrity, dest, opts)
|
|
232
230
|
.then(() => {
|
|
@@ -235,7 +233,7 @@ function copy (byDigest, cache, key, dest, opts = {}) {
|
|
|
235
233
|
: {
|
|
236
234
|
metadata: entry.metadata,
|
|
237
235
|
size: entry.size,
|
|
238
|
-
integrity: entry.integrity
|
|
236
|
+
integrity: entry.integrity,
|
|
239
237
|
}
|
|
240
238
|
})
|
|
241
239
|
})
|
|
@@ -248,7 +246,7 @@ function copy (byDigest, cache, key, dest, opts = {}) {
|
|
|
248
246
|
: {
|
|
249
247
|
metadata: res.metadata,
|
|
250
248
|
size: res.size,
|
|
251
|
-
integrity: res.integrity
|
|
249
|
+
integrity: res.integrity,
|
|
252
250
|
}
|
|
253
251
|
})
|
|
254
252
|
})
|
package/lib/content/read.js
CHANGED
|
@@ -20,17 +20,16 @@ function read (cache, integrity, opts = {}) {
|
|
|
20
20
|
// get size
|
|
21
21
|
return lstat(cpath).then(stat => ({ stat, cpath, sri }))
|
|
22
22
|
}).then(({ stat, cpath, sri }) => {
|
|
23
|
-
if (typeof size === 'number' && stat.size !== size)
|
|
23
|
+
if (typeof size === 'number' && stat.size !== size)
|
|
24
24
|
throw sizeError(size, stat.size)
|
|
25
|
-
|
|
26
|
-
if (stat.size > MAX_SINGLE_READ_SIZE)
|
|
25
|
+
|
|
26
|
+
if (stat.size > MAX_SINGLE_READ_SIZE)
|
|
27
27
|
return readPipeline(cpath, stat.size, sri, new Pipeline()).concat()
|
|
28
|
-
}
|
|
29
28
|
|
|
30
29
|
return readFile(cpath, null).then((data) => {
|
|
31
|
-
if (!ssri.checkData(data, sri))
|
|
30
|
+
if (!ssri.checkData(data, sri))
|
|
32
31
|
throw integrityError(sri, cpath)
|
|
33
|
-
|
|
32
|
+
|
|
34
33
|
return data
|
|
35
34
|
})
|
|
36
35
|
})
|
|
@@ -40,11 +39,11 @@ const readPipeline = (cpath, size, sri, stream) => {
|
|
|
40
39
|
stream.push(
|
|
41
40
|
new fsm.ReadStream(cpath, {
|
|
42
41
|
size,
|
|
43
|
-
readSize: MAX_SINGLE_READ_SIZE
|
|
42
|
+
readSize: MAX_SINGLE_READ_SIZE,
|
|
44
43
|
}),
|
|
45
44
|
ssri.integrityStream({
|
|
46
45
|
integrity: sri,
|
|
47
|
-
size
|
|
46
|
+
size,
|
|
48
47
|
})
|
|
49
48
|
)
|
|
50
49
|
return stream
|
|
@@ -56,13 +55,11 @@ function readSync (cache, integrity, opts = {}) {
|
|
|
56
55
|
const { size } = opts
|
|
57
56
|
return withContentSriSync(cache, integrity, (cpath, sri) => {
|
|
58
57
|
const data = fs.readFileSync(cpath)
|
|
59
|
-
if (typeof size === 'number' && size !== data.length)
|
|
58
|
+
if (typeof size === 'number' && size !== data.length)
|
|
60
59
|
throw sizeError(size, data.length)
|
|
61
|
-
}
|
|
62
60
|
|
|
63
|
-
if (ssri.checkData(data, sri))
|
|
61
|
+
if (ssri.checkData(data, sri))
|
|
64
62
|
return data
|
|
65
|
-
}
|
|
66
63
|
|
|
67
64
|
throw integrityError(sri, cpath)
|
|
68
65
|
})
|
|
@@ -78,9 +75,9 @@ function readStream (cache, integrity, opts = {}) {
|
|
|
78
75
|
// just lstat to ensure it exists
|
|
79
76
|
return lstat(cpath).then((stat) => ({ stat, cpath, sri }))
|
|
80
77
|
}).then(({ stat, cpath, sri }) => {
|
|
81
|
-
if (typeof size === 'number' && size !== stat.size)
|
|
78
|
+
if (typeof size === 'number' && size !== stat.size)
|
|
82
79
|
return stream.emit('error', sizeError(size, stat.size))
|
|
83
|
-
|
|
80
|
+
|
|
84
81
|
readPipeline(cpath, stat.size, sri, stream)
|
|
85
82
|
}, er => stream.emit('error', er))
|
|
86
83
|
|
|
@@ -109,22 +106,21 @@ function copySync (cache, integrity, dest) {
|
|
|
109
106
|
module.exports.hasContent = hasContent
|
|
110
107
|
|
|
111
108
|
function hasContent (cache, integrity) {
|
|
112
|
-
if (!integrity)
|
|
109
|
+
if (!integrity)
|
|
113
110
|
return Promise.resolve(false)
|
|
114
|
-
|
|
111
|
+
|
|
115
112
|
return withContentSri(cache, integrity, (cpath, sri) => {
|
|
116
113
|
return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat }))
|
|
117
114
|
}).catch((err) => {
|
|
118
|
-
if (err.code === 'ENOENT')
|
|
115
|
+
if (err.code === 'ENOENT')
|
|
119
116
|
return false
|
|
120
|
-
|
|
117
|
+
|
|
121
118
|
if (err.code === 'EPERM') {
|
|
122
119
|
/* istanbul ignore else */
|
|
123
|
-
if (process.platform !== 'win32')
|
|
120
|
+
if (process.platform !== 'win32')
|
|
124
121
|
throw err
|
|
125
|
-
|
|
122
|
+
else
|
|
126
123
|
return false
|
|
127
|
-
}
|
|
128
124
|
}
|
|
129
125
|
})
|
|
130
126
|
}
|
|
@@ -132,24 +128,23 @@ function hasContent (cache, integrity) {
|
|
|
132
128
|
module.exports.hasContent.sync = hasContentSync
|
|
133
129
|
|
|
134
130
|
function hasContentSync (cache, integrity) {
|
|
135
|
-
if (!integrity)
|
|
131
|
+
if (!integrity)
|
|
136
132
|
return false
|
|
137
|
-
|
|
133
|
+
|
|
138
134
|
return withContentSriSync(cache, integrity, (cpath, sri) => {
|
|
139
135
|
try {
|
|
140
136
|
const stat = fs.lstatSync(cpath)
|
|
141
137
|
return { size: stat.size, sri, stat }
|
|
142
138
|
} catch (err) {
|
|
143
|
-
if (err.code === 'ENOENT')
|
|
139
|
+
if (err.code === 'ENOENT')
|
|
144
140
|
return false
|
|
145
|
-
|
|
141
|
+
|
|
146
142
|
if (err.code === 'EPERM') {
|
|
147
143
|
/* istanbul ignore else */
|
|
148
|
-
if (process.platform !== 'win32')
|
|
144
|
+
if (process.platform !== 'win32')
|
|
149
145
|
throw err
|
|
150
|
-
|
|
146
|
+
else
|
|
151
147
|
return false
|
|
152
|
-
}
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
})
|
|
@@ -167,7 +162,8 @@ function withContentSri (cache, integrity, fn) {
|
|
|
167
162
|
const cpath = contentPath(cache, digests[0])
|
|
168
163
|
return fn(cpath, digests[0])
|
|
169
164
|
} else {
|
|
170
|
-
// Can't use race here because a generic error can happen before
|
|
165
|
+
// Can't use race here because a generic error can happen before
|
|
166
|
+
// a ENOENT error, and can happen before a valid result
|
|
171
167
|
return Promise
|
|
172
168
|
.all(digests.map((meta) => {
|
|
173
169
|
return withContentSri(cache, meta, fn)
|
|
@@ -184,15 +180,13 @@ function withContentSri (cache, integrity, fn) {
|
|
|
184
180
|
.then((results) => {
|
|
185
181
|
// Return the first non error if it is found
|
|
186
182
|
const result = results.find((r) => !(r instanceof Error))
|
|
187
|
-
if (result)
|
|
183
|
+
if (result)
|
|
188
184
|
return result
|
|
189
|
-
}
|
|
190
185
|
|
|
191
186
|
// Throw the No matching content found error
|
|
192
187
|
const enoentError = results.find((r) => r.code === 'ENOENT')
|
|
193
|
-
if (enoentError)
|
|
188
|
+
if (enoentError)
|
|
194
189
|
throw enoentError
|
|
195
|
-
}
|
|
196
190
|
|
|
197
191
|
// Throw generic error
|
|
198
192
|
throw results.find((r) => r instanceof Error)
|
package/lib/content/rm.js
CHANGED
|
@@ -11,10 +11,9 @@ module.exports = rm
|
|
|
11
11
|
function rm (cache, integrity) {
|
|
12
12
|
return hasContent(cache, integrity).then((content) => {
|
|
13
13
|
// ~pretty~ sure we can't end up with a content lacking sri, but be safe
|
|
14
|
-
if (content && content.sri)
|
|
14
|
+
if (content && content.sri)
|
|
15
15
|
return rimraf(contentPath(cache, content.sri)).then(() => true)
|
|
16
|
-
|
|
16
|
+
else
|
|
17
17
|
return false
|
|
18
|
-
}
|
|
19
18
|
})
|
|
20
19
|
}
|
package/lib/content/write.js
CHANGED
|
@@ -22,16 +22,15 @@ module.exports = write
|
|
|
22
22
|
|
|
23
23
|
function write (cache, data, opts = {}) {
|
|
24
24
|
const { algorithms, size, integrity } = opts
|
|
25
|
-
if (algorithms && algorithms.length > 1)
|
|
25
|
+
if (algorithms && algorithms.length > 1)
|
|
26
26
|
throw new Error('opts.algorithms only supports a single algorithm for now')
|
|
27
|
-
|
|
28
|
-
if (typeof size === 'number' && data.length !== size)
|
|
27
|
+
|
|
28
|
+
if (typeof size === 'number' && data.length !== size)
|
|
29
29
|
return Promise.reject(sizeError(size, data.length))
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
const sri = ssri.fromData(data, algorithms ? { algorithms } : {})
|
|
32
|
-
if (integrity && !ssri.checkData(data, integrity, opts))
|
|
32
|
+
if (integrity && !ssri.checkData(data, integrity, opts))
|
|
33
33
|
return Promise.reject(checksumError(integrity, sri))
|
|
34
|
-
}
|
|
35
34
|
|
|
36
35
|
return disposer(makeTmp(cache, opts), makeTmpDisposer,
|
|
37
36
|
(tmp) => {
|
|
@@ -112,13 +111,17 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
|
|
|
112
111
|
const hashStream = ssri.integrityStream({
|
|
113
112
|
integrity: opts.integrity,
|
|
114
113
|
algorithms: opts.algorithms,
|
|
115
|
-
size: opts.size
|
|
114
|
+
size: opts.size,
|
|
115
|
+
})
|
|
116
|
+
hashStream.on('integrity', i => {
|
|
117
|
+
integrity = i
|
|
118
|
+
})
|
|
119
|
+
hashStream.on('size', s => {
|
|
120
|
+
size = s
|
|
116
121
|
})
|
|
117
|
-
hashStream.on('integrity', i => { integrity = i })
|
|
118
|
-
hashStream.on('size', s => { size = s })
|
|
119
122
|
|
|
120
123
|
const outStream = new fsm.WriteStream(tmpTarget, {
|
|
121
|
-
flags: 'wx'
|
|
124
|
+
flags: 'wx',
|
|
122
125
|
})
|
|
123
126
|
|
|
124
127
|
// NB: this can throw if the hashStream has a problem with
|
|
@@ -132,21 +135,23 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) {
|
|
|
132
135
|
|
|
133
136
|
return pipeline.promise()
|
|
134
137
|
.then(() => ({ integrity, size }))
|
|
135
|
-
.catch(er => rimraf(tmpTarget).then(() => {
|
|
138
|
+
.catch(er => rimraf(tmpTarget).then(() => {
|
|
139
|
+
throw er
|
|
140
|
+
}))
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
function makeTmp (cache, opts) {
|
|
139
144
|
const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
|
|
140
145
|
return fixOwner.mkdirfix(cache, path.dirname(tmpTarget)).then(() => ({
|
|
141
146
|
target: tmpTarget,
|
|
142
|
-
moved: false
|
|
147
|
+
moved: false,
|
|
143
148
|
}))
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
function makeTmpDisposer (tmp) {
|
|
147
|
-
if (tmp.moved)
|
|
152
|
+
if (tmp.moved)
|
|
148
153
|
return Promise.resolve()
|
|
149
|
-
|
|
154
|
+
|
|
150
155
|
return rimraf(tmp.target)
|
|
151
156
|
}
|
|
152
157
|
|
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,30 @@ 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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
54
|
+
|
|
55
|
+
// if this entry is valid, and it is either the first entry or
|
|
56
|
+
// the newEntries array doesn't already include an entry that
|
|
57
|
+
// matches this one based on the provided matchFn, then we add
|
|
58
|
+
// it to the beginning of our list
|
|
59
|
+
if ((!opts.validateEntry || opts.validateEntry(entry) === true) &&
|
|
60
|
+
(newEntries.length === 0 ||
|
|
61
|
+
!newEntries.find((oldEntry) => matchFn(oldEntry, entry))))
|
|
62
|
+
newEntries.unshift(entry)
|
|
63
|
+
}
|
|
47
64
|
|
|
48
65
|
const newIndex = '\n' + newEntries.map((entry) => {
|
|
49
66
|
const stringified = JSON.stringify(entry)
|
|
@@ -56,14 +73,13 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
56
73
|
await fixOwner.mkdirfix(cache, path.dirname(target))
|
|
57
74
|
return {
|
|
58
75
|
target,
|
|
59
|
-
moved: false
|
|
76
|
+
moved: false,
|
|
60
77
|
}
|
|
61
78
|
}
|
|
62
79
|
|
|
63
80
|
const teardown = async (tmp) => {
|
|
64
|
-
if (!tmp.moved)
|
|
81
|
+
if (!tmp.moved)
|
|
65
82
|
return rimraf(tmp.target)
|
|
66
|
-
}
|
|
67
83
|
}
|
|
68
84
|
|
|
69
85
|
const write = async (tmp) => {
|
|
@@ -76,16 +92,20 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
76
92
|
try {
|
|
77
93
|
await fixOwner.chownr(cache, bucket)
|
|
78
94
|
} catch (err) {
|
|
79
|
-
if (err.code !== 'ENOENT')
|
|
95
|
+
if (err.code !== 'ENOENT')
|
|
80
96
|
throw err
|
|
81
|
-
}
|
|
82
97
|
}
|
|
83
98
|
}
|
|
84
99
|
|
|
85
100
|
// write the file atomically
|
|
86
101
|
await disposer(setup(), teardown, write)
|
|
87
102
|
|
|
88
|
-
|
|
103
|
+
// we reverse the list we generated such that the newest
|
|
104
|
+
// entries come first in order to make looping through them easier
|
|
105
|
+
// the true passed to formatEntry tells it to keep null
|
|
106
|
+
// integrity values, if they made it this far it's because
|
|
107
|
+
// validateEntry returned true, and as such we should return it
|
|
108
|
+
return newEntries.reverse().map((entry) => formatEntry(cache, entry, true))
|
|
89
109
|
}
|
|
90
110
|
|
|
91
111
|
module.exports.insert = insert
|
|
@@ -98,7 +118,7 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
98
118
|
integrity: integrity && ssri.stringify(integrity),
|
|
99
119
|
time: Date.now(),
|
|
100
120
|
size,
|
|
101
|
-
metadata
|
|
121
|
+
metadata,
|
|
102
122
|
}
|
|
103
123
|
return fixOwner
|
|
104
124
|
.mkdirfix(cache, path.dirname(bucket))
|
|
@@ -110,14 +130,15 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
110
130
|
// another while still preserving the string length of the JSON in
|
|
111
131
|
// question. So, we just slap the length in there and verify it on read.
|
|
112
132
|
//
|
|
113
|
-
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
133
|
+
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
134
|
+
// this.
|
|
114
135
|
return appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
115
136
|
})
|
|
116
137
|
.then(() => fixOwner.chownr(cache, bucket))
|
|
117
138
|
.catch((err) => {
|
|
118
|
-
if (err.code === 'ENOENT')
|
|
139
|
+
if (err.code === 'ENOENT')
|
|
119
140
|
return undefined
|
|
120
|
-
|
|
141
|
+
|
|
121
142
|
throw err
|
|
122
143
|
// There's a class of race conditions that happen when things get deleted
|
|
123
144
|
// during fixOwner, or between the two mkdirfix/chownr calls.
|
|
@@ -140,7 +161,7 @@ function insertSync (cache, key, integrity, opts = {}) {
|
|
|
140
161
|
integrity: integrity && ssri.stringify(integrity),
|
|
141
162
|
time: Date.now(),
|
|
142
163
|
size,
|
|
143
|
-
metadata
|
|
164
|
+
metadata,
|
|
144
165
|
}
|
|
145
166
|
fixOwner.mkdirfix.sync(cache, path.dirname(bucket))
|
|
146
167
|
const stringified = JSON.stringify(entry)
|
|
@@ -148,9 +169,8 @@ function insertSync (cache, key, integrity, opts = {}) {
|
|
|
148
169
|
try {
|
|
149
170
|
fixOwner.chownr.sync(cache, bucket)
|
|
150
171
|
} catch (err) {
|
|
151
|
-
if (err.code !== 'ENOENT')
|
|
172
|
+
if (err.code !== 'ENOENT')
|
|
152
173
|
throw err
|
|
153
|
-
}
|
|
154
174
|
}
|
|
155
175
|
return formatEntry(cache, entry)
|
|
156
176
|
}
|
|
@@ -162,19 +182,17 @@ function find (cache, key) {
|
|
|
162
182
|
return bucketEntries(bucket)
|
|
163
183
|
.then((entries) => {
|
|
164
184
|
return entries.reduce((latest, next) => {
|
|
165
|
-
if (next && next.key === key)
|
|
185
|
+
if (next && next.key === key)
|
|
166
186
|
return formatEntry(cache, next)
|
|
167
|
-
|
|
187
|
+
else
|
|
168
188
|
return latest
|
|
169
|
-
}
|
|
170
189
|
}, null)
|
|
171
190
|
})
|
|
172
191
|
.catch((err) => {
|
|
173
|
-
if (err.code === 'ENOENT')
|
|
192
|
+
if (err.code === 'ENOENT')
|
|
174
193
|
return null
|
|
175
|
-
|
|
194
|
+
else
|
|
176
195
|
throw err
|
|
177
|
-
}
|
|
178
196
|
})
|
|
179
197
|
}
|
|
180
198
|
|
|
@@ -184,31 +202,37 @@ function findSync (cache, key) {
|
|
|
184
202
|
const bucket = bucketPath(cache, key)
|
|
185
203
|
try {
|
|
186
204
|
return bucketEntriesSync(bucket).reduce((latest, next) => {
|
|
187
|
-
if (next && next.key === key)
|
|
205
|
+
if (next && next.key === key)
|
|
188
206
|
return formatEntry(cache, next)
|
|
189
|
-
|
|
207
|
+
else
|
|
190
208
|
return latest
|
|
191
|
-
}
|
|
192
209
|
}, null)
|
|
193
210
|
} catch (err) {
|
|
194
|
-
if (err.code === 'ENOENT')
|
|
211
|
+
if (err.code === 'ENOENT')
|
|
195
212
|
return null
|
|
196
|
-
|
|
213
|
+
else
|
|
197
214
|
throw err
|
|
198
|
-
}
|
|
199
215
|
}
|
|
200
216
|
}
|
|
201
217
|
|
|
202
218
|
module.exports.delete = del
|
|
203
219
|
|
|
204
|
-
function del (cache, key, opts) {
|
|
205
|
-
|
|
220
|
+
function del (cache, key, opts = {}) {
|
|
221
|
+
if (!opts.removeFully)
|
|
222
|
+
return insert(cache, key, null, opts)
|
|
223
|
+
|
|
224
|
+
const bucket = bucketPath(cache, key)
|
|
225
|
+
return rimraf(bucket)
|
|
206
226
|
}
|
|
207
227
|
|
|
208
228
|
module.exports.delete.sync = delSync
|
|
209
229
|
|
|
210
|
-
function delSync (cache, key, opts) {
|
|
211
|
-
|
|
230
|
+
function delSync (cache, key, opts = {}) {
|
|
231
|
+
if (!opts.removeFully)
|
|
232
|
+
return insertSync(cache, key, null, opts)
|
|
233
|
+
|
|
234
|
+
const bucket = bucketPath(cache, key)
|
|
235
|
+
return rimraf.sync(bucket)
|
|
212
236
|
}
|
|
213
237
|
|
|
214
238
|
module.exports.lsStream = lsStream
|
|
@@ -239,12 +263,12 @@ function lsStream (cache) {
|
|
|
239
263
|
// reduced is a map of key => entry
|
|
240
264
|
for (const entry of reduced.values()) {
|
|
241
265
|
const formatted = formatEntry(cache, entry)
|
|
242
|
-
if (formatted)
|
|
266
|
+
if (formatted)
|
|
243
267
|
stream.write(formatted)
|
|
244
|
-
}
|
|
245
268
|
}
|
|
246
269
|
}).catch(err => {
|
|
247
|
-
if (err.code === 'ENOENT')
|
|
270
|
+
if (err.code === 'ENOENT')
|
|
271
|
+
return undefined
|
|
248
272
|
throw err
|
|
249
273
|
})
|
|
250
274
|
})
|
|
@@ -288,9 +312,9 @@ function bucketEntriesSync (bucket, filter) {
|
|
|
288
312
|
function _bucketEntries (data, filter) {
|
|
289
313
|
const entries = []
|
|
290
314
|
data.split('\n').forEach((entry) => {
|
|
291
|
-
if (!entry)
|
|
315
|
+
if (!entry)
|
|
292
316
|
return
|
|
293
|
-
|
|
317
|
+
|
|
294
318
|
const pieces = entry.split('\t')
|
|
295
319
|
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
|
|
296
320
|
// Hash is no good! Corruption or malice? Doesn't matter!
|
|
@@ -304,9 +328,8 @@ function _bucketEntries (data, filter) {
|
|
|
304
328
|
// Entry is corrupted!
|
|
305
329
|
return
|
|
306
330
|
}
|
|
307
|
-
if (obj)
|
|
331
|
+
if (obj)
|
|
308
332
|
entries.push(obj)
|
|
309
|
-
}
|
|
310
333
|
})
|
|
311
334
|
return entries
|
|
312
335
|
}
|
|
@@ -348,24 +371,23 @@ function hash (str, digest) {
|
|
|
348
371
|
|
|
349
372
|
function formatEntry (cache, entry, keepAll) {
|
|
350
373
|
// Treat null digests as deletions. They'll shadow any previous entries.
|
|
351
|
-
if (!entry.integrity && !keepAll)
|
|
374
|
+
if (!entry.integrity && !keepAll)
|
|
352
375
|
return null
|
|
353
|
-
|
|
376
|
+
|
|
354
377
|
return {
|
|
355
378
|
key: entry.key,
|
|
356
379
|
integrity: entry.integrity,
|
|
357
380
|
path: entry.integrity ? contentPath(cache, entry.integrity) : undefined,
|
|
358
381
|
size: entry.size,
|
|
359
382
|
time: entry.time,
|
|
360
|
-
metadata: entry.metadata
|
|
383
|
+
metadata: entry.metadata,
|
|
361
384
|
}
|
|
362
385
|
}
|
|
363
386
|
|
|
364
387
|
function readdirOrEmpty (dir) {
|
|
365
388
|
return readdir(dir).catch((err) => {
|
|
366
|
-
if (err.code === 'ENOENT' || err.code === 'ENOTDIR')
|
|
389
|
+
if (err.code === 'ENOENT' || err.code === 'ENOTDIR')
|
|
367
390
|
return []
|
|
368
|
-
}
|
|
369
391
|
|
|
370
392
|
throw err
|
|
371
393
|
})
|
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
|
|
@@ -62,13 +62,12 @@ class ObjProxy {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function pickMem (opts) {
|
|
65
|
-
if (!opts || !opts.memoize)
|
|
65
|
+
if (!opts || !opts.memoize)
|
|
66
66
|
return MEMOIZED
|
|
67
|
-
|
|
67
|
+
else if (opts.memoize.get && opts.memoize.set)
|
|
68
68
|
return opts.memoize
|
|
69
|
-
|
|
69
|
+
else if (typeof opts.memoize === 'object')
|
|
70
70
|
return new ObjProxy(opts.memoize)
|
|
71
|
-
|
|
71
|
+
else
|
|
72
72
|
return MEMOIZED
|
|
73
|
-
}
|
|
74
73
|
}
|
package/lib/util/disposer.js
CHANGED
|
@@ -8,9 +8,9 @@ function disposer (creatorFn, disposerFn, fn) {
|
|
|
8
8
|
.then(
|
|
9
9
|
// disposer resolved, do something with original fn's promise
|
|
10
10
|
() => {
|
|
11
|
-
if (shouldThrow)
|
|
11
|
+
if (shouldThrow)
|
|
12
12
|
throw result
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
return result
|
|
15
15
|
},
|
|
16
16
|
// Disposer fn failed, crash process
|
package/lib/util/fix-owner.js
CHANGED
|
@@ -49,9 +49,8 @@ function fixOwner (cache, filepath) {
|
|
|
49
49
|
const { uid, gid } = owner
|
|
50
50
|
|
|
51
51
|
// No need to override if it's already what we used.
|
|
52
|
-
if (self.uid === uid && self.gid === gid)
|
|
52
|
+
if (self.uid === uid && self.gid === gid)
|
|
53
53
|
return
|
|
54
|
-
}
|
|
55
54
|
|
|
56
55
|
return inflight('fixOwner: fixing ownership on ' + filepath, () =>
|
|
57
56
|
chownr(
|
|
@@ -59,9 +58,9 @@ function fixOwner (cache, filepath) {
|
|
|
59
58
|
typeof uid === 'number' ? uid : self.uid,
|
|
60
59
|
typeof gid === 'number' ? gid : self.gid
|
|
61
60
|
).catch((err) => {
|
|
62
|
-
if (err.code === 'ENOENT')
|
|
61
|
+
if (err.code === 'ENOENT')
|
|
63
62
|
return null
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
throw err
|
|
66
65
|
})
|
|
67
66
|
)
|
|
@@ -94,9 +93,9 @@ function fixOwnerSync (cache, filepath) {
|
|
|
94
93
|
)
|
|
95
94
|
} catch (err) {
|
|
96
95
|
// only catch ENOENT, any other error is a problem.
|
|
97
|
-
if (err.code === 'ENOENT')
|
|
96
|
+
if (err.code === 'ENOENT')
|
|
98
97
|
return null
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
throw err
|
|
101
100
|
}
|
|
102
101
|
}
|
|
@@ -111,14 +110,13 @@ function mkdirfix (cache, p, cb) {
|
|
|
111
110
|
return Promise.resolve(inferOwner(cache)).then(() => {
|
|
112
111
|
return mkdirp(p)
|
|
113
112
|
.then((made) => {
|
|
114
|
-
if (made)
|
|
113
|
+
if (made)
|
|
115
114
|
return fixOwner(cache, made).then(() => made)
|
|
116
|
-
}
|
|
117
115
|
})
|
|
118
116
|
.catch((err) => {
|
|
119
|
-
if (err.code === 'EEXIST')
|
|
117
|
+
if (err.code === 'EEXIST')
|
|
120
118
|
return fixOwner(cache, p).then(() => null)
|
|
121
|
-
|
|
119
|
+
|
|
122
120
|
throw err
|
|
123
121
|
})
|
|
124
122
|
})
|
|
@@ -138,8 +136,7 @@ function mkdirfixSync (cache, p) {
|
|
|
138
136
|
if (err.code === 'EEXIST') {
|
|
139
137
|
fixOwnerSync(cache, p)
|
|
140
138
|
return null
|
|
141
|
-
} else
|
|
139
|
+
} else
|
|
142
140
|
throw err
|
|
143
|
-
}
|
|
144
141
|
}
|
|
145
142
|
}
|
package/lib/util/move-file.js
CHANGED
|
@@ -38,19 +38,17 @@ function moveFile (src, dest) {
|
|
|
38
38
|
} else if (err.code === 'EEXIST' || err.code === 'EBUSY') {
|
|
39
39
|
// file already exists, so whatever
|
|
40
40
|
return resolve()
|
|
41
|
-
} else
|
|
41
|
+
} else
|
|
42
42
|
return reject(err)
|
|
43
|
-
|
|
44
|
-
} else {
|
|
43
|
+
} else
|
|
45
44
|
return resolve()
|
|
46
|
-
}
|
|
47
45
|
})
|
|
48
46
|
})
|
|
49
47
|
.then(() => {
|
|
50
48
|
// content should never change for any reason, so make it read-only
|
|
51
49
|
return Promise.all([
|
|
52
50
|
unlink(src),
|
|
53
|
-
!isWindows && chmod(dest, '0444')
|
|
51
|
+
!isWindows && chmod(dest, '0444'),
|
|
54
52
|
])
|
|
55
53
|
})
|
|
56
54
|
.catch(() => {
|
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
|
|
@@ -54,9 +54,9 @@ function verify (cache, opts) {
|
|
|
54
54
|
stats[k] = s[k]
|
|
55
55
|
})
|
|
56
56
|
const end = new Date()
|
|
57
|
-
if (!stats.runTime)
|
|
57
|
+
if (!stats.runTime)
|
|
58
58
|
stats.runTime = {}
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
stats.runTime[label] = end - start
|
|
61
61
|
return Promise.resolve(stats)
|
|
62
62
|
})
|
|
@@ -108,9 +108,9 @@ function garbageCollect (cache, opts) {
|
|
|
108
108
|
const indexStream = index.lsStream(cache)
|
|
109
109
|
const liveContent = new Set()
|
|
110
110
|
indexStream.on('data', (entry) => {
|
|
111
|
-
if (opts.filter && !opts.filter(entry))
|
|
111
|
+
if (opts.filter && !opts.filter(entry))
|
|
112
112
|
return
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
liveContent.add(entry.integrity.toString())
|
|
115
115
|
})
|
|
116
116
|
return new Promise((resolve, reject) => {
|
|
@@ -120,14 +120,14 @@ function garbageCollect (cache, opts) {
|
|
|
120
120
|
return glob(path.join(contentDir, '**'), {
|
|
121
121
|
follow: false,
|
|
122
122
|
nodir: true,
|
|
123
|
-
nosort: true
|
|
123
|
+
nosort: true,
|
|
124
124
|
}).then((files) => {
|
|
125
125
|
return Promise.resolve({
|
|
126
126
|
verifiedContent: 0,
|
|
127
127
|
reclaimedCount: 0,
|
|
128
128
|
reclaimedSize: 0,
|
|
129
129
|
badContentCount: 0,
|
|
130
|
-
keptSize: 0
|
|
130
|
+
keptSize: 0,
|
|
131
131
|
}).then((stats) =>
|
|
132
132
|
pMap(
|
|
133
133
|
files,
|
|
@@ -171,14 +171,14 @@ function verifyContent (filepath, sri) {
|
|
|
171
171
|
.then((s) => {
|
|
172
172
|
const contentInfo = {
|
|
173
173
|
size: s.size,
|
|
174
|
-
valid: true
|
|
174
|
+
valid: true,
|
|
175
175
|
}
|
|
176
176
|
return ssri
|
|
177
177
|
.checkStream(new fsm.ReadStream(filepath), sri)
|
|
178
178
|
.catch((err) => {
|
|
179
|
-
if (err.code !== 'EINTEGRITY')
|
|
179
|
+
if (err.code !== 'EINTEGRITY')
|
|
180
180
|
throw err
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
return rimraf(filepath).then(() => {
|
|
183
183
|
contentInfo.valid = false
|
|
184
184
|
})
|
|
@@ -186,9 +186,9 @@ function verifyContent (filepath, sri) {
|
|
|
186
186
|
.then(() => contentInfo)
|
|
187
187
|
})
|
|
188
188
|
.catch((err) => {
|
|
189
|
-
if (err.code === 'ENOENT')
|
|
189
|
+
if (err.code === 'ENOENT')
|
|
190
190
|
return { size: 0, valid: false }
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
throw err
|
|
193
193
|
})
|
|
194
194
|
}
|
|
@@ -199,7 +199,7 @@ function rebuildIndex (cache, opts) {
|
|
|
199
199
|
const stats = {
|
|
200
200
|
missingContent: 0,
|
|
201
201
|
rejectedEntries: 0,
|
|
202
|
-
totalEntries: 0
|
|
202
|
+
totalEntries: 0,
|
|
203
203
|
}
|
|
204
204
|
const buckets = {}
|
|
205
205
|
for (const k in entries) {
|
|
@@ -209,9 +209,9 @@ function rebuildIndex (cache, opts) {
|
|
|
209
209
|
const entry = entries[k]
|
|
210
210
|
const excluded = opts.filter && !opts.filter(entry)
|
|
211
211
|
excluded && stats.rejectedEntries++
|
|
212
|
-
if (buckets[hashed] && !excluded)
|
|
212
|
+
if (buckets[hashed] && !excluded)
|
|
213
213
|
buckets[hashed].push(entry)
|
|
214
|
-
|
|
214
|
+
else if (buckets[hashed] && excluded) {
|
|
215
215
|
// skip
|
|
216
216
|
} else if (excluded) {
|
|
217
217
|
buckets[hashed] = []
|
|
@@ -244,7 +244,7 @@ function rebuildBucket (cache, bucket, stats, opts) {
|
|
|
244
244
|
return index
|
|
245
245
|
.insert(cache, entry.key, entry.integrity, {
|
|
246
246
|
metadata: entry.metadata,
|
|
247
|
-
size: entry.size
|
|
247
|
+
size: entry.size,
|
|
248
248
|
})
|
|
249
249
|
.then(() => {
|
|
250
250
|
stats.totalEntries++
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cacache",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.2.0",
|
|
4
4
|
"cache-version": {
|
|
5
5
|
"content": "2",
|
|
6
6
|
"index": "5"
|
|
@@ -13,15 +13,17 @@
|
|
|
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": "npm run npmclilint -- \"*.*js\" \"lib/**/*.*js\" \"test/**/*.*js\"",
|
|
24
|
+
"npmclilint": "npmcli-lint",
|
|
25
|
+
"lintfix": "npm run lint -- --fix",
|
|
26
|
+
"postsnap": "npm run lintfix --"
|
|
25
27
|
},
|
|
26
28
|
"repository": "https://github.com/npm/cacache",
|
|
27
29
|
"keywords": [
|
|
@@ -39,23 +41,6 @@
|
|
|
39
41
|
"disk cache",
|
|
40
42
|
"disk storage"
|
|
41
43
|
],
|
|
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
44
|
"license": "ISC",
|
|
60
45
|
"dependencies": {
|
|
61
46
|
"@npmcli/move-file": "^1.0.1",
|
|
@@ -77,11 +62,10 @@
|
|
|
77
62
|
"unique-filename": "^1.1.1"
|
|
78
63
|
},
|
|
79
64
|
"devDependencies": {
|
|
65
|
+
"@npmcli/lint": "^1.0.1",
|
|
80
66
|
"benchmark": "^2.1.4",
|
|
81
67
|
"chalk": "^4.0.0",
|
|
82
68
|
"require-inject": "^1.4.4",
|
|
83
|
-
"standard": "^14.3.1",
|
|
84
|
-
"standard-version": "^7.1.0",
|
|
85
69
|
"tacks": "^1.3.0",
|
|
86
70
|
"tap": "^15.0.9"
|
|
87
71
|
},
|
package/put.js
CHANGED
|
@@ -9,7 +9,7 @@ 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
|
|
@@ -21,9 +21,9 @@ function putData (cache, key, data, opts = {}) {
|
|
|
21
21
|
return index
|
|
22
22
|
.insert(cache, key, res.integrity, { ...opts, size: res.size })
|
|
23
23
|
.then((entry) => {
|
|
24
|
-
if (memoize)
|
|
24
|
+
if (memoize)
|
|
25
25
|
memo.put(cache, entry, data, opts)
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
return res.integrity
|
|
28
28
|
})
|
|
29
29
|
})
|
|
@@ -67,17 +67,16 @@ function putStream (cache, key, opts = {}) {
|
|
|
67
67
|
return index
|
|
68
68
|
.insert(cache, key, integrity, { ...opts, size })
|
|
69
69
|
.then((entry) => {
|
|
70
|
-
if (memoize && memoData)
|
|
70
|
+
if (memoize && memoData)
|
|
71
71
|
memo.put(cache, entry, memoData, opts)
|
|
72
|
-
|
|
73
|
-
if (integrity)
|
|
72
|
+
|
|
73
|
+
if (integrity)
|
|
74
74
|
pipeline.emit('integrity', integrity)
|
|
75
|
-
|
|
76
|
-
if (size)
|
|
75
|
+
|
|
76
|
+
if (size)
|
|
77
77
|
pipeline.emit('size', size)
|
|
78
|
-
}
|
|
79
78
|
})
|
|
80
|
-
}
|
|
79
|
+
},
|
|
81
80
|
}))
|
|
82
81
|
|
|
83
82
|
return pipeline
|
package/rm.js
CHANGED
|
@@ -11,9 +11,9 @@ const rmContent = require('./lib/content/rm')
|
|
|
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
|