Merge pull request #2733 from ethereum/filemanager-api

Move filemanager api to new api
pull/5370/head
yann300 5 years ago committed by GitHub
commit db18ddbb61
  1. 23999
      package-lock.json
  2. 4
      package.json
  3. 2
      src/app.js
  4. 2
      src/app/editor/contextView.js
  5. 4
      src/app/editor/sourceHighlighter.js
  6. 34
      src/app/files/file-explorer.js
  7. 264
      src/app/files/fileManager.js
  8. 58
      src/app/files/fileProvider.js
  9. 31
      src/app/files/remixDProvider.js
  10. 2
      src/app/panels/main-view.js
  11. 8
      src/app/panels/tab-proxy.js
  12. 2
      src/app/tabs/compileTab/compilerContainer.js
  13. 2
      src/app/tabs/runTab/model/recorder.js
  14. 4
      src/app/tabs/test-tab.js
  15. 4
      src/app/tabs/testTab/testTab.js
  16. 2
      src/app/ui/renderer.js
  17. 4
      src/lib/cmdInterpreterAPI.js
  18. 38
      src/lib/remixd.js
  19. 8
      test-browser/commands/openFile.js
  20. 2
      test-browser/tests/defaultLayout.test.js
  21. 12
      test-browser/tests/editor.test.js
  22. 6
      test-browser/tests/generalSettings.test.js
  23. 10
      test-browser/tests/gist.test.js
  24. 8
      test-browser/tests/libraryDeployment.test.js
  25. 2
      test-browser/tests/pluginManager.test.js
  26. 6
      test-browser/tests/publishContract.test.js
  27. 2
      test-browser/tests/remixd.test.js
  28. 4
      test-browser/tests/runAndDeploy.js
  29. 2
      test-browser/tests/signingMessage.test.js
  30. 2
      test-browser/tests/solidityImport.test.js
  31. 10
      test-browser/tests/solidityUnittests.test.js
  32. 6
      test-browser/tests/terminal.test.js

23999
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -62,7 +62,7 @@
"remix-solidity": "0.3.30",
"remix-tabs": "1.0.48",
"remix-tests": "0.1.33",
"remixd": "0.1.8-alpha.10",
"remixd": "0.1.8-alpha.16",
"request": "^2.83.0",
"rimraf": "^2.6.1",
"selenium-standalone": "^6.17.0",
@ -81,7 +81,6 @@
"dependencies": {
"@remixproject/engine": "^0.2.3",
"http-server": "^0.11.1",
"remixd": "0.1.8-alpha.10",
"standard": "^8.5.0"
},
"repository": {
@ -185,7 +184,6 @@
"nightwatch_local_fileExplorer": "nightwatch ./test-browser/tests/fileExplorer.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_debugger": "nightwatch ./test-browser/tests/debugger.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_editor": "nightwatch ./test-browser/tests/editor.test.js --config nightwatch.js --env chrome ",
"nightwatch_local_runAndDeploy": "nightwatch ./test-browser/tests/runAndDeploy.js --config nightwatch.js --env chrome-runAndDeploy ",
"onchange": "onchange build/app.js -- npm-run-all lint",
"prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build",

@ -419,7 +419,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
if (error) console.error(error)
if (Object.keys(filesList).length === 0) {
for (let file in examples) {
fileManager.setFile(examples[file].name, examples[file].content)
fileManager.writeFile(examples[file].name, examples[file].content)
}
}
})

