From 3a34db1449acad39653e9065a5e50bb3183f5e22 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Wed, 26 Aug 2020 15:44:11 -0700 Subject: [PATCH 01/13] Add proper context handling to ensure artifacts available in child process --- packages/core/lib/console.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 0f6b537f63a..39284ff6ad1 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -42,6 +42,7 @@ class Console extends EventEmitter { "build_directory" ]); + this.context = {}; this.options = options; this.command = new Command(tasks); @@ -58,10 +59,18 @@ class Console extends EventEmitter { }); } + setContextVars(obj) { + const context = {}; + Object.keys(obj || {}).forEach(function (key) { + context[key] = obj[key]; + }); + return context; + } + start() { try { this.interfaceAdapter.getAccounts().then(fetchedAccounts => { - const abstractions = this.provision(); + this.provision(); this.repl = repl.start({ prompt: "truffle(" + this.options.network + ")> ", @@ -71,8 +80,7 @@ class Console extends EventEmitter { this.repl.context.web3 = this.web3; this.repl.context.interfaceAdapter = this.interfaceAdapter; this.repl.context.accounts = fetchedAccounts; - - this.resetContractsInConsoleContext(abstractions); + this.repl.context = this.context; }); } catch (error) { this.options.logger.log( @@ -118,7 +126,6 @@ class Console extends EventEmitter { }); this.resetContractsInConsoleContext(abstractions); - return abstractions; } @@ -130,6 +137,8 @@ class Console extends EventEmitter { abstractions.forEach(abstraction => { contextVars[abstraction.contract_name] = abstraction; }); + + this.context = this.setContextVars(contextVars); } runSpawn(inputStrings, options, callback) { @@ -143,7 +152,6 @@ class Console extends EventEmitter { const spawnOptions = { stdio: ["inherit", "inherit", "inherit"] }; const spawnInput = "--network " + options.network + " -- " + inputStrings; - try { spawnSync( "node", @@ -244,6 +252,8 @@ class Console extends EventEmitter { breakOnSigint: true, filename: filename }; + + vm.createContext(context); return script.runInContext(context, options); }; From 67a0ff5c0a96101b2ea0e84f42a93139f65f3532 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Wed, 26 Aug 2020 15:50:43 -0700 Subject: [PATCH 02/13] Change stderr from parent to pipe because we don't need to see the same warnings we already saw in the parent --- packages/core/lib/console.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 39284ff6ad1..288b9da0454 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -149,7 +149,7 @@ class Console extends EventEmitter { childPath = path.join(__dirname, "../lib/console-child.js"); } - const spawnOptions = { stdio: ["inherit", "inherit", "inherit"] }; + const spawnOptions = { stdio: ["inherit", "inherit", "pipe"] }; const spawnInput = "--network " + options.network + " -- " + inputStrings; try { From 66f81a6b51ca28def845574da76098f1925ff314 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Wed, 26 Aug 2020 16:59:37 -0700 Subject: [PATCH 03/13] Fix context setting to ensure changes within repl are picked up by child process, and add comments --- packages/core/lib/console.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 288b9da0454..5256dbd1244 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -70,17 +70,20 @@ class Console extends EventEmitter { start() { try { this.interfaceAdapter.getAccounts().then(fetchedAccounts => { - this.provision(); + const abstractions = this.provision(); this.repl = repl.start({ prompt: "truffle(" + this.options.network + ")> ", eval: this.interpret.bind(this) }); + this.resetContractsInConsoleContext(abstractions); + + // set these repl context vars after setting contracts to + // make sure they don't get overwritten this.repl.context.web3 = this.web3; this.repl.context.interfaceAdapter = this.interfaceAdapter; this.repl.context.accounts = fetchedAccounts; - this.repl.context = this.context; }); } catch (error) { this.options.logger.log( @@ -139,6 +142,11 @@ class Console extends EventEmitter { }); this.context = this.setContextVars(contextVars); + + // make sure the repl gets the new contracts in its context + if (this.repl) { + this.repl.context = this.context; + } } runSpawn(inputStrings, options, callback) { @@ -149,6 +157,9 @@ class Console extends EventEmitter { childPath = path.join(__dirname, "../lib/console-child.js"); } + // stderr is piped here because we don't need to repeatedly see the parent + // errors/warnings in child process - specifically the error re: having + // multiple config files const spawnOptions = { stdio: ["inherit", "inherit", "pipe"] }; const spawnInput = "--network " + options.network + " -- " + inputStrings; @@ -159,11 +170,8 @@ class Console extends EventEmitter { spawnOptions ); - try { - this.provision(); - } catch (e) { - console.log(e); - } + // re-provision to ensure any changes are available in the repl + this.provision(); } catch (err) { callback(err); } From f0ee0f625e8d62bf316195d4cce9ec760383cc91 Mon Sep 17 00:00:00 2001 From: Faina Shalts Date: Wed, 26 Aug 2020 19:08:35 -0700 Subject: [PATCH 04/13] Revert "Revert "Run each console command in its own child process"" --- packages/core/cli.js | 4 +- packages/core/index.js | 1 - packages/core/lib/command.js | 7 +- packages/core/lib/console-child.js | 46 ++++++ packages/core/lib/console.js | 72 ++++++---- packages/core/lib/debug/interpreter.js | 32 ++--- packages/core/lib/repl.js | 132 ------------------ .../truffle/test/scenarios/library/api.js | 7 +- packages/truffle/webpack.config.js | 73 +++++----- 9 files changed, 149 insertions(+), 225 deletions(-) create mode 100644 packages/core/lib/console-child.js delete mode 100644 packages/core/lib/repl.js diff --git a/packages/core/cli.js b/packages/core/cli.js index 2aac802358d..9152eaa4c6d 100755 --- a/packages/core/cli.js +++ b/packages/core/cli.js @@ -41,8 +41,8 @@ listeners.forEach(listener => process.removeListener("warning", listener)); let options = { logger: console }; const inputArguments = process.argv.slice(2); -const userWantsGeneralHelp = - inputArguments.length === 1 && ['help', '--help'].includes(inputArguments[0]); +const userWantsGeneralHelp = + inputArguments.length === 1 && ["help", "--help"].includes(inputArguments[0]); if (userWantsGeneralHelp) { command.displayGeneralHelp(); diff --git a/packages/core/index.js b/packages/core/index.js index db0f74e0f19..dfb602225cb 100644 --- a/packages/core/index.js +++ b/packages/core/index.js @@ -4,7 +4,6 @@ var pkg = require("./package.json"); module.exports = { build: require("./lib/build"), create: require("./lib/commands/create/helpers"), - console: require("./lib/repl"), contracts: require("@truffle/workflow-compile"), package: require("./lib/package"), test: require("./lib/test"), diff --git a/packages/core/lib/command.js b/packages/core/lib/command.js index 365574f9128..1e9d629352c 100644 --- a/packages/core/lib/command.js +++ b/packages/core/lib/command.js @@ -11,7 +11,7 @@ class Command { let args = yargs(); - Object.keys(this.commands).forEach(function(command) { + Object.keys(this.commands).forEach(function (command) { args = args.command(commands[command]); }); @@ -68,7 +68,7 @@ class Command { return { name: chosenCommand, argv, - command + command, }; } @@ -134,10 +134,11 @@ class Command { const newOptions = Object.assign({}, clone, argv); result.command.run(newOptions, callback); + analytics.send({ command: result.name ? result.name : "other", args: result.argv._, - version: bundled || "(unbundled) " + core + version: bundled || "(unbundled) " + core, }); } catch (err) { callback(err); diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js new file mode 100644 index 00000000000..6c6d77da51e --- /dev/null +++ b/packages/core/lib/console-child.js @@ -0,0 +1,46 @@ +const Command = require("../lib/command"); +const TruffleError = require("@truffle/error"); +const Config = require("@truffle/config"); +const Web3 = require("web3"); +const yargs = require("yargs"); + +const input = process.argv[2].split(" -- "); +const inputStrings = input[1]; + +//detect config so we can get the provider and resolver without having to serialize +//and deserialize them +const detectedConfig = Config.detect({ network: yargs(input[0]).network }); +const customConfig = detectedConfig.networks.develop || {}; + +//need host and port for provider url +const ganacheOptions = { + host: customConfig.host || "127.0.0.1", + port: customConfig.port || 9545 +}; +const url = `http://${ganacheOptions.host}:${ganacheOptions.port}/`; + +//set up the develop network to use, including setting up provider +detectedConfig.networks.develop = { + host: customConfig.host || "127.0.0.1", + port: customConfig.port || 9545, + network_id: customConfig.network_id || 5777, + provider: function () { + return new Web3.providers.HttpProvider(url, { keepAlive: false }); + } +}; + +const command = new Command(require("../lib/commands")); + +command.run(inputStrings, detectedConfig, 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()); + } + process.exit(1); + } + process.exit(0); +}); diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index d741122d38a..0f6b537f63a 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -1,4 +1,4 @@ -const ReplManager = require("./repl"); +const repl = require("repl"); const Command = require("./command"); const provision = require("@truffle/provisioner"); const { @@ -12,6 +12,7 @@ const TruffleError = require("@truffle/error"); const fse = require("fs-extra"); const path = require("path"); const EventEmitter = require("events"); +const spawnSync = require("child_process").spawnSync; const processInput = input => { const inputComponents = input.trim().split(" "); @@ -43,9 +44,10 @@ class Console extends EventEmitter { this.options = options; - this.repl = options.repl || new ReplManager(options); this.command = new Command(tasks); + this.repl = null; + this.interfaceAdapter = createInterfaceAdapter({ provider: options.provider, networkType: options.networks[options.network].type @@ -54,37 +56,22 @@ class Console extends EventEmitter { provider: options.provider, networkType: options.networks[options.network].type }); - - // Bubble the ReplManager's exit event - this.repl.on("exit", () => this.emit("exit")); - - // Bubble the ReplManager's reset event - this.repl.on("reset", () => this.emit("reset")); } - 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; - + start() { try { this.interfaceAdapter.getAccounts().then(fetchedAccounts => { const abstractions = this.provision(); - this.repl.start({ + this.repl = repl.start({ prompt: "truffle(" + this.options.network + ")> ", - context: { - web3: this.web3, - interfaceAdapter: this.interfaceAdapter, - accounts: fetchedAccounts - }, - interpreter: this.interpret.bind(this), - done: callback + eval: this.interpret.bind(this) }); + this.repl.context.web3 = this.web3; + this.repl.context.interfaceAdapter = this.interfaceAdapter; + this.repl.context.accounts = fetchedAccounts; + this.resetContractsInConsoleContext(abstractions); }); } catch (error) { @@ -143,8 +130,41 @@ class Console extends EventEmitter { abstractions.forEach(abstraction => { contextVars[abstraction.contract_name] = abstraction; }); + } + + runSpawn(inputStrings, options, callback) { + let childPath; + if (typeof BUNDLE_CONSOLE_CHILD_FILENAME !== "undefined") { + childPath = path.join(__dirname, BUNDLE_CONSOLE_CHILD_FILENAME); + } else { + childPath = path.join(__dirname, "../lib/console-child.js"); + } - this.repl.setContextVars(contextVars); + const spawnOptions = { stdio: ["inherit", "inherit", "inherit"] }; + + const spawnInput = "--network " + options.network + " -- " + inputStrings; + + try { + spawnSync( + "node", + ["--no-deprecation", childPath, spawnInput], + spawnOptions + ); + + try { + this.provision(); + } catch (e) { + console.log(e); + } + } catch (err) { + callback(err); + } + //want repl to exit when it receives an exit command + this.repl.on("exit", () => { + process.exit(); + }); + //display prompt when child repl process is finished + this.repl.displayPrompt(); } interpret(input, context, filename, callback) { @@ -152,7 +172,7 @@ class Console extends EventEmitter { if ( this.command.getCommand(processedInput, this.options.noAliases) != null ) { - return this.command.run(processedInput, this.options, error => { + return this.runSpawn(processedInput, this.options, error => { if (error) { // Perform error handling ourselves. if (error instanceof TruffleError) { diff --git a/packages/core/lib/debug/interpreter.js b/packages/core/lib/debug/interpreter.js index 8e27e8a56c5..c3d627f550e 100644 --- a/packages/core/lib/debug/interpreter.js +++ b/packages/core/lib/debug/interpreter.js @@ -10,7 +10,7 @@ const selectors = require("@truffle/debugger").selectors; const { session, solidity, trace, evm, controller } = selectors; const analytics = require("../services/analytics"); -const ReplManager = require("../repl"); +const repl = require("repl"); const { DebugPrinter } = require("./printer"); @@ -40,9 +40,8 @@ class DebugInterpreter { this.printer = new DebugPrinter(config, session); this.txHash = txHash; this.lastCommand = "n"; - - this.repl = config.repl || new ReplManager(config); this.enabledExpressions = new Set(); + this.repl = null; } async setOrClearBreakpoint(args, setOrClear) { @@ -276,24 +275,14 @@ class DebugInterpreter { ? DebugUtils.formatPrompt(this.network, this.txHash) : DebugUtils.formatPrompt(this.network); - this.repl.start({ - prompt, - interpreter: util.callbackify(this.interpreter.bind(this)), + this.repl = repl.start({ + prompt: prompt, + eval: util.callbackify(this.interpreter.bind(this)), ignoreUndefined: true, done: terminate }); } - setPrompt(prompt) { - this.repl.activate.bind(this.repl)({ - prompt, - context: {}, - //this argument only *adds* things, so it's safe to set it to {} - ignoreUndefined: true - //set to true because it's set to true below :P - }); - } - async interpreter(cmd) { cmd = cmd.trim(); let cmdArgs, splitArgs; @@ -304,10 +293,7 @@ class DebugInterpreter { } //split arguments for commands that want that; split on runs of spaces - splitArgs = cmd - .trim() - .split(/ +/) - .slice(1); + splitArgs = cmd.trim().split(/ +/).slice(1); debug("splitArgs %O", splitArgs); //warning: this bit *alters* cmd! @@ -324,7 +310,7 @@ class DebugInterpreter { //quit if that's what we were given if (cmd === "q") { - return await util.promisify(this.repl.stop.bind(this.repl))(); + process.exit(); } let alreadyFinished = this.session.view(trace.finishedOrUnloaded); @@ -407,7 +393,7 @@ class DebugInterpreter { if (this.session.view(selectors.session.status.success)) { txSpinner.succeed(); //if successful, change prompt - this.setPrompt(DebugUtils.formatPrompt(this.network, cmdArgs)); + this.repl.setPrompt(DebugUtils.formatPrompt(this.network, cmdArgs)); } else { txSpinner.fail(); loadFailed = true; @@ -430,7 +416,7 @@ class DebugInterpreter { if (this.session.view(selectors.session.status.loaded)) { await this.session.unload(); this.printer.print("Transaction unloaded."); - this.setPrompt(DebugUtils.formatPrompt(this.network)); + this.repl.setPrompt(DebugUtils.formatPrompt(this.network)); } else { this.printer.print("No transaction to unload."); this.printer.print(""); diff --git a/packages/core/lib/repl.js b/packages/core/lib/repl.js deleted file mode 100644 index fb69a7e1389..00000000000 --- a/packages/core/lib/repl.js +++ /dev/null @@ -1,132 +0,0 @@ -var repl = require("repl"); -var expect = require("@truffle/expect"); -var EventEmitter = require("events"); -var inherits = require("util").inherits; - -inherits(ReplManager, EventEmitter); - -function ReplManager(options) { - EventEmitter.call(this); - - expect.options(options, [ - "working_directory", - "contracts_directory", - "contracts_build_directory", - "migrations_directory", - "network", - "network_id", - "provider", - "resolver", - "build_directory" - ]); - - this.options = options; - this.repl = options.repl; - - this.contexts = []; -} - -ReplManager.prototype.start = function(options) { - var self = this; - - this.contexts.push({ - prompt: options.prompt, - interpreter: options.interpreter, - ignoreUndefined: options.ignoreUndefined || false, - done: options.done - }); - - var currentContext = this.contexts[this.contexts.length - 1]; - - if (!this.repl) { - this.repl = repl.start({ - prompt: currentContext.prompt, - eval: this.interpret.bind(this) - }); - - this.repl.on("exit", async function() { - // If we exit for some reason, call done functions for good measure - // then ensure the process is completely killed. Once the repl exits, - // the process is in a bad state and can't be recovered (e.g., stdin is closed). - try { - for (const context of self.contexts) { - if (context.done) await context.done(); - } - } catch (error) { - throw error; - } finally { - process.exit(); - } - }); - } - - // Bubble the internal repl's exit event - this.repl.on("exit", function() { - self.emit("exit"); - }); - - // Bubble the internal repl's reset event - this.repl.on("reset", function() { - process.stdout.write("\u001B[2J\u001B[0;0f"); - self.emit("reset"); - }); - - this.repl.setPrompt(options.prompt); - this.setContextVars(options.context || {}); - this.activate(options); -}; - -ReplManager.prototype.setContextVars = function(obj) { - var self = this; - if (this.repl) { - Object.keys(obj || {}).forEach(function(key) { - self.repl.context[key] = obj[key]; - }); - } -}; - -ReplManager.prototype.activate = function(session) { - const { prompt, context, ignoreUndefined } = session; - this.repl.setPrompt(prompt); - this.repl.ignoreUndefined = ignoreUndefined; - this.setContextVars(context); -}; - -ReplManager.prototype.stop = function(callback) { - var oldContext = this.contexts.pop(); - - if (oldContext.done) { - oldContext.done(); - } - - var currentContext = this.contexts[this.contexts.length - 1]; - - if (currentContext) { - this.activate(currentContext); - } else { - // If there's no new context, stop the process altogether. - // Though this might seem like an out of place process.exit(), - // once the Node repl closes, the state of the process is not - // recoverable; e.g., stdin is closed and can't be reopened. - // Since we can't recover to a state before the repl was opened, - // we should just exit. He're, we'll exit after we've popped - // off the stack of all repl contexts. - process.exit(); - } - - if (callback) { - callback(); - } -}; - -ReplManager.prototype.interpret = function( - replInput, - context, - filename, - callback -) { - const currentContext = this.contexts[this.contexts.length - 1]; - currentContext.interpreter(replInput, context, filename, callback); -}; - -module.exports = ReplManager; diff --git a/packages/truffle/test/scenarios/library/api.js b/packages/truffle/test/scenarios/library/api.js index f69d92ec4b6..6511ec30c7a 100644 --- a/packages/truffle/test/scenarios/library/api.js +++ b/packages/truffle/test/scenarios/library/api.js @@ -5,7 +5,7 @@ describe("Truffle Library APIs [ @standalone ]", () => { if (process.env.NO_BUILD) return; let truffle; - before(function() { + before(function () { this.timeout(10000); truffle = require("../../../build/library.bundled.js"); }); @@ -23,11 +23,6 @@ describe("Truffle Library APIs [ @standalone ]", () => { assert(truffle.create.migration, "create.migration undefined"); }); - it("truffle.console API definition", () => { - // This one returns a constructor. - assert(truffle.console, "console undefined"); - }); - it("truffle.contracts API definition", () => { assert(truffle.contracts.compile, "contracts.compile undefined"); assert( diff --git a/packages/truffle/webpack.config.js b/packages/truffle/webpack.config.js index c2e63314e43..d4a651fc223 100644 --- a/packages/truffle/webpack.config.js +++ b/packages/truffle/webpack.config.js @@ -40,13 +40,21 @@ module.exports = { "@truffle/core", "index.js" ), + consoleChild: path.join( + __dirname, + "../..", + "node_modules", + "@truffle/core", + "lib", + "console-child.js" + ) }, target: "node", node: { // For this option, see here: https://github.com/webpack/webpack/issues/1599 __dirname: false, - __filename: false, + __filename: false }, context: rootDir, @@ -54,12 +62,12 @@ module.exports = { path: outputDir, filename: "[name].bundled.js", library: "", - libraryTarget: "commonjs", + libraryTarget: "commonjs" }, devtool: "source-map", optimization: { - minimize: false, + minimize: false }, module: { @@ -69,11 +77,11 @@ module.exports = { test: /\.js$/, include: [ path.resolve(__dirname, "../core"), - path.resolve(__dirname, "../environment"), + path.resolve(__dirname, "../environment") ], - use: "shebang-loader", - }, - ], + use: "shebang-loader" + } + ] }, externals: [ @@ -81,7 +89,7 @@ module.exports = { // Here, we leave it as an external, and use the original-require // module that's a dependency of Truffle instead. /^original-require$/, - /^mocha$/, + /^mocha$/ ], resolve: { @@ -96,12 +104,12 @@ module.exports = { "bn.js" ), "original-fs": path.join(__dirname, "./nil.js"), - "scrypt": "js-scrypt", - }, + "scrypt": "js-scrypt" + } }, stats: { - warnings: false, + warnings: false }, plugins: [ @@ -110,6 +118,7 @@ module.exports = { BUNDLE_CHAIN_FILENAME: JSON.stringify("chain.bundled.js"), BUNDLE_ANALYTICS_FILENAME: JSON.stringify("analytics.bundled.js"), BUNDLE_LIBRARY_FILENAME: JSON.stringify("library.bundled.js"), + BUNDLE_CONSOLE_CHILD_FILENAME: JSON.stringify("consoleChild.bundled.js") }), // Put the shebang back on. @@ -128,7 +137,7 @@ module.exports = { "init", "initSource" ), - to: "initSource", + to: "initSource" }, { from: path.join( @@ -139,7 +148,7 @@ module.exports = { "lib", "testing", "Assert.sol" - ), + ) }, { from: path.join( @@ -150,7 +159,7 @@ module.exports = { "lib", "testing", "AssertAddress.sol" - ), + ) }, { from: path.join( @@ -161,7 +170,7 @@ module.exports = { "lib", "testing", "AssertAddressArray.sol" - ), + ) }, { from: path.join( @@ -172,7 +181,7 @@ module.exports = { "lib", "testing", "AssertAddressPayableArray.sol" - ), + ) }, { from: path.join( @@ -183,7 +192,7 @@ module.exports = { "lib", "testing", "AssertBalance.sol" - ), + ) }, { from: path.join( @@ -194,7 +203,7 @@ module.exports = { "lib", "testing", "AssertBool.sol" - ), + ) }, { from: path.join( @@ -205,7 +214,7 @@ module.exports = { "lib", "testing", "AssertBytes32.sol" - ), + ) }, { from: path.join( @@ -216,7 +225,7 @@ module.exports = { "lib", "testing", "AssertBytes32Array.sol" - ), + ) }, { from: path.join( @@ -227,7 +236,7 @@ module.exports = { "lib", "testing", "AssertGeneral.sol" - ), + ) }, { from: path.join( @@ -238,7 +247,7 @@ module.exports = { "lib", "testing", "AssertInt.sol" - ), + ) }, { from: path.join( @@ -249,7 +258,7 @@ module.exports = { "lib", "testing", "AssertIntArray.sol" - ), + ) }, { from: path.join( @@ -260,7 +269,7 @@ module.exports = { "lib", "testing", "AssertString.sol" - ), + ) }, { from: path.join( @@ -271,7 +280,7 @@ module.exports = { "lib", "testing", "AssertUint.sol" - ), + ) }, { from: path.join( @@ -282,7 +291,7 @@ module.exports = { "lib", "testing", "AssertUintArray.sol" - ), + ) }, { from: path.join( @@ -293,7 +302,7 @@ module.exports = { "lib", "testing", "NewSafeSend.sol" - ), + ) }, { from: path.join( @@ -304,7 +313,7 @@ module.exports = { "lib", "testing", "OldSafeSend.sol" - ), + ) }, { from: path.join( @@ -318,13 +327,13 @@ module.exports = { "templates/" ), to: "templates", - flatten: true, - }, + flatten: true + } ]), new CleanWebpackPlugin(), // Make web3 1.0 packable - new webpack.IgnorePlugin(/^electron$/), - ], + new webpack.IgnorePlugin(/^electron$/) + ] }; From 075036149b999d55f7e6177e6393b6bfbb0548b3 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Thu, 27 Aug 2020 16:02:04 -0700 Subject: [PATCH 05/13] fix yargs to properly pass network --- packages/core/lib/console-child.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 6c6d77da51e..cf59f868007 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -9,9 +9,10 @@ const inputStrings = input[1]; //detect config so we can get the provider and resolver without having to serialize //and deserialize them -const detectedConfig = Config.detect({ network: yargs(input[0]).network }); +const detectedConfig = Config.detect({ network: yargs(input[0]).argv.network }); const customConfig = detectedConfig.networks.develop || {}; - +// console.log("custom config? " + JSON.stringify(customConfig)); +// console.log("detected config " + JSON.stringify(detectedConfig)); //need host and port for provider url const ganacheOptions = { host: customConfig.host || "127.0.0.1", From f711427458a6feadf646bb187de2d3504b550150 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Thu, 27 Aug 2020 17:06:15 -0700 Subject: [PATCH 06/13] Remove console logs from earlier debugging --- packages/core/lib/console-child.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index cf59f868007..83dcc010221 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -11,8 +11,7 @@ const inputStrings = input[1]; //and deserialize them const detectedConfig = Config.detect({ network: yargs(input[0]).argv.network }); const customConfig = detectedConfig.networks.develop || {}; -// console.log("custom config? " + JSON.stringify(customConfig)); -// console.log("detected config " + JSON.stringify(detectedConfig)); + //need host and port for provider url const ganacheOptions = { host: customConfig.host || "127.0.0.1", From 217192b048a15352f04d925f8463fa4139aa680f Mon Sep 17 00:00:00 2001 From: fainashalts Date: Thu, 27 Aug 2020 17:57:35 -0700 Subject: [PATCH 07/13] Replace setContextVars fx to use ES6 spread operators --- packages/core/lib/console.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 5256dbd1244..2419beede27 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -60,11 +60,7 @@ class Console extends EventEmitter { } setContextVars(obj) { - const context = {}; - Object.keys(obj || {}).forEach(function (key) { - context[key] = obj[key]; - }); - return context; + return { ...obj }; } start() { From 2186ab05f510f51ff8f898968a3cce796cd5acaf Mon Sep 17 00:00:00 2001 From: fainashalts Date: Thu, 27 Aug 2020 18:18:14 -0700 Subject: [PATCH 08/13] Rework resetContractsInConsoleContext to preserve existing context vars --- packages/core/lib/console.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 2419beede27..409040b5c2d 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -42,7 +42,6 @@ class Console extends EventEmitter { "build_directory" ]); - this.context = {}; this.options = options; this.command = new Command(tasks); @@ -73,13 +72,11 @@ class Console extends EventEmitter { eval: this.interpret.bind(this) }); - this.resetContractsInConsoleContext(abstractions); - - // set these repl context vars after setting contracts to - // make sure they don't get overwritten this.repl.context.web3 = this.web3; this.repl.context.interfaceAdapter = this.interfaceAdapter; this.repl.context.accounts = fetchedAccounts; + + this.resetContractsInConsoleContext(abstractions); }); } catch (error) { this.options.logger.log( @@ -137,11 +134,12 @@ class Console extends EventEmitter { contextVars[abstraction.contract_name] = abstraction; }); - this.context = this.setContextVars(contextVars); - // make sure the repl gets the new contracts in its context if (this.repl) { - this.repl.context = this.context; + this.repl.context = { + ...this.repl.context, + ...this.setContextVars(contextVars) + }; } } From bab017a3090d6c617d4c7837ecd760f49feca986 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Fri, 28 Aug 2020 13:53:14 -0700 Subject: [PATCH 09/13] Remove spread operator use to ensure JS scripts persist between commands --- packages/core/lib/console.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 409040b5c2d..19400e020bc 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -58,10 +58,6 @@ class Console extends EventEmitter { }); } - setContextVars(obj) { - return { ...obj }; - } - start() { try { this.interfaceAdapter.getAccounts().then(fetchedAccounts => { @@ -136,10 +132,9 @@ class Console extends EventEmitter { // make sure the repl gets the new contracts in its context if (this.repl) { - this.repl.context = { - ...this.repl.context, - ...this.setContextVars(contextVars) - }; + Object.keys(contextVars || {}).forEach(key => { + this.repl.context[key] = contextVars[key]; + }); } } From 6f13f08c0a7f0ce1329617de246e909fae83e4d3 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Fri, 28 Aug 2020 14:14:28 -0700 Subject: [PATCH 10/13] Remove this.repl check and move provisioning in start() to after repl creation --- packages/core/lib/console.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 19400e020bc..bbde8f58ae3 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -61,8 +61,6 @@ class Console extends EventEmitter { start() { try { this.interfaceAdapter.getAccounts().then(fetchedAccounts => { - const abstractions = this.provision(); - this.repl = repl.start({ prompt: "truffle(" + this.options.network + ")> ", eval: this.interpret.bind(this) @@ -72,7 +70,7 @@ class Console extends EventEmitter { this.repl.context.interfaceAdapter = this.interfaceAdapter; this.repl.context.accounts = fetchedAccounts; - this.resetContractsInConsoleContext(abstractions); + this.provision(); }); } catch (error) { this.options.logger.log( @@ -131,11 +129,9 @@ class Console extends EventEmitter { }); // make sure the repl gets the new contracts in its context - if (this.repl) { - Object.keys(contextVars || {}).forEach(key => { - this.repl.context[key] = contextVars[key]; - }); - } + Object.keys(contextVars || {}).forEach(key => { + this.repl.context[key] = contextVars[key]; + }); } runSpawn(inputStrings, options, callback) { From 029d6b55bf5f63503d784dc26acd27cbe6e0d046 Mon Sep 17 00:00:00 2001 From: fainashalts Date: Fri, 28 Aug 2020 15:28:32 -0700 Subject: [PATCH 11/13] Move repl.start outside of fetching accounts, move exit listener to start function --- packages/core/lib/console.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index bbde8f58ae3..8f8ee9f221c 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -60,17 +60,21 @@ class Console extends EventEmitter { start() { try { - this.interfaceAdapter.getAccounts().then(fetchedAccounts => { - this.repl = repl.start({ - prompt: "truffle(" + this.options.network + ")> ", - eval: this.interpret.bind(this) - }); + this.repl = repl.start({ + prompt: "truffle(" + this.options.network + ")> ", + eval: this.interpret.bind(this) + }); + this.interfaceAdapter.getAccounts().then(fetchedAccounts => { this.repl.context.web3 = this.web3; this.repl.context.interfaceAdapter = this.interfaceAdapter; this.repl.context.accounts = fetchedAccounts; + }); + this.provision(); - this.provision(); + //want repl to exit when it receives an exit command + this.repl.on("exit", () => { + process.exit(); }); } catch (error) { this.options.logger.log( @@ -160,10 +164,7 @@ class Console extends EventEmitter { } catch (err) { callback(err); } - //want repl to exit when it receives an exit command - this.repl.on("exit", () => { - process.exit(); - }); + //display prompt when child repl process is finished this.repl.displayPrompt(); } From be9b260f354219dfd69b935b3e7c16fff139abca Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 9 Sep 2020 11:19:22 -0400 Subject: [PATCH 12/13] Split code shared by cli.js and console-child.js out into its own bundle --- packages/core/cli.js | 4 ++-- packages/core/lib/console-child.js | 2 +- packages/truffle/webpack.config.js | 12 +++++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/core/cli.js b/packages/core/cli.js index 9152eaa4c6d..1778b855914 100755 --- a/packages/core/cli.js +++ b/packages/core/cli.js @@ -31,7 +31,7 @@ if (!semver.satisfies(process.version, ">=" + minimumNodeVersion)) { const Command = require("./lib/command"); -const command = new Command(require("./lib/commands")); +const command = new Command(require("./commands.bundled.js")); // This should be removed when issue is resolved upstream: // https://github.com/ethereum/web3.js/issues/1648 @@ -49,7 +49,7 @@ if (userWantsGeneralHelp) { process.exit(0); } -command.run(inputArguments, options, function(err) { +command.run(inputArguments, options, function (err) { if (err) { if (err instanceof TaskError) { analytics.send({ diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 83dcc010221..1abbf835ab7 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -29,7 +29,7 @@ detectedConfig.networks.develop = { } }; -const command = new Command(require("../lib/commands")); +const command = new Command(require("./commands.bundled.js")); command.run(inputStrings, detectedConfig, error => { if (error) { diff --git a/packages/truffle/webpack.config.js b/packages/truffle/webpack.config.js index d4a651fc223..fb8a6dd1729 100644 --- a/packages/truffle/webpack.config.js +++ b/packages/truffle/webpack.config.js @@ -47,6 +47,14 @@ module.exports = { "@truffle/core", "lib", "console-child.js" + ), + commands: path.join( + __dirname, + "../..", + "node_modules", + "@truffle/core", + "lib", + "commands/index.js" ) }, @@ -89,7 +97,9 @@ module.exports = { // Here, we leave it as an external, and use the original-require // module that's a dependency of Truffle instead. /^original-require$/, - /^mocha$/ + /^mocha$/, + // this is the commands portion shared by cli.js and console-child.js + /^\.\/commands.bundled.js$/ ], resolve: { From eb8112cc962f37ddcba69cb658c23afdbc923b60 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 9 Sep 2020 12:30:34 -0400 Subject: [PATCH 13/13] Add conditional logic to either use the raw JS or the bundles depending on the context --- packages/core/cli.js | 7 ++++++- packages/core/lib/console-child.js | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/core/cli.js b/packages/core/cli.js index 1778b855914..336f9cc74e0 100755 --- a/packages/core/cli.js +++ b/packages/core/cli.js @@ -31,7 +31,12 @@ if (!semver.satisfies(process.version, ">=" + minimumNodeVersion)) { const Command = require("./lib/command"); -const command = new Command(require("./commands.bundled.js")); +// enable Truffle to run both from the bundles out of packages/dist +// and using the raw JS directly - we inject BUNDLE_VERSION when building +const command = + typeof BUNDLE_VERSION !== "undefined" + ? new Command(require("./commands.bundled.js")) + : new Command(require("./lib/commands")); // This should be removed when issue is resolved upstream: // https://github.com/ethereum/web3.js/issues/1648 diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 1abbf835ab7..dd5b56ad8ad 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -29,7 +29,12 @@ detectedConfig.networks.develop = { } }; -const command = new Command(require("./commands.bundled.js")); +// enable Truffle to run both from the bundles out of packages/dist +// and using the raw JS directly - we inject BUNDLE_VERSION when building +const command = + typeof BUNDLE_VERSION !== "undefined" + ? new Command(require("./commands.bundled.js")) + : new Command(require("./commands")); command.run(inputStrings, detectedConfig, error => { if (error) {