diff --git a/packages/truffle-core/lib/commands/console.js b/packages/truffle-core/lib/commands/console.js index f8470e9a2e8..9493e9e1a94 100644 --- a/packages/truffle-core/lib/commands/console.js +++ b/packages/truffle-core/lib/commands/console.js @@ -29,19 +29,19 @@ const command = { const commands = require("./index"); const excluded = ["console", "init", "watch", "develop"]; - const available_commands = Object.keys(commands).filter(function(name) { + const availableCommands = Object.keys(commands).filter(name => { return excluded.indexOf(name) === -1; }); - let console_commands = {}; - available_commands.forEach(function(name) { - console_commands[name] = commands[name]; + const consoleCommands = {}; + availableCommands.forEach(name => { + consoleCommands[name] = commands[name]; }); Environment.detect(config) .then(() => { const c = new Console( - console_commands, + consoleCommands, config.with({ noAliases: true }) ); c.start(done); diff --git a/packages/truffle-core/lib/commands/develop.js b/packages/truffle-core/lib/commands/develop.js index 6d1b76f1c22..1fdcfa33f65 100644 --- a/packages/truffle-core/lib/commands/develop.js +++ b/packages/truffle-core/lib/commands/develop.js @@ -21,11 +21,11 @@ const command = { const commands = require("./index"); const excluded = ["console", "develop", "unbox", "init"]; - const available_commands = Object.keys(commands).filter( + const availableCommands = Object.keys(commands).filter( name => !excluded.includes(name) ); - const console_commands = available_commands.reduce( + const consoleCommands = availableCommands.reduce( (acc, name) => Object.assign({}, acc, { [name]: commands[name] }), {} ); @@ -33,7 +33,7 @@ const command = { Environment.develop(config, ganacheOptions) .then(() => { const c = new Console( - console_commands, + consoleCommands, config.with({ noAliases: true }) ); c.start(done); diff --git a/packages/truffle-core/lib/console.js b/packages/truffle-core/lib/console.js index 763d59efd40..65f4bdd3f53 100644 --- a/packages/truffle-core/lib/console.js +++ b/packages/truffle-core/lib/console.js @@ -1,248 +1,220 @@ -var ReplManager = require("./repl"); -var Command = require("./command"); -var provision = require("truffle-provisioner"); -var contract = require("truffle-contract"); -var Web3Shim = require("truffle-interface-adapter").Web3Shim; -var vm = require("vm"); -var expect = require("truffle-expect"); -var TruffleError = require("truffle-error"); -var fs = require("fs"); -var path = require("path"); -var EventEmitter = require("events"); -var inherits = require("util").inherits; - -inherits(Console, EventEmitter); - -function Console(tasks, options) { - EventEmitter.call(this); - - var self = this; - - expect.options(options, [ - "working_directory", - "contracts_directory", - "contracts_build_directory", - "migrations_directory", - "networks", - "network", - "network_id", - "provider", - "resolver", - "build_directory" - ]); - - this.options = options; - - this.repl = options.repl || new ReplManager(options); - this.command = new Command(tasks); - - this.web3 = new Web3Shim({ - provider: options.provider, - networkType: options.networks[options.network].type - }); - - // Bubble the ReplManager's exit event - this.repl.on("exit", function() { - self.emit("exit"); - }); -} - -Console.prototype.start = function(callback) { - var self = this; +const ReplManager = require("./repl"); +const Command = require("./command"); +const provision = require("truffle-provisioner"); +const contract = require("truffle-contract"); +const { Web3Shim } = require("truffle-interface-adapter"); +const vm = require("vm"); +const expect = require("truffle-expect"); +const TruffleError = require("truffle-error"); +const fse = require("fs-extra"); +const path = require("path"); +const EventEmitter = require("events"); + +class Console extends EventEmitter { + constructor(tasks, options) { + super(); + EventEmitter.call(this); + + expect.options(options, [ + "working_directory", + "contracts_directory", + "contracts_build_directory", + "migrations_directory", + "networks", + "network", + "network_id", + "provider", + "resolver", + "build_directory" + ]); + + this.options = options; + + this.repl = options.repl || new ReplManager(options); + this.command = new Command(tasks); + + this.web3 = new Web3Shim({ + provider: options.provider, + networkType: options.networks[options.network].type + }); - if (!this.repl) { - this.repl = new Repl(this.options); + // Bubble the ReplManager's exit event + this.repl.on("exit", () => this.emit("exit")); } - // TODO: This should probalby be elsewhere. - // It's here to ensure the repl manager instance gets - // passed down to commands. - this.options.repl = this.repl; + start(callback) { + if (!this.repl) this.repl = new Repl(this.options); + + // TODO: This should probalby be elsewhere. + // It's here to ensure the repl manager instance gets + // passed down to commands. + this.options.repl = this.repl; + + try { + const abstractions = this.provision(); + this.repl.start({ + prompt: "truffle(" + this.options.network + ")> ", + context: { + web3: this.web3 + }, + interpreter: this.interpret.bind(this), + done: callback + }); - this.provision(function(err, abstractions) { - if (err) { - self.options.logger.log( + this.resetContractsInConsoleContext(abstractions); + } catch (error) { + this.options.logger.log( "Unexpected error: Cannot provision contracts while instantiating the console." ); - self.options.logger.log(err.stack || err.message || err); + this.options.logger.log(error.stack || error.message || error); } + } - self.repl.start({ - prompt: "truffle(" + self.options.network + ")> ", - context: { - web3: self.web3 - }, - interpreter: self.interpret.bind(self), - done: callback - }); - - self.resetContractsInConsoleContext(abstractions); - }); -}; - -Console.prototype.provision = function(callback) { - var self = this; - - fs.readdir(this.options.contracts_build_directory, function(err, files) { - if (err) { + provision() { + let files; + try { + files = fse.readdirSync(this.options.contracts_build_directory); + } catch (error) { // Error reading the build directory? Must mean it doesn't exist or we don't have access to it. // Couldn't provision the contracts if we wanted. It's possible we're hiding very rare FS // errors, but that's better than showing the user error messages that will be "build folder // doesn't exist" 99.9% of the time. } - var promises = []; + let jsonBlobs = []; files = files || []; - files.forEach(function(file) { - promises.push( - new Promise(function(accept, reject) { - fs.readFile( - path.join(self.options.contracts_build_directory, file), - "utf8", - function(err, body) { - if (err) return reject(err); - try { - body = JSON.parse(body); - } catch (e) { - return reject( - new Error("Cannot parse " + file + ": " + e.message) - ); - } - - accept(body); - } - ); - }) - ); + files.forEach(file => { + try { + const body = fse.readFileSync( + path.join(this.options.contracts_build_directory, file), + "utf8" + ); + jsonBlobs.push(JSON.parse(body)); + } catch (error) { + throw new Error(`Error parsing or reading ${file}: ${error.message}`); + } }); - Promise.all(promises) - .then(function(json_blobs) { - var abstractions = json_blobs.map(function(json) { - var abstraction = contract(json); - provision(abstraction, self.options); - return abstraction; - }); - - self.resetContractsInConsoleContext(abstractions); - - callback(null, abstractions); - }) - .catch(callback); - }); -}; + const abstractions = jsonBlobs.map(json => { + const abstraction = contract(json); + provision(abstraction, this.options); + return abstraction; + }); -Console.prototype.resetContractsInConsoleContext = function(abstractions) { - var self = this; + this.resetContractsInConsoleContext(abstractions); - abstractions = abstractions || []; + return abstractions; + } - var contextVars = {}; + resetContractsInConsoleContext(abstractions) { + abstractions = abstractions || []; - abstractions.forEach(function(abstraction) { - contextVars[abstraction.contract_name] = abstraction; - }); + const contextVars = {}; - self.repl.setContextVars(contextVars); -}; + abstractions.forEach(abstraction => { + contextVars[abstraction.contract_name] = abstraction; + }); -Console.prototype.interpret = function(cmd, context, filename, callback) { - var self = this; + this.repl.setContextVars(contextVars); + } - if (this.command.getCommand(cmd.trim(), this.options.noAliases) != null) { - return self.command.run(cmd.trim(), this.options, function(err) { - if (err) { - // Perform error handling ourselves. - if (err instanceof TruffleError) { - console.log(err.message); - } else { - // Bubble up all other unexpected errors. - console.log(err.stack || err.toString()); + interpret(cmd, context, filename, callback) { + if (this.command.getCommand(cmd.trim(), this.options.noAliases) != null) { + return this.command.run(cmd.trim(), this.options, error => { + if (error) { + // Perform error handling ourselves. + if (error instanceof TruffleError) { + console.log(error.message); + } else { + // Bubble up all other unexpected errors. + console.log(error.stack || error.toString()); + } + return callback(); } - return callback(); - } - // Reprovision after each command as it may change contracts. - self.provision(function(err) { - // Don't pass abstractions to the callback if they're there or else - // they'll get printed in the repl. - callback(err); + // Reprovision after each command as it may change contracts. + try { + this.provision(); + callback(); + } catch (error) { + // Don't pass abstractions to the callback if they're there or else + // they'll get printed in the repl. + callback(error); + } }); - }); - } + } - // Much of the following code is from here, though spruced up: - // https://github.com/nfcampos/await-outside - - /* - - allow whitespace before everything else - - optionally capture `var|let|const = ` - - varname only matches if it starts with a-Z or _ or $ - and if contains only those chars or numbers - - this is overly restrictive but is easier to maintain - - capture `await ` - */ - let includesAwait = /^\s*((?:(?:var|const|let)\s+)?[a-zA-Z_$][0-9a-zA-Z_$]*\s*=\s*)?(\(?\s*await[\s\S]*)/; - - var match = cmd.match(includesAwait); - var source = cmd; - var assignment = null; - - // If our code includes an await, add special processing to ensure it's evaluated properly. - if (match) { - var assign = match[1]; - var expression = match[2]; - - var RESULT = "__await_outside_result"; - - // Wrap the await inside an async function. - // Strange indentation keeps column offset correct in stack traces - source = `(async function() { try { ${ - assign ? `global.${RESULT} =` : "return" - } ( -${expression.trim()} -); } catch(e) { global.ERROR = e; throw e; } }())`; - - assignment = assign - ? `${assign.trim()} global.${RESULT}; void delete global.${RESULT};` - : null; - } + // Much of the following code is from here, though spruced up: + // https://github.com/nfcampos/await-outside + + /* + - allow whitespace before everything else + - optionally capture `var|let|const = ` + - varname only matches if it starts with a-Z or _ or $ + and if contains only those chars or numbers + - this is overly restrictive but is easier to maintain + - capture `await ` + */ + let includesAwait = /^\s*((?:(?:var|const|let)\s+)?[a-zA-Z_$][0-9a-zA-Z_$]*\s*=\s*)?(\(?\s*await[\s\S]*)/; + + const match = cmd.match(includesAwait); + let source = cmd; + let assignment = null; + + // If our code includes an await, add special processing to ensure it's evaluated properly. + if (match) { + let assign = match[1]; + const expression = match[2]; + + const RESULT = "__await_outside_result"; + + // Wrap the await inside an async function. + // Strange indentation keeps column offset correct in stack traces + source = `(async function() { try { ${ + assign ? `global.${RESULT} =` : "return" + } ( + ${expression.trim()} + ); } catch(e) { global.ERROR = e; throw e; } }())`; + + assignment = assign + ? `${assign.trim()} global.${RESULT}; void delete global.${RESULT};` + : null; + } - var runScript = function(s) { - const options = { - displayErrors: true, - breakOnSigint: true, - filename: filename + const runScript = script => { + const options = { + displayErrors: true, + breakOnSigint: true, + filename: filename + }; + return script.runInContext(context, options); }; - return s.runInContext(context, options); - }; - - try { - const options = { displayErrors: true, lineOffset: -1 }; - var script = vm.createScript(source, options); - } catch (e) { - // If syntax error, or similar, bail. - return callback(e); - } - // Ensure our script returns a promise whether we're using an - // async function or not. If our script is an async function, - // this will ensure the console waits until that await is finished. - Promise.resolve(runScript(script)) - .then(function(value) { - // If there's an assignment to run, run that. - if (assignment) { - return runScript(vm.createScript(assignment)); - } else { + let script; + try { + const options = { displayErrors: true, lineOffset: -1 }; + script = vm.createScript(source, options); + } catch (error) { + // If syntax error, or similar, bail. + return callback(error); + } + + // Ensure our script returns a promise whether we're using an + // async function or not. If our script is an async function, + // this will ensure the console waits until that await is finished. + Promise.resolve(runScript(script)) + .then(value => { + // If there's an assignment to run, run that. + if (assignment) return runScript(vm.createScript(assignment)); return value; - } - }) - .then(function(value) { - // All good? Return the value (e.g., eval'd script or assignment) - callback(null, value); - }) - .catch(callback); -}; + }) + .then(value => { + // All good? Return the value (e.g., eval'd script or assignment) + callback(null, value); + }) + .catch(callback); + } +} module.exports = Console; diff --git a/packages/truffle-core/test/ethpm.js b/packages/truffle-core/test/ethpm.js index bb6a82423cd..c20c426acb6 100644 --- a/packages/truffle-core/test/ethpm.js +++ b/packages/truffle-core/test/ethpm.js @@ -14,8 +14,6 @@ describe.skip("EthPM integration", function() { var config; var host; var registry; - var ipfs_api; - var ipfs_daemon; var provider; var blockchain_uri; @@ -74,8 +72,6 @@ describe.skip("EthPM integration", function() { host = results.host; registry = results.registry; - ipfs_api = results.ipfs_api; - ipfs_daemon = results.ipfs_daemon; done(); } diff --git a/packages/truffle-environment/chain.js b/packages/truffle-environment/chain.js index 714a9fab5f6..da886779676 100644 --- a/packages/truffle-environment/chain.js +++ b/packages/truffle-environment/chain.js @@ -195,17 +195,15 @@ Supervisor.prototype.exit = function() { * Lifecycle * (quit on last connection) */ -function LifecycleMixin() { - var self = this; -} +function LifecycleMixin() {} // start counting active connections -LifecycleMixin.prototype.start = function(supervisor) { +LifecycleMixin.prototype.start = function(_supervisor) { this.connections = 0; }; // increment -LifecycleMixin.prototype.connect = function(supervisor) { +LifecycleMixin.prototype.connect = function(_supervisor) { this.connections++; }; @@ -228,7 +226,7 @@ function GanacheMixin(options) { } // start Ganache and capture promise that resolves when ready -GanacheMixin.prototype.start = function(supervisor) { +GanacheMixin.prototype.start = function(_supervisor) { var self = this; this.ready = new Promise(function(accept, reject) { @@ -244,14 +242,13 @@ GanacheMixin.prototype.start = function(supervisor) { // wait for Ganache to be ready then emit signal to client socket GanacheMixin.prototype.connect = function(supervisor, socket) { - var self = this; this.ready.then(function() { supervisor.emit(socket, "truffle.ready"); }); }; // cleanup Ganache process on exit -GanacheMixin.prototype.exit = function(supervisor) { +GanacheMixin.prototype.exit = function(_supervisor) { this.ganache.close(function(err) { if (err) { console.error(err.stack || err); diff --git a/packages/truffle-environment/develop.js b/packages/truffle-environment/develop.js index 420c3a9295b..bff21023fcb 100644 --- a/packages/truffle-environment/develop.js +++ b/packages/truffle-environment/develop.js @@ -1,13 +1,13 @@ -var IPC = require("node-ipc").IPC; -var path = require("path"); -var spawn = require("child_process").spawn; -var debug = require("debug"); +const { IPC } = require("node-ipc"); +const path = require("path"); +const { spawn } = require("child_process"); +const debug = require("debug"); -var Develop = { - start: function(ipcNetwork, options, callback) { +const Develop = { + start: async function(ipcNetwork, options) { options = options || {}; - var chainPath; + let chainPath; // The path to the dev env process depends on whether or not // we're running in the bundled version. If not, use chain.js @@ -20,18 +20,16 @@ var Develop = { chainPath = path.join(__dirname, "./", "chain.js"); } - var cmd = spawn("node", [chainPath, ipcNetwork, JSON.stringify(options)], { + return spawn("node", [chainPath, ipcNetwork, JSON.stringify(options)], { detached: true, stdio: "ignore" }); - - callback(); }, connect: function(options, callback) { - var debugServer = debug("develop:ipc:server"); - var debugClient = debug("develop:ipc:client"); - var debugRPC = debug("develop:ganache"); + const debugServer = debug("develop:ipc:server"); + const debugClient = debug("develop:ipc:client"); + const debugRPC = debug("develop:ganache"); if (typeof options === "function") { callback = options; @@ -106,30 +104,30 @@ var Develop = { }, connectOrStart: function(options, ganacheOptions, callback) { - var self = this; + const self = this; options.retry = false; - var ipcNetwork = options.network || "develop"; + const ipcNetwork = options.network || "develop"; - var connectedAlready = false; + let connectedAlready = false; this.connect( options, - function(error, disconnect) { + async function(error, disconnect) { if (error) { - self.start(ipcNetwork, ganacheOptions, function() { - options.retry = true; - self.connect( - options, - function(error, disconnect) { - if (connectedAlready) return; - - connectedAlready = true; - callback(true, disconnect); - } - ); - }); + await self.start(ipcNetwork, ganacheOptions); + + options.retry = true; + self.connect( + options, + function(error, disconnect) { + if (connectedAlready) return; + + connectedAlready = true; + callback(true, disconnect); + } + ); } else { connectedAlready = true; callback(false, disconnect);