1
1
"use strict" ;
2
2
import * as child_process from 'child_process' ;
3
- import * as path from " path" ;
3
+ import * as path from ' path' ;
4
4
import { IInterpreterProvider , PythonInterpreter } from '../contracts' ;
5
- import { IS_WINDOWS } from "../../../common/utils" ;
5
+ import { IS_WINDOWS , fsExistsAsync } from "../../../common/utils" ;
6
+ import { VersionUtils } from "../../../common/versionUtils" ;
6
7
7
8
// where to find the Python binary within a conda env
8
9
const CONDA_RELATIVE_PY_PATH = IS_WINDOWS ? [ 'python.exe' ] : [ 'bin' , 'python' ] ;
@@ -15,32 +16,62 @@ type CondaInfo = {
15
16
default_prefix : string ;
16
17
}
17
18
export class CondaEnvProvider implements IInterpreterProvider {
19
+ constructor ( private registryLookupForConda ?: IInterpreterProvider ) {
20
+ }
18
21
public getInterpreters ( ) {
19
- return this . suggestionsFromConda ( ) ;
22
+ return this . getSuggestionsFromConda ( ) ;
20
23
}
21
- private suggestionsFromConda ( ) : Promise < PythonInterpreter [ ] > {
22
- return new Promise ( ( resolve , reject ) => {
23
- // interrogate conda (if it's on the path) to find all environments
24
- child_process . execFile ( 'conda' , [ 'info' , '--json' ] , ( _ , stdout ) => {
25
- if ( stdout . length === 0 ) {
26
- return resolve ( [ ] ) ;
27
- }
28
24
29
- try {
30
- const info = JSON . parse ( stdout ) ;
31
- resolve ( this . parseCondaInfo ( info ) ) ;
32
- } catch ( e ) {
33
- // Failed because either:
34
- // 1. conda is not installed
35
- // 2. `conda info --json` has changed signature
36
- // 3. output of `conda info --json` has changed in structure
37
- // In all cases, we can't offer conda pythonPath suggestions.
38
- return resolve ( [ ] ) ;
39
- }
25
+ private getSuggestionsFromConda ( ) : Promise < PythonInterpreter [ ] > {
26
+ return this . getCondaFile ( )
27
+ . then ( condaFile => {
28
+ return new Promise < PythonInterpreter [ ] > ( ( resolve , reject ) => {
29
+ // interrogate conda (if it's on the path) to find all environments
30
+ child_process . execFile ( condaFile , [ 'info' , '--json' ] , ( _ , stdout ) => {
31
+ if ( stdout . length === 0 ) {
32
+ return resolve ( [ ] ) ;
33
+ }
34
+
35
+ try {
36
+ const info = JSON . parse ( stdout ) ;
37
+ resolve ( this . parseCondaInfo ( info ) ) ;
38
+ } catch ( e ) {
39
+ // Failed because either:
40
+ // 1. conda is not installed
41
+ // 2. `conda info --json` has changed signature
42
+ // 3. output of `conda info --json` has changed in structure
43
+ // In all cases, we can't offer conda pythonPath suggestions.
44
+ return resolve ( [ ] ) ;
45
+ }
46
+ } ) ;
47
+ } ) ;
40
48
} ) ;
41
- } ) ;
42
49
}
43
-
50
+ public getCondaFile ( ) {
51
+ if ( this . registryLookupForConda ) {
52
+ return this . registryLookupForConda . getInterpreters ( )
53
+ . then ( interpreters => interpreters . filter ( this . isCondaEnvironment ) )
54
+ . then ( condaInterpreters => this . getLatestVersion ( condaInterpreters ) )
55
+ . then ( condaInterpreter => {
56
+ return condaInterpreter ? path . join ( path . dirname ( condaInterpreter . path ) , 'Scripts' , 'conda.exe' ) : 'conda' ;
57
+ } )
58
+ . then ( condaPath => {
59
+ return fsExistsAsync ( condaPath ) . then ( exists => exists ? condaPath : 'conda' ) ;
60
+ } ) ;
61
+ }
62
+ return Promise . resolve ( 'conda' ) ;
63
+ }
64
+ public isCondaEnvironment ( interpreter : PythonInterpreter ) {
65
+ return ( interpreter . displayName || '' ) . toUpperCase ( ) . indexOf ( 'ANACONDA' ) >= 0 ||
66
+ ( interpreter . companyDisplayName || '' ) . toUpperCase ( ) . indexOf ( 'CONTINUUM' ) >= 0 ;
67
+ }
68
+ public getLatestVersion ( interpreters : PythonInterpreter [ ] ) {
69
+ const sortedInterpreters = interpreters . filter ( interpreter => interpreter . version && interpreter . version . length > 0 ) ;
70
+ sortedInterpreters . sort ( ( a , b ) => VersionUtils . compareVersion ( a . version ! , b . version ! ) ) ;
71
+ if ( sortedInterpreters . length > 0 ) {
72
+ return sortedInterpreters [ sortedInterpreters . length - 1 ] ;
73
+ }
74
+ }
44
75
public async parseCondaInfo ( info : CondaInfo ) {
45
76
// "sys.version": "3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]",
46
77
const displayName = this . getDisplayNameFromVersionInfo ( info [ 'sys.version' ] ) ;
@@ -76,4 +107,4 @@ export class CondaEnvProvider implements IInterpreterProvider {
76
107
}
77
108
return AnacondaDisplayName ;
78
109
}
79
- }
110
+ }
0 commit comments