Merge pull request #2589 from ethereum/vmSandbox

Script Execution - Async/Await support
pull/5370/head
yann300 5 years ago committed by GitHub
commit 02915fbadf
  1. 3
      src/app.js
  2. 2
      src/app/components/hidden-panel.js
  3. 37
      src/app/panels/terminal.js
  4. 2
      src/remixAppManager.js
  5. 57
      test-browser/tests/terminal.js

@ -332,6 +332,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
engine.register([ engine.register([
menuicons, menuicons,
landingPage, landingPage,
hiddenPanel,
sidePanel, sidePanel,
pluginManagerComponent, pluginManagerComponent,
filePanel, filePanel,
@ -384,7 +385,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter']) await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter'])
await appManager.activatePlugin(['mainPanel', 'menuicons']) await appManager.activatePlugin(['mainPanel', 'menuicons'])
await appManager.activatePlugin(['home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'terminal']) await appManager.activatePlugin(['home', 'sidePanel', 'hiddenPanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'scriptRunner', 'terminal'])
// Set workspace after initial activation // Set workspace after initial activation
if (Array.isArray(workspace)) await appManager.activatePlugin(workspace) if (Array.isArray(workspace)) await appManager.activatePlugin(workspace)

@ -14,7 +14,7 @@ const profile = {
displayName: 'Hidden Panel', displayName: 'Hidden Panel',
description: '', description: '',
version: packageJson.version, version: packageJson.version,
methods: [] methods: ['addView', 'removeView']
} }
export class HiddenPanel extends AbstractPanel { export class HiddenPanel extends AbstractPanel {

@ -81,7 +81,7 @@ class Terminal extends Plugin {
scopedCommands.log(`> ${script}`) scopedCommands.log(`> ${script}`)
self._shell(script, scopedCommands, function (error, output) { self._shell(script, scopedCommands, function (error, output) {
if (error) scopedCommands.error(error) if (error) scopedCommands.error(error)
else scopedCommands.log(output) else if (output) scopedCommands.log(output)
}) })
}, { activate: true }) }, { activate: true })
function basicFilter (value, query) { try { return value.indexOf(query) !== -1 } catch (e) { return false } } function basicFilter (value, query) { try { return value.indexOf(query) !== -1 } catch (e) { return false } }
@ -98,6 +98,26 @@ class Terminal extends Plugin {
if (opts.shell) self._shell = opts.shell // ??? if (opts.shell) self._shell = opts.shell // ???
register(self) register(self)
} }
onActivation () {
this.on('scriptRunner', 'log', (msg) => {
this.commands['log'].apply(this.commands, msg.data)
})
this.on('scriptRunner', 'info', (msg) => {
this.commands['info'].apply(this.commands, msg.data)
})
this.on('scriptRunner', 'warn', (msg) => {
this.commands['warn'].apply(this.commands, msg.data)
})
this.on('scriptRunner', 'error', (msg) => {
this.commands['error'].apply(this.commands, msg.data)
})
}
onDeactivation () {
this.off('scriptRunner', 'log')
this.off('scriptRunner', 'info')
this.off('scriptRunner', 'warn')
this.off('scriptRunner', 'error')
}
logHtml (html) { logHtml (html) {
var command = this.commands['html'] var command = this.commands['html']
if (typeof command === 'function') command(html) if (typeof command === 'function') command(html)
@ -124,6 +144,7 @@ class Terminal extends Plugin {
${self._view.input} ${self._view.input}
</div> </div>
` `
self._view.icon = yo` self._view.icon = yo`
<i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize} <i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize}
class="btn btn-secondary btn-sm align-items-center ${css.toggleTerminal} fas fa-angle-double-down" data-id="terminalToggleIcon"></i>` class="btn btn-secondary btn-sm align-items-center ${css.toggleTerminal} fas fa-angle-double-down" data-id="terminalToggleIcon"></i>`
@ -659,17 +680,27 @@ class Terminal extends Plugin {
} }
return self.commands[name] return self.commands[name]
} }
_shell (script, scopedCommands, done) { // default shell async _shell (script, scopedCommands, done) { // default shell
if (script.indexOf('remix:') === 0) { if (script.indexOf('remix:') === 0) {
return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.') return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.')
} }
var self = this var self = this
if (script.indexOf('remix.') === 0) {
// we keep the old feature. This will basically only be called when the command is querying the "remix" object.
// for all the other case, we use the Code Executor plugin
var context = domTerminalFeatures(self, scopedCommands, self.blockchain) var context = domTerminalFeatures(self, scopedCommands, self.blockchain)
try { try {
var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered)) var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered))
var result = vm.runInContext(script, cmds) var result = vm.runInContext(script, cmds)
self._jsSandboxContext = Object.assign(cmds, context) self._jsSandboxContext = Object.assign(cmds, context)
done(null, result) return done(null, result)
} catch (error) {
return done(error.message)
}
}
try {
await this.call('scriptRunner', 'execute', script)
done()
} catch (error) { } catch (error) {
done(error.message) done(error.message)
} }

