Skip to content

Commit f9641a3

Browse files
Akos Kittajbicker
Akos Kitta
authored andcommitted
Initial support of the default paths from the CLI.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
1 parent 59553bf commit f9641a3

File tree

10 files changed

+161
-67
lines changed

10 files changed

+161
-67
lines changed

.vscode/tasks.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "2.0.0",
55
"tasks": [
66
{
7-
"label": "Arduino-PoC - Start Browser Example",
7+
"label": "Arduino Editor - Start Browser Example",
88
"type": "shell",
99
"command": "yarn --cwd ./arduino-ide-browser start",
1010
"group": "build",
@@ -15,7 +15,7 @@
1515
}
1616
},
1717
{
18-
"label": "Arduino-PoC - Watch Theia Extension",
18+
"label": "Arduino Editor - Watch Theia Extension",
1919
"type": "shell",
2020
"command": "yarn --cwd ./arduino-ide-extension watch",
2121
"group": "build",
@@ -26,7 +26,7 @@
2626
}
2727
},
2828
{
29-
"label": "Arduino-PoC - Watch Browser Example",
29+
"label": "Arduino Editor - Watch Browser Example",
3030
"type": "shell",
3131
"command": "yarn --cwd ./arduino-ide-browser watch",
3232
"group": "build",
@@ -37,11 +37,11 @@
3737
}
3838
},
3939
{
40-
"label": "Arduino-PoC - Watch All",
40+
"label": "Arduino Editor - Watch All",
4141
"type": "shell",
4242
"dependsOn": [
43-
"Arduino-PoC - Watch Theia Extension",
44-
"Arduino-PoC - Watch Browser Example"
43+
"Arduino Editor - Watch Theia Extension",
44+
"Arduino Editor - Watch Browser Example"
4545
]
4646
}
4747
]

