From 05637b6b3b818e1730b1808055c8671700204b9f Mon Sep 17 00:00:00 2001 From: achingbrain Date: Fri, 27 Mar 2020 15:52:05 +0000 Subject: [PATCH] feat: support mtime-nsecs in mfs cli These are supported in the core and the http interface but got missed off the cli. Fixes #2803 --- packages/ipfs/src/cli/commands/add.js | 30 +++---------- packages/ipfs/src/cli/commands/files/mkdir.js | 20 ++++++--- packages/ipfs/src/cli/commands/files/touch.js | 21 ++++++--- packages/ipfs/src/cli/commands/files/write.js | 21 ++++++--- packages/ipfs/src/cli/utils.js | 44 +++++++++++++++++-- packages/ipfs/test/cli/files/mkdir.js | 19 +++++++- packages/ipfs/test/cli/files/touch.js | 31 ++++++++++--- packages/ipfs/test/cli/files/write.js | 22 +++++++++- 8 files changed, 153 insertions(+), 55 deletions(-) diff --git a/packages/ipfs/src/cli/commands/add.js b/packages/ipfs/src/cli/commands/add.js index de5bd47edf..d2580e0875 100644 --- a/packages/ipfs/src/cli/commands/add.js +++ b/packages/ipfs/src/cli/commands/add.js @@ -6,7 +6,11 @@ const getFolderSize = promisify(require('get-folder-size')) const byteman = require('byteman') const mh = require('multihashes') const multibase = require('multibase') -const { createProgressBar } = require('../utils') +const { + createProgressBar, + coerceMtime, + coerceMtimeNsecs +} = require('../utils') const { cidToString } = require('../../utils/cid') const globSource = require('ipfs-utils/src/files/glob-source') @@ -142,32 +146,12 @@ module.exports = { }, mtime: { type: 'number', - coerce: (value) => { - value = parseInt(value) - - if (isNaN(value)) { - throw new Error('mtime must be a number') - } - - return value - }, + coerce: coerceMtime, describe: 'Modification time in seconds before or since the Unix Epoch to apply to created UnixFS entries' }, 'mtime-nsecs': { type: 'number', - coerce: (value) => { - value = parseInt(value) - - if (isNaN(value)) { - throw new Error('mtime-nsecs must be a number') - } - - if (value < 0 || value > 999999999) { - throw new Error('mtime-nsecs must be in the range [0,999999999]') - } - - return value - }, + coerce: coerceMtimeNsecs, describe: 'Modification time fraction in nanoseconds' } }, diff --git a/packages/ipfs/src/cli/commands/files/mkdir.js b/packages/ipfs/src/cli/commands/files/mkdir.js index 5f156dfd16..56c8291c91 100644 --- a/packages/ipfs/src/cli/commands/files/mkdir.js +++ b/packages/ipfs/src/cli/commands/files/mkdir.js @@ -3,7 +3,9 @@ const { asBoolean, asOctal, - asDateFromSeconds + asMtimeFromSeconds, + coerceMtime, + coerceMtimeNsecs } = require('../../utils') module.exports = { @@ -49,9 +51,14 @@ module.exports = { describe: 'Mode to apply to the new directory' }, mtime: { - type: 'date', - coerce: asDateFromSeconds, - describe: 'Mtime to apply to the new directory in seconds' + type: 'number', + coerce: coerceMtime, + describe: 'Modification time in seconds before or since the Unix Epoch to apply to created UnixFS entries' + }, + 'mtime-nsecs': { + type: 'number', + coerce: coerceMtimeNsecs, + describe: 'Modification time fraction in nanoseconds' } }, @@ -65,7 +72,8 @@ module.exports = { flush, shardSplitThreshold, mode, - mtime + mtime, + mtimeNsecs } = argv return ipfs.files.mkdir(path, { @@ -75,7 +83,7 @@ module.exports = { flush, shardSplitThreshold, mode, - mtime + mtime: asMtimeFromSeconds(mtime, mtimeNsecs) }) } } diff --git a/packages/ipfs/src/cli/commands/files/touch.js b/packages/ipfs/src/cli/commands/files/touch.js index bceac05fa2..871ece5433 100644 --- a/packages/ipfs/src/cli/commands/files/touch.js +++ b/packages/ipfs/src/cli/commands/files/touch.js @@ -2,7 +2,9 @@ const { asBoolean, - asDateFromSeconds + asMtimeFromSeconds, + coerceMtime, + coerceMtimeNsecs } = require('../../utils') module.exports = { @@ -12,11 +14,15 @@ module.exports = { builder: { mtime: { + type: 'number', alias: 'm', - type: 'date', - coerce: asDateFromSeconds, - default: Date.now(), - describe: 'Time to use as the new modification time' + coerce: coerceMtime, + describe: 'Modification time in seconds before or since the Unix Epoch to apply to created UnixFS entries' + }, + 'mtime-nsecs': { + type: 'number', + coerce: coerceMtimeNsecs, + describe: 'Modification time fraction in nanoseconds' }, flush: { alias: 'f', @@ -52,11 +58,12 @@ module.exports = { cidVersion, hashAlg, shardSplitThreshold, - mtime + mtime, + mtimeNsecs } = argv return ipfs.files.touch(path, { - mtime, + mtime: asMtimeFromSeconds(mtime, mtimeNsecs), flush, cidVersion, hashAlg, diff --git a/packages/ipfs/src/cli/commands/files/write.js b/packages/ipfs/src/cli/commands/files/write.js index dc275d427f..a30db31091 100644 --- a/packages/ipfs/src/cli/commands/files/write.js +++ b/packages/ipfs/src/cli/commands/files/write.js @@ -3,7 +3,9 @@ const { asBoolean, asOctal, - asDateFromSeconds + asMtimeFromSeconds, + coerceMtime, + coerceMtimeNsecs } = require('../../utils') module.exports = { @@ -89,10 +91,14 @@ module.exports = { describe: 'The mode to use' }, mtime: { - alias: 'm', - type: 'date', - coerce: asDateFromSeconds, - describe: 'Time to use as the new modification time' + type: 'number', + coerce: coerceMtime, + describe: 'Modification time in seconds before or since the Unix Epoch to apply to created UnixFS entries' + }, + 'mtime-nsecs': { + type: 'number', + coerce: coerceMtimeNsecs, + describe: 'Modification time fraction in nanoseconds' } }, @@ -114,7 +120,8 @@ module.exports = { flush, shardSplitThreshold, mode, - mtime + mtime, + mtimeNsecs } = argv await ipfs.files.write(path, getStdin(), { @@ -132,7 +139,7 @@ module.exports = { flush, shardSplitThreshold, mode, - mtime + mtime: asMtimeFromSeconds(mtime, mtimeNsecs) }) } } diff --git a/packages/ipfs/src/cli/utils.js b/packages/ipfs/src/cli/utils.js index c466137cdc..77bf793280 100644 --- a/packages/ipfs/src/cli/utils.js +++ b/packages/ipfs/src/cli/utils.js @@ -133,8 +133,44 @@ const asOctal = (value) => { return parseInt(value, 8) } -const asDateFromSeconds = (value) => { - return new Date(parseInt(value, 10) * 1000) +const asMtimeFromSeconds = (secs, nsecs) => { + if (secs === null || secs === undefined) { + return undefined + } + + const output = { + secs + } + + if (nsecs !== null && nsecs !== undefined) { + output.nsecs = nsecs + } + + return output +} + +const coerceMtime = (value) => { + value = parseInt(value) + + if (isNaN(value)) { + throw new Error('mtime must be a number') + } + + return value +} + +const coerceMtimeNsecs = (value) => { + value = parseInt(value) + + if (isNaN(value)) { + throw new Error('mtime-nsecs must be a number') + } + + if (value < 0 || value > 999999999) { + throw new Error('mtime-nsecs must be in the range [0,999999999]') + } + + return value } module.exports = { @@ -148,5 +184,7 @@ module.exports = { ipfsPathHelp, asBoolean, asOctal, - asDateFromSeconds + asMtimeFromSeconds, + coerceMtime, + coerceMtimeNsecs } diff --git a/packages/ipfs/test/cli/files/mkdir.js b/packages/ipfs/test/cli/files/mkdir.js index 3d15322889..0fe580830b 100644 --- a/packages/ipfs/test/cli/files/mkdir.js +++ b/packages/ipfs/test/cli/files/mkdir.js @@ -177,7 +177,24 @@ describe('mkdir', () => { expect(ipfs.files.mkdir.getCall(0).args).to.deep.equal([ path, defaultOptions({ - mtime: new Date(5000) + mtime: { + secs: 5 + } + }) + ]) + }) + + it('should make a directory a different mtime and mtime nsecs', async () => { + await cli(`files mkdir --mtime 5 --mtime-nsecs 10 ${path}`, { ipfs }) + + expect(ipfs.files.mkdir.callCount).to.equal(1) + expect(ipfs.files.mkdir.getCall(0).args).to.deep.equal([ + path, + defaultOptions({ + mtime: { + secs: 5, + nsecs: 10 + } }) ]) }) diff --git a/packages/ipfs/test/cli/files/touch.js b/packages/ipfs/test/cli/files/touch.js index ff263cf81f..65452d2397 100644 --- a/packages/ipfs/test/cli/files/touch.js +++ b/packages/ipfs/test/cli/files/touch.js @@ -28,7 +28,9 @@ describe('touch', () => { } const path = '/foo' - const mtime = new Date(100000) + const mtime = { + secs: 1000 + } let ipfs beforeEach(() => { @@ -40,7 +42,7 @@ describe('touch', () => { }) it('should update the mtime for a file', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -52,7 +54,7 @@ describe('touch', () => { }) it('should update the mtime without flushing', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} --flush false ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} --flush false ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -65,7 +67,7 @@ describe('touch', () => { }) it('should update the mtime without flushing (short option)', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} -f false ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} -f false ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -78,7 +80,7 @@ describe('touch', () => { }) it('should update the mtime with a different hash algorithm', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} --hash-alg sha3-256 ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} --hash-alg sha3-256 ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -91,7 +93,7 @@ describe('touch', () => { }) it('should update the mtime with a different hash algorithm (short option)', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} -h sha3-256 ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} -h sha3-256 ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -104,7 +106,7 @@ describe('touch', () => { }) it('should update the mtime with a shard split threshold', async () => { - await cli(`files touch -m ${mtime.getTime() / 1000} --shard-split-threshold 10 ${path}`, { ipfs }) + await cli(`files touch -m ${mtime.secs} --shard-split-threshold 10 ${path}`, { ipfs }) expect(ipfs.files.touch.callCount).to.equal(1) expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ @@ -115,4 +117,19 @@ describe('touch', () => { }) ]) }) + + it('should update the mtime and nsecs', async () => { + await cli(`files touch -m 5 --mtime-nsecs 10 ${path}`, { ipfs }) + + expect(ipfs.files.touch.callCount).to.equal(1) + expect(ipfs.files.touch.getCall(0).args).to.deep.equal([ + path, + defaultOptions({ + mtime: { + secs: 5, + nsecs: 10 + } + }) + ]) + }) }) diff --git a/packages/ipfs/test/cli/files/write.js b/packages/ipfs/test/cli/files/write.js index d6b2c4c55b..677010931e 100644 --- a/packages/ipfs/test/cli/files/write.js +++ b/packages/ipfs/test/cli/files/write.js @@ -417,7 +417,27 @@ describe('write', () => { path, stdin, defaultOptions({ - mtime: new Date(11000) + mtime: { + secs: 11 + } + }) + ]) + }) + + it('should write to a file with a specified mtime and mtime nsecs', async () => { + const path = '/foo' + + await cli(`files write --mtime 11 --mtime-nsecs 10 ${path}`, { ipfs, getStdin }) + + expect(ipfs.files.write.callCount).to.equal(1) + expect(ipfs.files.write.getCall(0).args).to.deep.equal([ + path, + stdin, + defaultOptions({ + mtime: { + secs: 11, + nsecs: 10 + } }) ]) })