diff --git a/.circleci/config.yml b/.circleci/config.yml index 04bea2dccc..188cde6d17 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -26,10 +26,10 @@ jobs: - checkout - restore_cache: keys: - - dep-bundle-15-{{ checksum "package.json" }} + - dep-bundle-16-{{ checksum "package.json" }} - run: npm install - save_cache: - key: dep-bundle-15-{{ checksum "package.json" }} + key: dep-bundle-16-{{ checksum "package.json" }} paths: - ~/repo/node_modules - run: npm run lint && npm run test && npm run downloadsolc && npm run make-mock-compiler && npm run build @@ -46,10 +46,10 @@ jobs: - checkout - restore_cache: keys: - - dep-bundle-10-{{ checksum "package.json" }} + - dep-bundle-11-{{ checksum "package.json" }} - run: npm install - save_cache: - key: dep-bundle-10-{{ checksum "package.json" }} + key: dep-bundle-11-{{ checksum "package.json" }} paths: - ~/repo/node_modules - run: npm run build_debugger diff --git a/src/app/files/compiler-metadata.js b/src/app/files/compiler-metadata.js new file mode 100644 index 0000000000..8a29287e84 --- /dev/null +++ b/src/app/files/compiler-metadata.js @@ -0,0 +1,69 @@ +'use strict' + +class CompilerMetadata { + constructor (events, opts) { + var self = this + self._events = events + self._opts = opts + } + + syncContractMetadata () { + var self = this + self._events.compiler.register('compilationFinished', (success, data, source) => { + if (success) { + var provider = self._opts.fileManager.currentFileProvider() + var path = self._opts.fileManager.currentPath() + if (provider && path) { + self._opts.compiler.visitContracts((contract) => { + var fileName = path + '/' + contract.name + '.json' + provider.get(fileName, (error, content) => { + if (!error) { + content = content || '{}' + var metadata + try { + metadata = JSON.parse(content) + } catch (e) { + console.log(e) + } + var linkReferences = metadata['linkReferences'] + var autoDeployLib = metadata['autoDeployLib'] + if (!linkReferences) linkReferences = {} + if (autoDeployLib === undefined) autoDeployLib = true + for (var libFile in contract.object.evm.bytecode.linkReferences) { + if (!linkReferences[libFile]) linkReferences[libFile] = {} + for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { + if (!linkReferences[libFile][lib]) { + linkReferences[libFile][lib] = '
' + } + } + } + metadata['linkReferences'] = linkReferences + metadata['autoDeployLib'] = autoDeployLib + provider.set(fileName, JSON.stringify(metadata, null, '\t')) + } + }) + }) + } + } + }) + } + + metadataOf (contractName, callback) { + var self = this + var provider = self._opts.fileManager.currentFileProvider() + var path = self._opts.fileManager.currentPath() + if (provider && path) { + var fileName = path + '/' + contractName + '.json' + provider.get(fileName, (error, content) => { + if (error) return callback(error) + try { + callback(null, JSON.parse(content)) + } catch (e) { + callback(e.message) + } + }) + } + } +} + +module.exports = CompilerMetadata diff --git a/src/app/files/fileManager.js b/src/app/files/fileManager.js index fbaf2dc0d7..17e13486f4 100644 --- a/src/app/files/fileManager.js +++ b/src/app/files/fileManager.js @@ -71,6 +71,14 @@ class FileManager { this.refreshTabs() } + currentFileProvider () { + var path = this.currentPath() + if (path) { + return this.fileProviderOf(path) + } + return null + } + currentPath () { var self = this var currentFile = self._deps.config.get('currentFile') diff --git a/src/app/panels/file-panel.js b/src/app/panels/file-panel.js index b30bfb86eb..e990d4a9db 100644 --- a/src/app/panels/file-panel.js +++ b/src/app/panels/file-panel.js @@ -2,6 +2,7 @@ var async = require('async') var $ = require('jquery') var yo = require('yo-yo') +var CompilerMetadata = require('../files/compiler-metadata') var remixLib = require('remix-lib') var Gists = require('gists') var EventManager = remixLib.EventManager @@ -48,7 +49,8 @@ function filepanel (localRegistry) { self._deps = { fileProviders: self._components.registry.get('fileproviders').api, fileManager: self._components.registry.get('filemanager').api, - config: self._components.registry.get('config').api + config: self._components.registry.get('config').api, + compiler: self._components.registry.get('compiler').api } var fileExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['browser']) var fileSystemExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['localhost']) @@ -57,6 +59,19 @@ function filepanel (localRegistry) { var gistExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['gist']) var configExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['config']) + // ----------------- editor panel ---------------------- + self._compilerMetadata = new CompilerMetadata( + { + compiler: self._deps.compiler.event + }, + { + fileManager: self._deps.fileManager, + compiler: self._deps.compiler + } + ) + self._compilerMetadata.syncContractMetadata() + + self.compilerMetadata = () => { return self._compilerMetadata } var dragbar = yo`
` function remixdDialog () { diff --git a/src/app/tabs/compile-tab.js b/src/app/tabs/compile-tab.js index 4de77bfd16..d128c99cc3 100644 --- a/src/app/tabs/compile-tab.js +++ b/src/app/tabs/compile-tab.js @@ -61,9 +61,9 @@ module.exports = class CompileTab { if (speed > self.data.maxTime) { const msg = `Last compilation took ${speed}ms. We suggest to turn off autocompilation.` self._view.warnCompilationSlow.setAttribute('title', msg) - self._view.warnCompilationSlow.style.display = 'inline-block' + self._view.warnCompilationSlow.style.visibility = 'visible' } else { - self._view.warnCompilationSlow.style.display = 'none' + self._view.warnCompilationSlow.style.visibility = 'hidden' } }) self._deps.editor.event.register('contentChanged', function changedFile () { @@ -75,7 +75,7 @@ module.exports = class CompileTab { self._deps.compiler.event.register('loadingCompiler', function start () { if (!self._view.compileIcon) return self._view.compileIcon.classList.add(`${css.spinningIcon}`) - self._view.warnCompilationSlow.style.display = 'none' + self._view.warnCompilationSlow.style.visibility = 'hidden' self._view.compileIcon.setAttribute('title', 'compiler is loading, please wait a few moments.') }) self._deps.compiler.event.register('compilationStarted', function start () { @@ -149,7 +149,7 @@ module.exports = class CompileTab { render () { const self = this if (self._view.el) return self._view.el - self._view.warnCompilationSlow = yo`` + self._view.warnCompilationSlow = yo`` self._view.compileIcon = yo`` self._view.compileButton = yo`
${self._view.compileIcon} Start to compile
` self._view.autoCompile = yo`` @@ -339,7 +339,10 @@ const css = csjs` margin-bottom: 2%; } .autocompileContainer { - width: 90px; + display: flex; + align-items: center; + } + .hideWarningsContainer { display: flex; align-items: center; } diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js index 75589c0ff0..f14f144d33 100644 --- a/src/app/tabs/run-tab.js +++ b/src/app/tabs/run-tab.js @@ -72,7 +72,8 @@ function runTab (opts, localRegistry) { config: self._components.registry.get('config').api, fileManager: self._components.registry.get('filemanager').api, editor: self._components.registry.get('editor').api, - logCallback: self._components.registry.get('logCallback').api + logCallback: self._components.registry.get('logCallback').api, + filePanel: self._components.registry.get('filepanel').api } self._deps.udapp.resetAPI(self._components.transactionContextAPI) self._view.recorderCount = yo`0` @@ -128,9 +129,9 @@ function runTab (opts, localRegistry) { status.appendChild(self._view.collapsedView) } }) - /* ------------------------- - MAIN HTML ELEMENT - --------------------------- */ + /* ------------------------- + MAIN HTML ELEMENT + --------------------------- */ var el = yo`
${settings(container, self)} @@ -386,6 +387,31 @@ function contractDropdown (events, self) { selectContractNames.addEventListener('change', setInputParamsPlaceHolder) + function createInstanceCallback (error, selectedContract, data) { + if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) + self._deps.logCallback(`creation of ${selectedContract.name} pending...`) + self._deps.udapp.createContract(data, (error, txResult) => { + if (!error) { + var isVM = executionContext.isVM() + if (isVM) { + var vmError = txExecution.checkVMError(txResult) + if (vmError.error) { + self._deps.logCallback(vmError.message) + return + } + } + if (txResult.result.status && txResult.result.status === '0x0') { + self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) + return + } + var noInstancesText = self._view.noInstancesText + if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } + var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress + instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) + } + }) + } + // DEPLOY INSTANCE function createInstance (args) { var selectedContract = getSelectedContract() @@ -396,39 +422,22 @@ function contractDropdown (events, self) { } var constructor = txHelper.getConstructorInterface(selectedContract.contract.object.abi) - txFormat.buildData(selectedContract.name, selectedContract.contract.object, self._deps.compiler.getContracts(), true, constructor, args, (error, data) => { - if (!error) { - self._deps.logCallback(`creation of ${selectedContract.name} pending...`) - self._deps.udapp.createContract(data, (error, txResult) => { - if (error) { - self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) - } else { - var isVM = executionContext.isVM() - if (isVM) { - var vmError = txExecution.checkVMError(txResult) - if (vmError.error) { - self._deps.logCallback(vmError.message) - return - } - } - if (txResult.result.status && txResult.result.status === '0x0') { - self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) - return - } - var noInstancesText = self._view.noInstancesText - if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } - var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress - instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) - } + self._deps.filePanel.compilerMetadata().metadataOf(selectedContract.name, (error, contractMetadata) => { + if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) + if (contractMetadata.autoDeployLib) { + txFormat.buildData(selectedContract.name, selectedContract.contract.object, self._deps.compiler.getContracts(), true, constructor, args, (error, data) => { + createInstanceCallback(error, selectedContract, data) + }, (msg) => { + self._deps.logCallback(msg) + }, (data, runTxCallback) => { + // called for libraries deployment + self._deps.udapp.runTx(data, runTxCallback) }) } else { - self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) + txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.contract.object, args, constructor, contractMetadata.linkReferences, selectedContract.contract.object.evm.bytecode.linkReferences, (error, data) => { + createInstanceCallback(error, selectedContract, data) + }) } - }, (msg) => { - self._deps.logCallback(msg) - }, (data, runTxCallback) => { - // called for libraries deployment - self._deps.udapp.runTx(data, runTxCallback) }) }