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

Commit

Permalink
feat: jsipfs add --only-hash (#1233) (#1266)
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddias authored Mar 17, 2018
1 parent f7eaa43 commit bddc5b4
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 18 deletions.
24 changes: 16 additions & 8 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 @@ -180,9 +186,12 @@ module.exports = {
const index = inPath.lastIndexOf('/') + 1
const options = {
strategy: argv.trickle ? 'trickle' : 'balanced',
shardSplitThreshold: argv.enableShardingExperiment ? argv.shardSplitThreshold : Infinity,
'cid-version': argv['cid-version'],
'raw-leaves': argv['raw-leaves']
shardSplitThreshold: argv.enableShardingExperiment
? argv.shardSplitThreshold
: Infinity,
cidVersion: argv.cidVersion,
rawLeaves: argv.rawLeaves,
onlyHash: argv.onlyHash
}

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

if (argv['raw-leaves']) {
if (options.rawLeaves) {
throw new Error('Not implemented: raw-leaves')
}

if (argv.enableShardingExperiment && utils.isDaemonOn()) {
if (options.enableShardingExperiment && utils.isDaemonOn()) {
throw new Error('Error: Enabling the sharding experiment should be done on the daemon')
}
const ipfs = argv.ipfs
Expand Down Expand Up @@ -230,8 +239,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
12 changes: 7 additions & 5 deletions src/http/api/resources/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ exports.add = {
// cid-version > 0 unless explicitly set to false.
//
// This retains feature parity without having to implement raw-leaves.
'raw-leaves': Joi.any().when('cid-version', {
'raw-leaves': Joi.boolean().when('cid-version', {
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 @@ -203,9 +204,10 @@ exports.add = {
}

const options = {
'cid-version': request.query['cid-version'],
'raw-leaves': request.query['raw-leaves'],
progress: request.query['progress'] ? progressHandler : null
cidVersion: request.query['cid-version'],
rawLeaves: request.query['raw-leaves'],
progress: request.query.progress ? progressHandler : null,
onlyHash: 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
49 changes: 49 additions & 0 deletions test/http-api/files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'

const chai = require('chai')
const dirtyChai = require('dirty-chai')
const DaemonFactory = require('ipfsd-ctl')
const expect = chai.expect
chai.use(dirtyChai)

const df = DaemonFactory.create({ exec: 'src/cli/bin.js' })

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(function (done) {
this.timeout(10 * 1000)
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

0 comments on commit bddc5b4

Please sign in to comment.