1
1
import * as os from 'os' ;
2
2
import * as which from 'which' ;
3
+ import * as semver from 'semver' ;
3
4
import { spawn } from 'child_process' ;
4
- import { join , delimiter } from 'path' ;
5
+ import { join } from 'path' ;
5
6
import { injectable , inject } from 'inversify' ;
6
7
import { ILogger } from '@theia/core' ;
7
8
import { FileUri } from '@theia/core/lib/node/file-uri' ;
@@ -13,43 +14,49 @@ export class ArduinoCli {
13
14
@inject ( ILogger )
14
15
protected logger : ILogger ;
15
16
17
+ private execPath : string | undefined ;
18
+
16
19
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
+ } ) ;
25
38
} ) ;
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 ;
27
55
}
28
56
29
57
async getVersion ( ) : Promise < string > {
30
58
const execPath = await this . getExecPath ( ) ;
31
59
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
- } ) ;
53
60
}
54
61
55
62
async getDefaultConfig ( ) : Promise < Config > {
0 commit comments