yarn actions

desktopoffline
bunsenstraat 1 year ago
parent 30c373c43a
commit 4acec88b5a
  1. 41
      apps/remix-ide/src/app/plugins/electron/scriptRunnerPlugin.ts
  2. 225
      apps/remixdesktop/src/plugins/scriptRunner.ts

@ -1,5 +1,7 @@
import { AppModal } from '@remix-ui/app';
import { ElectronPlugin } from '@remixproject/engine-electron';
export class scriptRunnerPlugin extends ElectronPlugin {
constructor(){
super({
@ -8,4 +10,43 @@ export class scriptRunnerPlugin extends ElectronPlugin {
description: 'scriptRunner'
})
}
async onActivation(): Promise<void> {
this.on('scriptRunner', 'missingModule', async (module: string) => {
console.log('missingModule', module)
const addModuleModal: AppModal = {
id: 'AddModuleModal',
title: `Missing module ${module}`,
message: `Do you want to install the missing module? ${module} \n\nYou can also install it manually using the terminal if you have yarn or npm installed:\nyarn add ${module}`,
okLabel: 'Install',
cancelLabel: 'No',
}
const result = await this.call('notification', 'modal', addModuleModal)
if (result) {
await this.addModule(module)
}
})
}
async addModule(module: string, version: string = ''): Promise<void> {
await this.checkPackageJson()
await this.call('scriptRunner', 'yarnAdd', module, version)
}
async checkPackageJson(): Promise<void> {
const exists = await this.call('fileManager', 'exists', 'package.json')
if(!exists){
const initPackageJsonModal: AppModal = {
id: 'InitPackageJsonModal',
title: `Missing package.json`,
message: `A package.json file is required to install the missing module. A package.json file contains meta data about your app or module. Do you want to create one?`,
okLabel: 'Yes, create a package.json file',
cancelLabel: 'No',
}
const result = await this.call('notification', 'modal', initPackageJsonModal)
if (result) {
await this.call('scriptRunner', 'yarnInit')
}
}
}
}

@ -1,15 +1,18 @@
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron"
import path from "path"
import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron'
import path from 'path'
import * as esbuild from 'esbuild'
import fs from 'fs/promises'
import os, { arch } from 'os'
import os, {arch} from 'os'
import {exec} from 'child_process'
import {promisify} from 'util'
const execAsync = promisify(exec)
export const cacheDir = path.join(os.homedir(), '.cache_remix_ide')
const profile = {
"name": "scriptRunner",
"displayName": "Script Runner",
"description": "Execute script and emit logs",
name: 'scriptRunner',
displayName: 'Script Runner',
description: 'Execute script and emit logs',
}
const convertPathToPosix = (pathName: string): string => {
@ -19,63 +22,155 @@ const convertPathToPosix = (pathName: string): string => {
export class ScriptRunnerPlugin extends ElectronBasePlugin {
constructor() {
super(profile, clientProfile, ScriptRunnerClient)
this.methods = [...super.methods, 'execute']
this.methods = [...super.methods]
}
}
const clientProfile = {
"name": "scriptRunner",
"displayName": "Script Runner",
"description": "Execute script and emit logs",
"methods": ["execute"]
name: 'scriptRunner',
displayName: 'Script Runner',
description: 'Execute script and emit logs',
methods: ['execute', 'yarnAdd', 'yarnInit'],
}
class ScriptRunnerClient extends ElectronBasePluginClient {
workingDir: string = ''
nodeVersion: string = ''
yarnVersion: string = ''
constructor(webContentsId: number, profile: any) {
super(webContentsId, profile)
this.onload(() => {
this.onload(async () => {
this.on('fs' as any, 'workingDirChanged', async (path: string) => {
this.workingDir = path
})
try {
const result = await execAsync('node --version')
this.nodeVersion = result.stdout
this.call('terminal' as any, 'log', `Node version: ${this.nodeVersion}`)
return result.stdout
} catch (error) {
this.call('terminal' as any, 'log', `Node not found`)
}
try {
const result = await execAsync('yarn --version')
console.log('result', result)
this.yarnVersion = result.stdout
this.call('terminal' as any, 'log', `Yarn version: ${this.yarnVersion}`)
return result.stdout
} catch (error) {
this.call('terminal' as any, 'log', `Yarn not found`)
}
})
}
async execute(content: string, dir: string): Promise<void> {
async yarnAdd(module: string, version: string = ''): Promise<void> {
const child = utilityProcess
.fork(path.join(__dirname, '/../tools/yarn/bin/', 'yarn.js'), [`--cwd=${this.workingDir}`, 'add', `${module}@${version}`], {
stdio: 'pipe',
})
.addListener('exit', () => {
console.log('exit')
})
child &&
child.stdout &&
child.stdout.on('data', (data) => {
this.call('terminal' as any, 'log', data.toString())
})
child &&
child.stdout &&
child.stdout.on('close', (data) => {
this.call('terminal' as any, 'log', 'close')
})
child &&
child.on('spawn', () => {
this.call('terminal' as any, 'log', 'yarn start')
})
child &&
child.on('exit', (data) => {
this.call('terminal' as any, 'log', 'yarn install done')
})
}
async yarnInit(): Promise<void> {
const child = utilityProcess
.fork(path.join(__dirname, '/../tools/yarn/bin/', 'yarn.js'), [`--cwd=${this.workingDir}`], {
stdio: 'pipe',
})
.addListener('exit', () => {
console.log('exit')
})
child &&
child.stdout &&
child.stdout.on('data', (data) => {
this.call('terminal' as any, 'log', data.toString())
})
child &&
child.stdout &&
child.stdout.on('close', (data) => {
this.call('terminal' as any, 'log', 'close')
})
child &&
child.on('spawn', () => {
this.call('terminal' as any, 'log', 'yarn start')
})
child &&
child.on('exit', (data) => {
this.call('terminal' as any, 'log', 'yarn install done')
})
}
async execute(content: string, dir: string): Promise<void> {
this.call('terminal' as any, 'log', this.workingDir)
const child = utilityProcess.fork(path.join(__dirname,'/../tools/yarn/bin/', 'yarn.js'), [`--cwd=${this.workingDir}`], {
stdio: 'pipe',
})
child && child.stdout && child.stdout.on('data', (data) => {
this.call('terminal' as any, 'log', data.toString())
})
child && child.stdout && child.stdout.on('end', (data) => {
this.call('terminal' as any, 'log', 'end')
})
dir = await convertPathToPosix(this.fixPath(dir))
dir = convertPathToPosix(this.fixPath(dir))
console.log('execute', path)
const out = convertPathToPosix(this.fixPath('dist'))
const build = await esbuild.build({
entryPoints: [dir],
bundle: true,
outdir: out,
plugins: [],
})
if(build.errors.length > 0) {
console.log('ERRORS', build.errors)
return
try {
const build = await esbuild.build({
entryPoints: [dir],
bundle: true,
outdir: out,
plugins: [],
})
console.log('build', build)
if (build.errors.length > 0) {
console.log('ERRORS', build.errors)
return
}
console.log(path.join(out, 'test.js'))
const child2 = utilityProcess.fork(path.join(out, 'test.js'), [], {
stdio: 'pipe',
})
child2 &&
child2.stdout &&
child2.stdout.on('data', (data) => {
this.call('terminal' as any, 'log', data.toString())
})
} catch (e: any) {
// find all errors in string with 'Could not resolve'
const errors = e.toString().match(/Could not resolve "([^"]*)"/g)
if (errors) {
for (const error of errors) {
const match = error.match(/Could not resolve "([^"]*)"/)
if (match) {
const module = match[1]
const modulePath = path.join(this.workingDir, 'node_modules', module)
try {
await fs.stat(modulePath)
} catch (e) {
console.log('modulePath', modulePath)
this.emit('missingModule', module)
this.call('terminal' as any, 'log', {
type: 'error',
value: `Missing module ${module}`,
})
}
}
}
}
console.log('ERROR', e)
}
console.log(path.join(out,'test.js'))
const child2 = utilityProcess.fork(path.join(out,'test.js'), [], {
stdio: 'pipe'
})
child2 && child2.stdout && child2.stdout.on('data', (data) => {
this.call('terminal' as any, 'log', data.toString())
})
}
fixPath(path: string): string {
@ -90,16 +185,25 @@ class ScriptRunnerClient extends ElectronBasePluginClient {
}
}
let onEndPlugin = {
name: 'onEnd',
setup(build: esbuild.PluginBuild) {
build.onEnd((result) => {
console.log(`build ended with ${result.errors.length} errors`)
})
},
}
const onResolvePlugin = {
name: 'onResolve',
setup(build: esbuild.PluginBuild) {
build.onLoad({
filter: /.*/,
}, async args => {
console.log('onLoad', args)
/*if(args.namespace && args.namespace !== 'file'){
build.onLoad(
{
filter: /.*/,
},
async (args) => {
console.log('onLoad', args)
/*if(args.namespace && args.namespace !== 'file'){
const imported = await resolver.resolve(args.path)
console.log('imported', imported)
return {
@ -107,16 +211,15 @@ const onResolvePlugin = {
loader: 'js',
}
}*/
return undefined
})
}
return undefined
}
)
},
}
import { URL } from "url"
import axios from "axios"
import { app, utilityProcess } from "electron"
import {URL} from 'url'
import axios from 'axios'
import {app, utilityProcess} from 'electron'
let httpPlugin = {
name: 'http',
@ -125,7 +228,7 @@ let httpPlugin = {
// esbuild doesn't attempt to map them to a file system location.
// Tag them with the "http-url" namespace to associate them with
// this plugin.
build.onResolve({ filter: /^https?:\/\// }, args => ({
build.onResolve({filter: /^https?:\/\//}, (args) => ({
path: args.path,
namespace: 'http-url',
}))
@ -135,7 +238,7 @@ let httpPlugin = {
// files will be in the "http-url" namespace. Make sure to keep
// the newly resolved URL in the "http-url" namespace so imports
// inside it will also be resolved as URLs recursively.
build.onResolve({ filter: /.*/, namespace: 'http-url' }, args => ({
build.onResolve({filter: /.*/, namespace: 'http-url'}, (args) => ({
path: new URL(args.path, args.importer).toString(),
namespace: 'http-url',
}))
@ -144,11 +247,11 @@ let httpPlugin = {
// from the internet. This has just enough logic to be able to
// handle the example import from unpkg.com but in reality this
// would probably need to be more complex.
build.onLoad({ filter: /.*/, namespace: 'http-url' }, async (args) => {
build.onLoad({filter: /.*/, namespace: 'http-url'}, async (args) => {
// Download the file
const response = await axios.get(args.path, { responseType: 'arraybuffer' })
const response = await axios.get(args.path, {responseType: 'arraybuffer'})
//console.log('response', response.data.toString())
return { contents: response.data.toString(), loader: 'js' }
return {contents: response.data.toString(), loader: 'js'}
})
},
}
Loading…
Cancel
Save