Merge pull request #1021 from ethereum/fixWorkspaceMigration

Fix workspace migration
pull/1018/head
yann300 4 years ago committed by GitHub
commit 1569fc92e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  2. 6
      apps/remix-ide/src/app.js
  3. 13
      apps/remix-ide/src/app/files/fileProvider.js
  4. 5
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  5. 86
      apps/remix-ide/src/app/ui/landing-page/landing-page.js
  6. 28
      apps/remix-ide/src/migrateFileSystem.js
  7. 68
      package-lock.json
  8. 1
      package.json

@ -84,12 +84,12 @@ module.exports = {
'Test NPM Import (with unpkg.com)': function (browser: NightwatchBrowser) {
browser
// .setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js')
.setSolidityCompilerVersion('soljson-v0.8.1+commit.df193b15.js')
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItemREADME.txt"')
.addFile('Untitled9.sol', sources[8]['Untitled9.sol'])
.clickLaunchIcon('fileExplorers')
.verifyContracts(['test13', 'ERC20', 'SafeMath'], { wait: 30000 })
.verifyContracts(['test13', 'ERC20'], { wait: 30000 })
.end()
},
tearDown: sauce
@ -122,6 +122,6 @@ const sources = [
'Untitled8.sol': { content: 'import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol"; contract test12 {}' }
},
{
'Untitled9.sol': { content: 'pragma solidity >=0.6.0 <0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract test13 {}' }
'Untitled9.sol': { content: 'pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract test13 {}' }
}
]

@ -18,7 +18,7 @@ import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel'
import FetchAndCompile from './app/compiler/compiler-sourceVerifier-fetchAndCompile'
import migrateFileSystem, { migrateToWorkspace } from './migrateFileSystem'
import migrateFileSystem from './migrateFileSystem'
const isElectron = require('is-electron')
const csjs = require('csjs-inject')
@ -325,11 +325,11 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// those views depend on app_manager
const menuicons = new VerticalIcons(appManager)
const landingPage = new LandingPage(appManager, menuicons)
const sidePanel = new SidePanel(appManager, menuicons)
const hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, engine)
const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage(appManager, menuicons, fileManager, filePanel)
const settings = new SettingsTab(
registry.get('config').api,
editor,
@ -494,7 +494,5 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// get the file list from the parent iframe
loadFileFromParent(fileManager)
migrateToWorkspace(fileManager, filePanel)
if (params.embed) framingService.embed()
}

