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

feat: jsipfs add --only-hash #1233

Merged
merged 10 commits into from
Mar 16, 2018
12 changes: 9 additions & 3 deletions src/cli/commands/files/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ module.exports = {
type: 'boolean',
default: false
},
'only-hash': {
alias: 'n',
type: 'boolean',
default: false,
describe: 'Only chunk and hash, do not write'
},
'enable-sharding-experiment': {
type: 'boolean',
default: false
Expand Down Expand Up @@ -182,7 +188,8 @@ module.exports = {
strategy: argv.trickle ? 'trickle' : 'balanced',
shardSplitThreshold: argv.enableShardingExperiment ? argv.shardSplitThreshold : Infinity,
'cid-version': argv['cid-version'],
'raw-leaves': argv['raw-leaves']
'raw-leaves': argv['raw-leaves'],
onlyHash: argv['only-hash']
}

// Temporary restriction on raw-leaves:
Expand Down Expand Up @@ -230,8 +237,7 @@ module.exports = {
}
}

const thing = (cb) => cb(null, ipfs.files.addPullStream(options))
thing(next)
next(null, ipfs.files.addPullStream(options))
}
], (err, addStream) => {
if (err) throw err
Expand Down
2 changes: 1 addition & 1 deletion src/core/components/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function prepareFile (self, opts, file, callback) {
opts = opts || {}

waterfall([
(cb) => self.object.get(file.multihash, cb),
(cb) => opts.onlyHash ? cb(null, file) : self.object.get(file.multihash, cb),
(node, cb) => {
let cid = new CID(node.multihash)

Expand Down
6 changes: 4 additions & 2 deletions src/http/api/resources/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ exports.add = {
is: 1,
then: Joi.boolean().valid(false).required(),
otherwise: Joi.boolean().valid(false)
})
}),
'only-hash': Joi.boolean()
})
// TODO: Necessary until validate "recursive", "stream-channels" etc.
.options({ allowUnknown: true })
Expand Down Expand Up @@ -205,7 +206,8 @@ exports.add = {
const options = {
'cid-version': request.query['cid-version'],
'raw-leaves': request.query['raw-leaves'],
progress: request.query['progress'] ? progressHandler : null
progress: request.query.progress ? progressHandler : null,
onlyHash: Boolean(request.query['only-hash'])
}

const aborter = abortable()
Expand Down
3 changes: 2 additions & 1 deletion test/cli/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ describe('config', () => runOnAndOff((thing) => {
})

it('call config with no arguments', () => {
return ipfs.fail('config')
return ipfs('config')
.then(out => expect(out).to.include('bin.js config <key> [value]'))
})
})

Expand Down
30 changes: 30 additions & 0 deletions test/cli/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
'use strict'

const fs = require('fs')
const os = require('os')
const expect = require('chai').expect
const path = require('path')
const compareDir = require('dir-compare').compareSync
Expand Down Expand Up @@ -270,6 +271,35 @@ describe('files', () => runOnAndOff((thing) => {
})
})

it('add --only-hash outputs correct hash', function () {
return ipfs('files add --only-hash src/init-files/init-docs/readme')
.then(out =>
expect(out)
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB readme\n')
)
})

it('add --only-hash does not add a file to the datastore', function () {
this.timeout(30 * 1000)
this.slow(10 * 1000)
const content = String(Math.random() + Date.now())
const filepath = path.join(os.tmpdir(), `${content}.txt`)
fs.writeFileSync(filepath, content)

return ipfs(`files add --only-hash ${filepath}`)
.then(out => {
const hash = out.split(' ')[1]

// 'jsipfs object get <hash>' should timeout with the daemon on
// and should fail fast with the daemon off
return Promise.race([
ipfs.fail(`object get ${hash}`),
new Promise((resolve, reject) => setTimeout(resolve, 4000))
])
.then(() => fs.unlinkSync(filepath))
})
})

it('cat', function () {
this.timeout(30 * 1000)

Expand Down
42 changes: 42 additions & 0 deletions test/http-api/files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'

const chai = require('chai')
const dirtyChai = require('dirty-chai')
chai.use(dirtyChai)

describe('.files', () => {
let ipfs = null
let ipfsd = null
before(function (done) {
this.timeout(20 * 1000)
df.spawn({ initOptions: { bits: 512 } }, (err, _ipfsd) => {
expect(err).to.not.exist()
ipfsd = _ipfsd
ipfs = ipfsd.api
done()
})
})

after((done) => ipfsd.stop(done))

describe('.add', function () {
it('performs a speculative add, --only-hash', () => {
const content = String(Math.random())

return ipfs.add(Buffer.from(content), { onlyHash: true })
.then(files => {
const getAttempt = ipfs.object.get(files[0].hash)
.then(() => {
throw new Error('Should not find an object for content added with --only-hash')
})

return Promise.race([
getAttempt,
new Promise((resolve, reject) => setTimeout(resolve, 4000))
])
})
})
})
})
19 changes: 16 additions & 3 deletions test/utils/ipfs-exec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,28 @@ module.exports = (repoPath, opts) => {
return res
}

/**
* Expect the command passed as @param arguments to fail.
* @return {Promise} Resolves if the command passed as @param arguments fails,
* rejects if it was successful.
*/
ipfs.fail = function ipfsFail () {
let args = Array.from(arguments)
let caught = false
if (args.length === 1) {
args = args[0].split(' ')
}

return exec(args).catch((err) => {
expect(err).to.exist()
})
return exec(args)
.catch(err => {
caught = true
expect(err).to.exist()
})
.then(() => {
if (!caught) {
throw new Error(`jsipfs expected to fail during command: jsipfs ${args.join(' ')}`)
}
})
}

return ipfs
Expand Down