11"use strict" ;
22import * as child_process from 'child_process' ;
3- import * as path from " path" ;
3+ import * as path from ' path' ;
44import { 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" ;
67
78// where to find the Python binary within a conda env
89const CONDA_RELATIVE_PY_PATH = IS_WINDOWS ? [ 'python.exe' ] : [ 'bin' , 'python' ] ;
@@ -15,32 +16,62 @@ type CondaInfo = {
1516 default_prefix : string ;
1617}
1718export class CondaEnvProvider implements IInterpreterProvider {
19+ constructor ( private registryLookupForConda ?: IInterpreterProvider ) {
20+ }
1821 public getInterpreters ( ) {
19- return this . suggestionsFromConda ( ) ;
22+ return this . getSuggestionsFromConda ( ) ;
2023 }
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- }
2824
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+ } ) ;
4048 } ) ;
41- } ) ;
4249 }
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+ }
4475 public async parseCondaInfo ( info : CondaInfo ) {
4576 // "sys.version": "3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]",
4677 const displayName = this . getDisplayNameFromVersionInfo ( info [ 'sys.version' ] ) ;
@@ -76,4 +107,4 @@ export class CondaEnvProvider implements IInterpreterProvider {
76107 }
77108 return AnacondaDisplayName ;
78109 }
79- }
110+ }
0 commit comments