Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 20bc3c6

Browse files
authoredNov 21, 2019
Merge pull request #81 from bcmi-labs/choose-cli
Only pick `arduino-cli` from the PATH if it's more recent
2 parents 9643dd3 + 125ee70 commit 20bc3c6

File tree

2 files changed

+47
-39
lines changed

2 files changed

+47
-39
lines changed
 

‎arduino-ide-extension/package.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,27 @@
1010
"@grpc/grpc-js": "^0.4.0",
1111
"@theia/application-package": "next",
1212
"@theia/core": "next",
13+
"@theia/cpp": "next",
1314
"@theia/editor": "next",
1415
"@theia/filesystem": "next",
1516
"@theia/git": "next",
1617
"@theia/languages": "next",
1718
"@theia/markers": "next",
1819
"@theia/monaco": "next",
19-
"@theia/outline-view": "next",
20-
"@theia/workspace": "next",
2120
"@theia/navigator": "next",
22-
"@theia/terminal": "next",
21+
"@theia/outline-view": "next",
2322
"@theia/search-in-workspace": "next",
24-
"@theia/cpp": "next",
23+
"@theia/terminal": "next",
24+
"@theia/workspace": "next",
25+
"@types/google-protobuf": "^3.7.1",
2526
"@types/ps-tree": "^1.1.0",
26-
"@types/which": "^1.3.1",
2727
"@types/react-select": "^3.0.0",
28-
"@types/google-protobuf": "^3.7.1",
28+
"@types/which": "^1.3.1",
2929
"css-element-queries": "^1.2.0",
30-
"react-select": "^3.0.4",
3130
"p-queue": "^5.0.0",
3231
"ps-tree": "^1.2.0",
32+
"react-select": "^3.0.4",
33+
"semver": "^6.3.0",
3334
"string-natural-compare": "^2.0.3",
3435
"tree-kill": "^1.2.1",
3536
"upath": "^1.1.2",
@@ -77,4 +78,4 @@
7778
"frontendElectron": "lib/electron-browser/electron-arduino-menu-module"
7879
}
7980
]
80-
}
81+
}

‎arduino-ide-extension/src/node/arduino-cli.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as os from 'os';
22
import * as which from 'which';
3+
import * as semver from 'semver';
34
import { spawn } from 'child_process';
4-
import { join, delimiter } from 'path';
5+
import { join } from 'path';
56
import { injectable, inject } from 'inversify';
67
import { ILogger } from '@theia/core';
78
import { FileUri } from '@theia/core/lib/node/file-uri';
@@ -13,43 +14,49 @@ export class ArduinoCli {
1314
@inject(ILogger)
1415
protected logger: ILogger;
1516

17+
private execPath: string | undefined;
18+
1619
async getExecPath(): Promise<string> {
17-
const build = join(__dirname, '..', '..', 'build');
18-
return new Promise<string>((resolve, reject) => {
19-
which(`arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`, { path: `${process.env.PATH}${delimiter}${build}` }, (err, path) => {
20-
if (err) {
21-
reject(err);
22-
return;
23-
}
24-
resolve(path);
20+
if (this.execPath) {
21+
return this.execPath;
22+
}
23+
const version = /\d+\.\d+\.\d+/;
24+
const cli = `arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`;
25+
const buildCli = join(__dirname, '..', '..', 'build', cli);
26+
const buildVersion = await this.spawn(`"${buildCli}"`, ['version']);
27+
const buildShortVersion = (buildVersion.match(version) || [])[0];
28+
this.execPath = buildCli;
29+
try {
30+
const pathCli = await new Promise<string>((resolve, reject) => {
31+
which(cli, (error, path) => {
32+
if (error) {
33+
reject(error);
34+
return;
35+
}
36+
resolve(path);
37+
});
2538
});
26-
});
39+
if (!pathCli) {
40+
return buildCli;
41+
}
42+
const pathVersion = await this.spawn(`"${pathCli}"`, ['version']);
43+
const pathShortVersion = (pathVersion.match(version) || [])[0];
44+
if (semver.gt(pathShortVersion, buildShortVersion)) {
45+
this.execPath = pathCli;
46+
return pathCli;
47+
}
48+
} catch (error) {
49+
this.logger.warn(`Could not check for Arduino CLI in $PATH, using embedded CLI instead:`, error);
50+
// Any errors here should be safe to ignore, e.g.:
51+
// - Could not search for CLI in $PATH
52+
// - Could not get version of CLI in $PATH
53+
}
54+
return buildCli;
2755
}
2856

2957
async getVersion(): Promise<string> {
3058
const execPath = await this.getExecPath();
3159
return this.spawn(`"${execPath}"`, ['version']);
32-
return new Promise<string>((resolve, reject) => {
33-
const buffers: Buffer[] = [];
34-
const cp = spawn(`"${execPath}"`, ['version'], { windowsHide: true, shell: true });
35-
cp.stdout.on('data', (b: Buffer) => buffers.push(b));
36-
cp.on('error', error => reject(error));
37-
cp.on('exit', (code, signal) => {
38-
if (code === 0) {
39-
const result = Buffer.concat(buffers).toString('utf8').trim()
40-
resolve(result);
41-
return;
42-
}
43-
if (signal) {
44-
reject(new Error(`Process exited with signal: ${signal}`));
45-
return;
46-
}
47-
if (code) {
48-
reject(new Error(`Process exited with exit code: ${code}`));
49-
return;
50-
}
51-
});
52-
});
5360
}
5461

5562
async getDefaultConfig(): Promise<Config> {

0 commit comments

Comments
 (0)
Please sign in to comment.