cacache 15.0.4 → 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 CHANGED
@@ -36,6 +36,8 @@ just as easily be used on its own.
36
36
  * [`rm.all`](#rm-all)
37
37
  * [`rm.entry`](#rm-entry)
38
38
  * [`rm.content`](#rm-content)
39
+ * [`index.compact`](#index-compact)
40
+ * [`index.insert`](#index-insert)
39
41
  * Utilities
40
42
  * [`clearMemoized`](#clear-memoized)
41
43
  * [`tmp.mkdir`](#tmp-mkdir)
@@ -456,13 +458,17 @@ cacache.rm.all(cachePath).then(() => {
456
458
  })
457
459
  ```
458
460
 
459
- #### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key) -> Promise`
461
+ #### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key, [opts]) -> Promise`
460
462
 
461
463
  Alias: `cacache.rm`
462
464
 
463
465
  Removes the index entry for `key`. Content will still be accessible if
464
466
  requested directly by content address ([`get.stream.byDigest`](#get-stream)).
465
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
+
466
472
  To remove the content itself (which might still be used by other entries), use
467
473
  [`rm.content`](#rm-content). Or, to safely vacuum any unused content, use
468
474
  [`verify`](#verify).
@@ -489,6 +495,34 @@ cacache.rm.content(cachePath, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
489
495
  })
490
496
  ```
491
497
 
498
+ #### <a name="index-compact"></a> `> cacache.index.compact(cache, key, matchFn, [opts]) -> Promise`
499
+
500
+ Uses `matchFn`, which must be a synchronous function that accepts two entries
501
+ and returns a boolean indicating whether or not the two entries match, to
502
+ deduplicate all entries in the cache for the given `key`.
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
+
513
+ The deduplicated list of entries is both written to the index, replacing the
514
+ existing content, and returned in the Promise.
515
+
516
+ #### <a name="index-insert"></a> `> cacache.index.insert(cache, key, integrity, opts) -> Promise`
517
+
518
+ Writes an index entry to the cache for the given `key` without writing content.
519
+
520
+ It is assumed if you are using this method, you have already stored the content
521
+ some other way and you only wish to add a new index to that content. The `metadata`
522
+ and `size` properties are read from `opts` and used as part of the index entry.
523
+
524
+ Returns a Promise resolving to the newly added entry.
525
+
492
526
  #### <a name="clear-memoized"></a> `> cacache.clearMemoized()`
493
527
 
494
528
  Completely resets the in-memory entry cache.
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
- } else if (memoize) {
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
- } else if (memoize) {
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
- } else {
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/index.js CHANGED
@@ -7,6 +7,11 @@ const rm = require('./rm.js')
7
7
  const verify = require('./verify.js')
8
8
  const { clearMemoized } = require('./lib/memoization.js')
9
9
  const tmp = require('./lib/util/tmp.js')
10
+ const index = require('./lib/entry-index.js')
11
+
12
+ module.exports.index = {}
13
+ module.exports.index.compact = index.compact
14
+ module.exports.index.insert = index.insert
10
15
 
11
16
  module.exports.ls = ls
12
17
  module.exports.ls.stream = ls.stream
@@ -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
- } else {
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
- } else {
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 a ENOENT error, and can happen before a valid result
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
- } else {
16
+ else
17
17
  return false
18
- }
19
18
  })
20
19
  }
@@ -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(() => { throw er }))
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