From fe638b6abb305407c822ce9e5b57b8ea06d76c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Tue, 7 Aug 2018 17:47:04 -0700 Subject: [PATCH] feat(read): add sync support to other internal read.js fns --- lib/content/read.js | 31 ++++++++++++++++++++++++++++++- test/content.read.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/content/read.js b/lib/content/read.js index e308ead..8f1acc0 100644 --- a/lib/content/read.js +++ b/lib/content/read.js @@ -73,8 +73,10 @@ function readStream (cache, integrity, opts) { let copyFileAsync if (fs.copyFile) { module.exports.copy = copy + module.exports.copy.sync = copySync copyFileAsync = BB.promisify(fs.copyFile) } + function copy (cache, integrity, dest, opts) { opts = ReadOpts(opts) return withContentSri(cache, integrity, (cpath, sri) => { @@ -82,11 +84,18 @@ function copy (cache, integrity, dest, opts) { }) } +function copySync (cache, integrity, dest, opts) { + opts = ReadOpts(opts) + return withContentSriSync(cache, integrity, (cpath, sri) => { + return fs.copyFileSync(cpath, dest) + }) +} + module.exports.hasContent = hasContent function hasContent (cache, integrity) { if (!integrity) { return BB.resolve(false) } return withContentSri(cache, integrity, (cpath, sri) => { - return lstatAsync(cpath).then(stat => ({size: stat.size, sri})) + return lstatAsync(cpath).then(stat => ({size: stat.size, sri, stat})) }).catch(err => { if (err.code === 'ENOENT') { return false } if (err.code === 'EPERM') { @@ -99,6 +108,26 @@ function hasContent (cache, integrity) { }) } +module.exports.hasContent.sync = hasContentSync +function hasContentSync (cache, integrity) { + if (!integrity) { return false } + return withContentSriSync(cache, integrity, (cpath, sri) => { + try { + const stat = fs.lstatSync(cpath) + return {size: stat.size, sri, stat} + } catch (err) { + if (err.code === 'ENOENT') { return false } + if (err.code === 'EPERM') { + if (process.platform !== 'win32') { + throw err + } else { + return false + } + } + } + }) +} + function withContentSri (cache, integrity, fn) { return BB.try(() => { const sri = ssri.parse(integrity) diff --git a/test/content.read.js b/test/content.read.js index 38f3cd7..d55736c 100644 --- a/test/content.read.js +++ b/test/content.read.js @@ -146,7 +146,7 @@ test('read: errors if content size does not match size option', function (t) { ) }) -test('hasContent: returns { sri, size } when a cache file exists', function (t) { +test('hasContent: tests content existence', t => { const fixture = new Tacks(CacheContent({ 'sha1-deadbeef': '' })) @@ -156,6 +156,7 @@ test('hasContent: returns { sri, size } when a cache file exists', function (t) .then(content => { t.ok(content.sri, 'returned sri for this content') t.equal(content.size, 0, 'returned the right size for this content') + t.ok(content.stat.isFile(), 'returned actual stat object') }), read.hasContent(CACHE, 'sha1-not-there') .then(content => { @@ -168,6 +169,28 @@ test('hasContent: returns { sri, size } when a cache file exists', function (t) ) }) +test('hasContent.sync: checks content existence synchronously', t => { + const fixture = new Tacks(CacheContent({ + 'sha1-deadbeef': '' + })) + fixture.create(CACHE) + const content = read.hasContent.sync(CACHE, 'sha1-deadbeef') + t.ok(content.sri, 'returned sri for this content') + t.equal(content.size, 0, 'returned the right size for this content') + t.ok(content.stat.isFile(), 'returned actual stat object') + t.equal( + read.hasContent.sync(CACHE, 'sha1-not-there'), + false, + 'returned false for missing content' + ) + t.equal( + read.hasContent.sync(CACHE, 'sha1-not-here sha1-also-not-here'), + false, + 'multi-content hash failures work ok' + ) + t.done() +}) + test('copy: copies content to a destination path', { skip: !fs.copyFile && 'Not supported on node versions without fs.copyFile' }, t => { @@ -184,3 +207,22 @@ test('copy: copies content to a destination path', { t.deepEqual(data, CONTENT, 'file successfully copied') }) }) + +test('copy.sync: copies content to a destination path synchronously', { + skip: !fs.copyFile && 'Not supported on node versions without fs.copyFile' +}, t => { + const CONTENT = Buffer.from('foobarbaz') + const INTEGRITY = ssri.fromData(CONTENT) + const DEST = path.join(CACHE, 'foobar-file') + const fixture = new Tacks(CacheContent({ + [INTEGRITY]: CONTENT + })) + fixture.create(CACHE) + read.copy.sync(CACHE, INTEGRITY, DEST) + t.deepEqual( + fs.readFileSync(DEST), + CONTENT, + 'file successfully copied' + ) + t.done() +})