diff --git a/src/cli/commands/pin/add.js b/src/cli/commands/pin/add.js new file mode 100644 index 0000000000..a0ff92806b --- /dev/null +++ b/src/cli/commands/pin/add.js @@ -0,0 +1,73 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') +const debug = require('debug') +const log = debug('cli:pin') +log.error = debug('cli:pin:error') +const bs58 = require('bs58') + +module.exports = Command.extend({ + desc: 'Pins objects to local storage.', + + options: { + // Recursively pin the object linked to by the specified object(s) + recursive: { + alias: 'r', + type: 'boolean', + default: true + } + }, + + run: (recursive, path) => { + utils.getIPFS((err, ipfs) => { + if (err) { + console.error(err) + throw err + } + const matched = path.match(/^(?:\/ipfs\/)?([^\/]+(?:\/[^\/]+)*)\/?$/) + if (!matched) { + err = new Error('invalid ipfs ref path') + console.error(err) + throw err + } + const split = matched[1].split('/') + const rootHash = split[0] + const key = new Buffer(bs58.decode(rootHash)) + const links = split.slice(1, split.length) + const pathFn = (err, obj) => { + if (err) { + console.error(err) + throw err + } + if (links.length) { + const linkName = links.shift() + const nextLink = obj.links.filter((link) => { + return (link.name === linkName) + }) + if (!nextLink.length) { + err = new Error( + 'pin: no link named ' + linkName + + ' under ' + obj.toJSON().Hash + ) + console.error(err) + throw err + } + const nextHash = nextLink[0].hash + ipfs.object.get(nextHash, pathFn) + } else { + ipfs.pinner.pin(obj, recursive, (err) => { + if (err) { + console.error(err) + throw err + } + const mode = recursive ? ' recursively' : ' directly' + console.log('pinned ' + obj.toJSON().Hash + mode) + }) + } + } + + ipfs.object.get(key, pathFn) + }) + } +}) diff --git a/test/cli/test-pin.js b/test/cli/test-pin.js new file mode 100644 index 0000000000..3a7892a9f3 --- /dev/null +++ b/test/cli/test-pin.js @@ -0,0 +1,58 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const nexpect = require('nexpect') +const repoPath = require('./index').repoPath +const _ = require('lodash') + +// use a tree of ipfs objects for recursive tests: +// root +// |`leaf +// `branch +// `subLeaf + +const filenames = [ + 'root.json', 'leaf.json', 'branch.json', 'subLeaf.json' +] +const keys = { + 'root.json': 'QmWQwS2Xh1SFGMPzUVYQ52b7RC7fTfiaPHm3ZyTRZuHmer', + 'leaf.json': 'QmaZoTQ6wFe7EtvaePBUeXavfeRqCAq3RUMomFxBpZLrLA', + 'branch.json': 'QmNxjjP7dtx6pzxWGBRCrgmjX3JqKL7uF2Kjx7ExiZDbSB', + 'subLeaf.json': 'QmUzzznkyQL7FjjBztG3D1tTjBuxeArLceDZnuSowUggXL' +} +const rootHash = keys['root.json'] + +describe('pin', function () { + this.timeout(20 * 1000) + const env = _.clone(process.env) + env.IPFS_PATH = repoPath + const opts = {env: env, stream: 'all'} + const bin = process.cwd() + '/src/cli/bin.js' + const filesDir = process.cwd() + '/test/test-data/tree/' + + before((done) => { + var doneCount = 0 + filenames.forEach((filename) => { + const hash = keys[filename] + nexpect.spawn('node', [bin, 'object', 'put', filesDir + filename], opts) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(stdout[0]).to.equal('added ' + hash) + doneCount === filenames.length - 1 ? done() : doneCount++ + }) + }) + }) + + describe('api offline', () => { + it('add (recursively by default)', (done) => { + nexpect.spawn('node', [bin, 'pin', 'add', rootHash], opts) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout[0]).to.equal('pinned ' + rootHash + ' recursively') + done() + }) + }) + }) +}) diff --git a/test/test-data/tree/branch.json b/test/test-data/tree/branch.json new file mode 100644 index 0000000000..459498c85c --- /dev/null +++ b/test/test-data/tree/branch.json @@ -0,0 +1 @@ +{"Links":[{"Name":"subLeaf","Hash":"QmUzzznkyQL7FjjBztG3D1tTjBuxeArLceDZnuSowUggXL","Size":15}],"Data":"\u0008\u0001"} diff --git a/test/test-data/tree/leaf.json b/test/test-data/tree/leaf.json new file mode 100644 index 0000000000..547be2cd24 --- /dev/null +++ b/test/test-data/tree/leaf.json @@ -0,0 +1 @@ +{"Links":[],"Data":"\u0008\u0002\u0012\u0004leaf\u0018\u0004"} diff --git a/test/test-data/tree/root.json b/test/test-data/tree/root.json new file mode 100644 index 0000000000..22f1229788 --- /dev/null +++ b/test/test-data/tree/root.json @@ -0,0 +1 @@ +{"Links":[{"Name":"leaf","Hash":"QmaZoTQ6wFe7EtvaePBUeXavfeRqCAq3RUMomFxBpZLrLA","Size":12},{"Name":"branch","Hash":"QmNxjjP7dtx6pzxWGBRCrgmjX3JqKL7uF2Kjx7ExiZDbSB","Size":68}],"Data":"\u0008\u0001"} diff --git a/test/test-data/tree/subLeaf.json b/test/test-data/tree/subLeaf.json new file mode 100644 index 0000000000..d77789e6f0 --- /dev/null +++ b/test/test-data/tree/subLeaf.json @@ -0,0 +1 @@ +{"Links":[],"Data":"\u0008\u0002\u0012\u0007subLeaf\u0018\u0007"}