cacache 16.0.5 → 16.1.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 +13 -0
- package/lib/content/read.js +76 -94
- package/lib/content/rm.js +9 -9
- package/lib/content/write.js +57 -64
- package/lib/entry-index.js +97 -106
- package/lib/get.js +67 -94
- package/lib/put.js +20 -27
- package/lib/util/fix-owner.js +36 -39
- package/lib/util/move-file.js +35 -48
- package/lib/util/tmp.js +5 -7
- package/lib/verify.js +158 -192
- package/package.json +3 -12
- package/lib/util/disposer.js +0 -31
package/lib/entry-index.js
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('util')
|
|
4
4
|
const crypto = require('crypto')
|
|
5
|
-
const fs = require('fs')
|
|
5
|
+
const fs = require('@npmcli/fs')
|
|
6
6
|
const Minipass = require('minipass')
|
|
7
7
|
const path = require('path')
|
|
8
8
|
const ssri = require('ssri')
|
|
9
9
|
const uniqueFilename = require('unique-filename')
|
|
10
10
|
|
|
11
|
-
const { disposer } = require('./util/disposer')
|
|
12
11
|
const contentPath = require('./content/path')
|
|
13
12
|
const fixOwner = require('./util/fix-owner')
|
|
14
13
|
const hashToSegments = require('./util/hash-to-segments')
|
|
@@ -18,11 +17,6 @@ const _rimraf = require('rimraf')
|
|
|
18
17
|
const rimraf = util.promisify(_rimraf)
|
|
19
18
|
rimraf.sync = _rimraf.sync
|
|
20
19
|
|
|
21
|
-
const appendFile = util.promisify(fs.appendFile)
|
|
22
|
-
const readFile = util.promisify(fs.readFile)
|
|
23
|
-
const readdir = util.promisify(fs.readdir)
|
|
24
|
-
const writeFile = util.promisify(fs.writeFile)
|
|
25
|
-
|
|
26
20
|
module.exports.NotFoundError = class NotFoundError extends Error {
|
|
27
21
|
constructor (cache, key) {
|
|
28
22
|
super(`No cache entry for ${key} found in ${cache}`)
|
|
@@ -86,7 +80,7 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
const write = async (tmp) => {
|
|
89
|
-
await writeFile(tmp.target, newIndex, { flag: 'wx' })
|
|
83
|
+
await fs.writeFile(tmp.target, newIndex, { flag: 'wx' })
|
|
90
84
|
await fixOwner.mkdirfix(cache, path.dirname(bucket))
|
|
91
85
|
// we use @npmcli/move-file directly here because we
|
|
92
86
|
// want to overwrite the existing file
|
|
@@ -102,7 +96,12 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
// write the file atomically
|
|
105
|
-
await
|
|
99
|
+
const tmp = await setup()
|
|
100
|
+
try {
|
|
101
|
+
await write(tmp)
|
|
102
|
+
} finally {
|
|
103
|
+
await teardown(tmp)
|
|
104
|
+
}
|
|
106
105
|
|
|
107
106
|
// we reverse the list we generated such that the newest
|
|
108
107
|
// entries come first in order to make looping through them easier
|
|
@@ -114,7 +113,7 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
114
113
|
|
|
115
114
|
module.exports.insert = insert
|
|
116
115
|
|
|
117
|
-
function insert (cache, key, integrity, opts = {}) {
|
|
116
|
+
async function insert (cache, key, integrity, opts = {}) {
|
|
118
117
|
const { metadata, size } = opts
|
|
119
118
|
const bucket = bucketPath(cache, key)
|
|
120
119
|
const entry = {
|
|
@@ -124,36 +123,32 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
124
123
|
size,
|
|
125
124
|
metadata,
|
|
126
125
|
}
|
|
127
|
-
|
|
128
|
-
.mkdirfix(cache, path.dirname(bucket))
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return undefined
|
|
145
|
-
}
|
|
126
|
+
try {
|
|
127
|
+
await fixOwner.mkdirfix(cache, path.dirname(bucket))
|
|
128
|
+
const stringified = JSON.stringify(entry)
|
|
129
|
+
// NOTE - Cleverness ahoy!
|
|
130
|
+
//
|
|
131
|
+
// This works because it's tremendously unlikely for an entry to corrupt
|
|
132
|
+
// another while still preserving the string length of the JSON in
|
|
133
|
+
// question. So, we just slap the length in there and verify it on read.
|
|
134
|
+
//
|
|
135
|
+
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
136
|
+
// this.
|
|
137
|
+
await fs.appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
138
|
+
await fixOwner.chownr(cache, bucket)
|
|
139
|
+
} catch (err) {
|
|
140
|
+
if (err.code === 'ENOENT') {
|
|
141
|
+
return undefined
|
|
142
|
+
}
|
|
146
143
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return formatEntry(cache, entry)
|
|
156
|
-
})
|
|
144
|
+
throw err
|
|
145
|
+
// There's a class of race conditions that happen when things get deleted
|
|
146
|
+
// during fixOwner, or between the two mkdirfix/chownr calls.
|
|
147
|
+
//
|
|
148
|
+
// It's perfectly fine to just not bother in those cases and lie
|
|
149
|
+
// that the index entry was written. Because it's a cache.
|
|
150
|
+
}
|
|
151
|
+
return formatEntry(cache, entry)
|
|
157
152
|
}
|
|
158
153
|
|
|
159
154
|
module.exports.insert.sync = insertSync
|
|
@@ -183,25 +178,24 @@ function insertSync (cache, key, integrity, opts = {}) {
|
|
|
183
178
|
|
|
184
179
|
module.exports.find = find
|
|
185
180
|
|
|
186
|
-
function find (cache, key) {
|
|
181
|
+
async function find (cache, key) {
|
|
187
182
|
const bucket = bucketPath(cache, key)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
} else {
|
|
194
|
-
return latest
|
|
195
|
-
}
|
|
196
|
-
}, null)
|
|
197
|
-
})
|
|
198
|
-
.catch((err) => {
|
|
199
|
-
if (err.code === 'ENOENT') {
|
|
200
|
-
return null
|
|
183
|
+
try {
|
|
184
|
+
const entries = await bucketEntries(bucket)
|
|
185
|
+
return entries.reduce((latest, next) => {
|
|
186
|
+
if (next && next.key === key) {
|
|
187
|
+
return formatEntry(cache, next)
|
|
201
188
|
} else {
|
|
202
|
-
|
|
189
|
+
return latest
|
|
203
190
|
}
|
|
204
|
-
})
|
|
191
|
+
}, null)
|
|
192
|
+
} catch (err) {
|
|
193
|
+
if (err.code === 'ENOENT') {
|
|
194
|
+
return null
|
|
195
|
+
} else {
|
|
196
|
+
throw err
|
|
197
|
+
}
|
|
198
|
+
}
|
|
205
199
|
}
|
|
206
200
|
|
|
207
201
|
module.exports.find.sync = findSync
|
|
@@ -253,67 +247,64 @@ function lsStream (cache) {
|
|
|
253
247
|
const indexDir = bucketDir(cache)
|
|
254
248
|
const stream = new Minipass({ objectMode: true })
|
|
255
249
|
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
// Set all this up to run on the stream and then just return the stream
|
|
251
|
+
Promise.resolve().then(async () => {
|
|
252
|
+
const buckets = await readdirOrEmpty(indexDir)
|
|
253
|
+
await Promise.all(buckets.map(async (bucket) => {
|
|
258
254
|
const bucketPath = path.join(indexDir, bucket)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
))
|
|
294
|
-
.then(
|
|
295
|
-
() => stream.end(),
|
|
296
|
-
err => stream.emit('error', err)
|
|
297
|
-
)
|
|
255
|
+
const subbuckets = await readdirOrEmpty(bucketPath)
|
|
256
|
+
await Promise.all(subbuckets.map(async (subbucket) => {
|
|
257
|
+
const subbucketPath = path.join(bucketPath, subbucket)
|
|
258
|
+
|
|
259
|
+
// "/cachename/<bucket 0xFF>/<bucket 0xFF>./*"
|
|
260
|
+
const subbucketEntries = await readdirOrEmpty(subbucketPath)
|
|
261
|
+
await Promise.all(subbucketEntries.map(async (entry) => {
|
|
262
|
+
const entryPath = path.join(subbucketPath, entry)
|
|
263
|
+
try {
|
|
264
|
+
const entries = await bucketEntries(entryPath)
|
|
265
|
+
// using a Map here prevents duplicate keys from showing up
|
|
266
|
+
// twice, I guess?
|
|
267
|
+
const reduced = entries.reduce((acc, entry) => {
|
|
268
|
+
acc.set(entry.key, entry)
|
|
269
|
+
return acc
|
|
270
|
+
}, new Map())
|
|
271
|
+
// reduced is a map of key => entry
|
|
272
|
+
for (const entry of reduced.values()) {
|
|
273
|
+
const formatted = formatEntry(cache, entry)
|
|
274
|
+
if (formatted) {
|
|
275
|
+
stream.write(formatted)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (err) {
|
|
279
|
+
if (err.code === 'ENOENT') {
|
|
280
|
+
return undefined
|
|
281
|
+
}
|
|
282
|
+
throw err
|
|
283
|
+
}
|
|
284
|
+
}))
|
|
285
|
+
}))
|
|
286
|
+
}))
|
|
287
|
+
stream.end()
|
|
288
|
+
}).catch(err => stream.emit('error', err))
|
|
298
289
|
|
|
299
290
|
return stream
|
|
300
291
|
}
|
|
301
292
|
|
|
302
293
|
module.exports.ls = ls
|
|
303
294
|
|
|
304
|
-
function ls (cache) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)
|
|
295
|
+
async function ls (cache) {
|
|
296
|
+
const entries = await lsStream(cache).collect()
|
|
297
|
+
return entries.reduce((acc, xs) => {
|
|
298
|
+
acc[xs.key] = xs
|
|
299
|
+
return acc
|
|
300
|
+
}, {})
|
|
311
301
|
}
|
|
312
302
|
|
|
313
303
|
module.exports.bucketEntries = bucketEntries
|
|
314
304
|
|
|
315
|
-
function bucketEntries (bucket, filter) {
|
|
316
|
-
|
|
305
|
+
async function bucketEntries (bucket, filter) {
|
|
306
|
+
const data = await fs.readFile(bucket, 'utf8')
|
|
307
|
+
return _bucketEntries(data, filter)
|
|
317
308
|
}
|
|
318
309
|
|
|
319
310
|
module.exports.bucketEntries.sync = bucketEntriesSync
|
|
@@ -402,7 +393,7 @@ function formatEntry (cache, entry, keepAll) {
|
|
|
402
393
|
}
|
|
403
394
|
|
|
404
395
|
function readdirOrEmpty (dir) {
|
|
405
|
-
return readdir(dir).catch((err) => {
|
|
396
|
+
return fs.readdir(dir).catch((err) => {
|
|
406
397
|
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') {
|
|
407
398
|
return []
|
|
408
399
|
}
|
package/lib/get.js
CHANGED
|
@@ -3,61 +3,53 @@
|
|
|
3
3
|
const Collect = require('minipass-collect')
|
|
4
4
|
const Minipass = require('minipass')
|
|
5
5
|
const Pipeline = require('minipass-pipeline')
|
|
6
|
-
const fs = require('fs')
|
|
7
|
-
const util = require('util')
|
|
8
6
|
|
|
9
7
|
const index = require('./entry-index')
|
|
10
8
|
const memo = require('./memoization')
|
|
11
9
|
const read = require('./content/read')
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
function getData (cache, key, opts = {}) {
|
|
11
|
+
async function getData (cache, key, opts = {}) {
|
|
16
12
|
const { integrity, memoize, size } = opts
|
|
17
13
|
const memoized = memo.get(cache, key, opts)
|
|
18
14
|
if (memoized && memoize !== false) {
|
|
19
|
-
return
|
|
15
|
+
return {
|
|
20
16
|
metadata: memoized.entry.metadata,
|
|
21
17
|
data: memoized.data,
|
|
22
18
|
integrity: memoized.entry.integrity,
|
|
23
19
|
size: memoized.entry.size,
|
|
24
|
-
}
|
|
20
|
+
}
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const entry = await index.find(cache, key, opts)
|
|
24
|
+
if (!entry) {
|
|
25
|
+
throw new index.NotFoundError(cache, key)
|
|
26
|
+
}
|
|
27
|
+
const data = await read(cache, entry.integrity, { integrity, size })
|
|
28
|
+
if (memoize) {
|
|
29
|
+
memo.put(cache, entry, data, opts)
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
data,
|
|
39
|
-
metadata: entry.metadata,
|
|
40
|
-
size: entry.size,
|
|
41
|
-
integrity: entry.integrity,
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
})
|
|
32
|
+
return {
|
|
33
|
+
data,
|
|
34
|
+
metadata: entry.metadata,
|
|
35
|
+
size: entry.size,
|
|
36
|
+
integrity: entry.integrity,
|
|
37
|
+
}
|
|
45
38
|
}
|
|
46
39
|
module.exports = getData
|
|
47
40
|
|
|
48
|
-
function getDataByDigest (cache, key, opts = {}) {
|
|
41
|
+
async function getDataByDigest (cache, key, opts = {}) {
|
|
49
42
|
const { integrity, memoize, size } = opts
|
|
50
43
|
const memoized = memo.get.byDigest(cache, key, opts)
|
|
51
44
|
if (memoized && memoize !== false) {
|
|
52
|
-
return
|
|
45
|
+
return memoized
|
|
53
46
|
}
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})
|
|
48
|
+
const res = await read(cache, key, { integrity, size })
|
|
49
|
+
if (memoize) {
|
|
50
|
+
memo.put.byDigest(cache, key, res, opts)
|
|
51
|
+
}
|
|
52
|
+
return res
|
|
61
53
|
}
|
|
62
54
|
module.exports.byDigest = getDataByDigest
|
|
63
55
|
|
|
@@ -135,36 +127,35 @@ function getStream (cache, key, opts = {}) {
|
|
|
135
127
|
}
|
|
136
128
|
|
|
137
129
|
const stream = new Pipeline()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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)
|
|
130
|
+
// Set all this up to run on the stream and then just return the stream
|
|
131
|
+
Promise.resolve().then(async () => {
|
|
132
|
+
const entry = await index.find(cache, key)
|
|
133
|
+
if (!entry) {
|
|
134
|
+
throw new index.NotFoundError(cache, key)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
stream.emit('metadata', entry.metadata)
|
|
138
|
+
stream.emit('integrity', entry.integrity)
|
|
139
|
+
stream.emit('size', entry.size)
|
|
140
|
+
stream.on('newListener', function (ev, cb) {
|
|
141
|
+
ev === 'metadata' && cb(entry.metadata)
|
|
142
|
+
ev === 'integrity' && cb(entry.integrity)
|
|
143
|
+
ev === 'size' && cb(entry.size)
|
|
166
144
|
})
|
|
167
|
-
|
|
145
|
+
|
|
146
|
+
const src = read.readStream(
|
|
147
|
+
cache,
|
|
148
|
+
entry.integrity,
|
|
149
|
+
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if (memoize) {
|
|
153
|
+
const memoStream = new Collect.PassThrough()
|
|
154
|
+
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
155
|
+
stream.unshift(memoStream)
|
|
156
|
+
}
|
|
157
|
+
stream.unshift(src)
|
|
158
|
+
}).catch((err) => stream.emit('error', err))
|
|
168
159
|
|
|
169
160
|
return stream
|
|
170
161
|
}
|
|
@@ -208,44 +199,26 @@ function info (cache, key, opts = {}) {
|
|
|
208
199
|
}
|
|
209
200
|
module.exports.info = info
|
|
210
201
|
|
|
211
|
-
function copy (cache, key, dest, opts = {}) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
size: entry.size,
|
|
222
|
-
integrity: entry.integrity,
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
})
|
|
202
|
+
async function copy (cache, key, dest, opts = {}) {
|
|
203
|
+
const entry = await index.find(cache, key, opts)
|
|
204
|
+
if (!entry) {
|
|
205
|
+
throw new index.NotFoundError(cache, key)
|
|
206
|
+
}
|
|
207
|
+
await read.copy(cache, entry.integrity, dest, opts)
|
|
208
|
+
return {
|
|
209
|
+
metadata: entry.metadata,
|
|
210
|
+
size: entry.size,
|
|
211
|
+
integrity: entry.integrity,
|
|
226
212
|
}
|
|
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
213
|
}
|
|
238
|
-
module.exports.copy = copy
|
|
239
214
|
|
|
240
|
-
|
|
241
|
-
if (read.copy) {
|
|
242
|
-
return read.copy(cache, key, dest, opts).then(() => key)
|
|
243
|
-
}
|
|
215
|
+
module.exports.copy = copy
|
|
244
216
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
217
|
+
async function copyByDigest (cache, key, dest, opts = {}) {
|
|
218
|
+
await read.copy(cache, key, dest, opts)
|
|
219
|
+
return key
|
|
248
220
|
}
|
|
221
|
+
|
|
249
222
|
module.exports.copy.byDigest = copyByDigest
|
|
250
223
|
|
|
251
224
|
module.exports.hasContent = read.hasContent
|
package/lib/put.js
CHANGED
|
@@ -14,20 +14,16 @@ const putOpts = (opts) => ({
|
|
|
14
14
|
|
|
15
15
|
module.exports = putData
|
|
16
16
|
|
|
17
|
-
function putData (cache, key, data, opts = {}) {
|
|
17
|
+
async function putData (cache, key, data, opts = {}) {
|
|
18
18
|
const { memoize } = opts
|
|
19
19
|
opts = putOpts(opts)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
memo.put(cache, entry, data, opts)
|
|
26
|
-
}
|
|
20
|
+
const res = await write(cache, data, opts)
|
|
21
|
+
const entry = await index.insert(cache, key, res.integrity, { ...opts, size: res.size })
|
|
22
|
+
if (memoize) {
|
|
23
|
+
memo.put(cache, entry, data, opts)
|
|
24
|
+
}
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
})
|
|
26
|
+
return res.integrity
|
|
31
27
|
}
|
|
32
28
|
|
|
33
29
|
module.exports.stream = putStream
|
|
@@ -37,6 +33,7 @@ function putStream (cache, key, opts = {}) {
|
|
|
37
33
|
opts = putOpts(opts)
|
|
38
34
|
let integrity
|
|
39
35
|
let size
|
|
36
|
+
let error
|
|
40
37
|
|
|
41
38
|
let memoData
|
|
42
39
|
const pipeline = new Pipeline()
|
|
@@ -58,28 +55,24 @@ function putStream (cache, key, opts = {}) {
|
|
|
58
55
|
.on('size', (s) => {
|
|
59
56
|
size = s
|
|
60
57
|
})
|
|
58
|
+
.on('error', (err) => {
|
|
59
|
+
error = err
|
|
60
|
+
})
|
|
61
61
|
|
|
62
62
|
pipeline.push(contentStream)
|
|
63
63
|
|
|
64
64
|
// last but not least, we write the index and emit hash and size,
|
|
65
65
|
// and memoize if we're doing that
|
|
66
66
|
pipeline.push(new Flush({
|
|
67
|
-
flush () {
|
|
68
|
-
|
|
69
|
-
.insert(cache, key, integrity, { ...opts, size })
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
pipeline.emit('integrity', integrity)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (size) {
|
|
80
|
-
pipeline.emit('size', size)
|
|
81
|
-
}
|
|
82
|
-
})
|
|
67
|
+
async flush () {
|
|
68
|
+
if (!error) {
|
|
69
|
+
const entry = await index.insert(cache, key, integrity, { ...opts, size })
|
|
70
|
+
if (memoize && memoData) {
|
|
71
|
+
memo.put(cache, entry, memoData, opts)
|
|
72
|
+
}
|
|
73
|
+
pipeline.emit('integrity', integrity)
|
|
74
|
+
pipeline.emit('size', size)
|
|
75
|
+
}
|
|
83
76
|
},
|
|
84
77
|
}))
|
|
85
78
|
|
package/lib/util/fix-owner.js
CHANGED
|
@@ -33,40 +33,38 @@ const getSelf = () => {
|
|
|
33
33
|
|
|
34
34
|
module.exports.chownr = fixOwner
|
|
35
35
|
|
|
36
|
-
function fixOwner (cache, filepath) {
|
|
36
|
+
async function fixOwner (cache, filepath) {
|
|
37
37
|
if (!process.getuid) {
|
|
38
38
|
// This platform doesn't need ownership fixing
|
|
39
|
-
return
|
|
39
|
+
return
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
getSelf()
|
|
43
43
|
if (self.uid !== 0) {
|
|
44
44
|
// almost certainly can't chown anyway
|
|
45
|
-
return
|
|
45
|
+
return
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
const { uid, gid } = owner
|
|
48
|
+
const { uid, gid } = await inferOwner(cache)
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// No need to override if it's already what we used.
|
|
51
|
+
if (self.uid === uid && self.gid === gid) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
55
|
+
return inflight('fixOwner: fixing ownership on ' + filepath, () =>
|
|
56
|
+
chownr(
|
|
57
|
+
filepath,
|
|
58
|
+
typeof uid === 'number' ? uid : self.uid,
|
|
59
|
+
typeof gid === 'number' ? gid : self.gid
|
|
60
|
+
).catch((err) => {
|
|
61
|
+
if (err.code === 'ENOENT') {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
throw err
|
|
66
|
+
})
|
|
67
|
+
)
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
module.exports.chownr.sync = fixOwnerSync
|
|
@@ -105,26 +103,25 @@ function fixOwnerSync (cache, filepath) {
|
|
|
105
103
|
|
|
106
104
|
module.exports.mkdirfix = mkdirfix
|
|
107
105
|
|
|
108
|
-
function mkdirfix (cache, p, cb) {
|
|
106
|
+
async function mkdirfix (cache, p, cb) {
|
|
109
107
|
// we have to infer the owner _before_ making the directory, even though
|
|
110
108
|
// we aren't going to use the results, since the cache itself might not
|
|
111
109
|
// exist yet. If we mkdirp it, then our current uid/gid will be assumed
|
|
112
110
|
// to be correct if it creates the cache folder in the process.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
})
|
|
111
|
+
await inferOwner(cache)
|
|
112
|
+
try {
|
|
113
|
+
const made = await mkdirp(p)
|
|
114
|
+
if (made) {
|
|
115
|
+
await fixOwner(cache, made)
|
|
116
|
+
return made
|
|
117
|
+
}
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (err.code === 'EEXIST') {
|
|
120
|
+
await fixOwner(cache, p)
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
123
|
+
throw err
|
|
124
|
+
}
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
module.exports.mkdirfix.sync = mkdirfixSync
|