From 80ac58ca27cc9f21823a23d1e6357f738fdb6781 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Mon, 6 Dec 2021 16:23:05 +0000 Subject: [PATCH] fix: ensure directory is passed (#3968) Fixes bug where importing files directly was broken --- packages/ipfs-cli/src/commands/add.js | 69 ++++++++++++++++++++++++--- packages/ipfs-cli/test/add.spec.js | 44 +++++++++++++++++ 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/packages/ipfs-cli/src/commands/add.js b/packages/ipfs-cli/src/commands/add.js index a79e10069f..c05657d027 100644 --- a/packages/ipfs-cli/src/commands/add.js +++ b/packages/ipfs-cli/src/commands/add.js @@ -14,6 +14,8 @@ import { import globSource from 'ipfs-utils/src/files/glob-source.js' import parseDuration from 'parse-duration' import merge from 'it-merge' +import fs from 'fs' +import path from 'path' const getFolderSize = promisify(getFolderSizeCb) @@ -25,6 +27,64 @@ async function getTotalBytes (paths) { return sizes.reduce((total, size) => total + size, 0) } +/** + * @param {string} target + * @param {object} options + * @param {boolean} [options.recursive] + * @param {boolean} [options.hidden] + * @param {boolean} [options.preserveMode] + * @param {boolean} [options.preserveMtime] + * @param {number} [options.mode] + * @param {import('ipfs-unixfs').MtimeLike} [options.mtime] + */ +async function * getSource (target, options = {}) { + const absolutePath = path.resolve(target) + const stats = await fs.promises.stat(absolutePath) + + if (stats.isFile()) { + let mtime = options.mtime + let mode = options.mode + + if (options.preserveMtime) { + mtime = stats.mtime + } + + if (options.preserveMode) { + mode = stats.mode + } + + yield { + path: path.basename(target), + content: fs.createReadStream(absolutePath), + mtime, + mode + } + + return + } + + const dirName = path.basename(absolutePath) + + let pattern = '*' + + if (options.recursive) { + pattern = '**/*' + } + + for await (const content of globSource(target, pattern, { + hidden: options.hidden, + preserveMode: options.preserveMode, + preserveMtime: options.preserveMtime, + mode: options.mode, + mtime: options.mtime + })) { + yield { + ...content, + path: `${dirName}${content.path}` + } + } +} + export default { command: 'add [file...]', @@ -287,15 +347,10 @@ export default { date = { secs: mtime, nsecs: mtimeNsecs } } - let pattern = '*' - - if (recursive) { - pattern = '**/*' - } - const source = file - ? merge(...file.map(file => globSource(file, pattern, { + ? merge(...file.map(file => getSource(file, { hidden, + recursive, preserveMode, preserveMtime, mode, diff --git a/packages/ipfs-cli/test/add.spec.js b/packages/ipfs-cli/test/add.spec.js index 9f9010869e..39bb5b1022 100644 --- a/packages/ipfs-cli/test/add.spec.js +++ b/packages/ipfs-cli/test/add.spec.js @@ -9,6 +9,8 @@ import { cli } from './utils/cli.js' import sinon from 'sinon' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { matchIterable } from './utils/match-iterable.js' +import all from 'it-all' +import map from 'it-map' // TODO: Test against all algorithms Object.keys(mh.names) // This subset is known to work with both go-ipfs and js-ipfs as of 2017-09-05 @@ -62,6 +64,48 @@ describe('add', () => { const out = await cli('add --progress false README.md', { ipfs }) expect(out).to.equal(`added ${cid} README.md\n`) + + const files = await all(map(ipfs.addAll.getCall(0).args[0], (file) => file.path)) + expect(files).to.deep.equal([ + 'README.md' + ]) + }) + + it('should add a directory', async () => { + const cid = CID.parse('QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB') + + ipfs.addAll.withArgs(matchIterable(), defaultOptions).returns([{ + cid, + path: 'bitswap/index.js' + }, { + cid, + path: 'bitswap/unwant.js' + }, { + cid, + path: 'bitswap/wantlist.js' + }, { + cid, + path: 'bitswap/stat.js' + }, { + cid, + path: 'bitswap' + }]) + ipfs.bases.getBase.withArgs('base58btc').returns(base58btc) + + const out = await cli('add --recursive src/commands/bitswap', { ipfs }) + expect(out).to.include(`added ${cid} bitswap/index.js\n`) + expect(out).to.include(`added ${cid} bitswap/unwant.js\n`) + expect(out).to.include(`added ${cid} bitswap/wantlist.js\n`) + expect(out).to.include(`added ${cid} bitswap/stat.js\n`) + expect(out).to.include(`added ${cid} bitswap\n`) + + const files = await all(map(ipfs.addAll.getCall(0).args[0], (file) => file.path)) + expect(files.sort()).to.deep.equal([ + 'bitswap/index.js', + 'bitswap/unwant.js', + 'bitswap/wantlist.js', + 'bitswap/stat.js' + ].sort()) }) it('should strip control characters from paths when add a file', async () => {