Skip to content

Commit

Permalink
feat: allow fully deleting indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
nlf committed May 20, 2021
1 parent 26dda5a commit 460b951
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 8 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,17 @@ cacache.rm.all(cachePath).then(() => {
})
```

#### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key) -> Promise`
#### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key, [opts]) -> Promise`

Alias: `cacache.rm`

Removes the index entry for `key`. Content will still be accessible if
requested directly by content address ([`get.stream.byDigest`](#get-stream)).

By default, this appends a new entry to the index with an integrity of `null`.
If `opts.removeFully` is set to `true` then the index file itself will be
physically deleted rather than appending a `null`.

To remove the content itself (which might still be used by other entries), use
[`rm.content`](#rm-content). Or, to safely vacuum any unused content, use
[`verify`](#verify).
Expand Down
22 changes: 17 additions & 5 deletions lib/entry-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const fixOwner = require('./util/fix-owner')
const hashToSegments = require('./util/hash-to-segments')
const indexV = require('../package.json')['cache-version'].index
const moveFile = require('@npmcli/move-file')
const rimraf = util.promisify(require('rimraf'))
const _rimraf = require('rimraf')
const rimraf = util.promisify(_rimraf)
rimraf.sync = _rimraf.sync

const appendFile = util.promisify(fs.appendFile)
const readFile = util.promisify(fs.readFile)
Expand Down Expand Up @@ -201,14 +203,24 @@ function findSync (cache, key) {

module.exports.delete = del

function del (cache, key, opts) {
return insert(cache, key, null, opts)
function del (cache, key, opts = {}) {
if (!opts.removeFully) {
return insert(cache, key, null, opts)
}

const bucket = bucketPath(cache, key)
return rimraf(bucket)
}

module.exports.delete.sync = delSync

function delSync (cache, key, opts) {
return insertSync(cache, key, null, opts)
function delSync (cache, key, opts = {}) {
if (!opts.removeFully) {
return insertSync(cache, key, null, opts)
}

const bucket = bucketPath(cache, key)
return rimraf.sync(bucket)
}

module.exports.lsStream = lsStream
Expand Down
4 changes: 2 additions & 2 deletions rm.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ const rmContent = require('./lib/content/rm')
module.exports = entry
module.exports.entry = entry

function entry (cache, key) {
function entry (cache, key, opts) {
memo.clearMemoized()
return index.delete(cache, key)
return index.delete(cache, key, opts)
}

module.exports.content = content
Expand Down
34 changes: 34 additions & 0 deletions test/entry-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,40 @@ test('delete.sync: removes a cache entry', (t) => {
})
})

test('delete.sync: removeFully deletes the index entirely', async (t) => {
const bucket = index.bucketPath(CACHE, KEY)
await index.insert(CACHE, KEY, INTEGRITY)
const entries = await index.bucketEntries(bucket)
t.equal(entries.length, 1, 'has an entry')

// do a normal delete first, this appends a null integrity
index.delete.sync(CACHE, KEY)
const delEntries = await index.bucketEntries(bucket)
t.equal(delEntries.length, 2, 'should now have 2 entries')
t.equal(delEntries[1].integrity, null, 'has a null integrity last')

// then a full delete
index.delete.sync(CACHE, KEY, { removeFully: true })
await t.rejects(index.bucketEntries(bucket), { code: 'ENOENT' }, 'rejects with ENOENT because file is gone')
})

test('delete: removeFully deletes the index entirely', async (t) => {
const bucket = index.bucketPath(CACHE, KEY)
await index.insert(CACHE, KEY, INTEGRITY)
const entries = await index.bucketEntries(bucket)
t.equal(entries.length, 1, 'has an entry')

// do a normal delete first, this appends a null integrity
await index.delete(CACHE, KEY)
const delEntries = await index.bucketEntries(bucket)
t.equal(delEntries.length, 2, 'should now have 2 entries')
t.equal(delEntries[1].integrity, null, 'has a null integrity last')

// then a full delete
await index.delete(CACHE, KEY, { removeFully: true })
await t.rejects(index.bucketEntries(bucket), { code: 'ENOENT' }, 'rejects with ENOENT because file is gone')
})

test('find: error on parsing json data', (t) => {
// mocks readFile in order to return a borked json payload
const { find } = getEntryIndex({
Expand Down

0 comments on commit 460b951

Please sign in to comment.