@ -4,7 +4,7 @@ import { EventEmitter } from 'events'
import QueryParams from './lib/query-params' import QueryParams from './lib/query-params'
const requiredModules = [ // services + layout views + system views const requiredModules = [ // services + layout views + system views
'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'scriptRunner',
'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers',
'terminal', 'settings', 'pluginManager'] 'terminal', 'settings', 'pluginManager']

@ -10,7 +10,7 @@ module.exports = {
'Should execution a simple console command': function (browser) { 'Should execution a simple console command': function (browser) {
browser browser
.waitForElementVisible('*[data-id="terminalCli"]', 10000) .waitForElementVisible('*[data-id="terminalCli"]', 10000)
.executeScript('1+1') .executeScript('console.log(1 + 1)')
.journalLastChild('2') .journalLastChild('2')
}, },
@ -52,8 +52,63 @@ module.exports = {
.executeScript('remix.debugHelp()') .executeScript('remix.debugHelp()')
.journalChildIncludes('Here are some examples of scripts that can be run (using remix.exeCurrent() or directly from the console)') .journalChildIncludes('Here are some examples of scripts that can be run (using remix.exeCurrent() or directly from the console)')
.journalChildIncludes('Please see https://www.npmjs.com/package/remix-debug for more informations') .journalChildIncludes('Please see https://www.npmjs.com/package/remix-debug for more informations')
},
'Async/Await Script': function (browser) {
browser
.addFile('asyncAwait.js', { content: asyncAwait })
.switchFile('browser/asyncAwait.js')
.executeScript(`remix.execute('browser/asyncAwait.js')`)
.journalLastChild('Waiting Promise')
.pause(5500)
.journalLastChild('result - Promise Resolved')
},
'Call Remix File Manager from a script': function (browser) {
browser
.addFile('asyncAwaitWithFileManagerAccess.js', { content: asyncAwaitWithFileManagerAccess })
.switchFile('browser/asyncAwaitWithFileManagerAccess.js')
.executeScript(`remix.execute('browser/asyncAwaitWithFileManagerAccess.js')`)
.journalLastChildIncludes('contract Ballot {')
.end() .end()
}, },
tearDown: sauce tearDown: sauce
} }
const asyncAwait = `
var p = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Promise Resolved")
}, 5000)
})
}
var run = async () => {
console.log('Waiting Promise')
var result = await p()
console.log('result - ', result)
}
run()
`
const asyncAwaitWithFileManagerAccess = `
var p = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Promise Resolved")
}, 0)
})
}
var run = async () => {
console.log('Waiting Promise')
var result = await p()
let text = await remix.call('fileManager', 'getFile', 'browser/3_Ballot.sol')
console.log('result - ', text)
}
run()
`

Loading…
Cancel
Save