Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit bddc5b4

Browse files
authored
feat: jsipfs add --only-hash (#1233) (#1266)
1 parent f7eaa43 commit bddc5b4

File tree

7 files changed

+121
-18
lines changed

7 files changed

+121
-18
lines changed

src/cli/commands/files/add.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ module.exports = {
139139
type: 'boolean',
140140
default: false
141141
},
142+
'only-hash': {
143+
alias: 'n',
144+
type: 'boolean',
145+
default: false,
146+
describe: 'Only chunk and hash, do not write'
147+
},
142148
'enable-sharding-experiment': {
143149
type: 'boolean',
144150
default: false
@@ -180,9 +186,12 @@ module.exports = {
180186
const index = inPath.lastIndexOf('/') + 1
181187
const options = {
182188
strategy: argv.trickle ? 'trickle' : 'balanced',
183-
shardSplitThreshold: argv.enableShardingExperiment ? argv.shardSplitThreshold : Infinity,
184-
'cid-version': argv['cid-version'],
185-
'raw-leaves': argv['raw-leaves']
189+
shardSplitThreshold: argv.enableShardingExperiment
190+
? argv.shardSplitThreshold
191+
: Infinity,
192+
cidVersion: argv.cidVersion,
193+
rawLeaves: argv.rawLeaves,
194+
onlyHash: argv.onlyHash
186195
}
187196

188197
// Temporary restriction on raw-leaves:
@@ -193,15 +202,15 @@ module.exports = {
193202
// cid-version > 0 unless explicitly set to false.
194203
//
195204
// This retains feature parity without having to implement raw-leaves.
196-
if (argv['cid-version'] > 0 && argv['raw-leaves'] !== false) {
205+
if (options.cidVersion > 0 && options.rawLeaves !== false) {
197206
throw new Error('Implied argument raw-leaves must be passed and set to false when cid-version is > 0')
198207
}
199208

200-
if (argv['raw-leaves']) {
209+
if (options.rawLeaves) {
201210
throw new Error('Not implemented: raw-leaves')
202211
}
203212

204-
if (argv.enableShardingExperiment && utils.isDaemonOn()) {
213+
if (options.enableShardingExperiment && utils.isDaemonOn()) {
205214
throw new Error('Error: Enabling the sharding experiment should be done on the daemon')
206215
}
207216
const ipfs = argv.ipfs
@@ -230,8 +239,7 @@ module.exports = {
230239
}
231240
}
232241

233-
const thing = (cb) => cb(null, ipfs.files.addPullStream(options))
234-
thing(next)
242+
next(null, ipfs.files.addPullStream(options))
235243
}
236244
], (err, addStream) => {
237245
if (err) throw err

src/core/components/files.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function prepareFile (self, opts, file, callback) {
2323
opts = opts || {}
2424

2525
waterfall([
26-
(cb) => self.object.get(file.multihash, cb),
26+
(cb) => opts.onlyHash ? cb(null, file) : self.object.get(file.multihash, cb),
2727
(node, cb) => {
2828
let cid = new CID(node.multihash)
2929

src/http/api/resources/files.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,12 @@ exports.add = {
143143
// cid-version > 0 unless explicitly set to false.
144144
//
145145
// This retains feature parity without having to implement raw-leaves.
146-
'raw-leaves': Joi.any().when('cid-version', {
146+
'raw-leaves': Joi.boolean().when('cid-version', {
147147
is: 1,
148148
then: Joi.boolean().valid(false).required(),
149149
otherwise: Joi.boolean().valid(false)
150-
})
150+
}),
151+
'only-hash': Joi.boolean()
151152
})
152153
// TODO: Necessary until validate "recursive", "stream-channels" etc.
153154
.options({ allowUnknown: true })
@@ -203,9 +204,10 @@ exports.add = {
203204
}
204205

205206
const options = {
206-
'cid-version': request.query['cid-version'],
207-
'raw-leaves': request.query['raw-leaves'],
208-
progress: request.query['progress'] ? progressHandler : null
207+
cidVersion: request.query['cid-version'],
208+
rawLeaves: request.query['raw-leaves'],
209+
progress: request.query.progress ? progressHandler : null,
210+
onlyHash: request.query['only-hash']
209211
}
210212

211213
const aborter = abortable()

test/cli/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ describe('config', () => runOnAndOff((thing) => {
6868
})
6969

7070
it('call config with no arguments', () => {
71-
return ipfs.fail('config')
71+
return ipfs('config')
72+
.then(out => expect(out).to.include('bin.js config <key> [value]'))
7273
})
7374
})
7475

test/cli/files.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
'use strict'
33

44
const fs = require('fs')
5+
const os = require('os')
56
const expect = require('chai').expect
67
const path = require('path')
78
const compareDir = require('dir-compare').compareSync
@@ -270,6 +271,35 @@ describe('files', () => runOnAndOff((thing) => {
270271
})
271272
})
272273

274+
it('add --only-hash outputs correct hash', function () {
275+
return ipfs('files add --only-hash src/init-files/init-docs/readme')
276+
.then(out =>
277+
expect(out)
278+
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB readme\n')
279+
)
280+
})
281+
282+
it('add --only-hash does not add a file to the datastore', function () {
283+
this.timeout(30 * 1000)
284+
this.slow(10 * 1000)
285+
const content = String(Math.random() + Date.now())
286+
const filepath = path.join(os.tmpdir(), `${content}.txt`)
287+
fs.writeFileSync(filepath, content)
288+
289+
return ipfs(`files add --only-hash ${filepath}`)
290+
.then(out => {
291+
const hash = out.split(' ')[1]
292+
293+
// 'jsipfs object get <hash>' should timeout with the daemon on
294+
// and should fail fast with the daemon off
295+
return Promise.race([
296+
ipfs.fail(`object get ${hash}`),
297+
new Promise((resolve, reject) => setTimeout(resolve, 4000))
298+
])
299+
.then(() => fs.unlinkSync(filepath))
300+
})
301+
})
302+
273303
it('cat', function () {
274304
this.timeout(30 * 1000)
275305

test/http-api/files.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* eslint-env mocha */
2+
/* eslint max-nested-callbacks: ["error", 8] */
3+
'use strict'
4+
5+
const chai = require('chai')
6+
const dirtyChai = require('dirty-chai')
7+
const DaemonFactory = require('ipfsd-ctl')
8+
const expect = chai.expect
9+
chai.use(dirtyChai)
10+
11+
const df = DaemonFactory.create({ exec: 'src/cli/bin.js' })
12+
13+
describe('.files', () => {
14+
let ipfs = null
15+
let ipfsd = null
16+
before(function (done) {
17+
this.timeout(20 * 1000)
18+
df.spawn({ initOptions: { bits: 512 } }, (err, _ipfsd) => {
19+
expect(err).to.not.exist()
20+
ipfsd = _ipfsd
21+
ipfs = ipfsd.api
22+
done()
23+
})
24+
})
25+
26+
after(function (done) {
27+
this.timeout(10 * 1000)
28+
ipfsd.stop(done)
29+
})
30+
31+
describe('.add', function () {
32+
it('performs a speculative add, --only-hash', () => {
33+
const content = String(Math.random())
34+
35+
return ipfs.add(Buffer.from(content), { onlyHash: true })
36+
.then(files => {
37+
const getAttempt = ipfs.object.get(files[0].hash)
38+
.then(() => {
39+
throw new Error('Should not find an object for content added with --only-hash')
40+
})
41+
42+
return Promise.race([
43+
getAttempt,
44+
new Promise((resolve, reject) => setTimeout(resolve, 4000))
45+
])
46+
})
47+
})
48+
})
49+
})

test/utils/ipfs-exec.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,28 @@ module.exports = (repoPath, opts) => {
5151
return res
5252
}
5353

54+
/**
55+
* Expect the command passed as @param arguments to fail.
56+
* @return {Promise} Resolves if the command passed as @param arguments fails,
57+
* rejects if it was successful.
58+
*/
5459
ipfs.fail = function ipfsFail () {
5560
let args = Array.from(arguments)
61+
let caught = false
5662
if (args.length === 1) {
5763
args = args[0].split(' ')
5864
}
5965

60-
return exec(args).catch((err) => {
61-
expect(err).to.exist()
62-
})
66+
return exec(args)
67+
.catch(err => {
68+
caught = true
69+
expect(err).to.exist()
70+
})
71+
.then(() => {
72+
if (!caught) {
73+
throw new Error(`jsipfs expected to fail during command: jsipfs ${args.join(' ')}`)
74+
}
75+
})
6376
}
6477

6578
return ipfs

0 commit comments

Comments
 (0)