Merge branch 'filesystem_events' of https://github.com/ethereum/remix-project into flattentree

flattentree
filip mertens 11 months ago
commit e81f05549a
  1. 15
      apps/remix-ide/src/app/files/fileManager.ts
  2. 101
      apps/remixdesktop/src/plugins/fsPlugin.ts
  3. 2
      libs/remix-ui/run-tab/src/lib/actions/events.ts
  4. 4
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  5. 1
      libs/remix-ui/workspace/src/lib/actions/events.ts
  6. 1
      libs/remix-ui/workspace/src/lib/actions/index.ts
  7. 1
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts

@ -5,7 +5,6 @@ import JSZip from 'jszip'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import {Registry} from '@remix-project/remix-lib' import {Registry} from '@remix-project/remix-lib'
import { EventEmitter } from 'events'
import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper' import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper'
import helper from '../../lib/helper.js' import helper from '../../lib/helper.js'
import { RemixAppManager } from '../../remixAppManager' import { RemixAppManager } from '../../remixAppManager'
@ -42,7 +41,6 @@ const createError = (err) => {
class FileManager extends Plugin { class FileManager extends Plugin {
mode: string mode: string
openedFiles: any openedFiles: any
events: EventEmitter
editor: any editor: any
_components: any _components: any
appManager: RemixAppManager appManager: RemixAppManager
@ -56,7 +54,6 @@ class FileManager extends Plugin {
super(profile) super(profile)
this.mode = 'browser' this.mode = 'browser'
this.openedFiles = {} // list all opened files this.openedFiles = {} // list all opened files
this.events = new EventEmitter()
this.editor = editor this.editor = editor
this._components = {} this._components = {}
this._components.registry = Registry.getInstance() this._components.registry = Registry.getInstance()
@ -565,7 +562,6 @@ class FileManager extends Plugin {
} }
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('fileRenamed', oldName, newName, isFolder) this.emit('fileRenamed', oldName, newName, isFolder)
this.events.emit('fileRenamed', oldName, newName, isFolder)
} }
currentFileProvider() { currentFileProvider() {
@ -583,7 +579,6 @@ class FileManager extends Plugin {
async closeAllFiles() { async closeAllFiles() {
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('filesAllClosed') this.emit('filesAllClosed')
this.events.emit('filesAllClosed')
for (const file in this.openedFiles) { for (const file in this.openedFiles) {
await this.closeFile(file) await this.closeFile(file)
} }
@ -595,11 +590,9 @@ class FileManager extends Plugin {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
} }
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('fileClosed', name) this.emit('fileClosed', name)
this.events.emit('fileClosed', name)
} }
currentPath() { currentPath() {
@ -703,8 +696,9 @@ class FileManager extends Plugin {
delete this.openedFiles[path] delete this.openedFiles[path]
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('fileRemoved', path) this.emit('fileRemoved', path)
this.events.emit('fileRemoved', path) if (path === this._deps.config.get('currentFile')) {
this.openFile(this._deps.config.get('currentFile')) this.openFile(this._deps.config.get('currentFile'))
}
} }
async unselectCurrentFile() { async unselectCurrentFile() {
@ -712,13 +706,11 @@ class FileManager extends Plugin {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
} }
async openFile(file?: string) { async openFile(file?: string) {
if (!file) { if (!file) {
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
} else { } else {
file = this.normalize(file) file = this.normalize(file)
const resolved = this.getPathFromUrl(file) const resolved = this.getPathFromUrl(file)
@ -752,7 +744,6 @@ class FileManager extends Plugin {
} }
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('currentFileChanged', file) this.emit('currentFileChanged', file)
this.events.emit('currentFileChanged', file)
return true return true
} }
} }

@ -90,7 +90,7 @@ const clientProfile: Profile = {
} }
class FSPluginClient extends ElectronBasePluginClient { class FSPluginClient extends ElectronBasePluginClient {
watcher: chokidar.FSWatcher watchers: Record<string, chokidar.FSWatcher> = {}
workingDir: string = '' workingDir: string = ''
trackDownStreamUpdate: Record<string, string> = {} trackDownStreamUpdate: Record<string, string> = {}
@ -148,13 +148,10 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
async rmdir(path: string): Promise<void> { async rmdir(path: string): Promise<void> {
if (this.watcher) await this.watcher.close()
await fs.rm(this.fixPath(path), { await fs.rm(this.fixPath(path), {
recursive: true, recursive: true,
}) })
this.emit('change', 'unlinkDir', path) this.emit('change', 'unlinkDir', path)
await this.watch()
} }
async unlink(path: string): Promise<void> { async unlink(path: string): Promise<void> {
@ -203,59 +200,89 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
async watch(): Promise<void> { async watch(): Promise<void> {
if (this.watcher) this.watcher.close()
try{ try{
this.watcher = chokidar this.on('filePanel' as any, 'expandPathChanged', async (paths: string[]) => {
.watch(this.workingDir, { for (let path of paths) {
if (!this.watchers[path]) {
path = this.fixPath(path)
this.watchers[path] = await this.watcherInit(path)
console.log('added watcher', path)
}
}
paths = paths.map(path => this.fixPath(path))
for (const watcher in this.watchers) {
if (watcher === this.workingDir) continue
if (!paths.includes(watcher)) {
this.watchers[watcher].close()
delete this.watchers[watcher]
console.log('removed watcher', watcher)
}
}
})
this.watchers[this.workingDir] = await this.watcherInit(this.workingDir) // root
console.log('added root watcher', this.workingDir)
} catch(e){
console.log('error watching', e)
}
}
private async watcherInit (path: string) {
const watcher = chokidar
.watch(path, {
ignorePermissionErrors: true, ignorePermissionErrors: true,
ignoreInitial: true, ignoreInitial: true,
ignored: [ ignored: [
'**/.git/index.lock', // this file is created and unlinked all the time when git is running on Windows '**/.git/index.lock', // this file is created and unlinked all the time when git is running on Windows
], ],
depth: 20 depth: 1
}) })
.on('all', async (eventName, path, stats) => { .on('all', async (eventName, path, stats) => {
let pathWithoutPrefix = path.replace(this.workingDir, '') this.watcherExec(eventName, path)
pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix)
if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1)
if (eventName === 'change') {
// remove workingDir from path
const newContent = await fs.readFile(path, 'utf-8')
const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix]
if (currentContent !== newContent) {
try {
this.emit('change', eventName, pathWithoutPrefix)
} catch (e) {
console.log('error emitting change', e)
}
}
} else {
try {
this.emit('change', eventName, pathWithoutPrefix)
} catch (e) {
console.log('error emitting change', e)
}
}
}) })
.on('error', error => { .on('error', error => {
this.watcher.close() watcher.close()
if(error.message.includes('ENOSPC')) { if(error.message.includes('ENOSPC')) {
this.emit('error', 'ENOSPC') this.emit('error', 'ENOSPC')
} }
console.log(`Watcher error: ${error}`) console.log(`Watcher error: ${error}`)
}) })
}catch(e){ return watcher
console.log('error watching', e) }
private async watcherExec (eventName: string, path: string) {
let pathWithoutPrefix = path.replace(this.workingDir, '')
pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix)
if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1)
if (eventName === 'change') {
// remove workingDir from path
const newContent = await fs.readFile(path, 'utf-8')
const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix]
if (currentContent !== newContent) {
try {
console.log('emitting', eventName, pathWithoutPrefix)
this.emit('change', eventName, pathWithoutPrefix)
} catch (e) {
console.log('error emitting change', e)
}
}
} else {
try {
console.log('emitting', eventName, pathWithoutPrefix)
this.emit('change', eventName, pathWithoutPrefix)
} catch (e) {
console.log('error emitting change', e)
}
} }
} }
async closeWatch(): Promise<void> { async closeWatch(): Promise<void> {
if (this.watcher) this.watcher.close() for (const watcher in this.watchers) {
this.watchers[watcher].close()
}
} }
async updateRecentFolders(path: string): Promise<void> { async updateRecentFolders(path: string): Promise<void> {

@ -104,7 +104,7 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
} }
}) })
plugin.fileManager.events.on('currentFileChanged', (currentFile: string) => { plugin.on('fileManager', 'currentFileChanged', (currentFile: string) => {
if (/.(.abi)$/.exec(currentFile)) { if (/.(.abi)$/.exec(currentFile)) {
dispatch(setLoadType('abi')) dispatch(setLoadType('abi'))
} else if (/.(.sol)$/.exec(currentFile) || } else if (/.(.sol)$/.exec(currentFile) ||

@ -175,10 +175,10 @@ export const SolidityUnitTesting = (props: Record<string, any>) => {
return tmp ? tmp[1] : version return tmp ? tmp[1] : version
} }
testTab.fileManager.events.on('noFileSelected', async () => { testTab.on('fileManager', 'noFileSelected', async () => {
await updateForNewCurrent() await updateForNewCurrent()
}) })
testTab.fileManager.events.on('currentFileChanged', async (file: string) => { testTab.on('fileManager', 'currentFileChanged', async (file: string) => {
await updateForNewCurrent(file) await updateForNewCurrent(file)
}) })
testTab.on('solidity', 'compilerLoaded', async (version: string, license: string) => { testTab.on('solidity', 'compilerLoaded', async (version: string, license: string) => {

@ -220,6 +220,7 @@ const fileRemoved = async (removePath: string) => {
const fileRenamed = async (oldPath: string) => { const fileRenamed = async (oldPath: string) => {
const provider = plugin.fileManager.currentFileProvider() const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(oldPath) || ROOT_PATH const path = extractParentFromKey(oldPath) || ROOT_PATH
const promise: Promise<FileTree> = new Promise((resolve) => { const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error) if (error) console.error(error)

@ -378,6 +378,7 @@ export const handleClickFile = async (path: string, type: 'file' | 'folder' | 'g
} }
export const handleExpandPath = (paths: string[]) => { export const handleExpandPath = (paths: string[]) => {
plugin.emit('expandPathChanged', paths)
dispatch(setExpandPath(paths)) dispatch(setExpandPath(paths))
} }

@ -331,7 +331,6 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
case 'FILE_ADDED_SUCCESS': { case 'FILE_ADDED_SUCCESS': {
const payload = action.payload const payload = action.payload
return { return {
...state, ...state,
browser: { browser: {

Loading…
Cancel
Save