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

Commit

Permalink
feat: ipfs.ls (#1073)
Browse files Browse the repository at this point in the history
  • Loading branch information
pgte authored and daviddias committed Nov 14, 2017
1 parent 7dd4e01 commit 35687cb
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 8 deletions.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@
"form-data": "^2.3.1",
"gulp": "^3.9.1",
"hat": "0.0.3",
"interface-ipfs-core": "~0.33.2",
"ipfsd-ctl": "~0.24.0",
"interface-ipfs-core": "~0.34.3",
"ipfsd-ctl": "~0.24.1",
"left-pad": "^1.1.3",
"lodash": "^4.17.4",
"mocha": "^4.0.1",
Expand Down Expand Up @@ -105,18 +105,18 @@
"hapi": "^16.6.2",
"hapi-set-header": "^1.0.2",
"hoek": "^5.0.2",
"ipfs-api": "^15.0.1",
"ipfs-api": "^15.1.0",
"ipfs-bitswap": "~0.17.4",
"ipfs-block": "~0.6.1",
"ipfs-block-service": "~0.13.0",
"ipfs-multipart": "~0.1.0",
"ipfs-repo": "~0.18.3",
"ipfs-unixfs": "~0.1.14",
"ipfs-unixfs-engine": "~0.23.1",
"ipfs-unixfs-engine": "~0.24.1",
"ipld-resolver": "~0.14.1",
"is-ipfs": "^0.3.2",
"is-stream": "^1.1.0",
"joi": "^13.0.1",
"joi": "^13.0.2",
"libp2p": "~0.13.1",
"libp2p-circuit": "~0.1.4",
"libp2p-floodsub": "~0.11.1",
Expand Down Expand Up @@ -157,7 +157,7 @@
"readable-stream": "2.3.3",
"safe-buffer": "^5.1.1",
"stream-to-pull-stream": "^1.7.2",
"tar-stream": "^1.5.4",
"tar-stream": "^1.5.5",
"temp": "~0.8.3",
"through2": "^2.0.3",
"update-notifier": "^2.3.0",
Expand Down
58 changes: 58 additions & 0 deletions src/cli/commands/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'

const utils = require('../utils')
const Unixfs = require('ipfs-unixfs')
const pull = require('pull-stream')

module.exports = {
command: 'ls <key>',

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.ls(path, (err, links) => {
if (err) {
throw err
}

if (argv.headers) {
links = [{hash: 'Hash', size: 'Size', name: 'Name'}].concat(links)
}

links = links.filter((link) => link.path !== path)
links.forEach((link) => {
if (link.type === 'dir') {
// directory: add trailing "/"
link.name = (link.name || '') + '/'
}
})
const multihashWidth = Math.max.apply(null, links.map((file) => file.hash.length))
const sizeWidth = Math.max.apply(null, links.map((file) => String(file.size).length))

links.forEach((file) => {
utils.print(utils.rightpad(file.hash, multihashWidth + 1) +
utils.rightpad(file.size || '', sizeWidth + 1) +
file.name)
})
})
}
}
8 changes: 8 additions & 0 deletions src/cli/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
16 changes: 15 additions & 1 deletion src/core/components/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const waterfall = require('async/waterfall')
const isStream = require('is-stream')
const Duplex = require('stream').Duplex
const CID = require('cids')
const toB58String = require('multihashes').toB58String

module.exports = function files (self) {
const createAddPullStream = (options) => {
Expand Down Expand Up @@ -118,7 +119,20 @@ module.exports = function files (self) {

getPull: promisify((ipfsPath, callback) => {
callback(null, exporter(ipfsPath, self._ipldResolver))
})
}),

immutableLs: promisify((ipfsPath, callback) => {
pull(
self.files.immutableLsPullStream(ipfsPath),
pull.collect(callback))
}),

immutableLsPullStream: (ipfsPath) => {
return pull(
exporter(ipfsPath, self._ipldResolver, { maxDepth: 1 }),
pull.filter((node) => node.depth === 1),
pull.map((node) => Object.assign({}, node, { hash: toB58String(node.hash) })))
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class IPFS extends EventEmitter {

this.state = require('./state')(this)

// ipfs.ls
this.ls = this.files.immutableLs

boot(this)
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/http/api/resources/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,47 @@ exports.add = {
)
}
}

exports.immutableLs = {
// uses common parseKey method that returns a `key`
parseArgs: exports.parseKey,

// main route handler which is called after the above `parseArgs`, but only if the args were valid
handler: (request, reply) => {
const key = request.pre.args.key
const ipfs = request.server.app.ipfs

ipfs.ls(key, (err, files) => {
if (err) {
reply({
Message: 'Failed to list dir: ' + err.message,
Code: 0
}).code(500)
}

reply({
Objects: [{
Hash: key,
Links: files.map((file) => ({
Name: file.name,
Hash: file.hash,
Size: file.size,
Type: toTypeCode(file.type)
}))
}]
})
})
}
}

function toTypeCode (type) {
switch (type) {
case 'dir':
return 1
case 'file':
return 2
default:
return 0
}
}

12 changes: 12 additions & 0 deletions src/http/api/routes/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,16 @@ module.exports = (server) => {
validate: resources.files.add.validate
}
})

api.route({
// TODO fix method
method: '*',
path: '/api/v0/ls',
config: {
pre: [
{ method: resources.files.immutableLs.parseArgs, assign: 'args' }
],
handler: resources.files.immutableLs.handler
}
})
}
2 changes: 1 addition & 1 deletion test/cli/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 43 additions & 0 deletions test/cli/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,49 @@ 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(['',
'List files for the given directory',
'',
'Options:',
' -v, --version Show version number [boolean]',
' --silent Show no 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) => {
Expand Down

0 comments on commit 35687cb

Please sign in to comment.