add git service in remixd & use it from the terminal

pull/638/head
yann300 4 years ago
parent 09ce1a6bbd
commit c76772137b
  1. 5
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  2. 3
      apps/remix-ide/src/app.js
  3. 27
      apps/remix-ide/src/app/files/git-handle.js
  4. 3
      apps/remix-ide/src/app/files/remixd-handle.js
  5. 2
      apps/remix-ide/src/app/panels/file-panel.js
  6. 3
      apps/remix-ide/src/app/panels/styles/terminal-styles.js
  7. 9
      apps/remix-ide/src/app/panels/terminal.js
  8. 2
      apps/remix-ide/src/remixAppManager.js
  9. 15
      libs/remixd/src/bin/remixd.ts
  10. 1
      libs/remixd/src/serviceList.ts
  11. 62
      libs/remixd/src/services/gitClient.ts
  12. 4
      libs/remixd/src/types/index.ts
  13. 16
      libs/remixd/src/websocket.ts

@ -71,6 +71,11 @@ module.exports = {
.testContracts('test_import_node_modules_with_github_import.sol', sources[4]['browser/test_import_node_modules_with_github_import.sol'], ['ERC20', 'test11'])
.clickLaunchIcon('pluginManager')
.scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_remixd"] button')
},
'Run git status': function (browser) {
browser.executeScript('git status')
.journalLastChildIncludes('On branch master')
.end()
},
tearDown: sauce