@ -112,7 +112,7 @@ class ContextView {
if (provider) {
provider.exists(filename, (error, exist) => {
if (error) return console.log(error)
this._deps.fileManager.switchFile(filename)
this._deps.fileManager.open(filename)
jumpToLine(lineColumn)
})
}

@ -31,7 +31,7 @@ class SourceHighlighter {
}
}
currentSourceLocationFromfileName (lineColumnPos, filePath, style) {
async currentSourceLocationFromfileName (lineColumnPos, filePath, style) {
if (this.statementMarker) this._deps.editor.removeMarker(this.statementMarker, this.source)
if (this.fullLineMarker) this._deps.editor.removeMarker(this.fullLineMarker, this.source)
this.statementMarker = null
@ -40,7 +40,7 @@ class SourceHighlighter {
if (lineColumnPos) {
this.source = filePath
if (this._deps.config.get('currentFile') !== this.source) {
this._deps.fileManager.switchFile(this.source)
await this._deps.fileManager.open(this.source)
}
const css = csjs`

@ -60,7 +60,7 @@ function fileExplorer (localRegistry, files, menuItems) {
}
self.events.register('focus', function (path) {
self._deps.fileManager.switchFile(path)
self._deps.fileManager.open(path)
})
self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` })
@ -234,11 +234,16 @@ function fileExplorer (localRegistry, files, menuItems) {
const currentFoldername = extractNameFromKey(key)
modalDialogCustom.confirm(`Confirm to delete folder`, `Are you sure you want to delete ${currentFoldername} folder?`,
() => {
if (!files.remove(key)) {
async () => {
const fileManager = self._deps.fileManager
const removeFolder = await fileManager.remove(key)
if (!removeFolder) {
tooltip(`failed to remove ${key}. Make sure the directory is empty before removing it.`)
} else {
self.updatePath('browser')
const { type } = fileManager.currentFileProvider()
self.updatePath(type)
}
}, () => {})
}
@ -275,9 +280,16 @@ function fileExplorer (localRegistry, files, menuItems) {
modalDialogCustom.confirm(
`Delete file`, `Are you sure you want to delete ${currentFilename} file?`,
() => {
files.remove(key)
self.updatePath('browser')
async () => {
const fileManager = self._deps.fileManager
const removeFile = await fileManager.remove(key)
if (!removeFile) {
tooltip(`Failed to remove file ${key}.`)
} else {
const { type } = fileManager.currentFileProvider()
self.updatePath(type)
}
},
() => {}
)
@ -578,13 +590,15 @@ fileExplorer.prototype.createNewFile = function (parentFolder = 'browser') {
let self = this
modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => {
if (!input) input = 'New file'
helper.createNonClashingName(parentFolder + '/' + input, self.files, (error, newName) => {
helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => {
if (error) return tooltip('Failed to create file ' + newName + ' ' + error)
const fileManager = self._deps.fileManager
const createFile = await fileManager.writeFile(newName, '')
if (!self.files.set(newName, '')) {
if (!createFile) {
tooltip('Failed to create file ' + newName)
} else {
self._deps.fileManager.switchFile(newName)
await fileManager.open(newName)
if (newName.includes('_test.sol')) {
self.events.trigger('newTestFileCreated', [newName])
}

@ -23,12 +23,19 @@ const profile = {
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjk2IDM4NHE0MCAwIDY4IDI4dDI4IDY4djEyMTZxMCA0MC0yOCA2OHQtNjggMjhoLTk2MHEtNDAgMC02OC0yOHQtMjgtNjh2LTI4OGgtNTQ0cS00MCAwLTY4LTI4dC0yOC02OHYtNjcycTAtNDAgMjAtODh0NDgtNzZsNDA4LTQwOHEyOC0yOCA3Ni00OHQ4OC0yMGg0MTZxNDAgMCA2OCAyOHQyOCA2OHYzMjhxNjgtNDAgMTI4LTQwaDQxNnptLTU0NCAyMTNsLTI5OSAyOTloMjk5di0yOTl6bS02NDAtMzg0bC0yOTkgMjk5aDI5OXYtMjk5em0xOTYgNjQ3bDMxNi0zMTZ2LTQxNmgtMzg0djQxNnEwIDQwLTI4IDY4dC02OCAyOGgtNDE2djY0MGg1MTJ2LTI1NnEwLTQwIDIwLTg4dDQ4LTc2em05NTYgODA0di0xMTUyaC0zODR2NDE2cTAgNDAtMjggNjh0LTY4IDI4aC00MTZ2NjQwaDg5NnoiLz48L3N2Zz4=',
permission: true,
version: packageJson.version,
methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile', 'switchFile'],
methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'rename', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile'],
kind: 'file-system'
}
// File System profile
// - methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile', 'switchFile']
const errorMsg = {
ENOENT: 'No such file or directory',
EISDIR: 'Path is a directory',
ENOTDIR: 'Path is not on a directory',
EEXIST: 'File already exists',
EPERM: 'Permission denied'
}
const createError = (err) => {
return new Error(`${errorMsg[err.code]} ${err.message || ''}`)
}
class FileManager extends Plugin {
constructor (editor) {
@ -42,6 +49,202 @@ class FileManager extends Plugin {
this.init()
}
/**
* Emit error if path doesn't exist
* @param {string} path path of the file/directory
* @param {string} message message to display if path doesn't exist.
*/
async _handleExists (path, message) {
const exists = await this.exists(path)
if (!exists) {
throw createError({ code: 'ENOENT', message })
}
}
/**
* Emit error if path is not a file
* @param {string} path path of the file/directory
* @param {string} message message to display if path is not a file.
*/
async _handleIsFile (path, message) {
const isFile = await this.isFile(path)
if (!isFile) {
throw createError({ code: 'EISDIR', message })
}
}
/**
* Emit error if path is not a directory
* @param {string} path path of the file/directory
* @param {string} message message to display if path is not a directory.
*/
async _handleIsDir (path, message) {
const isDir = await this.isDirectory(path)
if (!isDir) {
throw createError({ code: 'ENOTDIR', message })
}
}
/** The current opened file */
file () {
const file = this.currentFile()
if (!file) throw createError({ code: 'ENOENT', message: 'No file selected' })
return file
}
/**
* Verify if the path exists (directory or file)
* @param {string} path path of the directory or file
* @returns {boolean} true if the path exists
*/
exists (path) {
const provider = this.fileProviderOf(path)
const result = provider.exists(path, (err, result) => {
if (err) return false
return result
})
return result
}
/**
* Verify if the path provided is a file
* @param {string} path path of the directory or file
* @returns {boolean} true if path is a file.
*/
isFile (path) {
const provider = this.fileProviderOf(path)
const result = provider.isFile(path)
return result
}
/**
* Verify if the path provided is a directory
* @param {string} path path of the directory
* @returns {boolean} true if path is a directory.
*/
isDirectory (path) {
const provider = this.fileProviderOf(path)
const result = provider.isDirectory(path)
return result
}
/**
* Open the content of the file in the context (eg: Editor)
* @param {string} path path of the file
* @returns {void}
*/
async open (path) {
await this._handleExists(path, `Cannot open file ${path}`)
await this._handleIsFile(path, `Cannot open file ${path}`)
return this.openFile(path)
}
/**
* Set the content of a specific file
* @param {string} path path of the file
* @param {string} data content to write on the file
* @returns {void}
*/
async writeFile (path, data) {
if (await this.exists(path)) {
await this._handleIsFile(path, `Cannot write file ${path}`)
return await this.setFileContent(path, data)
} else {
return await this.setFileContent(path, data)
}
}
/**
* Return the content of a specific file
* @param {string} path path of the file
* @returns {string} content of the file
*/
async readFile (path) {
await this._handleExists(path, `Cannot read file ${path}`)
await this._handleIsFile(path, `Cannot read file ${path}`)
return this.getFileContent(path)
}
/**
* Upsert a file with the content of the source file
* @param {string} src path of the source file
* @param {string} dest path of the destrination file
* @returns {void}
*/
async copyFile (src, dest) {
await this._handleExists(src, `Cannot copy from ${src}`)
await this._handleIsFile(src, `Cannot copy from ${src}`)
await this._handleIsFile(dest, `Cannot paste content into ${dest}`)
const content = await this.readFile(src)
await this.writeFile(dest, content)
}
/**
* Change the path of a file/directory
* @param {string} oldPath current path of the file/directory
* @param {string} newPath new path of the file/directory
* @returns {void}
*/
async rename (oldPath, newPath) {
await this.__handleExists(oldPath, `Cannot rename ${oldPath}`)
const isFile = await this.isFile(oldPath)
this.fileRenamedEvent(oldPath, newPath, !isFile)
}
/**
* Create a directory
* @param {string} path path of the new directory
* @returns {void}
*/
async mkdir (path) {
if (await this.exists(path)) {
throw createError({ code: 'EEXIST', message: `Cannot create directory ${path}` })
}
const provider = this.fileProviderOf(path)
provider.createDir(path)
}
/**
* Get the list of files in the directory
* @param {string} path path of the directory
* @returns {string[]} list of the file/directory name in this directory
*/
async readdir (path) {
await this._handleExists(path)
await this._handleIsDir(path)
return new Promise((resolve, reject) => {
const provider = this.fileProviderOf(path)
provider.resolveDirectory(path, (error, filesProvider) => {
if (error) reject(error)
resolve(filesProvider)
})
})
}
/**
* Removes a file or directory recursively
* @param {string} path path of the directory/file to remove
* @returns {void}
*/
async remove (path) {
await this._handleExists(path, `Cannot remove file or directory ${path}`)
const provider = this.fileProviderOf(path)
return await provider.remove(path)
}
init () {
this._deps = {
config: this._components.registry.get('config').api,
@ -56,6 +259,11 @@ class FileManager extends Plugin {
this._deps.localhostExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) })
this._deps.localhostExplorer.event.register('errored', (event) => { this.removeTabsOf(this._deps.localhostExplorer) })
this._deps.localhostExplorer.event.register('closed', (event) => { this.removeTabsOf(this._deps.localhostExplorer) })
this.getCurrentFile = this.file
this.getFile = this.readFile
this.getFolder = this.readdir
this.setFile = this.writeFile
this.switchFile = this.open
}
fileChangedEvent (path) {
@ -71,7 +279,7 @@ class FileManager extends Plugin {
delete this.openedFiles[oldName]
this.openedFiles[newName] = newName
}
this.switchFile(newName)
this.openFile(newName)
} else {
var newFocus
for (var k in this.openedFiles) {
@ -85,7 +293,7 @@ class FileManager extends Plugin {
}
}
if (newFocus) {
this.switchFile(newFocus)
this.openFile(newFocus)
}
}
// TODO: Only keep `this.emit` (issue#2210)
@ -129,15 +337,10 @@ class FileManager extends Plugin {
return path ? path[1] : null
}
getCurrentFile () {
const path = this.currentFile()
if (!path) throw new Error('No file selected')
return path
}
getFile (path) {
getFileContent (path) {
const provider = this.fileProviderOf(path)
if (!provider) throw new Error(`${path} not available`)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO: change provider to Promise
return new Promise((resolve, reject) => {
if (this.currentFile() === path) return resolve(this.editor.currentContent())
@ -148,9 +351,9 @@ class FileManager extends Plugin {
})
}
async setFile (path, content) {
async setFileContent (path, content) {
if (this.currentRequest) {
const canCall = await this.askUserPermission('setFile', '')
const canCall = await this.askUserPermission('writeFile', '')
if (canCall) {
this._setFileInternal(path, content)
// inform the user about modification after permission is granted and even if permission was saved before
@ -167,12 +370,12 @@ class FileManager extends Plugin {
`, '', { time: 3000 })
}
}
this._setFileInternal(path, content)
return await this._setFileInternal(path, content)
}
_setFileInternal (path, content) {
const provider = this.fileProviderOf(path)
if (!provider) throw new Error(`${path} not availble`)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO : Add permission
// TODO : Change Provider to Promise
return new Promise((resolve, reject) => {
@ -189,11 +392,10 @@ class FileManager extends Plugin {
if (fileProvider) {
helper.createNonClashingNameWithPrefix(path, fileProvider, '', (error, copyName) => {
if (error) {
console.log('createNonClashingNameWithPrefix', error)
copyName = path + '.' + this.currentRequest.from
}
this._setFileInternal(copyName, content)
this.switchFile(copyName)
this.openFile(copyName)
})
}
}
@ -216,7 +418,7 @@ class FileManager extends Plugin {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('fileRemoved', path)
this.events.emit('fileRemoved', path)
this.switchFile()
this.openFile()
}
unselectCurrentFile () {
@ -227,8 +429,8 @@ class FileManager extends Plugin {
this.events.emit('noFileSelected')
}
switchFile (file) {
const _switchFile = (file) => {
openFile (file) {
const _openFile = (file) => {
this.saveCurrentFile()
this._deps.config.set('currentFile', file)
this.openedFiles[file] = file
@ -247,14 +449,14 @@ class FileManager extends Plugin {
}
})
}
if (file) return _switchFile(file)
if (file) return _openFile(file)
else {
var browserProvider = this._deps.filesProviders['browser']
browserProvider.resolveDirectory('browser', (error, filesProvider) => {
if (error) console.error(error)
var fileList = Object.keys(filesProvider)
if (fileList.length) {
_switchFile(browserProvider.type + '/' + fileList[0])
_openFile(browserProvider.type + '/' + fileList[0])
} else {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected')
@ -264,18 +466,6 @@ class FileManager extends Plugin {
}
}
getFolder (path) {
// TODO : Change provider with promise
return new Promise((resolve, reject) => {
const provider = this.fileProviderOf(path)
if (!provider) return reject(`provider for path ${path} not found`)
provider.resolveDirectory(path, (error, filesProvider) => {
if (error) reject(error)
resolve(filesProvider)
})
})
}
getProvider (name) {
return this._deps.filesProviders[name]
}

@ -66,12 +66,12 @@ class FileProvider {
exists (path, cb) {
// todo check the type (directory/file) as well #2386
// currently it is not possible to have a file and folder with same path
cb(null, this._exists(path))
return cb(null, this._exists(path))
}
_exists (path) {
var unprefixedpath = this.removePrefix(path)
return window.remixFileSystem.existsSync(unprefixedpath)
return path === this.type ? true : window.remixFileSystem.existsSync(unprefixedpath)
}
init (cb) {
@ -94,19 +94,8 @@ class FileProvider {
var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath)
if (exists && window.remixFileSystem.readFileSync(unprefixedpath, 'utf8') === content) return true
if (!exists && unprefixedpath.indexOf('/') !== -1) {
const paths = unprefixedpath.split('/')
paths.pop() // last element should the filename
if (paths.length && paths[0] === '') paths.shift()
let currentCheck = ''
paths.forEach((value) => {
currentCheck = currentCheck + '/' + value
if (!window.remixFileSystem.existsSync(currentCheck)) {
window.remixFileSystem.mkdirSync(currentCheck)
this.event.trigger('folderAdded', [this._normalizePath(currentCheck)])
}
})
this.createDir(path)
}
try {
window.remixFileSystem.writeFileSync(unprefixedpath, content)
@ -123,6 +112,22 @@ class FileProvider {
return true
}
createDir (path, cb) {
var unprefixedpath = this.removePrefix(path)
const paths = unprefixedpath.split('/')
paths.pop() // last element should the filename
if (paths.length && paths[0] === '') paths.shift()
let currentCheck = ''
paths.forEach((value) => {
currentCheck = currentCheck + '/' + value
if (!window.remixFileSystem.existsSync(currentCheck)) {
window.remixFileSystem.mkdirSync(currentCheck)
this.event.trigger('folderAdded', [this._normalizePath(currentCheck)])
}
})
if (cb) cb()
}
// this will not add a folder as readonly but keep the original url to be able to restore it later
addExternal (path, content, url) {
if (url) this.addNormalizedName(path, url)
@ -134,7 +139,14 @@ class FileProvider {
}
isDirectory (path) {
return window.remixFileSystem.statSync(path).isDirectory()
const unprefixedpath = this.removePrefix(path)
return path === this.type ? true : window.remixFileSystem.statSync(unprefixedpath).isDirectory()
}
isFile (path) {
path = this.removePrefix(path)
return window.remixFileSystem.statSync(path).isFile()
}
/**
@ -147,9 +159,7 @@ class FileProvider {
const stat = window.remixFileSystem.statSync(path)
try {
if (!stat.isDirectory()) {
window.remixFileSystem.unlinkSync(path, console.log)
this.event.trigger('fileRemoved', [this._normalizePath(path)])
return true
return this.removeFile(path)
} else {
const items = window.remixFileSystem.readdirSync(path)
if (items.length !== 0) {
@ -158,8 +168,7 @@ class FileProvider {
if (window.remixFileSystem.statSync(curPath).isDirectory()) { // delete folder
this.remove(curPath)
} else { // delete file
window.remixFileSystem.unlinkSync(curPath, console.log)
this.event.trigger('fileRemoved', [this._normalizePath(path)])
this.removeFile(curPath)
}
})
if (window.remixFileSystem.readdirSync(path).length === 0) window.remixFileSystem.rmdirSync(path, console.log)
@ -176,6 +185,15 @@ class FileProvider {
return true
}
removeFile (path) {
path = this.removePrefix(path)
if (window.remixFileSystem.existsSync(path) && !window.remixFileSystem.statSync(path).isDirectory()) {
window.remixFileSystem.unlinkSync(path, console.log)
this.event.trigger('fileRemoved', [this._normalizePath(path)])
return true
} else return false
}
rename (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath)

@ -81,11 +81,12 @@ module.exports = class RemixDProvider {
//
// this.remixd.exists(path, (error, isValid) => {})
exists (path, cb) {
var unprefixedpath = this.removePrefix(path)
this._remixd.call('sharedfolder', 'exists', {path: unprefixedpath}, (error, result) => {
cb(error, result)
})
async exists (path, cb) {
const unprefixedpath = this.removePrefix(path)
const callId = await this._remixd.call('sharedfolder', 'exists', {path: unprefixedpath})
const result = await this._remixd.receiveResponse(callId)
return cb(null, result)
}
get (path, cb) {
@ -117,9 +118,9 @@ module.exports = class RemixDProvider {
return this._readOnlyMode || this._readOnlyFiles[path] === 1
}
remove (path) {
async remove (path) {
var unprefixedpath = this.removePrefix(path)
this._remixd.call('sharedfolder', 'remove', {path: unprefixedpath}, (error, result) => {
const callId = await this._remixd.call('sharedfolder', 'remove', {path: unprefixedpath}, (error, result) => {
if (error) console.log(error)
var path = this.type + '/' + unprefixedpath
delete this.filesContent[path]
@ -127,6 +128,8 @@ module.exports = class RemixDProvider {
this.event.trigger('fileRemoved', [path])
})
})
return await this._remixd.receiveResponse(callId)
}
rename (oldPath, newPath, isFolder) {
@ -167,6 +170,20 @@ module.exports = class RemixDProvider {
path = self.removePrefix(path)
self.remixd.dir(path, callback)
}
async isDirectory (path) {
const unprefixedpath = this.removePrefix(path)
const callId = await this._remixd.call('sharedfolder', 'isDirectory', {path: unprefixedpath})
return await this._remixd.receiveResponse(callId)
}
async isFile (path) {
const unprefixedpath = this.removePrefix(path)
const callId = await this._remixd.call('sharedfolder', 'isFile', {path: unprefixedpath})
return await this._remixd.receiveResponse(callId)
}
}
function remixapi (remixd, self) {

@ -61,7 +61,7 @@ export class MainView {
self._view.mainPanel.style.display = 'none'
self._components.contextView.show()
})
self.tabProxy.event.on('switchFile', (file) => {
self.tabProxy.event.on('openFile', (file) => {
self._view.editor.style.display = 'block'
self._view.mainPanel.style.display = 'none'
self._components.contextView.show()

@ -34,8 +34,8 @@ export class TabProxy {
return
}
this.addTab(file, '', () => {
this.fileManager.switchFile(file)
this.event.emit('switchFile', file)
this.fileManager.open(file)
this.event.emit('openFile', file)
},
() => {
this.fileManager.closeFile(file)
@ -47,8 +47,8 @@ export class TabProxy {
if (isFolder) return
// should change the tab title too
this.addTab(newName, '', () => {
this.fileManager.switchFile(newName)
this.event.emit('switchFile', newName)
this.fileManager.open(newName)
this.event.emit('openFile', newName)
},
() => {
this.fileManager.closeFile(newName)

@ -141,7 +141,7 @@ class CompilerContainer {
// Load solc compiler version according to pragma in contract file
_setCompilerVersionFromPragma (filename) {
if (!this.data.allversions) return
this.compileTabLogic.fileManager.getFile(filename).then(data => {
this.compileTabLogic.fileManager.readFile(filename).then(data => {
const pragmaArr = data.match(/(pragma solidity (.+?);)/g)
if (pragmaArr && pragmaArr.length === 1) {
const pragmaStr = pragmaArr[0].replace('pragma solidity', '').trim()

@ -319,7 +319,7 @@ class Recorder {
helper.createNonClashingName(newFile, fileProvider, (error, newFile) => {
if (error) return cb('Failed to create file. ' + newFile + ' ' + error)
if (!fileProvider.set(newFile, txJSON)) return cb('Failed to create file ' + newFile)
this.fileManager.switchFile(newFile)
this.fileManager.open(newFile)
})
})
}

@ -289,7 +289,7 @@ module.exports = class TestTab extends ViewPlugin {
}
async testFromPath (path) {
const fileContent = await this.fileManager.getFile(path)
const fileContent = await this.fileManager.readFile(path)
return this.testFromSource(fileContent, path)
}
@ -323,7 +323,7 @@ module.exports = class TestTab extends ViewPlugin {
return
}
this.resultStatistics.hidden = false
this.fileManager.getFile(testFilePath).then((content) => {
this.fileManager.readFile(testFilePath).then((content) => {
const runningTest = {}
runningTest[testFilePath] = { content }
const {currentVersion, evmVersion, optimize} = this.compileTab.getCurrentCompilerConfig()

@ -19,7 +19,7 @@ class TestTabLogic {
// This should be updated to pass complete path, if test file comes from different directory/path
const fileNameToImport = splittedFileName[splittedFileName.length - 1]
if (!fileProvider.set(newFile, this.generateTestContractSample(fileNameToImport))) return modalDialogCustom.alert('Failed to create test file ' + newFile)
this.fileManager.switchFile(newFile)
this.fileManager.open(newFile)
})
}
@ -31,7 +31,7 @@ class TestTabLogic {
const tests = []
let files
try {
files = await this.fileManager.getFolder(path)
files = await this.fileManager.readdir(path)
} catch (e) {
cb(e.message)
}

@ -41,7 +41,7 @@ Renderer.prototype._errorClick = function (errFile, errLine, errCol) {
if (provider) {
provider.exists(errFile, (error, exist) => {
if (error) return console.log(error)
self._deps.fileManager.switchFile(errFile)
self._deps.fileManager.open(errFile)
editor.gotoLine(errLine, errCol)
})
}

@ -151,7 +151,7 @@ class CmdInterpreterAPI {
toolTip(`Unable to load ${url}: ${err}`)
if (cb) cb(err)
} else {
self._deps.fileManager.setFile(type + '/' + cleanUrl, content)
self._deps.fileManager.writeFile(type + '/' + cleanUrl, content)
try {
content = JSON.parse(content)
async.eachOfSeries(content.sources, (value, file, callbackSource) => {
@ -164,7 +164,7 @@ class CmdInterpreterAPI {
return callbackSource(`Cannot retrieve the content of ${url}: ${error}`)
} else {
try {
await self._deps.fileManager.setFile(type + '/' + cleanUrl, content)
await self._deps.fileManager.writeFile(type + '/' + cleanUrl, content)
callbackSource()
} catch (e) {
callbackSource(e.message)

@ -11,6 +11,7 @@ class Remixd {
this.callid = 0
this.socket = null
this.connected = false
this.receiveResponse()
}
online () {
@ -74,6 +75,17 @@ class Remixd {
})
}
async receiveResponse (requestId) {
return new Promise((resolve, reject) => {
this.event.register('replied', (data) => {
if (data.id === requestId) {
if (data.error) reject(data.error)
else resolve(data.result)
}
})
})
}
errored (event) {
function remixdDialog () {
return yo`<div>Connection to Remixd closed. Localhost connection not available anymore.</div>`
@ -87,15 +99,23 @@ class Remixd {
}
call (service, fn, args, callback) {
this.ensureSocket((error) => {
if (error) return callback(error)
if (this.socket && this.socket.readyState === this.socket.OPEN) {
var data = this.format(service, fn, args)
this.callbacks[data.id] = callback
this.socket.send(JSON.stringify(data))
} else {
callback('Socket not ready. state:' + this.socket.readyState)
}
return new Promise((resolve, reject) => {
this.ensureSocket((error) => {
if (error) {
callback && typeof callback === 'function' && callback(error)
reject(error)
return
}
if (this.socket && this.socket.readyState === this.socket.OPEN) {
var data = this.format(service, fn, args)
this.callbacks[data.id] = callback
this.socket.send(JSON.stringify(data))
resolve(data.id)
} else {
callback && typeof callback === 'function' && callback('Socket not ready. state:' + this.socket.readyState)
reject('Socket not ready. state:' + this.socket.readyState)
}
})
})
}

@ -1,9 +1,9 @@
const EventEmitter = require('events')
class SwitchFile extends EventEmitter {
class OpenFile extends EventEmitter {
command (name) {
this.api.perform((done) => {
switchFile(this.api, name, () => {
openFile(this.api, name, () => {
done()
this.emit('complete')
})
@ -13,7 +13,7 @@ class SwitchFile extends EventEmitter {
}
// click on fileExplorer can toggle it. We go through settings to be sure FE is open
function switchFile (browser, name, done) {
function openFile (browser, name, done) {
browser.clickLaunchIcon('settings').clickLaunchIcon('fileExplorers')
.waitForElementVisible('li[key="' + name + '"]')
.click('li[key="' + name + '"]')
@ -23,4 +23,4 @@ function switchFile (browser, name, done) {
})
}
module.exports = SwitchFile
module.exports = OpenFile

@ -66,7 +66,7 @@ module.exports = {
'Switch Tabs using tabs icon': function (browser) {
browser
.waitForElementVisible('div[data-id="filePanelFileExplorerTree"]')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.assert.containsText('div[title="browser/3_Ballot.sol"]', '3_Ballot.sol')
.click('span[class^=dropdownCaret]')
.click('#homeItem')

@ -10,7 +10,7 @@ module.exports = {
'Should zoom in editor': function (browser) {
browser.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]')
.switchFile('browser/1_Storage.sol')
.openFile('browser/1_Storage.sol')
.waitForElementVisible('*[data-id="editorInput"]')
.checkElementStyle('*[data-id="editorInput"]', 'font-size', '12px')
.click('*[data-id="tabProxyZoomIn"]')
@ -74,7 +74,7 @@ module.exports = {
'Should highlight source code': function (browser) {
browser.addFile('sourcehighlight.js', sourcehighlightScript)
.switchFile('browser/sourcehighlight.js')
.openFile('browser/sourcehighlight.js')
.executeScript('remix.exeCurrent()')
.editorScroll('down', 60)
.waitForElementPresent('.highlightLine32')
@ -87,9 +87,9 @@ module.exports = {
'Should remove 1 highlight from source code': function (browser) {
browser.addFile('removeSourcehighlightScript.js', removeSourcehighlightScript)
.switchFile('browser/removeSourcehighlightScript.js')
.openFile('browser/removeSourcehighlightScript.js')
.executeScript('remix.exeCurrent()')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.editorScroll('down', 60)
.waitForElementNotPresent('.highlightLine32')
.checkElementStyle('.highlightLine40', 'background-color', 'rgb(8, 108, 181)')
@ -98,9 +98,9 @@ module.exports = {
'Should remove all highlights from source code': function (browser) {
browser.addFile('removeAllSourcehighlightScript.js', removeAllSourcehighlightScript)
.switchFile('browser/removeAllSourcehighlightScript.js')
.openFile('browser/removeAllSourcehighlightScript.js')
.executeScript('remix.exeCurrent()')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.editorScroll('down', 60)
.waitForElementNotPresent('.highlightLine32')
.waitForElementNotPresent('.highlightLine40')

@ -31,14 +31,14 @@ module.exports = {
.waitForElementVisible('*[data-id="settingsTabGenerateContractMetadata"]', 5000)
.click('*[data-id="settingsTabGenerateContractMetadata"]')
.click('*[data-id="verticalIconsFileExplorerIcons"]')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.click('*[data-id="verticalIconsKindsolidity"]')
.pause(2000)
.click('*[data-id="compilerContainerCompileBtn"]')
.pause(3000)
.click('*[data-id="verticalIconsKindfileExplorers"]')
.switchFile('browser/artifacts')
.switchFile('browser/artifacts/Ballot.json')
.openFile('browser/artifacts')
.openFile('browser/artifacts/Ballot.json')
},
'Should add new github access token': function (browser) {

@ -44,9 +44,9 @@ module.exports = {
browser
.modalFooterCancelClick()
.executeScript(`remix.loadgist('${gistid}')`)
.perform((done) => { if (runtimeBrowser === 'chrome') { browser.switchFile('browser/gists') } done() })
.switchFile(`browser/gists/${gistid}`)
.switchFile(`browser/gists/${gistid}/1_Storage.sol`)
.perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('browser/gists') } done() })
.openFile(`browser/gists/${gistid}`)
.openFile(`browser/gists/${gistid}/1_Storage.sol`)
.perform(done)
}
})
@ -86,8 +86,8 @@ module.exports = {
.waitForElementVisible('*[data-id="modalDialogCustomPromptText"]')
.setValue('*[data-id="modalDialogCustomPromptText"]', testData.validGistId)
.modalFooterOKClick()
.switchFile(`browser/gists/${testData.validGistId}`)
.switchFile(`browser/gists/${testData.validGistId}/ApplicationRegistry`)
.openFile(`browser/gists/${testData.validGistId}`)
.openFile(`browser/gists/${testData.validGistId}/ApplicationRegistry`)
.waitForElementVisible(`div[title='browser/gists/${testData.validGistId}/ApplicationRegistry']`)
.assert.containsText(`div[title='browser/gists/${testData.validGistId}/ApplicationRegistry'] > span`, 'ApplicationRegistry')
.end()

@ -59,7 +59,7 @@ module.exports = {
function checkDeployShouldFail (browser, callback) {
let config
browser.switchFile('browser/artifacts').switchFile('browser/artifacts/test.json')
browser.openFile('browser/artifacts').openFile('browser/artifacts/test.json')
.getEditorValue((content) => {
config = JSON.parse(content)
config.deploy['VM:-'].autoDeployLib = false
@ -67,7 +67,7 @@ function checkDeployShouldFail (browser, callback) {
.perform(() => {
browser.setEditorValue(JSON.stringify(config))
})
.switchFile('browser/Untitled5.sol')
.openFile('browser/Untitled5.sol')
.selectContract('test') // deploy lib
.createContract('')
.assert.containsText('div[class^="terminal"]', '<address> is not a valid address')
@ -77,7 +77,7 @@ function checkDeployShouldFail (browser, callback) {
function checkDeployShouldSucceed (browser, address, callback) {
let addressRef
let config
browser.switchFile('browser/artifacts').switchFile('browser/artifacts/test.json')
browser.openFile('browser/artifacts').openFile('browser/artifacts/test.json')
.getEditorValue((content) => {
config = JSON.parse(content)
config.deploy['VM:-'].autoDeployLib = false
@ -86,7 +86,7 @@ function checkDeployShouldSucceed (browser, address, callback) {
.perform(() => {
browser.setEditorValue(JSON.stringify(config))
})
.switchFile('browser/Untitled5.sol')
.openFile('browser/Untitled5.sol')
.selectContract('test') // deploy lib
.createContract('')
.getAddressAtPosition(1, (address) => {

@ -66,7 +66,7 @@ module.exports = {
.assert.containsText('*[data-id="pluginManagerSettingsPermissionForm"]', 'No Permission requested yet')
.modalFooterOKClick()
.click('*[data-id="verticalIconsFileExplorerIcons"]')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.click('*[plugin="ZoKrates"]')
.pause(5000)
.frame(0)

@ -13,7 +13,7 @@ module.exports = {
browser
.waitForElementVisible('#icon-panel', 10000)
.clickLaunchIcon('fileExplorers')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.verifyContracts(['Ballot'])
.click('#publishOnIpfs')
.getModalBody((value, done) => {
@ -37,7 +37,7 @@ module.exports = {
browser
.waitForElementVisible('#icon-panel')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/1_Storage.sol')
.openFile('browser/1_Storage.sol')
.clickLaunchIcon('udapp')
.waitForElementVisible('*[data-id="contractDropdownIpfsCheckbox"]')
.click('*[data-id="contractDropdownIpfsCheckbox"]')
@ -49,7 +49,7 @@ module.exports = {
'Should remember choice after page refresh': function (browser) {
browser
.refresh()
.switchFile('browser/1_Storage.sol')
.openFile('browser/1_Storage.sol')
.clickLaunchIcon('udapp')
.waitForElementVisible('*[data-id="contractDropdownIpfsCheckbox"]')
.verify.elementPresent('*[data-id="contractDropdownIpfsCheckbox"]:checked')

@ -115,6 +115,8 @@ function runTests (browser, testData) {
})
.clickLaunchIcon('fileExplorers')
.waitForElementVisible('[data-path="localhost/folder1"]')
.click('[data-path="localhost/folder1"]')
.click('[data-path="localhost/folder1"]') // click twice because remixd does not return nested folder details after update
.waitForElementVisible('[data-path="localhost/folder1/contract1.sol"]')
.waitForElementVisible('[data-path="localhost/folder1/renamed_contract_' + browserName + '.sol"]') // check if renamed file is preset
.waitForElementNotPresent('[data-path="localhost/folder1/contract_' + browserName + '.sol"]') // check if renamed (old) file is not present

@ -90,7 +90,7 @@ module.exports = {
'Should deploy contract on Goerli Test Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/Greet.sol')
.openFile('browser/Greet.sol')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
@ -141,7 +141,7 @@ module.exports = {
'Should deploy contract on Ethereum Main Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/Greet.sol')
.openFile('browser/Greet.sol')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')

@ -23,7 +23,7 @@ module.exports = {
browser.assert.ok(typeof signature.value === 'string', 'type of signature.value must be String')
})
.addFile('signMassage.sol', sources[0]['browser/signMassage.sol'])
.switchFile('browser/signMassage.sol')
.openFile('browser/signMassage.sol')
.pause(5000)
.selectContract('ECVerify')
.createContract('')

@ -15,7 +15,7 @@ module.exports = {
'Test Success Import': function (browser) {
browser.addFile('Untitled1.sol', sources[1]['browser/Untitled1.sol'])
.addFile('Untitled2.sol', sources[1]['browser/Untitled2.sol'])
.switchFile('browser/Untitled1.sol')
.openFile('browser/Untitled1.sol')
.verifyContracts(['test6', 'test4', 'test5'])
},

@ -27,7 +27,7 @@ module.exports = {
'Should generate test file': function (browser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/simple_storage.sol')
.openFile('browser/simple_storage.sol')
.click('*[data-id="verticalIconsKindsolidityUnitTesting"]')
.waitForElementPresent('*[data-id="testTabGenerateTestFile"]')
.click('*[data-id="testTabGenerateTestFile"]')
@ -100,7 +100,7 @@ module.exports = {
browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]')
.addFile('compilationError_test.sol', sources[0]['browser/compilationError_test.sol'])
.clickLaunchIcon('fileExplorers')
.switchFile('browser/compilationError_test.sol')
.openFile('browser/compilationError_test.sol')
.clickLaunchIcon('solidityUnitTesting')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 3)
@ -115,7 +115,7 @@ module.exports = {
browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]')
.addFile('deployError_test.sol', sources[0]['browser/deployError_test.sol'])
.clickLaunchIcon('fileExplorers')
.switchFile('browser/deployError_test.sol')
.openFile('browser/deployError_test.sol')
.clickLaunchIcon('solidityUnitTesting')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 4)
@ -129,7 +129,7 @@ module.exports = {
browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]')
.addFile('methodFailure_test.sol', sources[0]['browser/methodFailure_test.sol'])
.clickLaunchIcon('fileExplorers')
.switchFile('browser/methodFailure_test.sol')
.openFile('browser/methodFailure_test.sol')
.clickLaunchIcon('solidityUnitTesting')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 5)
@ -150,7 +150,7 @@ function runTests (browser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/3_Ballot.sol')
.openFile('browser/3_Ballot.sol')
.clickLaunchIcon('solidityUnitTesting')
.pause(500)
.scrollAndClick('#runTestsTabRunAction')

@ -57,7 +57,7 @@ module.exports = {
'Async/Await Script': function (browser) {
browser
.addFile('asyncAwait.js', { content: asyncAwait })
.switchFile('browser/asyncAwait.js')
.openFile('browser/asyncAwait.js')
.executeScript(`remix.execute('browser/asyncAwait.js')`)
.journalLastChild('Waiting Promise')
.pause(5500)
@ -67,7 +67,7 @@ module.exports = {
'Call Remix File Manager from a script': function (browser) {
browser
.addFile('asyncAwaitWithFileManagerAccess.js', { content: asyncAwaitWithFileManagerAccess })
.switchFile('browser/asyncAwaitWithFileManagerAccess.js')
.openFile('browser/asyncAwaitWithFileManagerAccess.js')
.pause(5000)
.executeScript(`remix.execute('browser/asyncAwaitWithFileManagerAccess.js')`)
.pause(6000)
@ -108,7 +108,7 @@ const asyncAwaitWithFileManagerAccess = `
var run = async () => {
console.log('Waiting Promise')
var result = await p()
let text = await remix.call('fileManager', 'getFile', 'browser/3_Ballot.sol')
let text = await remix.call('fileManager', 'readFile', 'browser/3_Ballot.sol')
console.log('result - ', text)
}

Loading…
Cancel
Save