Merge pull request #58 from bcmi-labs/use-sketch-as-ws

Use sketch folder as workspace
This commit is contained in:
Jan Bicker 2019-09-03 16:32:08 +02:00 committed by GitHub
commit 206b65f138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 418 additions and 181 deletions

3
.gitignore vendored
View File

@ -6,7 +6,8 @@ build/
downloads/ downloads/
!electron/build/ !electron/build/
src-gen/ src-gen/
arduino-ide-*/webpack.config.js browser-app/webpack.config.js
electron-app/webpack.config.js
.DS_Store .DS_Store
/workspace/static /workspace/static
# switching from `electron` to `browser` in dev mode. # switching from `electron` to `browser` in dev mode.

View File

@ -8,7 +8,7 @@ ports:
tasks: tasks:
- init: > - init: >
yarn && yarn &&
yarn --cwd ./arduino-ide-browser start yarn --cwd ./browser-app start
github: github:
prebuilds: prebuilds:

6
.vscode/launch.json vendored
View File

@ -14,7 +14,7 @@
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"name": "Launch Backend", "name": "Launch Backend",
"program": "${workspaceRoot}/arduino-ide-browser/src-gen/backend/main.js", "program": "${workspaceRoot}/browser-app/src-gen/backend/main.js",
"args": [ "args": [
"--hostname=0.0.0.0", "--hostname=0.0.0.0",
"--port=3000", "--port=3000",
@ -26,8 +26,8 @@
}, },
"sourceMaps": true, "sourceMaps": true,
"outFiles": [ "outFiles": [
"${workspaceRoot}/arduino-ide-browser/src-gen/backend/*.js", "${workspaceRoot}/browser-app/src-gen/backend/*.js",
"${workspaceRoot}/arduino-ide-browser/lib/**/*.js", "${workspaceRoot}/browser-app/lib/**/*.js",
"${workspaceRoot}/arduino-ide-extension/*/lib/**/*.js" "${workspaceRoot}/arduino-ide-extension/*/lib/**/*.js"
], ],
"smartStep": true, "smartStep": true,

16
.vscode/tasks.json vendored
View File

@ -4,9 +4,9 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "Arduino-PoC - Start Browser Example", "label": "Arduino Editor - Start Browser Example",
"type": "shell", "type": "shell",
"command": "yarn --cwd ./arduino-ide-browser start", "command": "yarn --cwd ./browser-app start",
"group": "build", "group": "build",
"presentation": { "presentation": {
"reveal": "always", "reveal": "always",
@ -15,7 +15,7 @@
} }
}, },
{ {
"label": "Arduino-PoC - Watch Theia Extension", "label": "Arduino Editor - Watch Theia Extension",
"type": "shell", "type": "shell",
"command": "yarn --cwd ./arduino-ide-extension watch", "command": "yarn --cwd ./arduino-ide-extension watch",
"group": "build", "group": "build",
@ -26,9 +26,9 @@
} }
}, },
{ {
"label": "Arduino-PoC - Watch Browser Example", "label": "Arduino Editor - Watch Browser Example",
"type": "shell", "type": "shell",
"command": "yarn --cwd ./arduino-ide-browser watch", "command": "yarn --cwd ./browser-app watch",
"group": "build", "group": "build",
"presentation": { "presentation": {
"reveal": "always", "reveal": "always",
@ -37,11 +37,11 @@
} }
}, },
{ {
"label": "Arduino-PoC - Watch All", "label": "Arduino Editor - Watch All",
"type": "shell", "type": "shell",
"dependsOn": [ "dependsOn": [
"Arduino-PoC - Watch Theia Extension", "Arduino Editor - Watch Theia Extension",
"Arduino-PoC - Watch Browser Example" "Arduino Editor - Watch Browser Example"
] ]
} }
] ]

View File

@ -17,7 +17,7 @@ git clone https://github.com/bcmi-labs/arduino-editor
cd arduino-editor cd arduino-editor
yarn yarn
yarn rebuild:electron yarn rebuild:electron
yarn --cwd arduino-ide-electron start yarn --cwd electron-app start
``` ```
If you want to switch back to the browser-based example, execute the following in the repository root If you want to switch back to the browser-based example, execute the following in the repository root
@ -26,7 +26,7 @@ yarn rebuild:browser
``` ```
Then you can start the browser example again: Then you can start the browser example again:
``` ```
yarn --cwd arduino-ide-browser start yarn --cwd browser-app start
``` ```
## Arduino-PoC Electron Application ## Arduino-PoC Electron Application

View File

