From 3820be06eda7deb71bdcd73d86925992679696a5 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 11 May 2018 09:18:55 +0100 Subject: [PATCH] perf(cli): load only sub-system modules and inline require ipfs License: MIT Signed-off-by: Alan Shaw --- src/cli/bin.js | 38 ++++++++++++++++++++++--------- src/cli/utils.js | 6 +++-- test/cli/daemon.js | 57 ++++++++++++++++++++++------------------------ 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/cli/bin.js b/src/cli/bin.js index 4e666d2a20..2ccf2f66a0 100755 --- a/src/cli/bin.js +++ b/src/cli/bin.js @@ -5,6 +5,8 @@ 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 @@ -16,6 +18,10 @@ 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', @@ -28,7 +34,14 @@ const cli = yargs type: 'string', default: '' }) - .commandDir('commands') + .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) => { @@ -43,16 +56,19 @@ const cli = yargs yargs.showHelp() }) -// 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) -}) +// 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 diff --git a/src/cli/utils.js b/src/cli/utils.js index b0fd5ff742..f993e0caef 100644 --- a/src/cli/utils.js +++ b/src/cli/utils.js @@ -2,9 +2,7 @@ const fs = require('fs') const os = require('os') -const APIctl = require('ipfs-api') const multiaddr = require('multiaddr') -const IPFS = require('../core') const path = require('path') const debug = require('debug') const log = debug('cli') @@ -35,6 +33,8 @@ function getAPICtl (apiAddr) { const apiPath = path.join(exports.getRepoPath(), 'api') apiAddr = multiaddr(fs.readFileSync(apiPath).toString()).toString() } + // Required inline to reduce startup time + const APIctl = require('ipfs-api') return APIctl(apiAddr) } @@ -43,6 +43,8 @@ exports.getIPFS = (argv, callback) => { return callback(null, getAPICtl(argv.api), (cb) => cb()) } + // Required inline to reduce startup time + const IPFS = require('../core') const node = new IPFS({ repo: exports.getRepoPath(), init: false, diff --git a/test/cli/daemon.js b/test/cli/daemon.js index 14207598da..d60d591279 100644 --- a/test/cli/daemon.js +++ b/test/cli/daemon.js @@ -5,8 +5,6 @@ const expect = require('chai').expect const clean = require('../utils/clean') const ipfsCmd = require('../utils/ipfs-exec') const isWindows = require('../utils/platforms').isWindows -const pull = require('pull-stream') -const toPull = require('stream-to-pull-stream') const os = require('os') const path = require('path') const hat = require('hat') @@ -37,31 +35,20 @@ function testSignal (ipfs, sig) { }).then(() => { const proc = ipfs('daemon') return new Promise((resolve, reject) => { - pull( - toPull(proc.stdout), - pull.collect((err, res) => { - expect(err).to.not.exist() - const data = res.toString() - if (data.includes(`Daemon is ready`)) { - if (proc.kill(sig)) { - resolve() - } else { - reject(new Error(`Unable to ${sig} process`)) - } + proc.stdout.on('data', (data) => { + if (data.toString().includes(`Daemon is ready`)) { + if (proc.kill(sig)) { + resolve() + } else { + reject(new Error(`Unable to ${sig} process`)) } - }) - ) - - pull( - toPull(proc.stderr), - pull.collect((err, res) => { - expect(err).to.not.exist() - const data = res.toString() - if (data.length > 0) { - reject(new Error(data)) - } - }) - ) + } + }) + proc.stderr.on('data', (data) => { + if (data.toString().length > 0) { + reject(new Error(data)) + } + }) }) }) } @@ -79,6 +66,8 @@ describe('daemon', () => { skipOnWindows('do not crash if Addresses.Swarm is empty', function (done) { this.timeout(100 * 1000) + // These tests are flaky, but retrying 3 times seems to make it work 99% of the time + this.retries(3) ipfs('init').then(() => { return ipfs('config', 'Addresses', JSON.stringify({ @@ -87,10 +76,18 @@ describe('daemon', () => { Gateway: '/ip4/127.0.0.1/tcp/0' }), '--json') }).then(() => { - return ipfs('daemon') - }).then((res) => { - expect(res).to.have.string('Daemon is ready') - done() + const res = ipfs('daemon') + const timeout = setTimeout(() => { + done(new Error('Daemon did not get ready in time')) + }, 1000 * 120) + res.stdout.on('data', (data) => { + const line = data.toString() + if (line.includes('Daemon is ready')) { + clearTimeout(timeout) + res.kill() + done() + } + }) }).catch(err => done(err)) })