arduino-ide-browser/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"theia": {
3131
"frontend": {
3232
"config": {
33-
"applicationName": "Arduino-PoC",
33+
"applicationName": "Arduino Editor",
3434
"defaultTheme": "arduino-theme",
3535
"preferences": {
3636
"editor.autoSave": "on"

arduino-ide-electron/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"target": "electron",
3434
"frontend": {
3535
"config": {
36-
"applicationName": "Arduino-PoC",
36+
"applicationName": "Arduino Editor",
3737
"defaultTheme": "arduino-theme",
3838
"preferences": {
3939
"editor.autoSave": "on"

arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx

-19
Original file line numberDiff line numberDiff line change
@@ -543,25 +543,6 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
543543
return undefined;
544544
}
545545

546-
// private async onNoBoardsInstalled() {
547-
// const action = await this.messageService.info("You have no boards installed. Use the boards manager to install one.", "Open Boards Manager");
548-
// if (!action) {
549-
// return;
550-
// }
551-
552-
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
553-
// }
554-
555-
// private async onUnknownBoard() {
556-
// const action = await this.messageService.warn("There's a board connected for which you need to install software." +
557-
// " If this were not a PoC we would offer you the right package now.", "Open Boards Manager");
558-
// if (!action) {
559-
// return;
560-
// }
561-
562-
// this.boardsListWidgetFrontendContribution.openView({ reveal: true });
563-
// }
564-
565546
private isArduinoToolbar(maybeToolbarWidget: any): boolean {
566547
if (maybeToolbarWidget instanceof ArduinoToolbar) {
567548
return true;

arduino-ide-extension/src/node/arduino-backend-module.ts

+11
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@ import { SketchesService, SketchesServicePath } from '../common/protocol/sketche
2222
import { MonitorServiceImpl } from './monitor/monitor-service-impl';
2323
import { MonitorService, MonitorServicePath, MonitorServiceClient } from '../common/protocol/monitor-service';
2424
import { MonitorClientProvider } from './monitor/monitor-client-provider';
25+
import { ArduinoCli } from './arduino-cli';
26+
import { ArduinoCliContribution } from './arduino-cli-contribution';
27+
import { CliContribution } from '@theia/core/lib/node';
2528

2629
export default new ContainerModule((bind, unbind, isBound, rebind) => {
30+
// Theia backend CLI contribution.
31+
bind(ArduinoCliContribution).toSelf().inSingletonScope();
32+
bind(CliContribution).toService(ArduinoCliContribution);
33+
34+
// Provides the path of the Ardunio CLI.
35+
bind(ArduinoCli).toSelf().inSingletonScope();
36+
37+
// Shared daemonn
2738
bind(ArduinoDaemon).toSelf().inSingletonScope();
2839
bind(BackendApplicationContribution).toService(ArduinoDaemon);
2940

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { injectable } from 'inversify';
2+
import { Argv, Arguments } from 'yargs';
3+
import { CliContribution } from '@theia/core/lib/node';
4+
5+
@injectable()
6+
export class ArduinoCliContribution implements CliContribution {
7+
8+
protected _debugCli = false
9+
10+
configure(conf: Argv): void {
11+
conf.option('debug-cli', {
12+
description: 'Can be specified if the CLI daemon process was started externally.',
13+
type: 'boolean',
14+
default: false,
15+
nargs: 1
16+
});
17+
}
18+
19+
setArguments(args: Arguments): void {
20+
this._debugCli = args['debug-cli'];
21+
}
22+
23+
get debugCli(): boolean {
24+
return this._debugCli;
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import * as os from 'os';
2+
import * as which from 'which';
3+
import * as cp from 'child_process';
4+
import { join, delimiter } from 'path';
5+
import { injectable } from 'inversify';
6+
7+
@injectable()
8+
export class ArduinoCli {
9+
10+
async getExecPath(): Promise<string> {
11+
const build = join(__dirname, '..', '..', 'build');
12+
return new Promise<string>((resolve, reject) => {
13+
which(`arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`, { path: `${process.env.PATH}${delimiter}${build}` }, (err, path) => {
14+
if (err) {
15+
reject(err);
16+
return;
17+
}
18+
resolve(path);
19+
});
20+
});
21+
}
22+
23+
async getDefaultConfig(): Promise<ArduinoCli.Config> {
24+
const command = await this.getExecPath();
25+
return new Promise<ArduinoCli.Config>((resolve, reject) => {
26+
cp.execFile(
27+
command,
28+
['config', 'dump', '--format', 'json'],
29+
{ encoding: 'utf8' },
30+
(error, stdout, stderr) => {
31+
32+
if (error) {
33+
throw error;
34+
}
35+
36+
if (stderr) {
37+
throw new Error(stderr);
38+
}
39+
40+
// const { sketchbook_path: sketchDirPath, arduino_data: dataDirPath } = JSON.parse(raw);
41+
42+
// https://github.com/arduino/arduino-cli/issues/342
43+
// XXX: this is a hack. The CLI provides a non-valid JSON.
44+
const config: Partial<ArduinoCli.Config> = {};
45+
const raw = stdout.trim();
46+
for (const line of raw.split(/\r?\n/) || []) {
47+
// TODO: Named capture groups are avail from ES2018.
48+
// const pair = line.match(/(?<key>[^:]+):(?<value>[^,]+),?/);
49+
const pair = line.split(':').map(entry => entry.trim());
50+
if (pair[0] === 'sketchbook_path') {
51+
config.sketchDirPath = pair[1];
52+
} else if (pair[0] === 'arduino_data') {
53+
config.dataDirPath = pair[1];
54+
}
55+
}
56+
57+
if (!config.dataDirPath) {
58+
reject(new Error(`Could not parse config. 'arduino_data' was missing from: ${stdout}`));
59+
return;
60+
}
61+
62+
if (!config.sketchDirPath) {
63+
reject(new Error(`Could not parse config. 'sketchbook_path' was missing from: ${stdout}`));
64+
return;
65+
}
66+
67+
resolve({ sketchDirPath: config.sketchDirPath, dataDirPath: config.dataDirPath });
68+
});
69+
});
70+
}
71+
72+
}
73+
74+
export namespace ArduinoCli {
75+
export interface Config {
76+
sketchDirPath: string;
77+
dataDirPath: string;
78+
}
79+
}

arduino-ide-extension/src/node/arduino-daemon.ts

+12-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import * as which from 'which';
2-
import * as os from 'os';
3-
import { join, delimiter } from 'path';
1+
import { join } from 'path';
42
import { exec, spawn, SpawnOptions } from 'child_process';
53
import { inject, injectable, named } from 'inversify';
64
import { ILogger } from '@theia/core/lib/common/logger';
@@ -9,35 +7,31 @@ import { Deferred } from '@theia/core/lib/common/promise-util';
97
import { environment } from '@theia/application-package/lib/environment';
108
import { DaemonLog } from './daemon-log';
119
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
10+
import { ArduinoCliContribution } from './arduino-cli-contribution';
11+
import { ArduinoCli } from './arduino-cli';
1212

1313
@injectable()
1414
export class ArduinoDaemon implements BackendApplicationContribution {
1515

16-
// Set this to `true` if you want to connect to a CLI running in debug mode.
17-
static DEBUG_CLI = false;
18-
1916
@inject(ILogger)
2017
@named('daemon')
2118
protected readonly logger: ILogger
2219

20+
@inject(ArduinoCli)
21+
protected readonly cli: ArduinoCli;
22+
23+
@inject(ArduinoCliContribution)
24+
protected readonly cliContribution: ArduinoCliContribution;
25+
2326
@inject(ToolOutputServiceServer)
2427
protected readonly toolOutputService: ToolOutputServiceServer;
2528

2629
protected isReady = new Deferred<boolean>();
2730

2831
async onStart() {
2932
try {
30-
if (!ArduinoDaemon.DEBUG_CLI) {
31-
const build = join(__dirname, '..', '..', 'build');
32-
const executable = await new Promise<string>((resolve, reject) => {
33-
which(`arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`, { path: `${process.env.PATH}${delimiter}${build}` }, (err, path) => {
34-
if (err) {
35-
reject(err);
36-
return;
37-
}
38-
resolve(path);
39-
});
40-
});
33+
if (!this.cliContribution.debugCli) {
34+
const executable = await this.cli.getExecPath();
4135
this.logger.info(`>>> Starting 'arduino-cli' daemon... [${executable}]`);
4236
const daemon = exec(`${executable} --debug daemon`, (err, stdout, stderr) => {
4337
if (err || stderr) {
@@ -74,7 +68,7 @@ export class ArduinoDaemon implements BackendApplicationContribution {
7468

7569
await new Promise(resolve => setTimeout(resolve, 2000));
7670
this.isReady.resolve();
77-
if (!ArduinoDaemon.DEBUG_CLI) {
71+
if (!this.cliContribution.debugCli) {
7872
this.logger.info(`<<< The 'arduino-cli' daemon is up an running.`);
7973
} else {
8074
this.logger.info(`Assuming the 'arduino-cli' already runs in debug mode.`);

arduino-ide-extension/src/node/core-client-provider-impl.ts

+21-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { inject, injectable } from 'inversify';
1+
import * as fs from 'fs';
22
import * as grpc from '@grpc/grpc-js';
3+
import * as PQueue from 'p-queue';
4+
import { inject, injectable } from 'inversify';
5+
import URI from '@theia/core/lib/common/uri';
6+
import { FileSystem } from '@theia/filesystem/lib/common';
7+
import { WorkspaceServiceExt } from '../browser/workspace-service-ext';
8+
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
39
import { ArduinoCoreClient } from './cli-protocol/commands/commands_grpc_pb';
410
import {
511
InitResp,
@@ -10,16 +16,9 @@ import {
1016
UpdateLibrariesIndexReq,
1117
UpdateLibrariesIndexResp
1218
} from './cli-protocol/commands/commands_pb';
13-
import { WorkspaceServiceExt } from '../browser/workspace-service-ext';
14-
import { FileSystem } from '@theia/filesystem/lib/common';
15-
import URI from '@theia/core/lib/common/uri';
16-
import { CoreClientProvider, Client } from './core-client-provider';
17-
import * as PQueue from 'p-queue';
18-
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
19+
import { ArduinoCli } from './arduino-cli';
1920
import { Instance } from './cli-protocol/commands/common_pb';
20-
import * as fs from 'fs-extra';
21-
import * as path from 'path';
22-
import * as os from 'os';
21+
import { CoreClientProvider, Client } from './core-client-provider';
2322

2423
@injectable()
2524
export class CoreClientProviderImpl implements CoreClientProvider {
@@ -36,6 +35,9 @@ export class CoreClientProviderImpl implements CoreClientProvider {
3635
@inject(ToolOutputServiceServer)
3736
protected readonly toolOutputService: ToolOutputServiceServer;
3837

38+
@inject(ArduinoCli)
39+
protected readonly cli: ArduinoCli;
40+
3941
async getClient(workspaceRootOrResourceUri?: string): Promise<Client | undefined> {
4042
return this.clientRequestQueue.add(() => new Promise<Client | undefined>(async resolve => {
4143
const roots = await this.workspaceServiceExt.roots();
@@ -76,19 +78,19 @@ export class CoreClientProviderImpl implements CoreClientProvider {
7678
throw new Error(`Could not resolve filesystem path of URI: ${rootUri}.`);
7779
}
7880

79-
const defaultDownloadsDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'downloads');
80-
if (!fs.existsSync(defaultDownloadsDirPath)) {
81-
fs.mkdirpSync(defaultDownloadsDirPath);
81+
const { dataDirPath, sketchDirPath } = await this.cli.getDefaultConfig();
82+
83+
if (!fs.existsSync(dataDirPath)) {
84+
throw new Error(`Data dir path does not exist: ${dataDirPath}.`);
8285
}
8386

84-
const defaultDataDirPath = path.resolve(os.homedir(), 'Arduino-PoC', 'data')
85-
if (!fs.existsSync(defaultDataDirPath)) {
86-
fs.mkdirpSync(defaultDataDirPath);
87+
if (!fs.existsSync(sketchDirPath)) {
88+
throw new Error(`Sketch dir path does not exist: ${sketchDirPath}.`);
8789
}
8890

89-
config.setSketchbookdir(rootPath);
90-
config.setDatadir(defaultDataDirPath);
91-
config.setDownloadsdir(defaultDownloadsDirPath);
91+
config.setSketchbookdir(sketchDirPath);
92+
config.setDatadir(dataDirPath);
93+
config.setDownloadsdir(dataDirPath);
9294
config.setBoardmanageradditionalurlsList(['https://downloads.arduino.cc/packages/package_index.json']);
9395

9496
const initReq = new InitReq();

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "arduino-poc",
2+
"name": "arduino-editor",
33
"version": "0.0.1",
4-
"description": "A PoC demonstrating an Arduino IDE built using Eclipse Theia",
4+
"description": "Arduino IDE built using Eclipse Theia",
55
"main": "index.js",
66
"repository": "https://github.com/bcmi-labs/arduino-editor.git",
77
"author": "Christian Weichel <christian.weichel@typefox.io>",
@@ -14,7 +14,7 @@
1414
"prepare": "lerna run prepare",
1515
"rebuild:browser": "theia rebuild:browser",
1616
"rebuild:electron": "theia rebuild:electron",
17-
"start": "cd arduino-ide-browser && yarn start",
17+
"start": "yarn --cwd ./arduino-ide-browser start",
1818
"watch": "lerna run watch --parallel"
1919
},
2020
"workspaces": [

0 commit comments

Comments
 (0)