@ -390,7 +390,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
debug,
analysis,
test,
filePanel.remixdHandle
filePanel.remixdHandle,
filePanel.gitHandle
])
try {

@ -0,0 +1,27 @@
import { WebsocketPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
const profile = {
name: 'git',
displayName: 'Git',
url: 'ws://127.0.0.1:65521',
methods: ['command'],
events: [],
description: 'Using Remixd daemon, allow to access git API',
kind: 'other',
version: packageJson.version
}
export class GitHandle extends WebsocketPlugin {
constructor () {
super(profile)
}
deactivate () {
super.deactivate()
}
activate () {
super.activate()
}
}

@ -40,6 +40,7 @@ export class RemixdHandle extends WebsocketPlugin {
deactivate () {
this.fileSystemExplorer.hide()
if (super.socket) super.deactivate()
this.appManager.ensureDeactivated('git')
this.locahostProvider.close((error) => {
if (error) console.log(error)
})
@ -52,6 +53,7 @@ export class RemixdHandle extends WebsocketPlugin {
async canceled () {
this.appManager.ensureDeactivated('remixd')
this.appManager.ensureDeactivated('git')
}
/**
@ -82,6 +84,7 @@ export class RemixdHandle extends WebsocketPlugin {
}
}, 3000)
this.locahostProvider.init(_ => this.fileSystemExplorer.ensureRoot())
this.appManager.ensureActivated('git')
}
}
if (this.locahostProvider.isConnected()) {

@ -5,6 +5,7 @@ var yo = require('yo-yo')
var EventManager = require('../../lib/events')
var FileExplorer = require('../files/file-explorer')
var { RemixdHandle } = require('../files/remixd-handle.js')
var { GitHandle } = require('../files/git-handle.js')
var globalRegistry = require('../../global/registry')
var css = require('./styles/file-panel-styles')
@ -60,6 +61,7 @@ module.exports = class Filepanel extends ViewPlugin {
var fileSystemExplorer = createProvider('localhost')
self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders.localhost, appManager)
self.gitHandle = new GitHandle()
const explorers = yo`
<div>

@ -54,6 +54,9 @@ var css = csjs`
padding : 1ch;
margin-top : 2ch;
}
.block > pre {
max-height : 200px;
}
.cli {
line-height : 1.7em;
font-family : monospace;

@ -485,7 +485,7 @@ class Terminal extends Plugin {
return self._view.el
function wrapScript (script) {
if (script.startsWith('remix.')) return script
if (script.trim().startsWith('remix.') || script.trim().startsWith('git')) return script
return `
try {
const ret = ${script};
@ -746,10 +746,15 @@ class Terminal extends Plugin {
}
}
try {
if (script.trim().indexOf('git') === 0) {
const result = await this.call('git', 'command', script)
self.commands.html(yo`<pre>${result}</pre>`)
} else {
await this.call('scriptRunner', 'execute', script)
}
done()
} catch (error) {
done(error.message)
done(error.message || error)
}
}
}

@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views
'terminal', 'settings', 'pluginManager']
export function isNative (name) {
const nativePlugins = ['vyper', 'workshops', 'debugger']
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd']
return nativePlugins.includes(name) || requiredModules.includes(name)
}

@ -38,15 +38,24 @@ import * as program from 'commander'
console.log('\x1b[33m%s\x1b[0m', '[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.')
console.log('\x1b[33m%s\x1b[0m', '[WARN] Symbolic links are not forwarded to Remix IDE\n')
try {
const sharedFolderClient = new servicesList.Sharedfolder()
const websocketHandler = new WebSocket(65520, { remixIdeUrl: program.remixIde }, sharedFolderClient)
// shared folder
const websocketHandler = new WebSocket(65520, { remixIdeUrl: program.remixIde }, () => new servicesList.Sharedfolder())
websocketHandler.start((ws: WS) => {
websocketHandler.start((ws: WS, sharedFolderClient: servicesList.Sharedfolder) => {
sharedFolderClient.setWebSocket(ws)
sharedFolderClient.setupNotifications(program.sharedFolder)
sharedFolderClient.sharedFolder(program.sharedFolder, program.readOnly || false)
})
killCallBack.push(websocketHandler.close.bind(websocketHandler))
// git
const websocketHandlerForGit = new WebSocket(65521, { remixIdeUrl: program.remixIde }, () => new servicesList.GitClient())
websocketHandlerForGit.start((ws: WS, gitClient: servicesList.GitClient) => {
gitClient.setWebSocket(ws)
gitClient.sharedFolder(program.sharedFolder, program.readOnly || false)
})
killCallBack.push(websocketHandlerForGit.close.bind(websocketHandlerForGit))
} catch (error) {
throw new Error(error)
}

@ -1 +1,2 @@
export { RemixdClient as Sharedfolder } from './services/remixdClient'
export { GitClient } from './services/gitClient'

@ -0,0 +1,62 @@
import * as WS from 'ws' // eslint-disable-line
import { PluginClient } from '@remixproject/plugin'
const { spawn } = require('child_process')
const gitRegex = '^git\\s[^&|;]*$'
export class GitClient extends PluginClient {
methods: ['command']
websocket: WS
currentSharedFolder: string
readOnly: boolean
setWebSocket (websocket: WS): void {
this.websocket = websocket
}
sharedFolder (currentSharedFolder: string, readOnly: boolean): void {
this.currentSharedFolder = currentSharedFolder
this.readOnly = readOnly
}
command (cmd: string) {
return new Promise((resolve, reject) => {
try {
try {
validateCommand(cmd, gitRegex)
} catch (e) {
return reject(e)
}
const options = { cwd: this.currentSharedFolder, shell: true }
const child = spawn(cmd, options)
let result = ''
let error = ''
child.stdout.on('data', (data) => {
result += data.toString()
})
child.stderr.on('data', (err) => {
error += err.toString()
})
child.on('close', (exitCode) => {
if (exitCode !== 0) {
reject(error)
} else {
resolve(result + error)
}
})
} catch (e) {
reject(e)
}
})
}
}
/**
* Validate that command can be run by service
* @param cmd
* @param regex
*/
function validateCommand (cmd, regex) {
if (!RegExp(regex).test(cmd)) { // git then space and then everything else
throw new Error('Invalid command for service!')
}
}

@ -3,9 +3,9 @@ import * as Websocket from 'ws'
type ServiceListKeys = keyof typeof ServiceList;
export type SharedFolder = typeof ServiceList[ServiceListKeys]
export type Service = typeof ServiceList[ServiceListKeys]
export type SharedFolderClient = InstanceType<typeof ServiceList[ServiceListKeys]>
export type ServiceClient = InstanceType<typeof ServiceList[ServiceListKeys]>
export type WebsocketOpt = {
remixIdeUrl: string

@ -1,15 +1,15 @@
import * as WS from 'ws'
import * as http from 'http'
import { WebsocketOpt, SharedFolderClient } from './types' // eslint-disable-line
import { WebsocketOpt, ServiceClient } from './types' // eslint-disable-line
import { getDomain } from './utils'
import { createClient } from '@remixproject/plugin-ws'
export default class WebSocket {
server: http.Server
wsServer: WS.Server
constructor (public port: number, public opt: WebsocketOpt, public sharedFolder: SharedFolderClient) {} //eslint-disable-line
constructor (public port: number, public opt: WebsocketOpt, public getclient: () => ServiceClient) {} //eslint-disable-line
start (callback?: (ws: WS) => void): void {
start (callback?: (ws: WS, client: ServiceClient) => void): void {
this.server = http.createServer((request, response) => {
console.log((new Date()) + ' Received request for ' + request.url)
response.writeHead(404)
@ -17,8 +17,8 @@ export default class WebSocket {
})
const loopback = '127.0.0.1'
this.server.listen(this.port, loopback, function () {
console.log((new Date()) + ' remixd is listening on ' + loopback + ':65520')
this.server.listen(this.port, loopback, () => {
console.log((new Date()) + ' remixd is listening on ' + loopback + ':' + this.port + '')
})
this.wsServer = new WS.Server({
server: this.server,
@ -32,10 +32,10 @@ export default class WebSocket {
}
})
this.wsServer.on('connection', (ws) => {
const { sharedFolder } = this
const client = this.getclient()
createClient(ws, sharedFolder as any)
if (callback) callback(ws)
createClient(ws, client as any)
if (callback) callback(ws, client)
})
}

Loading…
Cancel
Save