@ -199,21 +199,24 @@ class FileProvider {
* copy the folder recursively (internal use)
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
*/
_copyFolderToJsonInternal (path, visitFile) {
_copyFolderToJsonInternal (path, visitFile, visitFolder) {
visitFile = visitFile || (() => {})
visitFolder = visitFolder || (() => {})
return new Promise((resolve, reject) => {
const json = {}
path = this.removePrefix(path)
if (window.remixFileSystem.existsSync(path)) {
try {
const items = window.remixFileSystem.readdirSync(path)
visitFolder({ path })
if (items.length !== 0) {
items.forEach(async (item, index) => {
const file = {}
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}`
if (window.remixFileSystem.statSync(curPath).isDirectory()) {
file.children = await this._copyFolderToJsonInternal(curPath, visitFile)
file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder)
} else {
file.content = window.remixFileSystem.readFileSync(curPath, 'utf8')
visitFile({ path: curPath, content: file.content })
@ -234,10 +237,12 @@ class FileProvider {
* copy the folder recursively
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
*/
copyFolderToJson (path, visitFile) {
copyFolderToJson (path, visitFile, visitFolder) {
visitFile = visitFile || (() => {})
return this._copyFolderToJsonInternal(path, visitFile)
visitFolder = visitFolder || (() => {})
return this._copyFolderToJsonInternal(path, visitFile, visitFolder)
}
removeFile (path) {

@ -48,11 +48,14 @@ class WorkspaceFileProvider extends FileProvider {
})
}
async copyFolderToJson (directory, visitFile) {
async copyFolderToJson (directory, visitFile, visitFolder) {
visitFile = visitFile || (() => {})
visitFolder = visitFolder || (() => {})
const regex = new RegExp(`.workspaces/${this.workspace}/`, 'g')
let json = await super._copyFolderToJsonInternal(directory, ({ path, content }) => {
visitFile({ path: path.replace(regex, ''), content })
}, ({ path }) => {
visitFolder({ path: path.replace(regex, '') })
})
json = JSON.stringify(json).replace(regex, '')
return JSON.parse(json)

@ -1,11 +1,14 @@
import * as packageJson from '../../../../../../package.json'
import { ViewPlugin } from '@remixproject/engine-web'
import { migrateToWorkspace } from '../../../migrateFileSystem'
import JSZip from 'jszip'
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const globalRegistry = require('../../../global/registry')
const CompilerImport = require('../../compiler/compiler-imports')
const modalDialogCustom = require('../modal-dialog-custom')
const modalDialog = require('../modaldialog')
const tooltip = require('../tooltip')
const GistHandler = require('../../../lib/gist-handler')
const QueryParams = require('../../../lib/query-params.js')
@ -112,9 +115,11 @@ const profile = {
}
export class LandingPage extends ViewPlugin {
constructor (appManager, verticalIcons) {
constructor (appManager, verticalIcons, fileManager, filePanel) {
super(profile)
this.profile = profile
this.fileManager = fileManager
this.filePanel = filePanel
this.appManager = appManager
this.verticalIcons = verticalIcons
this.gistHandler = new GistHandler()
@ -297,6 +302,44 @@ export class LandingPage extends ViewPlugin {
this.call('fileExplorers', 'createNewFile')
}
const saveAs = (blob, name) => {
const node = document.createElement('a')
node.download = name
node.rel = 'noopener'
node.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s
setTimeout(function () {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}, 0) // 40s
}
const downloadFiles = async () => {
try {
tooltip('preparing files, please wait..')
const fileProviders = globalRegistry.get('fileproviders').api
const zip = new JSZip()
await fileProviders.browser.copyFolderToJson('/', ({ path, content }) => {
zip.file(path, content)
}, ({ path, content }) => {
zip.folder(path, content)
})
zip.generateAsync({ type: 'blob' }).then(function (blob) {
saveAs(blob, 'remixdbackup.zip')
}).catch((e) => {
tooltip(e.message)
})
} catch (e) {
tooltip(e.message)
}
}
const uploadFile = (target) => {
this.call('fileExplorers', 'uploadFile', target)
}
@ -357,6 +400,37 @@ export class LandingPage extends ViewPlugin {
query.update({ appVersion: '0.7.7' })
document.location.reload()
}
const migrate = async () => {
tooltip('migrating workspace...')
try {
const workspaceName = await migrateToWorkspace(this.fileManager, this.filePanel)
tooltip('done. ' + workspaceName + ' created.')
} catch (e) {
return tooltip(e.message)
}
}
const migrateWorkspace = async () => {
modalDialog(
'File system Migration',
yo`<span>Do you want to download your files to local device first?</span>`,
{
label: 'Download and Migrate',
fn: async () => {
await downloadFiles()
migrate()
}
},
{
label: 'Migrate',
fn: () => {
migrate()
}
}
)
}
const img = yo`<img class=${css.logoImg} src="assets/img/guitarRemiCroped.webp" onclick="${() => playRemi()}"></img>`
const playRemi = async () => { await document.getElementById('remiAudio').play() }
// to retrieve medium posts
@ -408,6 +482,10 @@ export class LandingPage extends ViewPlugin {
<i class="far fa-hdd"></i>
<span class="ml-1 ${css.text}" onclick=${() => connectToLocalhost()}>Connect to Localhost</span>
</p>
<p class="mb-1">
<i class="mr-1 far fa-file"></i>
<span class="ml-1 mb-1 ${css.text}" onclick=${() => downloadFiles()}>Download all Files</span>
</p>
<p class="mt-3 mb-0"><label>IMPORT FROM:</label></p>
<div class="btn-group">
<button class="btn mr-1 btn-secondary" data-id="landingPageImportFromGistButton" onclick="${() => importFromGist()}">Gist</button>
@ -431,10 +509,14 @@ export class LandingPage extends ViewPlugin {
${this.websiteIcon}
<a class="${css.text}" target="__blank" href="https://remix-project.org">Featuring website</a>
</p>
<p>
<p class="mb-1">
<i class="fab fa-ethereum ${css.image}"></i>
<span class="${css.text}" onclick=${() => switchToPreviousVersion()}>Old experience</span>
</p>
<p>
<i class="fas fa-exclamation-triangle text-warning ${css.image}"></i>
<span class="${css.text}" onclick=${() => migrateWorkspace()}>Migrate old filesystem to workspace</span>
</p>
</div>
</div>
</div>

@ -24,19 +24,27 @@ export default (fileProvider) => {
export async function migrateToWorkspace (fileManager, filePanel) {
const browserProvider = fileManager.getProvider('browser')
const workspaceProvider = fileManager.getProvider('workspace')
const flag = 'status'
const fileStorageBrowserWorkspace = new Storage('remix_browserWorkspace_migration:')
if (fileStorageBrowserWorkspace.get(flag) === 'done') return
const files = await browserProvider.copyFolderToJson('/')
console.log(files)
if (Object.keys(files).length > 0) {
const workspaceName = 'default_workspace'
const workspacePath = joinPath('browser', workspaceProvider.workspacesPath, workspaceName)
await filePanel.processCreateWorkspace(workspaceName)
filePanel.getWorkspaces() // refresh list
await populateWorkspace(workspacePath, files, browserProvider)
if (Object.keys(files).length === 0) {
// we don't have any root file, only .workspaces
// don't need to create a workspace
throw new Error('No file to migrate')
}
fileStorageBrowserWorkspace.set(flag, 'done')
if (Object.keys(files).length === 1 && files['/.workspaces']) {
// we don't have any root file, only .workspaces
// don't need to create a workspace
throw new Error('No file to migrate')
}
const workspaceName = 'workspace_migrated_' + Date.now()
await filePanel.processCreateWorkspace(workspaceName)
filePanel.getWorkspaces() // refresh list
const workspacePath = joinPath('browser', workspaceProvider.workspacesPath, workspaceName)
await populateWorkspace(workspacePath, files, browserProvider)
return workspaceName
}
const populateWorkspace = async (workspace, json, browserProvider) => {

68
package-lock.json generated

@ -24165,6 +24165,51 @@
"object.assign": "^4.1.0"
}
},
"jszip": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz",
"integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==",
"requires": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"set-immediate-shim": "~1.0.1"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"just-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
@ -24722,6 +24767,21 @@
"webpack-sources": "^1.2.0"
}
},
"lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"requires": {
"immediate": "~3.0.5"
},
"dependencies": {
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
}
}
},
"liftoff": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
@ -33929,8 +33989,7 @@
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"dev": true
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"parallel-transform": {
"version": "1.2.0",
@ -37502,6 +37561,11 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
},
"set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",

@ -153,6 +153,7 @@
"fs-extra": "^3.0.1",
"http-server": "^0.11.1",
"isbinaryfile": "^3.0.2",
"jszip": "^3.6.0",
"merge": "^1.2.0",
"npm-install-version": "^6.0.2",
"react": "16.13.1",

Loading…
Cancel
Save