diff --git a/README.md b/README.md index 3c6141043a..02cedf6cf7 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ You can check the development status at the [Waffle Board](https://waffle.io/ipf - [Network](#network) - [Node Management](#node-management) - [Domain data types](#domain-data-types) + - [Util](#util) - [FAQ](#faq) - [Running js-ipfs with Docker](#running-js-ipfs-with-docker) - [Packages](#packages) diff --git a/examples/browser-script-tag/index.html b/examples/browser-script-tag/index.html index 50ef0819e3..f95a295fd7 100644 --- a/examples/browser-script-tag/index.html +++ b/examples/browser-script-tag/index.html @@ -30,7 +30,7 @@
node.files.add(new node.types.Buffer('Hello world!'), (err, filesAdded) => {
if (err) {
- return console.error('Error - ipfs files add', err, res)
+ return console.error('Error - ipfs add', err, res)
}
filesAdded.forEach((file) => console.log('successfully stored', file.hash))
diff --git a/examples/circuit-relaying/package.json b/examples/circuit-relaying/package.json
index 3e92c83f8a..6a3e5cf58d 100644
--- a/examples/circuit-relaying/package.json
+++ b/examples/circuit-relaying/package.json
@@ -18,7 +18,7 @@
"ipfs-pubsub-room": "~0.3.0"
},
"devDependencies": {
- "aegir": "^13.0.5",
+ "aegir": "^14.0.0",
"http-server": "~0.10.0",
"ipfs-css": "~0.2.0",
"parcel-bundler": "^1.6.2",
diff --git a/package.json b/package.json
index 17e945a2e7..a0cff79ad9 100644
--- a/package.json
+++ b/package.json
@@ -108,6 +108,7 @@
"ipfs-block": "~0.7.1",
"ipfs-block-service": "~0.14.0",
"ipfs-http-response": "~0.1.2",
+ "ipfs-mfs": "~0.0.14",
"ipfs-multipart": "~0.1.0",
"ipfs-repo": "~0.22.1",
"ipfs-unixfs": "~0.1.15",
@@ -166,7 +167,8 @@
"through2": "^2.0.3",
"update-notifier": "^2.5.0",
"yargs": "^12.0.1",
- "yargs-parser": "^10.1.0"
+ "yargs-parser": "^10.1.0",
+ "yargs-promise": "^1.1.0"
},
"optionalDependencies": {
"prom-client": "^11.1.1",
diff --git a/src/cli/bin.js b/src/cli/bin.js
index 2ccf2f66a0..3307b6e9ef 100755
--- a/src/cli/bin.js
+++ b/src/cli/bin.js
@@ -2,13 +2,14 @@
'use strict'
+const YargsPromise = require('yargs-promise')
const yargs = require('yargs')
const updateNotifier = require('update-notifier')
const readPkgUp = require('read-pkg-up')
-const fs = require('fs')
-const path = require('path')
const utils = require('./utils')
const print = utils.print
+const mfs = require('ipfs-mfs/cli')
+const debug = require('debug')('ipfs:cli')
const pkg = readPkgUp.sync({cwd: __dirname}).pkg
updateNotifier({
@@ -18,10 +19,6 @@ updateNotifier({
const args = process.argv.slice(2)
-// Determine if the first argument is a sub-system command
-const commandNames = fs.readdirSync(path.join(__dirname, 'commands'))
-const isCommand = commandNames.includes(`${args[0]}.js`)
-
const cli = yargs
.option('silent', {
desc: 'Write no output',
@@ -34,14 +31,6 @@ const cli = yargs
type: 'string',
default: ''
})
- .commandDir('commands', {
- // Only include the commands for the sub-system we're using, or include all
- // if no sub-system command has been passed.
- include (path, filename) {
- if (!isCommand) return true
- return `${args[0]}.js` === filename
- }
- })
.epilog(utils.ipfsPathHelp)
.demandCommand(1)
.fail((msg, err, yargs) => {
@@ -56,20 +45,6 @@ const cli = yargs
yargs.showHelp()
})
-// If not a sub-system command then load the top level aliases
-if (!isCommand) {
- // NOTE: This creates an alias of
- // `jsipfs files {add, get, cat}` to `jsipfs {add, get, cat}`.
- // This will stay until https://github.com/ipfs/specs/issues/98 is resolved.
- const addCmd = require('./commands/files/add')
- const catCmd = require('./commands/files/cat')
- const getCmd = require('./commands/files/get')
- const aliases = [addCmd, catCmd, getCmd]
- aliases.forEach((alias) => {
- cli.command(alias.command, alias.describe, alias.builder, alias.handler)
- })
-}
-
// Need to skip to avoid locking as these commands
// don't require a daemon
if (args[0] === 'daemon' || args[0] === 'init') {
@@ -77,6 +52,8 @@ if (args[0] === 'daemon' || args[0] === 'init') {
.help()
.strict()
.completion()
+ .command(require('./commands/daemon'))
+ .command(require('./commands/init'))
.parse(args)
} else {
// here we have to make a separate yargs instance with
@@ -86,19 +63,61 @@ if (args[0] === 'daemon' || args[0] === 'init') {
if (err) {
throw err
}
+
utils.getIPFS(argv, (err, ipfs, cleanup) => {
- if (err) { throw err }
+ if (err) {
+ throw err
+ }
+
+ // add mfs commands
+ mfs(cli)
+
+ // NOTE: This creates an alias of
+ // `jsipfs files {add, get, cat}` to `jsipfs {add, get, cat}`.
+ // This will stay until https://github.com/ipfs/specs/issues/98 is resolved.
+ const addCmd = require('./commands/files/add')
+ const catCmd = require('./commands/files/cat')
+ const getCmd = require('./commands/files/get')
+ const aliases = [addCmd, catCmd, getCmd]
+ aliases.forEach((alias) => {
+ cli.command(alias)
+ })
cli
+ .commandDir('commands')
.help()
.strict()
.completion()
- .parse(args, { ipfs: ipfs }, (err, argv, output) => {
- if (output) { print(output) }
- cleanup(() => {
- if (err) { throw err }
- })
+ let exitCode = 0
+
+ const parser = new YargsPromise(cli, { ipfs })
+ parser.parse(args)
+ .then(({ data, argv }) => {
+ if (data) {
+ print(data)
+ }
+ })
+ .catch((arg) => {
+ debug(arg)
+
+ // the argument can have a different shape depending on where the error came from
+ if (arg.message) {
+ print(arg.message)
+ } else if (arg.error && arg.error.message) {
+ print(arg.error.message)
+ } else {
+ print('Unknown error, please re-run the command with DEBUG=ipfs:cli to see debug output')
+ }
+
+ exitCode = 1
+ })
+ .then(() => cleanup())
+ .catch(() => {})
+ .then(() => {
+ if (exitCode !== 0) {
+ process.exit(exitCode)
+ }
})
})
})
diff --git a/src/cli/commands/files.js b/src/cli/commands/files.js
deleted file mode 100644
index 1e24b3c226..0000000000
--- a/src/cli/commands/files.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict'
-
-const print = require('../utils').print
-const lsCmd = require('./ls')
-
-module.exports = {
- command: 'files ',
-
- description: 'Operations over files (add, cat, get, ls, etc)',
-
- builder (yargs) {
- return yargs
- .commandDir('files')
- .command(lsCmd)
- },
-
- handler (argv) {
- print('Type `jsipfs files --help` for more instructions')
- }
-}
diff --git a/src/cli/commands/files/get.js b/src/cli/commands/files/get.js
index c177fb8719..d9e0a39a67 100644
--- a/src/cli/commands/files/get.js
+++ b/src/cli/commands/files/get.js
@@ -30,6 +30,7 @@ function fileHandler (dir) {
callback(err)
} else {
const fullFilePath = path.join(dir, file.path)
+
if (file.content) {
file.content
.pipe(fs.createWriteStream(fullFilePath))
diff --git a/src/cli/utils.js b/src/cli/utils.js
index f993e0caef..02f830f6c6 100644
--- a/src/cli/utils.js
+++ b/src/cli/utils.js
@@ -9,6 +9,7 @@ const log = debug('cli')
log.error = debug('cli:error')
const Progress = require('progress')
const byteman = require('byteman')
+const promisify = require('promisify-es6')
exports = module.exports
@@ -40,7 +41,7 @@ function getAPICtl (apiAddr) {
exports.getIPFS = (argv, callback) => {
if (argv.api || isDaemonOn()) {
- return callback(null, getAPICtl(argv.api), (cb) => cb())
+ return callback(null, getAPICtl(argv.api), promisify((cb) => cb()))
}
// Required inline to reduce startup time
@@ -55,13 +56,13 @@ exports.getIPFS = (argv, callback) => {
}
})
- const cleanup = (cb) => {
+ const cleanup = promisify((cb) => {
if (node && node._repo && !node._repo.closed) {
- node._repo.close(() => cb())
+ node._repo.close((err) => cb(err))
} else {
cb()
}
- }
+ })
node.on('error', (err) => {
throw err
diff --git a/src/core/components/index.js b/src/core/components/index.js
index 7221575007..9eb36ad4c3 100644
--- a/src/core/components/index.js
+++ b/src/core/components/index.js
@@ -26,3 +26,4 @@ exports.dht = require('./dht')
exports.dns = require('./dns')
exports.key = require('./key')
exports.stats = require('./stats')
+exports.mfs = require('ipfs-mfs/core')
diff --git a/src/core/config.js b/src/core/config.js
index fe79374ee1..1b04d10a2f 100644
--- a/src/core/config.js
+++ b/src/core/config.js
@@ -7,6 +7,7 @@ const schema = Joi.object().keys({
Joi.object(), // TODO: schema for IPFS repo
Joi.string()
).allow(null),
+ repoOwner: Joi.boolean().default(true),
init: Joi.alternatives().try(
Joi.boolean(),
Joi.object().keys({ bits: Joi.number().integer() })
diff --git a/src/core/index.js b/src/core/index.js
index 1b561f96c6..36f7c3a118 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -133,6 +133,13 @@ class IPFS extends EventEmitter {
isIPFS: isIPFS
}
+ // ipfs.files
+ const mfs = components.mfs(this, this._options)
+
+ Object.keys(mfs).forEach(key => {
+ this.files[key] = mfs[key]
+ })
+
boot(this)
}
}
diff --git a/src/http/api/resources/files.js b/src/http/api/resources/files.js
index 1cd93e158e..a3b7e8eaed 100644
--- a/src/http/api/resources/files.js
+++ b/src/http/api/resources/files.js
@@ -34,7 +34,8 @@ exports.parseKey = (request, reply) => {
if (!request.query.arg) {
return reply({
Message: "Argument 'key' is required",
- Code: 0
+ Code: 0,
+ Type: 'error'
}).code(400).takeover()
}
@@ -54,7 +55,8 @@ exports.parseKey = (request, reply) => {
log.error(err)
return reply({
Message: 'invalid ipfs ref path',
- Code: 0
+ Code: 0,
+ Type: 'error'
}).code(500).takeover()
}
@@ -81,9 +83,9 @@ exports.cat = {
if (err) {
log.error(err)
if (err.message === 'No such file') {
- reply({Message: 'No such file'}).code(500)
+ reply({Message: 'No such file', Code: 0, Type: 'error'}).code(500)
} else {
- reply({Message: 'Failed to cat file: ' + err, Code: 0}).code(500)
+ reply({Message: 'Failed to cat file: ' + err, Code: 0, Type: 'error'}).code(500)
}
return
}
@@ -177,7 +179,8 @@ exports.add = {
if (!request.payload) {
return reply({
Message: 'Array, Buffer, or String is required.',
- code: 0
+ Code: 0,
+ Type: 'error'
}).code(400).takeover()
}
@@ -211,7 +214,8 @@ exports.add = {
if (!filesParsed) {
return reply({
Message: "File argument 'data' is required.",
- code: 0
+ Code: 0,
+ Type: 'error'
}).code(400).takeover()
}
fileAdder.end()
@@ -302,7 +306,8 @@ exports.immutableLs = {
if (err) {
return reply({
Message: 'Failed to list dir: ' + err.message,
- Code: 0
+ Code: 0,
+ Type: 'error'
}).code(500).takeover()
}
diff --git a/src/http/api/routes/files.js b/src/http/api/routes/files.js
index 2400f6012b..fc8222f180 100644
--- a/src/http/api/routes/files.js
+++ b/src/http/api/routes/files.js
@@ -1,6 +1,7 @@
'use strict'
const resources = require('./../resources')
+const mfs = require('ipfs-mfs/http')
module.exports = (server) => {
const api = server.select('API')
@@ -54,4 +55,6 @@ module.exports = (server) => {
handler: resources.files.immutableLs.handler
}
})
+
+ mfs(api)
}
diff --git a/src/http/error-handler.js b/src/http/error-handler.js
index 012a98f173..0c490d4639 100644
--- a/src/http/error-handler.js
+++ b/src/http/error-handler.js
@@ -14,9 +14,15 @@ module.exports = (api, server) => {
let statusCode = 200
let msg = 'Sorry, something went wrong, please retrace your steps.'
+ let code = 1
if (res.isBoom) {
statusCode = res.output.payload.statusCode
+ msg = res.output.payload.message
+
+ if (res.data && res.data.code !== undefined) {
+ code = res.data.code
+ }
if (res.message && res.isDeveloperError) {
msg = res.message.replace('Uncaught error: ', '')
@@ -36,7 +42,8 @@ module.exports = (api, server) => {
reply({
Message: msg,
- Code: 1
+ Code: code,
+ Type: 'error'
}).code(statusCode)
return
}
diff --git a/src/http/gateway/resources/gateway.js b/src/http/gateway/resources/gateway.js
index aef2451a33..c3a866c359 100644
--- a/src/http/gateway/resources/gateway.js
+++ b/src/http/gateway/resources/gateway.js
@@ -17,7 +17,8 @@ module.exports = {
if (!request.params.cid) {
return reply({
Message: 'Path Resolve error: path must contain at least one component',
- Code: 0
+ Code: 0,
+ Type: 'error'
}).code(400).takeover()
}
@@ -63,10 +64,10 @@ module.exports = {
return reply(errorToString).code(404)
case (errorToString.startsWith('Error: multihash length inconsistent')):
case (errorToString.startsWith('Error: Non-base58 character')):
- return reply({ Message: errorToString, code: 0 }).code(400)
+ return reply({ Message: errorToString, Code: 0, Type: 'error' }).code(400)
default:
log.error(err)
- return reply({ Message: errorToString, code: 0 }).code(500)
+ return reply({ Message: errorToString, Code: 0, Type: 'error' }).code(500)
}
}
}
diff --git a/test/cli/commands.js b/test/cli/commands.js
index 7a8502bc4c..2c0c5fc033 100644
--- a/test/cli/commands.js
+++ b/test/cli/commands.js
@@ -4,7 +4,8 @@
const expect = require('chai').expect
const runOnAndOff = require('../utils/on-and-off')
-const commandCount = 78
+const commandCount = 77
+
describe('commands', () => runOnAndOff((thing) => {
let ipfs
diff --git a/test/cli/file.js b/test/cli/file.js
index e20a16101f..e4a5e0c9ce 100644
--- a/test/cli/file.js
+++ b/test/cli/file.js
@@ -12,7 +12,7 @@ describe('file ls', () => runOnAndOff((thing) => {
before(function () {
this.timeout(50 * 1000)
ipfs = thing.ipfs
- return ipfs('files add -r test/fixtures/test-data/recursive-get-dir')
+ return ipfs('add -r test/fixtures/test-data/recursive-get-dir')
})
it('prints a filename', () => {
diff --git a/test/cli/files.js b/test/cli/files.js
index 32fe28fc00..2f749f1cfe 100644
--- a/test/cli/files.js
+++ b/test/cli/files.js
@@ -126,7 +126,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add with progress', function () {
this.timeout(30 * 1000)
- return ipfs('files add -p src/init-files/init-docs/readme')
+ return ipfs('add -p src/init-files/init-docs/readme')
.then((out) => {
expect(out)
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB readme\n')
@@ -136,7 +136,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add', function () {
this.timeout(30 * 1000)
- return ipfs('files add src/init-files/init-docs/readme')
+ return ipfs('add src/init-files/init-docs/readme')
.then((out) => {
expect(out)
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB readme\n')
@@ -156,7 +156,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add recursively test', function () {
this.timeout(60 * 1000)
- return ipfs('files add -r test/fixtures/test-data/recursive-get-dir')
+ return ipfs('add -r test/fixtures/test-data/recursive-get-dir')
.then((out) => {
expect(out).to.eql(recursiveGetDirResults.join('\n') + '\n')
})
@@ -165,7 +165,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add directory with trailing slash test', function () {
this.timeout(30 * 1000)
- return ipfs('files add -r test/fixtures/test-data/recursive-get-dir/')
+ return ipfs('add -r test/fixtures/test-data/recursive-get-dir/')
.then((out) => {
expect(out).to.eql(recursiveGetDirResults.join('\n') + '\n')
})
@@ -179,7 +179,7 @@ describe('files', () => runOnAndOff((thing) => {
'added QmXJGoo27bg7ExNAtr9vRcivxDwcfHtkxatGno9HrUdR16 odd-name-[v0]'
]
- return ipfs('files add -r test/fixtures/odd-name-[v0]')
+ return ipfs('add -r test/fixtures/odd-name-[v0]')
.then((out) => {
expect(out).to.eql(expected.join('\n') + '\n')
})
@@ -260,7 +260,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add --quiet', function () {
this.timeout(30 * 1000)
- return ipfs('files add -q src/init-files/init-docs/readme')
+ return ipfs('add -q src/init-files/init-docs/readme')
.then((out) => {
expect(out)
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB\n')
@@ -270,7 +270,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add --quieter', function () {
this.timeout(30 * 1000)
- return ipfs('files add -Q -w test/fixtures/test-data/hello test/test-data/node.json')
+ return ipfs('add -Q -w test/fixtures/test-data/hello test/test-data/node.json')
.then((out) => {
expect(out)
.to.eql('QmYRMUVULBfj7WrdPESnwnyZmtayN6Sdrwh1nKcQ9QgQeZ\n')
@@ -280,7 +280,7 @@ describe('files', () => runOnAndOff((thing) => {
it('add --silent', function () {
this.timeout(30 * 1000)
- return ipfs('files add --silent src/init-files/init-docs/readme')
+ return ipfs('add --silent src/init-files/init-docs/readme')
.then((out) => {
expect(out)
.to.eql('')
@@ -288,7 +288,7 @@ describe('files', () => runOnAndOff((thing) => {
})
it('add --only-hash outputs correct hash', function () {
- return ipfs('files add --only-hash src/init-files/init-docs/readme')
+ return ipfs('add --only-hash src/init-files/init-docs/readme')
.then(out =>
expect(out)
.to.eql('added QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB readme\n')
@@ -302,7 +302,7 @@ describe('files', () => runOnAndOff((thing) => {
const filepath = path.join(os.tmpdir(), `${content}.txt`)
fs.writeFileSync(filepath, content)
- return ipfs(`files add --only-hash ${filepath}`)
+ return ipfs(`add --only-hash ${filepath}`)
.then(out => {
const hash = out.split(' ')[1]
@@ -322,7 +322,7 @@ describe('files', () => runOnAndOff((thing) => {
const content = String(Math.random())
fs.writeFileSync(filePath, content)
- return ipfs(`files add -Q ${filePath}`)
+ return ipfs(`add -Q ${filePath}`)
.then(out => {
const hash = out.trim()
return ipfs(`pin ls ${hash}`)
@@ -337,7 +337,7 @@ describe('files', () => runOnAndOff((thing) => {
const content = String(Math.random())
fs.writeFileSync(filePath, content)
- return ipfs(`files add -Q --pin=false ${filePath}`)
+ return ipfs(`add -Q --pin=false ${filePath}`)
.then(out => ipfs.fail(`pin ls ${out.trim()}`))
.then(() => clean(filePath))
})
@@ -358,7 +358,7 @@ describe('files', () => runOnAndOff((thing) => {
it('cat', function () {
this.timeout(30 * 1000)
- return ipfs('files cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
+ return ipfs('cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
.then((out) => {
expect(out).to.eql(readme)
})
@@ -376,7 +376,7 @@ describe('files', () => runOnAndOff((thing) => {
it('cat part of a file using `count`', function () {
this.timeout(30 * 1000)
- return ipfs('files cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB --offset 21 --count 5')
+ return ipfs('cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB --offset 21 --count 5')
.then((out) => {
expect(out).to.eql(readme.substring(21, 26))
})
@@ -385,7 +385,7 @@ describe('files', () => runOnAndOff((thing) => {
it('cat part of a file using `length`', function () {
this.timeout(30 * 1000)
- return ipfs('files cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB --offset 21 --length 5')
+ return ipfs('cat QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB --offset 21 --length 5')
.then((out) => {
expect(out).to.eql(readme.substring(21, 26))
})
@@ -402,7 +402,7 @@ describe('files', () => runOnAndOff((thing) => {
it('get', function () {
this.timeout(20 * 1000)
- return ipfs('files get QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
+ return ipfs('get QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB')
.then((out) => {
expect(out)
.to.eql('Saving file(s) QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB\n')
@@ -437,7 +437,7 @@ describe('files', () => runOnAndOff((thing) => {
const outDir = path.join(process.cwd(), 'Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z')
rimraf(outDir)
- return ipfs('files get Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z')
+ return ipfs('get Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z')
.then((out) => {
expect(out).to.eql(
'Saving file(s) Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z\n'
diff --git a/test/cli/init.js b/test/cli/init.js
index 86e0dbacda..b1a826c1db 100644
--- a/test/cli/init.js
+++ b/test/cli/init.js
@@ -42,7 +42,7 @@ describe('init', function () {
// Test that the following was written when init-ing the repo
// jsipfs files cat /ipfs/QmfGBRT6BbWJd7yUc2uYdaUZJBbnEFvTqehPFoSMQ6wgdr/readme
- let command = out.substring(out.indexOf('files cat'), out.length - 2 /* omit the newline char */)
+ let command = out.substring(out.indexOf('cat'), out.length - 2 /* omit the newline char */)
return ipfs(command)
}).then((out) => expect(out).to.equal(readme))
})
diff --git a/test/cli/ls.js b/test/cli/ls.js
index bd4ed58bfd..4eccf82c07 100644
--- a/test/cli/ls.js
+++ b/test/cli/ls.js
@@ -9,7 +9,7 @@ describe('ls', () => runOnAndOff((thing) => {
before(() => {
ipfs = thing.ipfs
- return ipfs('files add -r test/fixtures/test-data/recursive-get-dir')
+ return ipfs('add -r test/fixtures/test-data/recursive-get-dir')
})
it('prints added files', function () {
diff --git a/test/cli/object.js b/test/cli/object.js
index df49543a65..4173ecd816 100644
--- a/test/cli/object.js
+++ b/test/cli/object.js
@@ -69,7 +69,9 @@ describe('object', () => runOnAndOff((thing) => {
})
})
- it('unaulterated data', () => {
+ it('unadulterated data', function () {
+ this.timeout(10 * 1000)
+
// has to be big enough to span several DAGNodes
const data = crypto.randomBytes(1024 * 300)
const file = path.join(os.tmpdir(), `file-${Math.random()}.txt`)
diff --git a/test/cli/pin.js b/test/cli/pin.js
index f6c77eb67a..1795f9a640 100644
--- a/test/cli/pin.js
+++ b/test/cli/pin.js
@@ -24,7 +24,7 @@ describe('pin', () => runOnAndOff(thing => {
before(function () {
this.timeout(15 * 1000)
ipfs = thing.ipfs
- return ipfs(`files add -r ${fixturePath}`)
+ return ipfs(`add -r ${fixturePath}`)
})
describe('rm', function () {
diff --git a/test/core/interface.spec.js b/test/core/interface.spec.js
index 977a379441..7daf289e26 100644
--- a/test/core/interface.spec.js
+++ b/test/core/interface.spec.js
@@ -29,54 +29,7 @@ describe('interface-ipfs-core tests', () => {
skip: { reason: 'TODO: DHT is not implemented in js-ipfs yet!' }
})
- tests.files(defaultCommonFactory, {
- skip: [
- {
- name: 'cp',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'mkdir',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'stat',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'rm',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'read',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'readReadableStream',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'readPullStream',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'write',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'mv',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'flush',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'ls',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- }
- ]
- })
+ tests.files(defaultCommonFactory)
tests.key(CommonFactory.create({
spawnOptions: {
diff --git a/test/http-api/files.js b/test/http-api/files.js
index 7e85697299..01839f49e1 100644
--- a/test/http-api/files.js
+++ b/test/http-api/files.js
@@ -7,6 +7,9 @@ const dirtyChai = require('dirty-chai')
const DaemonFactory = require('ipfsd-ctl')
const expect = chai.expect
chai.use(dirtyChai)
+const {
+ FILE_TYPES
+} = require('ipfs-mfs')
const df = DaemonFactory.create({ exec: 'src/cli/bin.js' })
@@ -46,4 +49,356 @@ describe('.files', () => {
})
})
})
+
+ describe('.ls', function () {
+ it('lists empty directory', () => {
+ return ipfs.files.ls()
+ .then(files => {
+ expect(files).to.be.empty()
+ })
+ })
+
+ it('lists files', () => {
+ const fileName = `single-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${fileName}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.ls())
+ .then(files => {
+ expect(files.length).to.equal(1)
+ expect(files[0].name).to.equal(fileName)
+ })
+ })
+
+ it('lists files in directories', () => {
+ const dirName = `dir-${Math.random()}`
+ const fileName = `file-in-dir-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${dirName}/${fileName}`, Buffer.from('Hello world'), {
+ create: true,
+ parents: true
+ })
+ .then(() => ipfs.files.ls(`/${dirName}`))
+ .then(files => {
+ expect(files.length).to.equal(1)
+ expect(files[0].name).to.equal(fileName)
+ })
+ })
+ })
+
+ describe('.cp', function () {
+ it('copies a file', () => {
+ const source = `source-file-${Math.random()}.txt`
+ const destination = `destination-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${source}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.cp(`/${source}`, `/${destination}`))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceFile = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceFile.type).to.equal(FILE_TYPES.file)
+
+ const destFile = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destFile.type).to.equal(FILE_TYPES.file)
+ })
+ })
+
+ it('copies a directory', () => {
+ const source = `source-dir-${Math.random()}`
+ const destination = `destination-dir-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${source}`)
+ .then(() => ipfs.files.cp(`/${source}`, `/${destination}`))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceDir = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceDir.type).to.equal(FILE_TYPES.directory)
+
+ const destDir = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destDir.type).to.equal(FILE_TYPES.directory)
+ })
+ })
+
+ it('copies a file with array args', () => {
+ const source = `source-file-${Math.random()}.txt`
+ const destination = `destination-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${source}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.cp([`/${source}`, `/${destination}`]))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceFile = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceFile.type).to.equal(FILE_TYPES.file)
+
+ const destFile = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destFile.type).to.equal(FILE_TYPES.file)
+ })
+ })
+
+ it('copies a directory with array args', () => {
+ const source = `source-dir-${Math.random()}`
+ const destination = `destination-dir-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${source}`)
+ .then(() => ipfs.files.cp([`/${source}`, `/${destination}`]))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceDir = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceDir.type).to.equal(FILE_TYPES.directory)
+
+ const destDir = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destDir.type).to.equal(FILE_TYPES.directory)
+ })
+ })
+ })
+
+ describe('.mkdir', function () {
+ it('makes a directory', () => {
+ const directory = `directory-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${directory}`)
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const dir = files
+ .filter(file => file.name === directory)
+ .pop()
+
+ expect(dir.type).to.equal(FILE_TYPES.directory)
+ })
+ })
+ })
+
+ describe('.mv', function () {
+ it('moves a file', () => {
+ const source = `source-file-${Math.random()}.txt`
+ const destination = `destination-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${source}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.mv(`/${source}`, `/${destination}`))
+ .then(() => ipfs.files.ls(`/`))
+ .then(files => {
+ const sourceFile = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceFile).to.not.exist()
+
+ const destFile = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destFile.type).to.equal(FILE_TYPES.file)
+ })
+ })
+
+ it('moves a directory', () => {
+ const source = `source-dir-${Math.random()}`
+ const destination = `destination-dir-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${source}`)
+ .then(() => ipfs.files.mv(`/${source}`, `/${destination}`))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceDir = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceDir).to.not.exist()
+
+ const destDir = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destDir.type).to.equal(FILE_TYPES.directory)
+ })
+ })
+
+ it('moves a file with array args', () => {
+ const source = `source-file-${Math.random()}.txt`
+ const destination = `destination-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${source}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.mv([`/${source}`, `/${destination}`]))
+ .then(() => ipfs.files.ls(`/`))
+ .then(files => {
+ const sourceFile = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceFile).to.not.exist()
+
+ const destFile = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destFile.type).to.equal(FILE_TYPES.file)
+ })
+ })
+
+ it('moves a directory with array args', () => {
+ const source = `source-dir-${Math.random()}`
+ const destination = `destination-dir-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${source}`)
+ .then(() => ipfs.files.mv([`/${source}`, `/${destination}`]))
+ .then(() => ipfs.files.ls(`/`, {
+ long: true
+ }))
+ .then(files => {
+ const sourceDir = files
+ .filter(file => file.name === source)
+ .pop()
+
+ expect(sourceDir).to.not.exist()
+
+ const destDir = files
+ .filter(file => file.name === destination)
+ .pop()
+
+ expect(destDir.type).to.equal(FILE_TYPES.directory)
+ })
+ })
+ })
+
+ describe('.read', function () {
+ it('reads a file', () => {
+ const fileName = `single-file-${Math.random()}.txt`
+ const content = Buffer.from('Hello world')
+
+ return ipfs.files.write(`/${fileName}`, content, {
+ create: true
+ })
+ .then(() => ipfs.files.read(`/${fileName}`))
+ .then(buffer => {
+ expect(buffer).to.deep.equal(content)
+ })
+ })
+ })
+
+ describe('.rm', function () {
+ it('removes a file', () => {
+ const fileName = `single-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${fileName}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.rm(`/${fileName}`))
+ .then(() => ipfs.files.ls(`/`))
+ .then(files => {
+ const file = files
+ .filter(file => file.name === fileName)
+ .pop()
+
+ expect(file).to.not.exist()
+ })
+ })
+
+ it('removes a directory', () => {
+ const dirName = `dir-${Math.random()}`
+ const fileName = `file-in-dir-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${dirName}/${fileName}`, Buffer.from('Hello world'), {
+ create: true,
+ parents: true
+ })
+ .then(() => ipfs.files.rm(`/${dirName}`, {
+ recursive: true
+ }))
+ .then(() => ipfs.files.ls(`/`))
+ .then(files => {
+ const dir = files
+ .filter(file => file.name === dirName)
+ .pop()
+
+ expect(dir).to.not.exist()
+ })
+ })
+ })
+
+ describe('.stat', function () {
+ it('stats a file', () => {
+ const fileName = `single-file-${Math.random()}.txt`
+
+ return ipfs.files.write(`/${fileName}`, Buffer.from('Hello world'), {
+ create: true
+ })
+ .then(() => ipfs.files.stat(`/${fileName}`))
+ .then(stats => {
+ expect(stats).to.deep.equal({
+ blocks: 1,
+ cumulativeSize: 69,
+ hash: 'Qmetpc7cZmN25Wcc6R27cGCAvCDqCS5GjHG4v7xABEfpmJ',
+ local: undefined,
+ size: 11,
+ sizeLocal: undefined,
+ type: 'file',
+ withLocality: false
+ })
+ })
+ })
+
+ it('stats a directory', () => {
+ const dirName = `dir-${Math.random()}`
+
+ return ipfs.files.mkdir(`/${dirName}`)
+ .then(() => ipfs.files.stat(`/${dirName}`))
+ .then(stats => {
+ expect(stats).to.deep.equal({
+ blocks: 0,
+ cumulativeSize: 4,
+ hash: 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn',
+ local: undefined,
+ size: 0,
+ sizeLocal: undefined,
+ type: 'directory',
+ withLocality: false
+ })
+ })
+ })
+ })
})
diff --git a/test/http-api/index.js b/test/http-api/index.js
index d619014896..901cb212ef 100644
--- a/test/http-api/index.js
+++ b/test/http-api/index.js
@@ -9,3 +9,4 @@ require('./inject')
require('./interface')
require('./object')
require('./version')
+require('./files')
diff --git a/test/http-api/interface.js b/test/http-api/interface.js
index 1f2955377b..e123093687 100644
--- a/test/http-api/interface.js
+++ b/test/http-api/interface.js
@@ -25,54 +25,7 @@ describe('interface-ipfs-core over ipfs-api tests', () => {
skip: { reason: 'TODO: DHT is not implemented in js-ipfs yet!' }
})
- tests.files(defaultCommonFactory, {
- skip: [
- {
- name: 'cp',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'mkdir',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'stat',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'rm',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'read',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'readReadableStream',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'readPullStream',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'write',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'mv',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'flush',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- },
- {
- name: 'ls',
- reason: 'TODO: MFS is not implemented in js-ipfs yet!'
- }
- ]
- })
+ tests.files(defaultCommonFactory)
tests.key(CommonFactory.create({
spawnOptions: {
diff --git a/test/utils/ipfs-exec.js b/test/utils/ipfs-exec.js
index 38742b76b5..786a3f7f3b 100644
--- a/test/utils/ipfs-exec.js
+++ b/test/utils/ipfs-exec.js
@@ -13,7 +13,7 @@ const _ = require('lodash')
// The top level export is a function that can be passed a `repoPath`
// and optional `opts` to customize the execution of the commands.
// This function returns the actual executer, which consists of
-// `ipfs('files get ')` and `ipfs.fail('files get ')`
+// `ipfs('get ')` and `ipfs.fail('files get ')`
// The first one executes and asserts that the command ran successfully
// and returns a promise which is resolved to `stdout` of the command.
// The `.fail` variation asserts that the command exited with `Code > 0`