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

Commit 84de6be

Browse files
JonKronedaviddias
authored andcommitted
feat: jsipfs add --only-hash (#1233)
* add --only-hash flag * skeleton http option passing, checkpoint commit to check some broken tests. * deep logging for debugging. Checkpoint * found the levledown problem! line endings! * add only-hash as a qs option for the send-files-stream. Also added some tests to help me figure that out * update --only-hash test, increase timeout for the afterAll hook. I think it takes longer because the --only-hash test leaves an unresolved ipfs.ls command. Would love to be able to cancel it :) * ipfs-exec/ipfs.fail should throw on a non-failing command && use random file for ipfs add --only-hash test. * fix an ipfs config test. * lint * clean: move test/http-api/extra/files.js to test/http-api/files.js
1 parent e174866 commit 84de6be

File tree

7 files changed

+104
-10
lines changed

7 files changed

+104
-10
lines changed

src/cli/commands/files/add.js

+9-3
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
@@ -182,7 +188,8 @@ module.exports = {
182188
strategy: argv.trickle ? 'trickle' : 'balanced',
183189
shardSplitThreshold: argv.enableShardingExperiment ? argv.shardSplitThreshold : Infinity,
184190
'cid-version': argv['cid-version'],
185-
'raw-leaves': argv['raw-leaves']
191+
'raw-leaves': argv['raw-leaves'],
192+
onlyHash: argv['only-hash']
186193
}
187194

188195
// Temporary restriction on raw-leaves:
@@ -230,8 +237,7 @@ module.exports = {
230237
}
231238
}
232239

233-
const thing = (cb) => cb(null, ipfs.files.addPullStream(options))
234-
thing(next)
240+
next(null, ipfs.files.addPullStream(options))
235241
}
236242
], (err, addStream) => {
237243
if (err) throw err

src/core/components/files.js

+1-1
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

+4-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ exports.add = {
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 })
@@ -205,7 +206,8 @@ exports.add = {
205206
const options = {
206207
'cid-version': request.query['cid-version'],
207208
'raw-leaves': request.query['raw-leaves'],
208-
progress: request.query['progress'] ? progressHandler : null
209+
progress: request.query.progress ? progressHandler : null,
210+
onlyHash: Boolean(request.query['only-hash'])
209211
}
210212

211213
const aborter = abortable()

test/cli/config.js

+2-1
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

+30
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

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
chai.use(dirtyChai)
8+
9+
describe('.files', () => {
10+
let ipfs = null
11+
let ipfsd = null
12+
before(function (done) {
13+
this.timeout(20 * 1000)
14+
df.spawn({ initOptions: { bits: 512 } }, (err, _ipfsd) => {
15+
expect(err).to.not.exist()
16+
ipfsd = _ipfsd
17+
ipfs = ipfsd.api
18+
done()
19+
})
20+
})
21+
22+
after((done) => ipfsd.stop(done))
23+
24+
describe('.add', function () {
25+
it('performs a speculative add, --only-hash', () => {
26+
const content = String(Math.random())
27+
28+
return ipfs.add(Buffer.from(content), { onlyHash: true })
29+
.then(files => {
30+
const getAttempt = ipfs.object.get(files[0].hash)
31+
.then(() => {
32+
throw new Error('Should not find an object for content added with --only-hash')
33+
})
34+
35+
return Promise.race([
36+
getAttempt,
37+
new Promise((resolve, reject) => setTimeout(resolve, 4000))
38+
])
39+
})
40+
})
41+
})
42+
})

test/utils/ipfs-exec.js

+16-3
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)