mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-12 07:06:32 +00:00
Initial support of the default paths from the CLI.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
59553bf81f
commit
f9641a3d76
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -4,7 +4,7 @@
|
|||||||
"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 ./arduino-ide-browser start",
|
||||||
"group": "build",
|
"group": "build",
|
||||||
@ -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,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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 ./arduino-ide-browser watch",
|
||||||
"group": "build",
|
"group": "build",
|
||||||
@ -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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -543,25 +543,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;
|
||||||
|
@ -22,8 +22,19 @@ import { SketchesService, SketchesServicePath } from '../common/protocol/sketche
|
|||||||
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';
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
27
arduino-ide-extension/src/node/arduino-cli-contribution.ts
Normal file
27
arduino-ide-extension/src/node/arduino-cli-contribution.ts
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
arduino-ide-extension/src/node/arduino-cli.ts
Normal file
79
arduino-ide-extension/src/node/arduino-cli.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import * as os from 'os';
|
||||||
|
import * as which from 'which';
|
||||||
|
import * as cp from 'child_process';
|
||||||
|
import { join, delimiter } from 'path';
|
||||||
|
import { injectable } from 'inversify';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class ArduinoCli {
|
||||||
|
|
||||||
|
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<ArduinoCli.Config> {
|
||||||
|
const command = await this.getExecPath();
|
||||||
|
return new Promise<ArduinoCli.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: sketchDirPath, arduino_data: dataDirPath } = JSON.parse(raw);
|
||||||
|
|
||||||
|
// https://github.com/arduino/arduino-cli/issues/342
|
||||||
|
// XXX: this is a hack. The CLI provides a non-valid JSON.
|
||||||
|
const config: Partial<ArduinoCli.Config> = {};
|
||||||
|
const raw = stdout.trim();
|
||||||
|
for (const line of raw.split(/\r?\n/) || []) {
|
||||||
|
// TODO: Named capture groups are avail from ES2018.
|
||||||
|
// const pair = line.match(/(?<key>[^:]+):(?<value>[^,]+),?/);
|
||||||
|
const pair = line.split(':').map(entry => entry.trim());
|
||||||
|
if (pair[0] === 'sketchbook_path') {
|
||||||
|
config.sketchDirPath = pair[1];
|
||||||
|
} else if (pair[0] === 'arduino_data') {
|
||||||
|
config.dataDirPath = pair[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.dataDirPath) {
|
||||||
|
reject(new Error(`Could not parse config. 'arduino_data' was missing from: ${stdout}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.sketchDirPath) {
|
||||||
|
reject(new Error(`Could not parse config. 'sketchbook_path' was missing from: ${stdout}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({ sketchDirPath: config.sketchDirPath, dataDirPath: config.dataDirPath });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ArduinoCli {
|
||||||
|
export interface Config {
|
||||||
|
sketchDirPath: string;
|
||||||
|
dataDirPath: string;
|
||||||
|
}
|
||||||
|
}
|
@ -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,17 +30,8 @@ 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} --debug daemon`, (err, stdout, stderr) => {
|
||||||
if (err || stderr) {
|
if (err || stderr) {
|
||||||
@ -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.`);
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { inject, injectable } from 'inversify';
|
import * as fs from 'fs';
|
||||||
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 +16,9 @@ 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 * as os from 'os';
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class CoreClientProviderImpl implements CoreClientProvider {
|
export class CoreClientProviderImpl implements CoreClientProvider {
|
||||||
@ -36,6 +35,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 +78,19 @@ 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 { dataDirPath, sketchDirPath } = await this.cli.getDefaultConfig();
|
||||||
if (!fs.existsSync(defaultDownloadsDirPath)) {
|
|
||||||
fs.mkdirpSync(defaultDownloadsDirPath);
|
if (!fs.existsSync(dataDirPath)) {
|
||||||
|
throw new Error(`Data dir path does not exist: ${dataDirPath}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultDataDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'data')
|
if (!fs.existsSync(sketchDirPath)) {
|
||||||
if (!fs.existsSync(defaultDataDirPath)) {
|
throw new Error(`Sketch dir path does not exist: ${sketchDirPath}.`);
|
||||||
fs.mkdirpSync(defaultDataDirPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.setSketchbookdir(rootPath);
|
config.setSketchbookdir(sketchDirPath);
|
||||||
config.setDatadir(defaultDataDirPath);
|
config.setDatadir(dataDirPath);
|
||||||
config.setDownloadsdir(defaultDownloadsDirPath);
|
config.setDownloadsdir(dataDirPath);
|
||||||
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();
|
||||||
|
@ -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,7 +14,7 @@
|
|||||||
"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 ./arduino-ide-browser start",
|
||||||
"watch": "lerna run watch --parallel"
|
"watch": "lerna run watch --parallel"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user