@ -12,6 +12,7 @@
"@theia/core": "next", "@theia/core": "next",
"@theia/editor": "next", "@theia/editor": "next",
"@theia/filesystem": "next", "@theia/filesystem": "next",
"@theia/git": "next",
"@theia/languages": "next", "@theia/languages": "next",
"@theia/markers": "next", "@theia/markers": "next",
"@theia/monaco": "next", "@theia/monaco": "next",
@ -19,7 +20,6 @@
"@theia/workspace": "next", "@theia/workspace": "next",
"@theia/navigator": "next", "@theia/navigator": "next",
"@theia/terminal": "next", "@theia/terminal": "next",
"@theia/git": "next",
"@theia/search-in-workspace": "next", "@theia/search-in-workspace": "next",
"@types/ps-tree": "^1.1.0", "@types/ps-tree": "^1.1.0",
"@types/which": "^1.3.1", "@types/which": "^1.3.1",
@ -40,11 +40,12 @@
}, },
"devDependencies": { "devDependencies": {
"decompress": "^4.2.0", "decompress": "^4.2.0",
"decompress-tarbz2": "^4.1.1", "decompress-targz": "^4.1.1",
"decompress-unzip": "^4.0.1", "decompress-unzip": "^4.0.1",
"download": "^7.1.0", "download": "^7.1.0",
"grpc-tools": "^1.7.3", "grpc-tools": "^1.7.3",
"grpc_tools_node_protoc_ts": "^2.5.0", "grpc_tools_node_protoc_ts": "^2.5.0",
"moment": "^2.24.0",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",
"shelljs": "^0.8.3", "shelljs": "^0.8.3",

View File

@ -1,11 +1,16 @@
// @ts-check // @ts-check
// The links to the downloads as of today (11.08.) are the followings: // The links to the downloads as of today (02.09.) are the followings:
// - https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli-nightly-latest-${FILE_NAME} // In order to get the latest nightly build for your platform use the following links replacing <DATE> with the current date, using the format YYYYMMDD (i.e for 2019/Aug/06 use 20190806 )
// - https://downloads.arduino.cc/arduino-cli/arduino-cli-latest-${FILE_NAME} // Linux 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Linux_64bit.tar.gz
// Linux ARM 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Linux_ARM64.tar.gz
// Windows 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Windows_64bit.zip
// Mac OSX: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_macOS_64bit.tar.gz
// [...]
// redirecting to latest generated builds by replacing latest with the latest available build date, using the format YYYYMMDD (i.e for 2019/Aug/06 latest is replaced with 20190806
(async () => { (async () => {
const DEFAULT_VERSION = 'nightly'; const DEFAULT_VERSION = 'latest'; // require('moment')().format('YYYYMMDD');
const os = require('os'); const os = require('os');
const fs = require('fs'); const fs = require('fs');
@ -14,7 +19,7 @@
const download = require('download'); const download = require('download');
const decompress = require('decompress'); const decompress = require('decompress');
const unzip = require('decompress-unzip'); const unzip = require('decompress-unzip');
const untarbz = require('decompress-tarbz2'); const untargz = require('decompress-targz');
process.on('unhandledRejection', (reason, _) => { process.on('unhandledRejection', (reason, _) => {
shell.echo(String(reason)); shell.echo(String(reason));
@ -31,11 +36,7 @@
.option('cli-version', { .option('cli-version', {
alias: 'cv', alias: 'cv',
default: DEFAULT_VERSION, default: DEFAULT_VERSION,
choices: [ describe: `The version of the 'arduino-cli' to download with the YYYYMMDD format, or 'latest'. Defaults to ${DEFAULT_VERSION}.`
// 'latest', // TODO: How do we get the source for `latest`. Currently, `latest` is the `0.3.7-alpha.preview`.
'nightly'
],
describe: `The version of the 'arduino-cli' to download. Defaults to ${DEFAULT_VERSION}.`
}) })
.option('force-download', { .option('force-download', {
alias: 'fd', alias: 'fd',
@ -68,13 +69,12 @@
const suffix = (() => { const suffix = (() => {
switch (platform) { switch (platform) {
case 'darwin': return 'macosx.zip'; case 'darwin': return 'macOS_64bit.tar.gz';
case 'win32': return 'windows.zip'; case 'win32': return 'Windows_64bit.zip';
case 'linux': { case 'linux': {
switch (arch) { switch (arch) {
case 'arm64': return 'linuxarm.tar.bz2'; case 'arm64': return 'Linux_ARM64.tar.gz';
case 'x32': return 'linux32.tar.bz2'; case 'x64': return 'Linux_64bit.tar.gz';
case 'x64': return 'linux64.tar.bz2';
default: return undefined; default: return undefined;
} }
} }
@ -86,7 +86,7 @@
shell.exit(1); shell.exit(1);
} }
const url = `https://downloads.arduino.cc/arduino-cli/${version === 'nightly' ? 'nightly/' : ''}arduino-cli-${version}-latest-${suffix}`; const url = `https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-${version}_${suffix}`;
shell.echo(`>>> Downloading 'arduino-cli' from '${url}'...`); shell.echo(`>>> Downloading 'arduino-cli' from '${url}'...`);
const data = await download(url); const data = await download(url);
shell.echo(`<<< Download succeeded.`); shell.echo(`<<< Download succeeded.`);
@ -94,16 +94,21 @@
const files = await decompress(data, downloads, { const files = await decompress(data, downloads, {
plugins: [ plugins: [
unzip(), unzip(),
untarbz() untargz()
] ]
}); });
shell.echo('<<< Decompressing succeeded.'); if (files.length === 0) {
if (files.length !== 1) {
shell.echo('Error ocurred when decompressing the CLI.'); shell.echo('Error ocurred when decompressing the CLI.');
shell.exit(1); shell.exit(1);
} }
if (shell.mv('-f', path.join(downloads, files[0].path), cli).code !== 0) { const cliIndex = files.findIndex(f => f.path.startsWith('arduino-cli'));
if (cliIndex === -1) {
shell.echo('The downloaded artifact does not contains the CLI.');
shell.exit(1);
}
shell.echo('<<< Decompressing succeeded.');
if (shell.mv('-f', path.join(downloads, files[cliIndex].path), cli).code !== 0) {
shell.echo(`Could not move file to ${cli}.`); shell.echo(`Could not move file to ${cli}.`);
shell.exit(1); shell.exit(1);
} }

View File

@ -46,6 +46,7 @@ import { BoardsConfigDialog } from './boards/boards-config-dialog';
import { BoardsToolBarItem } from './boards/boards-toolbar-item'; import { BoardsToolBarItem } from './boards/boards-toolbar-item';
import { BoardsConfig } from './boards/boards-config'; import { BoardsConfig } from './boards/boards-config';
import { MonitorService } from '../common/protocol/monitor-service'; import { MonitorService } from '../common/protocol/monitor-service';
import { ConfigService } from '../common/protocol/config-service';
export namespace ArduinoMenus { export namespace ArduinoMenus {
export const SKETCH = [...MAIN_MENU_BAR, '3_sketch']; export const SKETCH = [...MAIN_MENU_BAR, '3_sketch'];
@ -133,21 +134,19 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
@inject(LabelProvider) @inject(LabelProvider)
protected readonly labelProvider: LabelProvider; protected readonly labelProvider: LabelProvider;
@inject(QuickOpenService) @inject(QuickOpenService)
protected readonly quickOpenService: QuickOpenService; protected readonly quickOpenService: QuickOpenService;
@inject(WorkspaceService)
protected readonly workspaceService: WorkspaceService;
@inject(ConfigService)
protected readonly configService: ConfigService;
protected boardsToolbarItem: BoardsToolBarItem | null; protected boardsToolbarItem: BoardsToolBarItem | null;
protected wsSketchCount: number = 0; protected wsSketchCount: number = 0;
constructor(@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService) {
this.workspaceService.onWorkspaceChanged(() => {
if (this.workspaceService.workspace) {
this.registerSketchesInMenu(this.menuRegistry);
}
})
}
@postConstruct() @postConstruct()
protected async init(): Promise<void> { protected async init(): Promise<void> {
// This is a hack. Otherwise, the backend services won't bind. // This is a hack. Otherwise, the backend services won't bind.
@ -161,6 +160,8 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
} }
this.boardsServiceClient.onBoardsConfigChanged(updateStatusBar); this.boardsServiceClient.onBoardsConfigChanged(updateStatusBar);
updateStatusBar(this.boardsServiceClient.boardsConfig); updateStatusBar(this.boardsServiceClient.boardsConfig);
this.registerSketchesInMenu(this.menuRegistry);
} }
registerToolbarItems(registry: TabBarToolbarRegistry): void { registerToolbarItems(registry: TabBarToolbarRegistry): void {
@ -453,7 +454,13 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
} }
protected async getWorkspaceSketches(): Promise<Sketch[]> { protected async getWorkspaceSketches(): Promise<Sketch[]> {
const sketches = this.sketches.getSketches(this.workspaceService.workspace);
let sketches: Sketch[] = [];
const config = await this.configService.getConfiguration();
const stat = await this.fileSystem.getFileStat(config.sketchDirUri);
if (!!stat) {
sketches = await this.sketches.getSketches(stat);
}
return sketches; return sketches;
} }
@ -461,13 +468,18 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
const url = new URL(window.location.href); const url = new URL(window.location.href);
const currentSketch = url.searchParams.get('sketch'); const currentSketch = url.searchParams.get('sketch');
// Nothing to do if we want to open the same sketch which is already opened. // Nothing to do if we want to open the same sketch which is already opened.
if (!!currentSketch && new URI(currentSketch).toString() === new URI(uri).toString()) { const sketchUri = new URI(uri);
this.messageService.info(`The '${this.labelProvider.getLongName(new URI(uri))}' is already opened.`); if (!!currentSketch && new URI(currentSketch).toString() === sketchUri.toString()) {
this.messageService.info(`The '${this.labelProvider.getLongName(sketchUri)}' is already opened.`);
// NOOP. // NOOP.
return; return;
} }
// Preserve the current window if the `sketch` is not in the `searchParams`. // Preserve the current window if the `sketch` is not in the `searchParams`.
url.searchParams.set('sketch', uri); url.searchParams.set('sketch', uri);
const hash = await this.fileSystem.getFsPath(sketchUri.toString());
if (hash) {
url.hash = hash;
}
if (!currentSketch) { if (!currentSketch) {
setTimeout(() => window.location.href = url.toString(), 100); setTimeout(() => window.location.href = url.toString(), 100);
return; return;
@ -543,25 +555,6 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
return undefined; return undefined;
} }
// private async onNoBoardsInstalled() {
// const action = await this.messageService.info("You have no boards installed. Use the boards manager to install one.", "Open Boards Manager");
// if (!action) {
// return;
// }
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
// }
// private async onUnknownBoard() {
// const action = await this.messageService.warn("There's a board connected for which you need to install software." +
// " If this were not a PoC we would offer you the right package now.", "Open Boards Manager");
// if (!action) {
// return;
// }
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
// }
private isArduinoToolbar(maybeToolbarWidget: any): boolean { private isArduinoToolbar(maybeToolbarWidget: any): boolean {
if (maybeToolbarWidget instanceof ArduinoToolbar) { if (maybeToolbarWidget instanceof ArduinoToolbar) {
return true; return true;

View File

@ -56,6 +56,7 @@ import { LibraryItemRenderer } from './library/library-item-renderer';
import { BoardItemRenderer } from './boards/boards-item-renderer'; import { BoardItemRenderer } from './boards/boards-item-renderer';
import { MonitorServiceClientImpl } from './monitor/monitor-service-client-impl'; import { MonitorServiceClientImpl } from './monitor/monitor-service-client-impl';
import { MonitorServicePath, MonitorService, MonitorServiceClient } from '../common/protocol/monitor-service'; import { MonitorServicePath, MonitorService, MonitorServiceClient } from '../common/protocol/monitor-service';
import { ConfigService, ConfigServicePath } from '../common/protocol/config-service';
const ElementQueries = require('css-element-queries/src/ElementQueries'); const ElementQueries = require('css-element-queries/src/ElementQueries');
if (!ARDUINO_PRO_MODE) { if (!ARDUINO_PRO_MODE) {
@ -96,6 +97,9 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
// Sketch list service // Sketch list service
bind(SketchesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, SketchesServicePath)).inSingletonScope(); bind(SketchesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, SketchesServicePath)).inSingletonScope();
// Config service
bind(ConfigService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ConfigServicePath)).inSingletonScope();
// Boards service // Boards service
bind(BoardsService).toDynamicValue(context => { bind(BoardsService).toDynamicValue(context => {
const connection = context.container.get(WebSocketConnectionProvider); const connection = context.container.get(WebSocketConnectionProvider);

View File

@ -4,6 +4,7 @@ import { WorkspaceServer } from "@theia/workspace/lib/common";
import { FileSystem, FileStat } from "@theia/filesystem/lib/common"; import { FileSystem, FileStat } from "@theia/filesystem/lib/common";
import URI from "@theia/core/lib/common/uri"; import URI from "@theia/core/lib/common/uri";
import { SketchFactory } from "./sketch-factory"; import { SketchFactory } from "./sketch-factory";
import { ConfigService } from "../common/protocol/config-service";
/** /**
* This is workaround to have custom frontend binding for the default workspace, although we * This is workaround to have custom frontend binding for the default workspace, although we
@ -21,16 +22,14 @@ export class AWorkspaceService extends WorkspaceService {
@inject(SketchFactory) @inject(SketchFactory)
protected readonly sketchFactory: SketchFactory; protected readonly sketchFactory: SketchFactory;
@inject(ConfigService)
protected readonly configService: ConfigService;
protected async getDefaultWorkspacePath(): Promise<string | undefined> { protected async getDefaultWorkspacePath(): Promise<string | undefined> {
let result = await super.getDefaultWorkspacePath(); let result = await super.getDefaultWorkspacePath();
if (!result) { if (!result) {
const userHome = await this.fileSystem.getCurrentUserHome(); const config = await this.configService.getConfiguration();
if (!userHome) { result = config.sketchDirUri;
return;
}
// The backend has created this location if it was missing.
result = new URI(userHome.uri).resolve('Arduino-PoC').resolve('Sketches').toString();
} }
const stat = await this.fileSystem.getFileStat(result); const stat = await this.fileSystem.getFileStat(result);

View File

@ -38,7 +38,8 @@ export class SketchFactory {
const sketchDir = parent.resolve(sketchName); const sketchDir = parent.resolve(sketchName);
const sketchFile = sketchDir.resolve(`${sketchName}.ino`); const sketchFile = sketchDir.resolve(`${sketchName}.ino`);
this.fileSystem.createFolder(sketchDir.toString()); this.fileSystem.createFolder(sketchDir.toString());
this.fileSystem.createFile(sketchFile.toString(), { content: ` this.fileSystem.createFile(sketchFile.toString(), {
content: `
void setup() { void setup() {
// put your setup code here, to run once: // put your setup code here, to run once:
@ -50,7 +51,11 @@ void loop() {
} }
` }); ` });
const location = new URL(window.location.href); const location = new URL(window.location.href);
location.searchParams.set('sketch', sketchFile.toString()); location.searchParams.set('sketch', sketchDir.toString());
const hash = await this.fileSystem.getFsPath(sketchDir.toString());
if (hash) {
location.hash = hash;
}
this.windowService.openNewWindow(location.toString()); this.windowService.openNewWindow(location.toString());
} catch (e) { } catch (e) {
throw new Error("Cannot create new sketch: " + e); throw new Error("Cannot create new sketch: " + e);

View File

@ -0,0 +1,11 @@
export const ConfigServicePath = '/services/config-service';
export const ConfigService = Symbol('ConfigService');
export interface ConfigService {
getConfiguration(): Promise<Config>;
}
export interface Config {
sketchDirUri: string;
dataDirUri: string;
}

View File

@ -19,11 +19,24 @@ import { DefaultWorkspaceServerExt } from './default-workspace-server-ext';
import { WorkspaceServer } from '@theia/workspace/lib/common'; import { WorkspaceServer } from '@theia/workspace/lib/common';
import { SketchesServiceImpl } from './sketches-service-impl'; import { SketchesServiceImpl } from './sketches-service-impl';
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service'; import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
import { ConfigService, ConfigServicePath } from '../common/protocol/config-service';
import { MonitorServiceImpl } from './monitor/monitor-service-impl'; import { MonitorServiceImpl } from './monitor/monitor-service-impl';
import { MonitorService, MonitorServicePath, MonitorServiceClient } from '../common/protocol/monitor-service'; import { MonitorService, MonitorServicePath, MonitorServiceClient } from '../common/protocol/monitor-service';
import { MonitorClientProvider } from './monitor/monitor-client-provider'; import { MonitorClientProvider } from './monitor/monitor-client-provider';
import { ArduinoCli } from './arduino-cli';
import { ArduinoCliContribution } from './arduino-cli-contribution';
import { CliContribution } from '@theia/core/lib/node';
import { ConfigServiceImpl } from './config-service-impl';
export default new ContainerModule((bind, unbind, isBound, rebind) => { export default new ContainerModule((bind, unbind, isBound, rebind) => {
// Theia backend CLI contribution.
bind(ArduinoCliContribution).toSelf().inSingletonScope();
bind(CliContribution).toService(ArduinoCliContribution);
// Provides the path of the Ardunio CLI.
bind(ArduinoCli).toSelf().inSingletonScope();
// Shared daemonn
bind(ArduinoDaemon).toSelf().inSingletonScope(); bind(ArduinoDaemon).toSelf().inSingletonScope();
bind(BackendApplicationContribution).toService(ArduinoDaemon); bind(BackendApplicationContribution).toService(ArduinoDaemon);
@ -42,6 +55,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bindBackendService(SketchesServicePath, SketchesService); bindBackendService(SketchesServicePath, SketchesService);
}); });
bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule); bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule);
bind(ConfigServiceImpl).toSelf().inSingletonScope();
bind(ConfigService).toService(ConfigServiceImpl);
// Config service
const configServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
bindBackendService(ConfigServicePath, ConfigService);
});
bind(ConnectionContainerModule).toConstantValue(configServiceConnectionModule);
// Boards service // Boards service
const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => { const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {

View File

@ -0,0 +1,27 @@
import { injectable } from 'inversify';
import { Argv, Arguments } from 'yargs';
import { CliContribution } from '@theia/core/lib/node';
@injectable()
export class ArduinoCliContribution implements CliContribution {
protected _debugCli = false
configure(conf: Argv): void {
conf.option('debug-cli', {
description: 'Can be specified if the CLI daemon process was started externally.',
type: 'boolean',
default: false,
nargs: 1
});
}
setArguments(args: Arguments): void {
this._debugCli = args['debug-cli'];
}
get debugCli(): boolean {
return this._debugCli;
}
}

View File

@ -0,0 +1,66 @@
import * as os from 'os';
import * as which from 'which';
import * as cp from 'child_process';
import { join, delimiter } from 'path';
import { injectable, inject } from 'inversify';
import { ILogger } from '@theia/core';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { Config } from '../common/protocol/config-service';
@injectable()
export class ArduinoCli {
@inject(ILogger)
protected logger: ILogger;
async getExecPath(): Promise<string> {
const build = join(__dirname, '..', '..', 'build');
return new Promise<string>((resolve, reject) => {
which(`arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`, { path: `${process.env.PATH}${delimiter}${build}` }, (err, path) => {
if (err) {
reject(err);
return;
}
resolve(path);
});
});
}
async getDefaultConfig(): Promise<Config> {
const command = await this.getExecPath();
return new Promise<Config>((resolve, reject) => {
cp.execFile(
command,
['config', 'dump', '--format', 'json'],
{ encoding: 'utf8' },
(error, stdout, stderr) => {
if (error) {
throw error;
}
if (stderr) {
throw new Error(stderr);
}
const { sketchbook_path, arduino_data } = JSON.parse(stdout.trim());
if (!sketchbook_path) {
reject(new Error(`Could not parse config. 'sketchbook_path' was missing from: ${stdout}`));
return;
}
if (!arduino_data) {
reject(new Error(`Could not parse config. 'arduino_data' was missing from: ${stdout}`));
return;
}
resolve({
sketchDirUri: FileUri.create(sketchbook_path).toString(),
dataDirUri: FileUri.create(arduino_data).toString()
});
});
});
}
}

View File

@ -1,6 +1,4 @@
import * as which from 'which'; import { join } from 'path';
import * as os from 'os';
import { join, delimiter } from 'path';
import { exec, spawn, SpawnOptions } from 'child_process'; import { exec, spawn, SpawnOptions } from 'child_process';
import { inject, injectable, named } from 'inversify'; import { inject, injectable, named } from 'inversify';
import { ILogger } from '@theia/core/lib/common/logger'; import { ILogger } from '@theia/core/lib/common/logger';
@ -9,17 +7,22 @@ import { Deferred } from '@theia/core/lib/common/promise-util';
import { environment } from '@theia/application-package/lib/environment'; import { environment } from '@theia/application-package/lib/environment';
import { DaemonLog } from './daemon-log'; import { DaemonLog } from './daemon-log';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { ArduinoCliContribution } from './arduino-cli-contribution';
import { ArduinoCli } from './arduino-cli';
@injectable() @injectable()
export class ArduinoDaemon implements BackendApplicationContribution { export class ArduinoDaemon implements BackendApplicationContribution {
// Set this to `true` if you want to connect to a CLI running in debug mode.
static DEBUG_CLI = false;
@inject(ILogger) @inject(ILogger)
@named('daemon') @named('daemon')
protected readonly logger: ILogger protected readonly logger: ILogger
@inject(ArduinoCli)
protected readonly cli: ArduinoCli;
@inject(ArduinoCliContribution)
protected readonly cliContribution: ArduinoCliContribution;
@inject(ToolOutputServiceServer) @inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer; protected readonly toolOutputService: ToolOutputServiceServer;
@ -27,19 +30,10 @@ export class ArduinoDaemon implements BackendApplicationContribution {
async onStart() { async onStart() {
try { try {
if (!ArduinoDaemon.DEBUG_CLI) { if (!this.cliContribution.debugCli) {
const build = join(__dirname, '..', '..', 'build'); const executable = await this.cli.getExecPath();
const executable = await new Promise<string>((resolve, reject) => {
which(`arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`, { path: `${process.env.PATH}${delimiter}${build}` }, (err, path) => {
if (err) {
reject(err);
return;
}
resolve(path);
});
});
this.logger.info(`>>> Starting 'arduino-cli' daemon... [${executable}]`); this.logger.info(`>>> Starting 'arduino-cli' daemon... [${executable}]`);
const daemon = exec(`${executable} --debug daemon`, (err, stdout, stderr) => { const daemon = exec(`${executable} daemon -v --log-level info --format json --log-format json`, (err, stdout, stderr) => {
if (err || stderr) { if (err || stderr) {
console.log(err || new Error(stderr)); console.log(err || new Error(stderr));
return; return;
@ -74,7 +68,7 @@ export class ArduinoDaemon implements BackendApplicationContribution {
await new Promise(resolve => setTimeout(resolve, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
this.isReady.resolve(); this.isReady.resolve();
if (!ArduinoDaemon.DEBUG_CLI) { if (!this.cliContribution.debugCli) {
this.logger.info(`<<< The 'arduino-cli' daemon is up an running.`); this.logger.info(`<<< The 'arduino-cli' daemon is up an running.`);
} else { } else {
this.logger.info(`Assuming the 'arduino-cli' already runs in debug mode.`); this.logger.info(`Assuming the 'arduino-cli' already runs in debug mode.`);

View File

@ -51,6 +51,9 @@ export class CompileReq extends jspb.Message {
getExportfile(): string; getExportfile(): string;
setExportfile(value: string): void; setExportfile(value: string): void;
getJobs(): number;
setJobs(value: number): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CompileReq.AsObject; toObject(includeInstance?: boolean): CompileReq.AsObject;
@ -77,6 +80,7 @@ export namespace CompileReq {
quiet: boolean, quiet: boolean,
vidpid: string, vidpid: string,
exportfile: string, exportfile: string,
jobs: number,
} }
} }

View File

@ -81,7 +81,8 @@ proto.cc.arduino.cli.commands.CompileReq.toObject = function(includeInstance, ms
verbose: jspb.Message.getFieldWithDefault(msg, 10, false), verbose: jspb.Message.getFieldWithDefault(msg, 10, false),
quiet: jspb.Message.getFieldWithDefault(msg, 11, false), quiet: jspb.Message.getFieldWithDefault(msg, 11, false),
vidpid: jspb.Message.getFieldWithDefault(msg, 12, ""), vidpid: jspb.Message.getFieldWithDefault(msg, 12, ""),
exportfile: jspb.Message.getFieldWithDefault(msg, 13, "") exportfile: jspb.Message.getFieldWithDefault(msg, 13, ""),
jobs: jspb.Message.getFieldWithDefault(msg, 14, 0)
}; };
if (includeInstance) { if (includeInstance) {
@ -171,6 +172,10 @@ proto.cc.arduino.cli.commands.CompileReq.deserializeBinaryFromReader = function(
var value = /** @type {string} */ (reader.readString()); var value = /** @type {string} */ (reader.readString());
msg.setExportfile(value); msg.setExportfile(value);
break; break;
case 14:
var value = /** @type {number} */ (reader.readInt32());
msg.setJobs(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@ -292,6 +297,13 @@ proto.cc.arduino.cli.commands.CompileReq.serializeBinaryToWriter = function(mess
f f
); );
} }
f = message.getJobs();
if (f !== 0) {
writer.writeInt32(
14,
f
);
}
}; };
@ -527,6 +539,21 @@ proto.cc.arduino.cli.commands.CompileReq.prototype.setExportfile = function(valu
}; };
/**
* optional int32 jobs = 14;
* @return {number}
*/
proto.cc.arduino.cli.commands.CompileReq.prototype.getJobs = function() {
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 14, 0));
};
/** @param {number} value */
proto.cc.arduino.cli.commands.CompileReq.prototype.setJobs = function(value) {
jspb.Message.setProto3IntField(this, 14, value);
};
/** /**
* Generated by JsPbCodeGenerator. * Generated by JsPbCodeGenerator.

View File

@ -0,0 +1,14 @@
import { injectable, inject } from "inversify";
import { ConfigService, Config } from "../common/protocol/config-service";
import { ArduinoCli } from "./arduino-cli";
@injectable()
export class ConfigServiceImpl implements ConfigService {
@inject(ArduinoCli)
protected readonly cli: ArduinoCli;
async getConfiguration(): Promise<Config> {
return this.cli.getDefaultConfig();
}
}

View File

@ -1,5 +1,12 @@
import { inject, injectable } from 'inversify'; import * as fs from 'fs';
import * as path from 'path';
import * as grpc from '@grpc/grpc-js'; import * as grpc from '@grpc/grpc-js';
import * as PQueue from 'p-queue';
import { inject, injectable } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { FileSystem } from '@theia/filesystem/lib/common';
import { WorkspaceServiceExt } from '../browser/workspace-service-ext';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { ArduinoCoreClient } from './cli-protocol/commands/commands_grpc_pb'; import { ArduinoCoreClient } from './cli-protocol/commands/commands_grpc_pb';
import { import {
InitResp, InitResp,
@ -10,16 +17,10 @@ import {
UpdateLibrariesIndexReq, UpdateLibrariesIndexReq,
UpdateLibrariesIndexResp UpdateLibrariesIndexResp
} from './cli-protocol/commands/commands_pb'; } from './cli-protocol/commands/commands_pb';
import { WorkspaceServiceExt } from '../browser/workspace-service-ext'; import { ArduinoCli } from './arduino-cli';
import { FileSystem } from '@theia/filesystem/lib/common';
import URI from '@theia/core/lib/common/uri';
import { CoreClientProvider, Client } from './core-client-provider';
import * as PQueue from 'p-queue';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { Instance } from './cli-protocol/commands/common_pb'; import { Instance } from './cli-protocol/commands/common_pb';
import * as fs from 'fs-extra'; import { CoreClientProvider, Client } from './core-client-provider';
import * as path from 'path'; import { FileUri } from '@theia/core/lib/node';
import * as os from 'os';
@injectable() @injectable()
export class CoreClientProviderImpl implements CoreClientProvider { export class CoreClientProviderImpl implements CoreClientProvider {
@ -36,6 +37,9 @@ export class CoreClientProviderImpl implements CoreClientProvider {
@inject(ToolOutputServiceServer) @inject(ToolOutputServiceServer)
protected readonly toolOutputService: ToolOutputServiceServer; protected readonly toolOutputService: ToolOutputServiceServer;
@inject(ArduinoCli)
protected readonly cli: ArduinoCli;
async getClient(workspaceRootOrResourceUri?: string): Promise<Client | undefined> { async getClient(workspaceRootOrResourceUri?: string): Promise<Client | undefined> {
return this.clientRequestQueue.add(() => new Promise<Client | undefined>(async resolve => { return this.clientRequestQueue.add(() => new Promise<Client | undefined>(async resolve => {
const roots = await this.workspaceServiceExt.roots(); const roots = await this.workspaceServiceExt.roots();
@ -76,19 +80,26 @@ export class CoreClientProviderImpl implements CoreClientProvider {
throw new Error(`Could not resolve filesystem path of URI: ${rootUri}.`); throw new Error(`Could not resolve filesystem path of URI: ${rootUri}.`);
} }
const defaultDownloadsDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'downloads'); const { dataDirUri, sketchDirUri } = await this.cli.getDefaultConfig();
if (!fs.existsSync(defaultDownloadsDirPath)) { const dataDirPath = FileUri.fsPath(dataDirUri);
fs.mkdirpSync(defaultDownloadsDirPath); const sketchDirPath = FileUri.fsPath(sketchDirUri);
if (!fs.existsSync(dataDirPath)) {
fs.mkdirSync(dataDirPath);
} }
const defaultDataDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'data') if (!fs.existsSync(sketchDirPath)) {
if (!fs.existsSync(defaultDataDirPath)) { fs.mkdirSync(sketchDirPath);
fs.mkdirpSync(defaultDataDirPath);
} }
config.setSketchbookdir(rootPath); const downloadDir = path.join(dataDirPath, 'staging');
config.setDatadir(defaultDataDirPath); if (!fs.existsSync(downloadDir)) {
config.setDownloadsdir(defaultDownloadsDirPath); fs.mkdirSync(downloadDir);
}
config.setSketchbookdir(sketchDirPath);
config.setDatadir(dataDirPath);
config.setDownloadsdir(downloadDir);
config.setBoardmanageradditionalurlsList(['https://downloads.arduino.cc/packages/package_index.json']); config.setBoardmanageradditionalurlsList(['https://downloads.arduino.cc/packages/package_index.json']);
const initReq = new InitReq(); const initReq = new InitReq();

View File

@ -8,7 +8,58 @@ export interface DaemonLog {
export namespace DaemonLog { export namespace DaemonLog {
export type Level = 'info' | 'debug' | 'warning' | 'error'; export interface Url {
readonly Scheme: string;
readonly Host: string;
readonly Path: string;
}
export namespace Url {
export function is(arg: any | undefined): arg is Url {
return !!arg
&& typeof arg.Scheme === 'string'
&& typeof arg.Host === 'string'
&& typeof arg.Path === 'string';
}
export function toString(url: Url): string {
const { Scheme, Host, Path } = url;
return `${Scheme}://${Host}${Path}`;
}
}
export interface System {
readonly os: string;
// readonly Resource: Resource;
}
export namespace System {
export function toString(system: System): string {
return `OS: ${system.os}`
}
}
export interface Tool {
readonly version: string;
readonly systems: System[];
}
export namespace Tool {
export function is(arg: any | undefined): arg is Tool {
return !!arg && typeof arg.version === 'string' && 'systems' in arg;
}
export function toString(tool: Tool): string {
const { version, systems } = tool;
return `Version: ${version}${!!systems ? ` Systems: [${tool.systems.map(System.toString).join(', ')}]` : ''}`;
}
}
export type Level = 'trace' | 'debug' | 'info' | 'warning' | 'error';
export function is(arg: any | undefined): arg is DaemonLog { export function is(arg: any | undefined): arg is DaemonLog {
return !!arg return !!arg
@ -20,61 +71,62 @@ export namespace DaemonLog {
export function toLogLevel(log: DaemonLog): LogLevel { export function toLogLevel(log: DaemonLog): LogLevel {
const { level } = log; const { level } = log;
switch (level) { switch (level) {
case 'info': return LogLevel.INFO; case 'trace': return LogLevel.TRACE;
case 'debug': return LogLevel.DEBUG; case 'debug': return LogLevel.DEBUG;
case 'error': return LogLevel.ERROR; case 'info': return LogLevel.INFO;
case 'warning': return LogLevel.WARN; case 'warning': return LogLevel.WARN;
case 'error': return LogLevel.ERROR;
default: return LogLevel.INFO; default: return LogLevel.INFO;
} }
} }
export function log(logger: ILogger, toLog: string): void { export function log(logger: ILogger, logMessages: string): void {
const segments = toLog.split('time').filter(s => s.trim().length > 0); const parsed = parse(logMessages);
for (const segment of segments) { for (const log of parsed) {
const maybeDaemonLog = parse(`time${segment}`.trim()); logger.log(toLogLevel(log), toMessage(log));
for (const logMsg of maybeDaemonLog) {
logger.log(toLogLevel(logMsg), logMsg.msg);
}
} }
} }
// Super naive.
function parse(toLog: string): DaemonLog[] { function parse(toLog: string): DaemonLog[] {
const messages = toLog.split('\ntime='); const messages = toLog.trim().split('\n');
const result: DaemonLog[] = []; const result: DaemonLog[] = [];
for (let i = 0; i < messages.length; i++) { for (let i = 0; i < messages.length; i++) {
const msg = (i > 0 ? 'time=' : '') + messages[i]; try {
const rawSegments = msg.split(/(\s+)/) const maybeDaemonLog = JSON.parse(messages[i]);
.map(segment => segment.replace(/['"]+/g, '')) if (DaemonLog.is(maybeDaemonLog)) {
.map(segment => segment.trim()) result.push(maybeDaemonLog);
.filter(segment => segment.length > 0); continue;
}
const timeIndex = rawSegments.findIndex(segment => segment.startsWith('time=')); } catch { /* NOOP */ }
const levelIndex = rawSegments.findIndex(segment => segment.startsWith('level='));
const msgIndex = rawSegments.findIndex(segment => segment.startsWith('msg='));
if (rawSegments.length > 2
&& timeIndex !== -1
&& levelIndex !== -1
&& msgIndex !== -1) {
result.push({
time: rawSegments[timeIndex].split('=')[1],
level: rawSegments[levelIndex].split('=')[1] as Level,
msg: [rawSegments[msgIndex].split('=')[1], ...rawSegments.slice(msgIndex + 1)].join(' ')
});
} else {
result.push({ result.push({
time: new Date().toString(), time: new Date().toString(),
level: 'info', level: 'info',
msg: msg msg: messages[i]
}); });
}
} }
// Otherwise, log the string as is.
return result; return result;
} }
export function toPrettyString(logMessage: string): string { export function toPrettyString(logMessages: string): string {
const parsed = parse(logMessage); const parsed = parse(logMessages);
return parsed.map(msg => `[${msg.level.toUpperCase() || 'INFO'}] ${msg.msg}\n`).join(''); return parsed.map(toMessage).join('\n');
} }
function toMessage(log: DaemonLog): string {
const details = Object.keys(log).filter(key => key !== 'msg' && key !== 'level' && key !== 'time').map(key => toDetails(log, key)).join(', ');
return `[${log.level.toUpperCase()}] ${log.msg}${!!details ? ` [${details}]` : ''}`
}
function toDetails(log: DaemonLog, key: string): string {
let value = (log as any)[key];
if (DaemonLog.Url.is(value)) {
value = DaemonLog.Url.toString(value);
} else if (DaemonLog.Tool.is(value)) {
value = DaemonLog.Tool.toString(value);
} else if (typeof value === 'object') {
value = JSON.stringify(value).replace(/\"([^(\")"]+)\":/g, '$1:'); // Remove the quotes from the property keys.
}
return `${key.toLowerCase()}: ${value}`;
}
} }

View File

@ -1,14 +1,15 @@
import * as os from 'os'; import { injectable, inject } from 'inversify';
import * as path from 'path';
import { injectable } from 'inversify';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { DefaultWorkspaceServer } from '@theia/workspace/lib/node/default-workspace-server'; import { DefaultWorkspaceServer } from '@theia/workspace/lib/node/default-workspace-server';
import { ConfigService } from '../common/protocol/config-service';
@injectable() @injectable()
export class DefaultWorkspaceServerExt extends DefaultWorkspaceServer { export class DefaultWorkspaceServerExt extends DefaultWorkspaceServer {
@inject(ConfigService) protected readonly configService: ConfigService;
protected async getWorkspaceURIFromCli(): Promise<string | undefined> { protected async getWorkspaceURIFromCli(): Promise<string | undefined> {
return FileUri.create(path.join(os.homedir(), 'Arduino-PoC', 'Sketches')).toString(); const config = await this.configService.getConfiguration();
return config.sketchDirUri;
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"private": true, "private": true,
"name": "arduino-ide-browser", "name": "browser-app",
"version": "0.0.1", "version": "0.0.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -30,7 +30,7 @@
"theia": { "theia": {
"frontend": { "frontend": {
"config": { "config": {
"applicationName": "Arduino-PoC", "applicationName": "Arduino Editor",
"defaultTheme": "arduino-theme", "defaultTheme": "arduino-theme",
"preferences": { "preferences": {
"editor.autoSave": "on" "editor.autoSave": "on"

View File

@ -1,6 +1,6 @@
{ {
"private": true, "private": true,
"name": "arduino-ide-electron", "name": "electron-app",
"version": "0.0.1", "version": "0.0.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -33,7 +33,7 @@
"target": "electron", "target": "electron",
"frontend": { "frontend": {
"config": { "config": {
"applicationName": "Arduino-PoC", "applicationName": "Arduino Editor",
"defaultTheme": "arduino-theme", "defaultTheme": "arduino-theme",
"preferences": { "preferences": {
"editor.autoSave": "on" "editor.autoSave": "on"

View File

@ -14,7 +14,7 @@
const workingCopy = 'working-copy'; const workingCopy = 'working-copy';
/** /**
* Relative path from the `__dirname` to the root where the `arduino-ide-extension` and the `arduino-ide-electron` folders are. * Relative path from the `__dirname` to the root where the `arduino-ide-extension` and the `electron-app` folders are.
* This could come handy when moving the location of the `electron/packager`. * This could come handy when moving the location of the `electron/packager`.
*/ */
const rootPath = join('..', '..'); const rootPath = join('..', '..');
@ -42,18 +42,18 @@
// Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. | // Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. |
//----------------------------------------------------------------------------------------------+ //----------------------------------------------------------------------------------------------+
mkdir('-p', path('..', workingCopy)); mkdir('-p', path('..', workingCopy));
for (const name of ['arduino-ide-extension', 'arduino-ide-electron', 'yarn.lock', 'package.json', 'lerna.json']) { for (const name of ['arduino-ide-extension', 'electron-app', 'yarn.lock', 'package.json', 'lerna.json']) {
cp('-rf', path(rootPath, name), path('..', workingCopy)); cp('-rf', path(rootPath, name), path('..', workingCopy));
} }
//-----------------------------------------------------+ //-----------------------------------------------------+
// No need to build the `arduino-ide-browser` example. | // No need to build the `browser-app` example. |
//-----------------------------------------------------+ //-----------------------------------------------------+
//@ts-ignore //@ts-ignore
let pkg = require('../working-copy/package.json'); let pkg = require('../working-copy/package.json');
const workspaces = pkg.workspaces; const workspaces = pkg.workspaces;
// We cannot remove the `arduino-ide-electron`. Otherwise, there is not way to collect the unused dependencies. // We cannot remove the `electron-app`. Otherwise, there is not way to collect the unused dependencies.
const dependenciesToRemove = ['arduino-ide-browser']; const dependenciesToRemove = ['browser-app'];
for (const dependencyToRemove of dependenciesToRemove) { for (const dependencyToRemove of dependenciesToRemove) {
const index = workspaces.indexOf(dependencyToRemove); const index = workspaces.indexOf(dependencyToRemove);
if (index !== -1) { if (index !== -1) {
@ -70,13 +70,13 @@
// Collect all unused dependencies by the backend. We have to remove them from the electron app. // Collect all unused dependencies by the backend. We have to remove them from the electron app.
// The `bundle.js` already contains everything we need for the frontend. // The `bundle.js` already contains everything we need for the frontend.
// We have to do it before changing the dependencies to `local-path`. // We have to do it before changing the dependencies to `local-path`.
const unusedDependencies = await utils.collectUnusedDependencies('../working-copy/arduino-ide-electron/'); const unusedDependencies = await utils.collectUnusedDependencies('../working-copy/electron-app/');
//------------------------------------------------------------------------------------+ //------------------------------------------------------------------------------------+
// Merge the `working-copy/package.json` with `electron/build/template-package.json`. | // Merge the `working-copy/package.json` with `electron/build/template-package.json`. |
//------------------------------------------------------------------------------------+ //------------------------------------------------------------------------------------+
// @ts-ignore // @ts-ignore
pkg = require('../working-copy/arduino-ide-electron/package.json'); pkg = require('../working-copy/electron-app/package.json');
// @ts-ignore // @ts-ignore
const template = require('../build/template-package.json'); const template = require('../build/template-package.json');
template.build.files = [ ...template.build.files, ...unusedDependencies.map(name => `!node_modules/${name}`) ]; template.build.files = [ ...template.build.files, ...unusedDependencies.map(name => `!node_modules/${name}`) ];

View File

@ -1,7 +1,7 @@
{ {
"name": "arduino-poc", "name": "arduino-editor",
"version": "0.0.1", "version": "0.0.1",
"description": "A PoC demonstrating an Arduino IDE built using Eclipse Theia", "description": "Arduino IDE built using Eclipse Theia",
"main": "index.js", "main": "index.js",
"repository": "https://github.com/bcmi-labs/arduino-editor.git", "repository": "https://github.com/bcmi-labs/arduino-editor.git",
"author": "Christian Weichel <christian.weichel@typefox.io>", "author": "Christian Weichel <christian.weichel@typefox.io>",
@ -14,12 +14,12 @@
"prepare": "lerna run prepare", "prepare": "lerna run prepare",
"rebuild:browser": "theia rebuild:browser", "rebuild:browser": "theia rebuild:browser",
"rebuild:electron": "theia rebuild:electron", "rebuild:electron": "theia rebuild:electron",
"start": "cd arduino-ide-browser && yarn start", "start": "yarn --cwd ./browser-app start",
"watch": "lerna run watch --parallel" "watch": "lerna run watch --parallel"
}, },
"workspaces": [ "workspaces": [
"arduino-ide-electron", "arduino-ide-extension",
"arduino-ide-browser", "electron-app",
"arduino-ide-extension" "browser-app"
] ]
} }

View File

@ -4473,7 +4473,7 @@ decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
is-stream "^1.1.0" is-stream "^1.1.0"
tar-stream "^1.5.2" tar-stream "^1.5.2"
decompress-tarbz2@^4.0.0, decompress-tarbz2@^4.1.1: decompress-tarbz2@^4.0.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b"
integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==
@ -4484,7 +4484,7 @@ decompress-tarbz2@^4.0.0, decompress-tarbz2@^4.1.1:
seek-bzip "^1.0.5" seek-bzip "^1.0.5"
unbzip2-stream "^1.0.9" unbzip2-stream "^1.0.9"
decompress-targz@^4.0.0: decompress-targz@^4.0.0, decompress-targz@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee"
integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==
@ -8098,7 +8098,7 @@ modify-values@^1.0.0:
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
moment@^2.10.6, moment@^2.18.1, moment@^2.21.0: moment@^2.10.6, moment@^2.18.1, moment@^2.21.0, moment@^2.24.0:
version "2.24.0" version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==