From 01433bae4fe70ca7bd5eaa09ddd078d7c92ee0cb Mon Sep 17 00:00:00 2001 From: filip mertens Date: Tue, 13 Jun 2023 07:47:33 +0200 Subject: [PATCH] isogit --- apps/1test/src/electron/fsPlugin.ts | 2 +- apps/1test/src/index.ts | 157 ++++++++-- apps/1test/src/remix/fsPlugin.ts | 2 +- apps/1test/src/remix/gitPlugin.ts | 2 + apps/remix-ide/src/app.js | 5 +- apps/remix-ide/src/app/files/dgitProvider.js | 275 ++++++++++++------ apps/remix-ide/src/app/files/fileManager.ts | 4 +- apps/remix-ide/src/app/plugins/fsPlugin.ts | 31 +- .../remix-ide/src/app/plugins/isoGitPlugin.ts | 19 ++ apps/remix-ide/src/app/tabs/theme-module.js | 37 ++- apps/remixdesktop/src/engine.ts | 12 +- .../src/{ => plugins}/fsPlugin.ts | 62 ++-- .../src/{ => plugins}/gitPlugin.ts | 15 +- apps/remixdesktop/src/plugins/isoGitPlugin.ts | 241 +++++++++++++++ .../src/{ => plugins}/xtermPlugin.ts | 0 apps/remixdesktop/src/preload.ts | 2 +- .../workspace/src/lib/actions/index.ts | 1 + 17 files changed, 676 insertions(+), 191 deletions(-) create mode 100644 apps/remix-ide/src/app/plugins/isoGitPlugin.ts rename apps/remixdesktop/src/{ => plugins}/fsPlugin.ts (72%) rename apps/remixdesktop/src/{ => plugins}/gitPlugin.ts (73%) create mode 100644 apps/remixdesktop/src/plugins/isoGitPlugin.ts rename apps/remixdesktop/src/{ => plugins}/xtermPlugin.ts (100%) diff --git a/apps/1test/src/electron/fsPlugin.ts b/apps/1test/src/electron/fsPlugin.ts index 7ba780a32a..97738d7bfb 100644 --- a/apps/1test/src/electron/fsPlugin.ts +++ b/apps/1test/src/electron/fsPlugin.ts @@ -35,7 +35,7 @@ const clientProfile: Profile = { class FSPluginClient extends ElectronBasePluginClient { watcher: chokidar.FSWatcher - workingDir: string = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/' + workingDir: string = '/Volumes/bunsen/code/empty/' constructor(webContentsId: number, profile: Profile) { super(webContentsId, profile) diff --git a/apps/1test/src/index.ts b/apps/1test/src/index.ts index 1af2c42204..75dbc2b97a 100644 --- a/apps/1test/src/index.ts +++ b/apps/1test/src/index.ts @@ -94,7 +94,7 @@ const menu = [shellMenu(commandKeys, execCommand)] Menu.setApplicationMenu(Menu.buildFromTemplate(menu)) import fs from 'fs/promises' -import { readlink } from 'fs'; +import { readlink, stat } from 'fs'; //const menu = Menu.buildFromTemplate(shellMenu([], undefined)) //Menu.setApplicationMenu(menu) @@ -109,43 +109,43 @@ const myFS = { //console.log('myFS.readdir', file) return file }, - - readFile: async (path: string, options: any): Promise=> { + + readFile: async (path: string, options: any): Promise => { //console.log('myFS.readFile', path, options) - const file = await (fs as any).readFile(path, options) - //console.log('myFS.readFile', file) - return file - + const file = await (fs as any).readFile(path, options) + //console.log('myFS.readFile', file) + return file + }, - + async writeFile(path: string, content: string): Promise { return fs.writeFile(path, content, 'utf8') }, - + async mkdir(path: string): Promise { return fs.mkdir(path) }, - + async rmdir(path: string): Promise { return fs.rmdir(path) }, - + async unlink(path: string): Promise { return fs.unlink(path) }, - + async rename(oldPath: string, newPath: string): Promise { return fs.rename(oldPath, newPath) }, - + async stat(path: string): Promise { //console.log('myFS.stat', path) const stat = await fs.stat(path) //console.log('myFS.stat', stat) return stat }, - + async lstat(path: string): Promise { const lstat = await fs.lstat(path) //console.log('myFS.stat', path, lstat) @@ -159,19 +159,23 @@ const myFS = { return fs.symlink(target, path) } - + } } console.log('myFS', myFS) - +import git, { CommitObject, ReadCommitResult } from 'isomorphic-git' async function checkGit() { - const git = require('isomorphic-git'); - const files = await git.statusMatrix({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project' }); + + const files = await git.statusMatrix({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project', filepaths: ['apps/1test/src/index.ts'] }); console.log('GIT', files) } + +//checkGit() + +/* setInterval(() => { const startTime = Date.now() @@ -180,4 +184,119 @@ checkGit() console.log('checkGit', Date.now() - startTime) }) -}, 3000) \ No newline at end of file +}, 3000) + +*/ +/* +git.add({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project', filepath: 'test.txt' }).then(() => { + console.log('git add') +}).catch((e: any) => { + console.log('git add error', e) +}) + +git.log({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project', depth:10 }).then((log: any) => { + console.log('git log', log) +}) +*/ + +// run a shell command +import { exec } from 'child_process'; +import { promisify } from 'util'; +const execAsync = promisify(exec); + +const statusTransFormMatrix = (status: string) => { + switch (status) { + case '??': + return [0, 2, 0] + case 'A ': + return [0, 2, 2] + case 'M ': + return [1, 2, 2] + case 'MM': + return [1, 2, 3] + case ' M': + return [1, 0, 1] + case ' D': + return [0, 2, 0] + case 'D ': + return [1, 0, 0] + case 'AM': + return [0, 2, 3] + default: + return [-1, -1, -1] + } +} + + + +execAsync('git status --porcelain -uall', { cwd: '/Volumes/bunsen/code/rmproject2/remix-project' }).then(async (result: any) => { + //console.log('git status --porcelain -uall', result.stdout) + // parse the result.stdout + const lines = result.stdout.split('\n') + const files: any = [] + const fileNames: any = [] + //console.log('lines', lines) + lines.forEach((line: string) => { + // get the first two characters of the line + const status = line.slice(0, 2) + + const file = line.split(' ').pop() + + //console.log('line', line) + if (status && file) { + fileNames.push(file) + files.push([ + file, + ...statusTransFormMatrix(status) + ]) + } + } + ) + // sort files by first column + files.sort((a: any, b: any) => { + if (a[0] < b[0]) { + return -1 + } + if (a[0] > b[0]) { + return 1 + } + return 0 + }) + + //console.log('files', files, files.length) + const iso = await git.statusMatrix({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project', filepaths: fileNames }); + //console.log('GIT', iso, iso.length) +}) + +git.log({ fs: myFS, dir: '/Volumes/bunsen/code/rmproject2/remix-project', depth:3 }).then((log: ReadCommitResult[]) => { + log.forEach((commit: ReadCommitResult) => { + console.log('commit', commit.commit.parent) + }) +}) + +// exec git log --pretty=format:"%h - %an, %ar : %s" -n 10 +execAsync(`git log --pretty=format:'{ "oid":"%H", "message":"%s", "author":"%an", "email": "%ae", "timestamp":"%at", "tree": "%T", "committer": "%cn", "committer-email": "%ce", "committer-timestamp": "%ct", "parent": "%P" }' -n 3`, { cwd: '/Volumes/bunsen/code/rmproject2/remix-project' }).then(async (result: any) =>{ + //console.log('git log', result.stdout) + const lines = result.stdout.split('\n') + const commits: ReadCommitResult[] = [] + lines.forEach((line: string) => { + console.log('line', line) + const data = JSON.parse(line) + let commit:ReadCommitResult = {} as ReadCommitResult + commit.oid = data.oid + commit.commit = {} as CommitObject + commit.commit.message = data.message + commit.commit.tree = data.tree + commit.commit.committer = {} as any + commit.commit.committer.name = data.committer + commit.commit.committer.email = data['committer-email'] + commit.commit.committer.timestamp = data['committer-timestamp'] + commit.commit.author = {} as any + commit.commit.author.name = data.author + commit.commit.author.email = data.email + commit.commit.author.timestamp = data.timestamp + commit.commit.parent = [data.parent] + console.log('commit', commit) + commits.push(commit) + }) +}) diff --git a/apps/1test/src/remix/fsPlugin.ts b/apps/1test/src/remix/fsPlugin.ts index 4dc5954fe8..01cf86ed75 100644 --- a/apps/1test/src/remix/fsPlugin.ts +++ b/apps/1test/src/remix/fsPlugin.ts @@ -1,6 +1,6 @@ import { ElectronPlugin } from './lib/electronPlugin'; -let workingDir = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/' +let workingDir = '/Volumes/bunsen/code/empty/' const fixPath = (path: string) => { /* diff --git a/apps/1test/src/remix/gitPlugin.ts b/apps/1test/src/remix/gitPlugin.ts index dcd64baf12..af7d70e1fc 100644 --- a/apps/1test/src/remix/gitPlugin.ts +++ b/apps/1test/src/remix/gitPlugin.ts @@ -9,4 +9,6 @@ export class gitPlugin extends ElectronPlugin { }) this.methods = ['log', 'status', 'add', 'commit', 'push', 'pull', 'clone', 'checkout', 'branch', 'merge', 'reset', 'revert', 'diff', 'stash', 'apply', 'cherryPick', 'rebase', 'tag', 'fetch', 'remote', 'config', 'show', 'init', 'help', 'version'] } + + } \ No newline at end of file diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 7bd5a2be04..7c3d9b1662 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -46,6 +46,7 @@ import { CodeFormat } from './app/plugins/code-format' import { SolidityUmlGen } from './app/plugins/solidity-umlgen' import { ContractFlattener } from './app/plugins/contractFlattener' import { fsPlugin } from './app/plugins/fsPlugin' +import { isoGitPlugin } from './app/plugins/isoGitPlugin' const isElectron = require('is-electron') @@ -318,6 +319,8 @@ class AppComponent { if (isElectron()) { const FSPlugin = new fsPlugin() this.engine.register([FSPlugin]) + const isoGit = new isoGitPlugin() + this.engine.register([isoGit]) } // LAYOUT & SYSTEM VIEWS @@ -436,7 +439,7 @@ class AppComponent { await this.appManager.activatePlugin(['solidity-script']) if(isElectron()){ - await this.appManager.activatePlugin(['fs']) + await this.appManager.activatePlugin(['fs', 'isogit']) } this.appManager.on( diff --git a/apps/remix-ide/src/app/files/dgitProvider.js b/apps/remix-ide/src/app/files/dgitProvider.js index 10fddea285..131f210bb4 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.js +++ b/apps/remix-ide/src/app/files/dgitProvider.js @@ -25,7 +25,7 @@ const profile = { kind: 'file-system' } class DGitProvider extends Plugin { - constructor () { + constructor() { super(profile) this.ipfsconfig = { host: 'jqgt.remixproject.org', @@ -48,13 +48,12 @@ class DGitProvider extends Plugin { this.ipfsSources = [this.remixIPFS, this.globalIPFSConfig, this.ipfsconfig] } - async onActivation () { - + async onActivation() { } - async getGitConfig () { + async getGitConfig() { - if(isElectron()){ + if (isElectron()) { return { fs: window.remixFileSystem, dir: '/' @@ -70,7 +69,7 @@ class DGitProvider extends Plugin { } } - async parseInput (input) { + async parseInput(input) { return { corsProxy: 'https://corsproxy.remixproject.org/', http, @@ -85,7 +84,15 @@ class DGitProvider extends Plugin { } } - async init (input) { + async init(input) { + if(isElectron()) { + await this.call('isogit', 'init', { + defaultBranch: (input && input.branch) || 'main' + }) + this.emit('init') + return + } + await git.init({ ...await this.getGitConfig(), defaultBranch: (input && input.branch) || 'main' @@ -93,7 +100,14 @@ class DGitProvider extends Plugin { this.emit('init') } - async status (cmd) { + async status(cmd) { + + if (isElectron()) { + const status = await this.call('isogit', 'status', cmd) + console.log('STATUS', status) + return status + } + console.log('status') const status = await git.statusMatrix({ ...await this.getGitConfig(), @@ -103,43 +117,76 @@ class DGitProvider extends Plugin { return status } - async add (cmd) { - await git.add({ - ...await this.getGitConfig(), - ...cmd - }) + async add(cmd) { + + if (isElectron()) { + await this.call('isogit', 'add', cmd) + } else { + await git.add({ + ...await this.getGitConfig(), + ...cmd + }) + } + this.emit('add') } - async rm (cmd) { - await git.remove({ - ...await this.getGitConfig(), - ...cmd - }) + async rm(cmd) { + + if (isElectron()) { + await this.call('isogit', 'rm', cmd) + } else { + await git.remove({ + ...await this.getGitConfig(), + ...cmd + }) + this.emit('rm') + + } } + async checkout(cmd, refresh = true) { - async checkout (cmd, refresh = true) { - await git.checkout({ - ...await this.getGitConfig(), - ...cmd - }) + if (isElectron()) { + await this.call('isogit', 'checkout', cmd) + } else { + await git.checkout({ + ...await this.getGitConfig(), + ...cmd + }) + } if (refresh) { - setTimeout(async () => { + setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) } this.emit('checkout') } - async log (cmd) { + async log(cmd) { + + if (isElectron()) { + const status = await this.call('isogit', 'log', { + ...cmd, + depth: 10 + }) + console.log('STATUS', status) + return status + } + + const status = await git.log({ ...await this.getGitConfig(), - ...cmd + ...cmd, + depth: 10 }) return status } - async remotes (config) { + async remotes(config) { + if (isElectron()) { + return await this.call('isogit', 'remotes', config) + } + let remotes = [] try { remotes = await git.listRemotes({ ...config ? config : await this.getGitConfig() }) @@ -149,13 +196,19 @@ class DGitProvider extends Plugin { return remotes } - async branch (cmd, refresh = true) { - const status = await git.branch({ - ...await this.getGitConfig(), - ...cmd - }) + async branch(cmd, refresh = true) { + + let status + if (isElectron()) { + status = await this.call('isogit', 'branch', cmd) + } else { + status = await git.branch({ + ...await this.getGitConfig(), + ...cmd + }) + } if (refresh) { - setTimeout(async () => { + setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) } @@ -163,20 +216,34 @@ class DGitProvider extends Plugin { return status } - async currentbranch (config) { - try{ + async currentbranch(config) { + + console.log('currentbranch') + + if (isElectron()) { + console.log('currentbranch electron') + return await this.call('isogit', 'currentbranch') + + } + + try { const defaultConfig = await this.getGitConfig() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const name = await git.currentBranch(cmd) return name - }catch(e){ + } catch (e) { return '' } } - async branches (config) { - try{ + async branches(config) { + + if (isElectron()) { + return await this.call('isogit', 'branches', config) + } + + try { const defaultConfig = await this.getGitConfig() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const remotes = await this.remotes(config) @@ -188,26 +255,44 @@ class DGitProvider extends Plugin { branches = [...branches, ...remotebranches] } return branches - }catch(e){ + } catch (e) { return [] } } - async commit (cmd) { - await this.init() - try { - const sha = await git.commit({ - ...await this.getGitConfig(), - ...cmd - }) - this.emit('commit') - return sha - } catch (e) { - throw new Error(e) + async commit(cmd) { + + if (isElectron()) { + try { + await this.call('isogit', 'init') + const sha = await this.call('isogit', 'commit', cmd) + this.emit('commit') + return sha + } catch (e) { + throw new Error(e) + } + } else { + + await this.init() + try { + const sha = await git.commit({ + ...await this.getGitConfig(), + ...cmd + }) + this.emit('commit') + return sha + } catch (e) { + throw new Error(e) + } } } - async lsfiles (cmd) { + async lsfiles(cmd) { + + if (isElectron()) { + return await this.call('isogit', 'lsfiles', cmd) + } + const filesInStaging = await git.listFiles({ ...await this.getGitConfig(), ...cmd @@ -215,7 +300,12 @@ class DGitProvider extends Plugin { return filesInStaging } - async resolveref (cmd) { + async resolveref(cmd) { + + if (isElectron()) { + return await this.call('isogit', 'resolveref', cmd) + } + const oid = await git.resolveRef({ ...await this.getGitConfig(), ...cmd @@ -223,7 +313,7 @@ class DGitProvider extends Plugin { return oid } - async readblob (cmd) { + async readblob(cmd) { const readBlobResult = await git.readBlob({ ...await this.getGitConfig(), ...cmd @@ -231,14 +321,14 @@ class DGitProvider extends Plugin { return readBlobResult } - async setIpfsConfig (config) { + async setIpfsConfig(config) { this.ipfsconfig = config return new Promise((resolve) => { resolve(this.checkIpfsConfig()) }) } - async checkIpfsConfig (config) { + async checkIpfsConfig(config) { this.ipfs = IpfsHttpClient(config || this.ipfsconfig) try { await this.ipfs.config.getAll() @@ -248,19 +338,19 @@ class DGitProvider extends Plugin { } } - async addremote (input) { + async addremote(input) { await git.addRemote({ ...await this.getGitConfig(), url: input.url, remote: input.remote }) } - async delremote (input) { + async delremote(input) { await git.deleteRemote({ ...await this.getGitConfig(), remote: input.remote }) } - async localStorageUsed () { + async localStorageUsed() { return this.calculateLocalStorage() } - async clone (input, workspaceName, workspaceExists = false) { + async clone(input, workspaceName, workspaceExists = false) { const permission = await this.askUserPermission('clone', 'Import multiple files into your workspaces.') if (!permission) return false if (this.calculateLocalStorage() > 10000) throw new Error('The local storage of the browser is full.') @@ -284,7 +374,7 @@ class DGitProvider extends Plugin { return result } - async push (input) { + async push(input) { const cmd = { force: input.force, ref: input.ref, @@ -295,12 +385,19 @@ class DGitProvider extends Plugin { email: input.email }, ...await this.parseInput(input), - ...await this.getGitConfig() + } - return await git.push(cmd) + if (isElectron()) { + return await this.call('isogit', 'push', cmd) + } + + return await git.push({ + ...await this.getGitConfig(), + ...cmd + }) } - async pull (input) { + async pull(input) { const cmd = { ref: input.ref, remoteRef: input.remoteRef, @@ -310,16 +407,25 @@ class DGitProvider extends Plugin { }, remote: input.remote, ...await this.parseInput(input), - ...await this.getGitConfig() + + } + let result + if (isElectron()) { + result = await this.call('isogit', 'pull', cmd) + } + else { + result = await git.pull({ + ...await this.getGitConfig(), + ...cmd + }) } - const result = await git.pull(cmd) setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) return result } - async fetch (input) { + async fetch(input) { const cmd = { ref: input.ref, remoteRef: input.remoteRef, @@ -329,16 +435,23 @@ class DGitProvider extends Plugin { }, remote: input.remote, ...await this.parseInput(input), - ...await this.getGitConfig() } - const result = await git.fetch(cmd) + let result + if (isElectron()) { + result = await this.call('isogit', 'fetch', cmd) + } else { + result = await git.fetch({ + ...await this.getGitConfig(), + ...cmd + }) + } setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) return result } - async export (config) { + async export(config) { if (!this.checkIpfsConfig(config)) return false const workspace = await this.call('filePanel', 'getCurrentWorkspace') const files = await this.getDirectory('/') @@ -358,7 +471,7 @@ class DGitProvider extends Plugin { return r.cid.string } - async pin (pinataApiKey, pinataSecretApiKey) { + async pin(pinataApiKey, pinataSecretApiKey) { const workspace = await this.call('filePanel', 'getCurrentWorkspace') const files = await this.getDirectory('/') this.filesToSend = [] @@ -425,7 +538,7 @@ class DGitProvider extends Plugin { } } - async pinList (pinataApiKey, pinataSecretApiKey) { + async pinList(pinataApiKey, pinataSecretApiKey) { const url = 'https://api.pinata.cloud/data/pinList?status=pinned' try { const result = await axios @@ -444,7 +557,7 @@ class DGitProvider extends Plugin { } } - async unPin (pinataApiKey, pinataSecretApiKey, hashToUnpin) { + async unPin(pinataApiKey, pinataSecretApiKey, hashToUnpin) { const url = `https://api.pinata.cloud/pinning/unpin/${hashToUnpin}` try { await axios @@ -460,7 +573,7 @@ class DGitProvider extends Plugin { } } - async importIPFSFiles (config, cid, workspace) { + async importIPFSFiles(config, cid, workspace) { const ipfs = IpfsHttpClient(config) let result = false try { @@ -489,7 +602,7 @@ class DGitProvider extends Plugin { return result } - calculateLocalStorage () { + calculateLocalStorage() { var _lsTotal = 0 var _xLen; var _x for (_x in localStorage) { @@ -503,7 +616,7 @@ class DGitProvider extends Plugin { return (_lsTotal / 1024).toFixed(2) } - async import (cmd) { + async import(cmd) { const permission = await this.askUserPermission('import', 'Import multiple files into your workspaces.') if (!permission) return false if (this.calculateLocalStorage() > 10000) throw new Error('The local storage of the browser is full.') @@ -522,13 +635,13 @@ class DGitProvider extends Plugin { if (!result) throw new Error(`Cannot pull files from IPFS at ${cid}`) } - async getItem (name) { + async getItem(name) { if (typeof window !== 'undefined') { return window.localStorage.getItem(name) } } - async setItem (name, content) { + async setItem(name, content) { try { if (typeof window !== 'undefined') { window.localStorage.setItem(name, content) @@ -540,7 +653,7 @@ class DGitProvider extends Plugin { return true } - async zip () { + async zip() { const zip = new JSZip() const workspace = await this.call('filePanel', 'getCurrentWorkspace') const files = await this.getDirectory('/') @@ -557,7 +670,7 @@ class DGitProvider extends Plugin { }) } - async createDirectories (strdirectories) { + async createDirectories(strdirectories) { const ignore = ['.', '/.', ''] if (ignore.indexOf(strdirectories) > -1) return false const directories = strdirectories.split('/') @@ -575,7 +688,7 @@ class DGitProvider extends Plugin { } } - async getDirectory (dir) { + async getDirectory(dir) { let result = [] const files = await this.call('fileManager', 'readdir', dir) const fileArray = normalize(files) @@ -599,7 +712,7 @@ class DGitProvider extends Plugin { } const addSlash = (file) => { - if (!file.startsWith('/'))file = '/' + file + if (!file.startsWith('/')) file = '/' + file return file } diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index ef1883f524..71dfc041af 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -195,8 +195,8 @@ class FileManager extends Plugin { path = this.normalize(path) path = this.limitPluginScope(path) path = this.getPathFromUrl(path).file - await this._handleExists(path, `Cannot open file ${path}`) - await this._handleIsFile(path, `Cannot open file ${path}`) + //await this._handleExists(path, `Cannot open file ${path}`) + //await this._handleIsFile(path, `Cannot open file ${path}`) await this.openFile(path) } diff --git a/apps/remix-ide/src/app/plugins/fsPlugin.ts b/apps/remix-ide/src/app/plugins/fsPlugin.ts index 76355d5873..ea273d65ae 100644 --- a/apps/remix-ide/src/app/plugins/fsPlugin.ts +++ b/apps/remix-ide/src/app/plugins/fsPlugin.ts @@ -1,6 +1,4 @@ import { ElectronPlugin } from '@remixproject/engine-electron'; -import once from 'just-once'; - let workingDir = null @@ -8,15 +6,6 @@ const fixPath = (path: string) => { return path } -function wrapCallback(opts, cb) { - if (typeof opts === "function") { - cb = opts; - } - cb = once(cb); - const resolve = (...args) => cb(null, ...args) - return [resolve, cb]; -} - export class fsPlugin extends ElectronPlugin { public fs: any public fsSync: any @@ -58,9 +47,9 @@ export class fsPlugin extends ElectronPlugin { }, readdir: async (path: string) => { path = fixPath(path) - console.log('readdir', path) + //console.log('readdir', path) const files = await this.call('fs', 'readdir', path) - console.log('readdir', path, files) + //console.log('readdir', path, files) return files }, unlink: async (path: string) => { @@ -73,13 +62,13 @@ export class fsPlugin extends ElectronPlugin { }, readFile: async (path: string, options) => { try { - console.log('readFile', path, options) + //console.log('readFile', path, options) path = fixPath(path) const file = await this.call('fs', 'readFile', path, options) - console.log('readFile', path, file) + //console.log('readFile', path, file) return file } catch (e) { - console.log('readFile error', e) + //console.log('readFile error', e) return undefined } } @@ -99,10 +88,10 @@ export class fsPlugin extends ElectronPlugin { if(!stat) return undefined stat.isDirectory = () => stat.isDirectoryValue stat.isFile = () => !stat.isDirectoryValue - //console.log('stat', path, stat) + ////console.log('stat', path, stat) return stat } catch (e) { - console.log('stat error', e) + //console.log('stat error', e) return undefined } }, @@ -115,7 +104,7 @@ export class fsPlugin extends ElectronPlugin { stat.isFile = () => !stat.isDirectoryValue return stat } catch (e) { - console.log('lstat error', e) + //console.log('lstat error', e) return undefined } }, @@ -145,12 +134,12 @@ export class fsPlugin extends ElectronPlugin { async onActivation() { - console.log('fsPluginClient onload', this.fs); + //console.log('fsPluginClient onload', this.fs); (window as any).remixFileSystem = this.fs; this.on('fs', 'workingDirChanged', async (path: string) => { - console.log('change working dir', path) + //console.log('change working dir', path) workingDir = path await this.call('fileManager', 'refresh') }) diff --git a/apps/remix-ide/src/app/plugins/isoGitPlugin.ts b/apps/remix-ide/src/app/plugins/isoGitPlugin.ts new file mode 100644 index 0000000000..8d0ff08a1f --- /dev/null +++ b/apps/remix-ide/src/app/plugins/isoGitPlugin.ts @@ -0,0 +1,19 @@ +import { ElectronPlugin } from '@remixproject/engine-electron'; + +export class isoGitPlugin extends ElectronPlugin { + constructor() { + super({ + displayName: 'isogit', + name: 'isogit', + description: 'isogit', + }) + this.methods = [] + + } + + onActivation(): void { + + } + + +} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/theme-module.js b/apps/remix-ide/src/app/tabs/theme-module.js index 566390055e..4f97e90bd6 100644 --- a/apps/remix-ide/src/app/tabs/theme-module.js +++ b/apps/remix-ide/src/app/tabs/theme-module.js @@ -28,7 +28,7 @@ const profile = { } export class ThemeModule extends Plugin { - constructor () { + constructor() { super(profile) this.events = new EventEmitter() this._deps = { @@ -37,8 +37,8 @@ export class ThemeModule extends Plugin { this.themes = {} themes.map((theme) => { this.themes[theme.name.toLocaleLowerCase()] = { - ...theme, - url: isElectron()? theme.url: window.location.origin + ( window.location.pathname.startsWith('/address/') || window.location.pathname.endsWith('.sol') ? '/' : window.location.pathname ) + theme.url + ...theme, + url: isElectron() ? theme.url : window.location.origin + (window.location.pathname.startsWith('/address/') || window.location.pathname.endsWith('.sol') ? '/' : window.location.pathname) + theme.url } }) this._paq = _paq @@ -56,22 +56,26 @@ export class ThemeModule extends Plugin { /** Return the active theme * @return {{ name: string, quality: string, url: string }} - The active theme */ - currentTheme () { + currentTheme() { + if (isElectron()) { + const theme = 'https://remix.ethereum.org/' + this.themes[this.active].url.replace(/\\/g, '/').replace(/\/\//g, '/').replace(/\/$/g, '') + return { ...this.themes[this.active], url: theme } + } return this.themes[this.active] } /** Returns all themes as an array */ - getThemes () { + getThemes() { return Object.keys(this.themes).map(key => this.themes[key]) } /** * Init the theme */ - initTheme (callback) { // callback is setTimeOut in app.js which is always passed + initTheme(callback) { // callback is setTimeOut in app.js which is always passed if (callback) this.initCallback = callback if (this.active) { - document.getElementById('theme-link') ? document.getElementById('theme-link').remove():null + document.getElementById('theme-link') ? document.getElementById('theme-link').remove() : null const nextTheme = this.themes[this.active] // Theme document.documentElement.style.setProperty('--theme', nextTheme.quality) @@ -91,8 +95,8 @@ export class ThemeModule extends Plugin { * Change the current theme * @param {string} [themeName] - The name of the theme */ - switchTheme (themeName) { - themeName = themeName && themeName.toLocaleLowerCase() + switchTheme(themeName) { + themeName = themeName && themeName.toLocaleLowerCase() if (themeName && !Object.keys(this.themes).includes(themeName)) { throw new Error(`Theme ${themeName} doesn't exist`) } @@ -101,7 +105,7 @@ export class ThemeModule extends Plugin { _paq.push(['trackEvent', 'themeModule', 'switchTo', next]) const nextTheme = this.themes[next] // Theme if (!this.forced) this._deps.config.set('settings/theme', next) - document.getElementById('theme-link') ? document.getElementById('theme-link').remove():null + document.getElementById('theme-link') ? document.getElementById('theme-link').remove() : null const theme = document.createElement('link') theme.setAttribute('rel', 'stylesheet') @@ -116,18 +120,21 @@ export class ThemeModule extends Plugin { if (themeName) this.active = themeName // TODO: Only keep `this.emit` (issue#2210) console.log('themeChanged', nextTheme) - if(isElectron()) { - nextTheme.url = nextTheme.url = 'https://remix.ethereum.org/' + nextTheme.url.replace(/\\/g, '/').replace(/\/\//g, '/').replace(/\/$/g, '') + if (isElectron()) { + const theme = 'https://remix.ethereum.org/' + nextTheme.url.replace(/\\/g, '/').replace(/\/\//g, '/').replace(/\/$/g, '') + this.emit('themeChanged', { ...nextTheme, url: theme }) + this.events.emit('themeChanged', { ...nextTheme, url: theme }) + } else { + this.emit('themeChanged', nextTheme) + this.events.emit('themeChanged', nextTheme) } - this.emit('themeChanged', nextTheme) - this.events.emit('themeChanged', nextTheme) } /** * fixes the invertion for images since this should be adjusted when we switch between dark/light qualified themes * @param {element} [image] - the dom element which invert should be fixed to increase visibility */ - fixInvert (image) { + fixInvert(image) { const invert = this.currentTheme().quality === 'dark' ? 1 : 0 if (image) { image.style.filter = `invert(${invert})` diff --git a/apps/remixdesktop/src/engine.ts b/apps/remixdesktop/src/engine.ts index 0493fc20df..e3a9a2a83d 100644 --- a/apps/remixdesktop/src/engine.ts +++ b/apps/remixdesktop/src/engine.ts @@ -1,19 +1,23 @@ import { Engine, PluginManager } from '@remixproject/engine'; import { ipcMain } from 'electron'; -import { FSPlugin } from './fsPlugin'; -import { GitPlugin } from './gitPlugin'; +import { FSPlugin } from './plugins/fsPlugin'; +import { GitPlugin } from './plugins/gitPlugin'; import { app } from 'electron'; -import { XtermPlugin } from './xtermPlugin'; +import { XtermPlugin } from './plugins/xtermPlugin'; +import git from 'isomorphic-git' +import { IsoGitPlugin } from './plugins/isoGitPlugin'; const engine = new Engine() const appManager = new PluginManager() const fsPlugin = new FSPlugin() const gitPlugin = new GitPlugin() const xtermPlugin = new XtermPlugin() +const isoGitPlugin = new IsoGitPlugin() engine.register(appManager) engine.register(fsPlugin) engine.register(gitPlugin) engine.register(xtermPlugin) +engine.register(isoGitPlugin) appManager.activatePlugin('fs') @@ -34,4 +38,4 @@ ipcMain.handle('getWebContentsID', (event, message) => { app.on('before-quit', async () => { await appManager.call('fs', 'closeWatch') app.quit() -}) \ No newline at end of file +}) diff --git a/apps/remixdesktop/src/fsPlugin.ts b/apps/remixdesktop/src/plugins/fsPlugin.ts similarity index 72% rename from apps/remixdesktop/src/fsPlugin.ts rename to apps/remixdesktop/src/plugins/fsPlugin.ts index 28e9ab6967..1ecbfbd32e 100644 --- a/apps/remixdesktop/src/fsPlugin.ts +++ b/apps/remixdesktop/src/plugins/fsPlugin.ts @@ -41,38 +41,38 @@ const clientProfile: Profile = { class FSPluginClient extends ElectronBasePluginClient { watcher: chokidar.FSWatcher - workingDir: string = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/' + workingDir: string = '/Volumes/bunsen/code/empty/' constructor(webContentsId: number, profile: Profile) { super(webContentsId, profile) this.onload(() => { - console.log('fsPluginClient onload') + //console.log('fsPluginClient onload') }) } async readdir(path: string): Promise { // call node fs.readdir - console.log('readdir', path) + //console.log('readdir', path) if (!path) return [] const files = fs.readdir(this.fixPath(path)) return files } async readFile(path: string, options: any): Promise { - console.log('readFile', path, options) + //console.log('readFile', path, options) // hacky fix for TS error if (!path) return undefined try { return (fs as any).readFile(this.fixPath(path), options) } catch (e) { - console.log('readFile error', e) + //console.log('readFile error', e) return undefined } } async writeFile(path: string, content: string, options: any): Promise { - console.log('writeFile', path, content, options) + //console.log('writeFile', path, content, options) return (fs as any).writeFile(this.fixPath(path), content, options) } @@ -95,14 +95,14 @@ class FSPluginClient extends ElectronBasePluginClient { async stat(path: string): Promise { try { const stat = await fs.stat(this.fixPath(path)) - //console.log('stat', path, stat) + ////console.log('stat', path, stat) const isDirectory = stat.isDirectory() return { ...stat, isDirectoryValue: isDirectory } } catch (e) { - console.log('stat error', e) + //console.log('stat error', e) return undefined } } @@ -116,40 +116,40 @@ class FSPluginClient extends ElectronBasePluginClient { isDirectoryValue: isDirectory } } catch (e) { - console.log('lstat error', e) + //console.log('lstat error', e) return undefined } } - async exists(path: string): Promise < boolean > { - return fs.access(this.fixPath(path)).then(() => true).catch(() => false) - } + async exists(path: string): Promise { + return fs.access(this.fixPath(path)).then(() => true).catch(() => false) + } - async currentPath(): Promise < string > { - return process.cwd() - } + async currentPath(): Promise { + return process.cwd() + } - async watch(path: string): Promise < void> { - if(this.watcher) this.watcher.close() + async watch(path: string): Promise { + if (this.watcher) this.watcher.close() this.watcher = - chokidar.watch(this.fixPath(path)).on('change', (path, stats) => { - console.log('change', path, stats) - this.emit('change', path, stats) - }) - } + chokidar.watch(this.fixPath(path)).on('change', (path, stats) => { + //console.log('change', path, stats) + this.emit('change', path, stats) + }) + } - async closeWatch(): Promise < void> { - console.log('closing Watcher', this.webContentsId) - if(this.watcher) this.watcher.close() - } + async closeWatch(): Promise { + //console.log('closing Watcher', this.webContentsId) + if (this.watcher) this.watcher.close() + } - async setWorkingDir(): Promise < void> { - const dirs = dialog.showOpenDialogSync(this.window, { - properties: ['openDirectory'] - }) - if(dirs && dirs.length > 0) { + async setWorkingDir(): Promise { + const dirs = dialog.showOpenDialogSync(this.window, { + properties: ['openDirectory'] + }) + if (dirs && dirs.length > 0) { this.workingDir = dirs[0] this.emit('workingDirChanged', dirs[0]) } diff --git a/apps/remixdesktop/src/gitPlugin.ts b/apps/remixdesktop/src/plugins/gitPlugin.ts similarity index 73% rename from apps/remixdesktop/src/gitPlugin.ts rename to apps/remixdesktop/src/plugins/gitPlugin.ts index 36faca385c..aebc82fabc 100644 --- a/apps/remixdesktop/src/gitPlugin.ts +++ b/apps/remixdesktop/src/plugins/gitPlugin.ts @@ -1,6 +1,5 @@ import { PluginClient } from "@remixproject/plugin"; import { Profile } from "@remixproject/plugin-utils"; -import { spawn } from "child_process"; import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" const profile: Profile = { @@ -33,20 +32,8 @@ class GitPluginClient extends ElectronBasePluginClient { }) } - async log(path: string): Promise { - const log = spawn('git', ['log'], { - cwd: path, - env: { - NODE_ENV: 'production', - PATH: process.env.PATH, - }, - }) + async log(cmd: any): Promise { - return new Promise((resolve, reject) => { - log.stdout.on('data', (data) => { - resolve(data.toString()) - }) - }) } diff --git a/apps/remixdesktop/src/plugins/isoGitPlugin.ts b/apps/remixdesktop/src/plugins/isoGitPlugin.ts new file mode 100644 index 0000000000..99a0d92e1f --- /dev/null +++ b/apps/remixdesktop/src/plugins/isoGitPlugin.ts @@ -0,0 +1,241 @@ +import { PluginClient } from "@remixproject/plugin"; +import { Profile } from "@remixproject/plugin-utils"; +import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" +import fs from 'fs/promises' +import git from 'isomorphic-git' + +const profile: Profile = { + name: 'isogit', + displayName: 'isogit', + description: 'isogit plugin', +} + +export class IsoGitPlugin extends ElectronBasePlugin { + client: PluginClient + constructor() { + super(profile, clientProfile, IsoGitPluginClient) + } +} + +const clientProfile: Profile = { + name: 'isogit', + displayName: 'isogit', + description: 'isogit plugin', + methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem'] +} + +class IsoGitPluginClient extends ElectronBasePluginClient { + workingDir: string = '/Volumes/bunsen/code/empty/' + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile) + this.onload(() => { + console.log('IsoGit client onload') + this.on('fs' as any, 'workingDirChanged', async (path: string) => { + console.log('workingDirChanged', path) + this.workingDir = path + await this.status({ + + }) + }) + }) + } + + async getGitConfig () { + return { + fs, + dir: this.workingDir, + } + } + + async status (cmd: any) { + console.log('status') + const status = await git.statusMatrix({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('STATUS', status, await this.getGitConfig()) + return status + } + + async log (cmd: any) { + console.log('log') + const log = await git.log({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('LOG', log) + return log + } + + async add (cmd: any) { + console.log('add') + const add = await git.add({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('ADD', add) + return add + } + + async rm(cmd: any) { + console.log('rm') + const rm = await git.remove({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('RM', rm) + return rm + } + + async commit (cmd: any) { + console.log('commit') + const commit = await git.commit({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('COMMIT', commit) + return commit + } + + async init (input: any) { + await git.init({ + ...await this.getGitConfig(), + defaultBranch: (input && input.branch) || 'main' + }) + } + + async branch (cmd: any) { + console.log('branch') + const branch = await git.branch({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('BRANCH', branch) + return branch + } + + async lsfiles (cmd: any) { + console.log('lsfiles') + const lsfiles = await git.listFiles({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('LSFILES', lsfiles) + return lsfiles + } + + async resolveref (cmd: any) { + console.log('resolveref') + const resolveref = await git.resolveRef({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('RESOLVEREF', resolveref) + return resolveref + } + + + async readblob (cmd: any) { + console.log('readblob') + const readblob = await git.readBlob({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('READBLOB', readblob) + return readblob + } + + async checkout (cmd: any) { + console.log('checkout') + const checkout = await git.checkout({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('CHECKOUT', checkout) + return checkout + } + + async push (cmd: any) { + console.log('push') + const push = await git.push({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('PUSH', push) + return push + } + + async pull (cmd: any) { + console.log('pull') + const pull = await git.pull({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('PULL', pull) + return pull + } + + async fetch(cmd: any) { + console.log('fetch') + const fetch = await git.fetch({ + ...await this.getGitConfig(), + ...cmd + }) + console.log('FETCH', fetch) + return fetch + } + + + + remotes = async () => { + let remotes = [] + remotes = await git.listRemotes({...await this.getGitConfig() }) + console.log('remotes', remotes) + return remotes + } + + async currentbranch() { + try { + const defaultConfig = await this.getGitConfig() + const name = await git.currentBranch(defaultConfig) + console.log('currentbranch', name) + return name + } catch (e) { + return '' + } + } + + + async branches() { + try { + let cmd: any = {...await this.getGitConfig()} + const remotes = await this.remotes() + let branches = [] + branches = (await git.listBranches(cmd)).map((branch) => { return { remote: undefined, name: branch } }) + for (const remote of remotes) { + cmd = { + ...cmd, + remote: remote.remote + } + + const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote.remote, name: branch } }) + branches = [...branches, ...remotebranches] + + } + console.log('branches', branches) + return branches + } catch (e) { + return [] + } + } + + + + + + + +} + + + diff --git a/apps/remixdesktop/src/xtermPlugin.ts b/apps/remixdesktop/src/plugins/xtermPlugin.ts similarity index 100% rename from apps/remixdesktop/src/xtermPlugin.ts rename to apps/remixdesktop/src/plugins/xtermPlugin.ts diff --git a/apps/remixdesktop/src/preload.ts b/apps/remixdesktop/src/preload.ts index b9918327aa..854049c24a 100644 --- a/apps/remixdesktop/src/preload.ts +++ b/apps/remixdesktop/src/preload.ts @@ -6,7 +6,7 @@ console.log('preload.ts') /* preload script needs statically defined API for each plugin */ -const exposedPLugins = ['fs', 'git', 'xterm'] +const exposedPLugins = ['fs', 'git', 'xterm', 'isogit'] console.log('preload.ts', process) let webContentsId: number | undefined diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index b381193b6a..70af2f08db 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -125,6 +125,7 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React. dispatch(setCurrentWorkspace({ name: 'electron', isGitRepo: false })) listenOnProviderEvents(electrOnProvider)(dispatch) + listenOnPluginEvents(plugin) dispatch(setMode('browser')) dispatch(fsInitializationCompleted()) plugin.emit('workspaceInitializationCompleted')