From 1e1531fd2ff085d36b8661084be8f2b27a9cc356 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Thu, 26 Nov 2020 15:13:53 +0000 Subject: [PATCH] docs: document type field in ipfs.get output (#3424) Also adds a test for deeply nested directories Co-authored-by: Hugo Dias --- docs/core-api/FILES.md | 13 ++++--- packages/interface-ipfs-core/src/get.js | 48 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/docs/core-api/FILES.md b/docs/core-api/FILES.md index 1cba93d31b..e1b21a1390 100644 --- a/docs/core-api/FILES.md +++ b/docs/core-api/FILES.md @@ -460,8 +460,9 @@ Each yielded object is of the form: ```js { - path: string, - content: >, + type: string, // 'file' or 'dir' + path: string, // a deeply nested path within the directory structure + content?: >, // only present if `type` is 'file' mode: Number, // implicit if not provided - 0644 for files, 0755 for directories mtime?: { secs: Number, nsecs: Number } } @@ -475,13 +476,13 @@ Here, each `path` corresponds to the name of a file, and `content` is an async i const cid = 'QmQ2r6iMNpky5f1m4cnm3Yqw8VSvjuKpTcK1X7dBR1LkJF' for await (const file of ipfs.get(cid)) { - console.log(file.path) + console.log(file.type, file.path) if (!file.content) continue; const content = [] -for await (const chunk of file.content) { + for await (const chunk of file.content) { content.push(chunk) } @@ -489,6 +490,10 @@ for await (const chunk of file.content) { } ``` +When invoking this method via the HTTP API client, the response arrives as a stream containing either the entire contents of the file (if the passed [CID][] resolves to a file) or recursive directory tree and all files contained therein (if the passed [CID][] resolves to a directory). + +If you are iterating over a directory, in order to proceed to the next entry in the stream, you must consume the `content` field of the current entry if it is present. + A great source of [examples](https://github.com/ipfs/js-ipfs/blob/master/packages/interface-ipfs-core/src/get.js) can be found in the tests for this API. ### `ipfs.ls(ipfsPath)` diff --git a/packages/interface-ipfs-core/src/get.js b/packages/interface-ipfs-core/src/get.js index 32a0751d55..2d05173796 100644 --- a/packages/interface-ipfs-core/src/get.js +++ b/packages/interface-ipfs-core/src/get.js @@ -9,6 +9,7 @@ const CID = require('cids') const all = require('it-all') const drain = require('it-drain') const last = require('it-last') +const map = require('it-map') const { getDescribe, getIt, expect } = require('./utils/mocha') const testTimeout = require('./utils/test-timeout') const importer = require('ipfs-unixfs-importer') @@ -158,6 +159,53 @@ module.exports = (common, options) => { ]) }) + it('should get a nested directory', async function () { + const content = (name, path) => ({ + path: `test-folder/${path}`, + content: fixtures.directory.files[name] + }) + + const dirs = [ + content('pp.txt', 'pp.txt'), + content('holmes.txt', 'foo/holmes.txt'), + content('jungle.txt', 'foo/bar/jungle.txt') + ] + + const res = await all(importer(dirs, ipfs.block)) + const root = res[res.length - 1] + expect(root.path).to.equal('test-folder') + expect(root.cid.toString()).to.equal('QmVMXXo3c2bDPH9ayy2VKoXpykfYJHwAcU5YCJjPf7jg3g') + + let files = await all( + map(ipfs.get(root.cid), async ({ path, content }) => { + content = content ? uint8ArrayToString(uint8ArrayConcat(await all(content))) : null + return { path, content } + }) + ) + + files = files.sort((a, b) => { + if (a.path > b.path) return 1 + if (a.path < b.path) return -1 + return 0 + }) + + // Check paths + const paths = files.map((file) => { return file.path }) + expect(paths).to.include.members([ + 'QmVMXXo3c2bDPH9ayy2VKoXpykfYJHwAcU5YCJjPf7jg3g', + 'QmVMXXo3c2bDPH9ayy2VKoXpykfYJHwAcU5YCJjPf7jg3g/pp.txt', + 'QmVMXXo3c2bDPH9ayy2VKoXpykfYJHwAcU5YCJjPf7jg3g/foo/holmes.txt', + 'QmVMXXo3c2bDPH9ayy2VKoXpykfYJHwAcU5YCJjPf7jg3g/foo/bar/jungle.txt' + ]) + + // Check contents + expect(files.map(f => f.content)).to.include.members([ + fixtures.directory.files['pp.txt'].toString(), + fixtures.directory.files['holmes.txt'].toString(), + fixtures.directory.files['jungle.txt'].toString() + ]) + }) + it('should get with ipfs path, as object and nested value', async () => { const file = { path: 'a/testfile.txt',