diff --git a/src/cli/commands/ls.js b/src/cli/commands/ls.js new file mode 100644 index 0000000000..f17afaa415 --- /dev/null +++ b/src/cli/commands/ls.js @@ -0,0 +1,60 @@ +'use strict' + +const {print, rightpad} = require('../utils') +const Unixfs = require('ipfs-unixfs') + +module.exports = { + command: 'ls ', + + describe: 'List files for the given directory', + + builder: { + v: { + alias: 'headers', + desc: 'Print table headers (Hash, Size, Name).', + type: 'boolean', + default: false + }, + 'resolve-type': { + desc: 'Resolve linked objects to find out their types. (not implemented yet)', + type: 'boolean', + default: false // should be true when implemented + } + }, + + handler (argv) { + let path = argv.key + if (path.startsWith('/ipfs/')) { + path = path.replace('/ipfs/', '') + } + + argv.ipfs.object.get(path, {enc: 'base58'}, (err, node) => { + if (err) { + throw err + } + let {data, links} = node.toJSON() + + const fileDesc = Unixfs.unmarshal(data) + if (fileDesc.type !== 'directory') { + throw new Error('merkeldag node was not a directory') // TODO: support shards + } + + if (argv['resolve-type']) { + throw new Error('--resolve-type not implemented yet') + } + + if (argv.headers) { + links = [{multihash: 'Hash', size: 'Size', name: 'Name'}].concat(links) + } + + const multihashWidth = Math.max.apply(null, links.map((file) => String(file.multihash).length)) + const sizeWidth = Math.max.apply(null, links.map((file) => String(file.size).length)) + + links.forEach((file) => { + print(rightpad(file.multihash, multihashWidth + 1) + + rightpad(file.size, sizeWidth + 1) + + file.name) + }) + }) + } +} diff --git a/src/cli/utils.js b/src/cli/utils.js index 4565fc316e..d44bf4b4fd 100644 --- a/src/cli/utils.js +++ b/src/cli/utils.js @@ -100,3 +100,11 @@ exports.createProgressBar = (totalBytes) => { total: totalBytes }) } + +exports.rightpad = (val, n) => { + let result = String(val) + for (let i = result.length; i < n; ++i) { + result += ' ' + } + return result +} diff --git a/test/cli/commands.js b/test/cli/commands.js index 94ffb4aad4..e6d9059d36 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,7 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 56 +const commandCount = 57 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/cli/files.js b/test/cli/files.js index c07762e1f3..1420a63620 100644 --- a/test/cli/files.js +++ b/test/cli/files.js @@ -254,6 +254,46 @@ describe('files', () => runOnAndOff((thing) => { }) }) + it('ls', () => { + return ipfs('ls QmYmW4HiZhotsoSqnv2o1oUusvkRM8b9RweBoH7ao5nki2') + .then((out) => { + expect(out).to.eql( + 'QmQQHYDwAQms78fPcvx1uFFsfho23YJNoewfLbi9AtdyJ9 123530 blocks\n' + + 'QmPkWYfSLCEBLZu7BZt4kigGDMe3cpogMbeVf97gN2xJDN 3939 config\n' + + 'Qma13ZrhKG52MWnwtZ6fMD8jGj8d4Q9sJgn5xtKgeZw5uz 5503 datastore\n' + + 'QmUhUuiTKkkK8J6JZ9zmj8iNHPuNfGYcszgRumzhHBxEEU 7397 init-docs\n' + + 'QmR56UJmAaZLXLdTT1ALrE9vVqV8soUEekm9BMd4FnuYqV 10 version\n') + }) + }) + + it('ls -v', () => { + return ipfs('ls /ipfs/QmYmW4HiZhotsoSqnv2o1oUusvkRM8b9RweBoH7ao5nki2 -v') + .then((out) => { + expect(out).to.eql( + 'Hash Size Name\n' + + 'QmQQHYDwAQms78fPcvx1uFFsfho23YJNoewfLbi9AtdyJ9 123530 blocks\n' + + 'QmPkWYfSLCEBLZu7BZt4kigGDMe3cpogMbeVf97gN2xJDN 3939 config\n' + + 'Qma13ZrhKG52MWnwtZ6fMD8jGj8d4Q9sJgn5xtKgeZw5uz 5503 datastore\n' + + 'QmUhUuiTKkkK8J6JZ9zmj8iNHPuNfGYcszgRumzhHBxEEU 7397 init-docs\n' + + 'QmR56UJmAaZLXLdTT1ALrE9vVqV8soUEekm9BMd4FnuYqV 10 version\n') + }) + }) + + it('ls --help', () => { + return ipfs('ls --help') + .then((out) => { + expect(out.split('\n').slice(1)).to.eql(['', + 'Options:', + ' -q, --quiet suppress output [boolean]', + ' --help Show help [boolean]', + ' -v, --headers Print table headers (Hash, Size, Name).', + ' [boolean] [default: false]', + ' --resolve-type Resolve linked objects to find out their types. (not', + ' implemented yet) [boolean] [default: false]', + '', '']) + }) + }) + it('get', () => { return ipfs('files get QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB') .then((out) => {