cacache 16.0.7 → 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 +74 -89
- package/lib/content/rm.js +9 -9
- package/lib/content/write.js +30 -32
- package/lib/entry-index.js +91 -104
- package/lib/get.js +67 -73
- package/lib/put.js +14 -21
- 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 +156 -192
- package/package.json +3 -7
package/lib/get.js
CHANGED
|
@@ -8,52 +8,48 @@ const index = require('./entry-index')
|
|
|
8
8
|
const memo = require('./memoization')
|
|
9
9
|
const read = require('./content/read')
|
|
10
10
|
|
|
11
|
-
function getData (cache, key, opts = {}) {
|
|
11
|
+
async function getData (cache, key, opts = {}) {
|
|
12
12
|
const { integrity, memoize, size } = opts
|
|
13
13
|
const memoized = memo.get(cache, key, opts)
|
|
14
14
|
if (memoized && memoize !== false) {
|
|
15
|
-
return
|
|
15
|
+
return {
|
|
16
16
|
metadata: memoized.entry.metadata,
|
|
17
17
|
data: memoized.data,
|
|
18
18
|
integrity: memoized.entry.integrity,
|
|
19
19
|
size: memoized.entry.size,
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
}
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data,
|
|
35
|
-
metadata: entry.metadata,
|
|
36
|
-
size: entry.size,
|
|
37
|
-
integrity: entry.integrity,
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
})
|
|
32
|
+
return {
|
|
33
|
+
data,
|
|
34
|
+
metadata: entry.metadata,
|
|
35
|
+
size: entry.size,
|
|
36
|
+
integrity: entry.integrity,
|
|
37
|
+
}
|
|
41
38
|
}
|
|
42
39
|
module.exports = getData
|
|
43
40
|
|
|
44
|
-
function getDataByDigest (cache, key, opts = {}) {
|
|
41
|
+
async function getDataByDigest (cache, key, opts = {}) {
|
|
45
42
|
const { integrity, memoize, size } = opts
|
|
46
43
|
const memoized = memo.get.byDigest(cache, key, opts)
|
|
47
44
|
if (memoized && memoize !== false) {
|
|
48
|
-
return
|
|
45
|
+
return memoized
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
})
|
|
48
|
+
const res = await read(cache, key, { integrity, size })
|
|
49
|
+
if (memoize) {
|
|
50
|
+
memo.put.byDigest(cache, key, res, opts)
|
|
51
|
+
}
|
|
52
|
+
return res
|
|
57
53
|
}
|
|
58
54
|
module.exports.byDigest = getDataByDigest
|
|
59
55
|
|
|
@@ -131,36 +127,35 @@ function getStream (cache, key, opts = {}) {
|
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
const stream = new Pipeline()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const src = read.readStream(
|
|
151
|
-
cache,
|
|
152
|
-
entry.integrity,
|
|
153
|
-
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
if (memoize) {
|
|
157
|
-
const memoStream = new Collect.PassThrough()
|
|
158
|
-
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
159
|
-
stream.unshift(memoStream)
|
|
160
|
-
}
|
|
161
|
-
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)
|
|
162
144
|
})
|
|
163
|
-
|
|
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))
|
|
164
159
|
|
|
165
160
|
return stream
|
|
166
161
|
}
|
|
@@ -204,27 +199,26 @@ function info (cache, key, opts = {}) {
|
|
|
204
199
|
}
|
|
205
200
|
module.exports.info = info
|
|
206
201
|
|
|
207
|
-
function copy (cache, key, dest, opts = {}) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
})
|
|
220
|
-
})
|
|
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,
|
|
212
|
+
}
|
|
221
213
|
}
|
|
222
214
|
|
|
223
215
|
module.exports.copy = copy
|
|
224
216
|
|
|
225
|
-
function copyByDigest (cache, key, dest, opts = {}) {
|
|
226
|
-
|
|
217
|
+
async function copyByDigest (cache, key, dest, opts = {}) {
|
|
218
|
+
await read.copy(cache, key, dest, opts)
|
|
219
|
+
return key
|
|
227
220
|
}
|
|
221
|
+
|
|
228
222
|
module.exports.copy.byDigest = copyByDigest
|
|
229
223
|
|
|
230
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
|
|
@@ -68,17 +64,14 @@ function putStream (cache, key, opts = {}) {
|
|
|
68
64
|
// last but not least, we write the index and emit hash and size,
|
|
69
65
|
// and memoize if we're doing that
|
|
70
66
|
pipeline.push(new Flush({
|
|
71
|
-
flush () {
|
|
67
|
+
async flush () {
|
|
72
68
|
if (!error) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
pipeline.emit('integrity', integrity)
|
|
80
|
-
pipeline.emit('size', size)
|
|
81
|
-
})
|
|
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)
|
|
82
75
|
}
|
|
83
76
|
},
|
|
84
77
|
}))
|
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
|
package/lib/util/move-file.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const util = require('util')
|
|
5
|
-
const chmod = util.promisify(fs.chmod)
|
|
6
|
-
const unlink = util.promisify(fs.unlink)
|
|
7
|
-
const stat = util.promisify(fs.stat)
|
|
3
|
+
const fs = require('@npmcli/fs')
|
|
8
4
|
const move = require('@npmcli/move-file')
|
|
9
5
|
const pinflight = require('promise-inflight')
|
|
10
6
|
|
|
11
7
|
module.exports = moveFile
|
|
12
8
|
|
|
13
|
-
function moveFile (src, dest) {
|
|
14
|
-
const isWindows =
|
|
15
|
-
process.platform === 'win32'
|
|
9
|
+
async function moveFile (src, dest) {
|
|
10
|
+
const isWindows = process.platform === 'win32'
|
|
16
11
|
|
|
17
12
|
// This isn't quite an fs.rename -- the assumption is that
|
|
18
13
|
// if `dest` already exists, and we get certain errors while
|
|
@@ -23,47 +18,39 @@ function moveFile (src, dest) {
|
|
|
23
18
|
// content their own way.
|
|
24
19
|
//
|
|
25
20
|
// Note that, as the name suggests, this strictly only supports file moves.
|
|
26
|
-
|
|
27
|
-
fs.link(src, dest
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
21
|
+
try {
|
|
22
|
+
await fs.link(src, dest)
|
|
23
|
+
} catch (err) {
|
|
24
|
+
if (isWindows && err.code === 'EPERM') {
|
|
25
|
+
// XXX This is a really weird way to handle this situation, as it
|
|
26
|
+
// results in the src file being deleted even though the dest
|
|
27
|
+
// might not exist. Since we pretty much always write files to
|
|
28
|
+
// deterministic locations based on content hash, this is likely
|
|
29
|
+
// ok (or at worst, just ends in a future cache miss). But it would
|
|
30
|
+
// be worth investigating at some time in the future if this is
|
|
31
|
+
// really what we want to do here.
|
|
32
|
+
} else if (err.code === 'EEXIST' || err.code === 'EBUSY') {
|
|
33
|
+
// file already exists, so whatever
|
|
34
|
+
} else {
|
|
35
|
+
throw err
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
await Promise.all([
|
|
40
|
+
fs.unlink(src),
|
|
41
|
+
!isWindows && fs.chmod(dest, '0444'),
|
|
42
|
+
])
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return pinflight('cacache-move-file:' + dest, async () => {
|
|
45
|
+
await fs.stat(dest).catch((err) => {
|
|
46
|
+
if (err.code !== 'ENOENT') {
|
|
47
|
+
// Something else is wrong here. Bail bail bail
|
|
48
|
+
throw err
|
|
43
49
|
}
|
|
44
|
-
} else {
|
|
45
|
-
return resolve()
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
.then(() => {
|
|
50
|
-
// content should never change for any reason, so make it read-only
|
|
51
|
-
return Promise.all([
|
|
52
|
-
unlink(src),
|
|
53
|
-
!isWindows && chmod(dest, '0444'),
|
|
54
|
-
])
|
|
55
|
-
})
|
|
56
|
-
.catch(() => {
|
|
57
|
-
return pinflight('cacache-move-file:' + dest, () => {
|
|
58
|
-
return stat(dest).catch((err) => {
|
|
59
|
-
if (err.code !== 'ENOENT') {
|
|
60
|
-
// Something else is wrong here. Bail bail bail
|
|
61
|
-
throw err
|
|
62
|
-
}
|
|
63
|
-
// file doesn't already exist! let's try a rename -> copy fallback
|
|
64
|
-
// only delete if it successfully copies
|
|
65
|
-
return move(src, dest)
|
|
66
|
-
})
|
|
67
50
|
})
|
|
51
|
+
// file doesn't already exist! let's try a rename -> copy fallback
|
|
52
|
+
// only delete if it successfully copies
|
|
53
|
+
return move(src, dest)
|
|
68
54
|
})
|
|
55
|
+
}
|
|
69
56
|
}
|
package/lib/util/tmp.js
CHANGED
|
@@ -7,15 +7,13 @@ const path = require('path')
|
|
|
7
7
|
|
|
8
8
|
module.exports.mkdir = mktmpdir
|
|
9
9
|
|
|
10
|
-
function mktmpdir (cache, opts = {}) {
|
|
10
|
+
async function mktmpdir (cache, opts = {}) {
|
|
11
11
|
const { tmpPrefix } = opts
|
|
12
12
|
const tmpDir = path.join(cache, 'tmp')
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return fs.mkdtemp(target, { owner: 'inherit' })
|
|
18
|
-
})
|
|
13
|
+
await fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' })
|
|
14
|
+
// do not use path.join(), it drops the trailing / if tmpPrefix is unset
|
|
15
|
+
const target = `${tmpDir}${path.sep}${tmpPrefix || ''}`
|
|
16
|
+
return fs.mkdtemp(target, { owner: 'inherit' })
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
module.exports.withTmp = withTmp
|