@@ -6,9 +6,10 @@ import { createDeferred, Deferred } from '../../../common/utils/async';
66import { createRunningWorkerPool , IWorkerPool , QueuePosition } from '../../../common/utils/workerPool' ;
77import { getInterpreterInfo , InterpreterInformation } from './interpreter' ;
88import { buildPythonExecInfo } from '../../exec' ;
9- import { traceError } from '../../../logging' ;
10- import { Conda , CONDA_RUN_TIMEOUT , CONDA_RUN_SCRIPT } from '../../common/environmentManagers/conda' ;
9+ import { traceError , traceInfo } from '../../../logging' ;
10+ import { Conda , CONDA_RUN_TIMEOUT , isCondaEnvironment } from '../../common/environmentManagers/conda' ;
1111import { PythonEnvInfo , PythonEnvKind } from '.' ;
12+ import { normCasePath } from '../../common/externalDependencies' ;
1213
1314export enum EnvironmentInfoServiceQueuePriority {
1415 Default ,
@@ -20,30 +21,28 @@ export interface IEnvironmentInfoService {
2021 env : PythonEnvInfo ,
2122 priority ?: EnvironmentInfoServiceQueuePriority ,
2223 ) : Promise < InterpreterInformation | undefined > ;
23- isInfoProvided ( interpreterPath : string ) : boolean ;
2424}
2525
2626async function buildEnvironmentInfo ( env : PythonEnvInfo ) : Promise < InterpreterInformation | undefined > {
27- let python = [ env . executable . filename ] ;
28- const isCondaEnv = env . kind === PythonEnvKind . Conda ;
29- if ( isCondaEnv ) {
30- const conda = await Conda . getConda ( ) ;
31- const runArgs = await conda ?. getRunArgs ( { name : env . name , prefix : env . location } ) ;
32- if ( runArgs ) {
33- python = [ ...runArgs , 'python' , CONDA_RUN_SCRIPT ] ;
34- }
35- }
36- const interpreterInfo = await getInterpreterInfo (
37- buildPythonExecInfo ( python , undefined , env . executable . filename ) ,
38- isCondaEnv ? CONDA_RUN_TIMEOUT : undefined ,
39- ) . catch ( ( reason ) => {
40- traceError ( reason ) ;
41- return undefined ;
42- } ) ;
27+ const python = [ env . executable . filename ] ;
28+ const interpreterInfo = await getInterpreterInfo ( buildPythonExecInfo ( python , undefined , env . executable . filename ) ) ;
29+ return interpreterInfo ;
30+ }
4331
44- if ( interpreterInfo === undefined || interpreterInfo . version === undefined ) {
32+ async function buildEnvironmentInfoUsingCondaRun ( env : PythonEnvInfo ) : Promise < InterpreterInformation | undefined > {
33+ const conda = await Conda . getConda ( ) ;
34+ const condaEnv = await conda ?. getCondaEnvironment ( env . executable . filename ) ;
35+ if ( ! condaEnv ) {
36+ return undefined ;
37+ }
38+ const python = await conda ?. getRunPythonArgs ( condaEnv ) ;
39+ if ( ! python ) {
4540 return undefined ;
4641 }
42+ const interpreterInfo = await getInterpreterInfo (
43+ buildPythonExecInfo ( python , undefined , env . executable . filename ) ,
44+ CONDA_RUN_TIMEOUT ,
45+ ) ;
4746 return interpreterInfo ;
4847}
4948
@@ -59,47 +58,96 @@ class EnvironmentInfoService implements IEnvironmentInfoService {
5958
6059 private workerPool ?: IWorkerPool < PythonEnvInfo , InterpreterInformation | undefined > ;
6160
61+ private condaRunWorkerPool ?: IWorkerPool < PythonEnvInfo , InterpreterInformation | undefined > ;
62+
6263 public dispose ( ) : void {
6364 if ( this . workerPool !== undefined ) {
6465 this . workerPool . stop ( ) ;
6566 this . workerPool = undefined ;
6667 }
68+ if ( this . condaRunWorkerPool !== undefined ) {
69+ this . condaRunWorkerPool . stop ( ) ;
70+ this . condaRunWorkerPool = undefined ;
71+ }
6772 }
6873
6974 public async getEnvironmentInfo (
7075 env : PythonEnvInfo ,
7176 priority ?: EnvironmentInfoServiceQueuePriority ,
7277 ) : Promise < InterpreterInformation | undefined > {
7378 const interpreterPath = env . executable . filename ;
74- const result = this . cache . get ( interpreterPath ) ;
79+ const result = this . cache . get ( normCasePath ( interpreterPath ) ) ;
7580 if ( result !== undefined ) {
76- // Another call for this environment has already been made, return its result
81+ // Another call for this environment has already been made, return its result.
7782 return result . promise ;
7883 }
7984
85+ const deferred = createDeferred < InterpreterInformation > ( ) ;
86+ this . cache . set ( normCasePath ( interpreterPath ) , deferred ) ;
87+ this . _getEnvironmentInfo ( env , priority )
88+ . then ( ( r ) => {
89+ deferred . resolve ( r ) ;
90+ } )
91+ . catch ( ( ex ) => {
92+ deferred . reject ( ex ) ;
93+ } ) ;
94+ return deferred . promise ;
95+ }
96+
97+ public async _getEnvironmentInfo (
98+ env : PythonEnvInfo ,
99+ priority ?: EnvironmentInfoServiceQueuePriority ,
100+ ) : Promise < InterpreterInformation | undefined > {
80101 if ( this . workerPool === undefined ) {
81102 this . workerPool = createRunningWorkerPool < PythonEnvInfo , InterpreterInformation | undefined > (
82103 buildEnvironmentInfo ,
83104 ) ;
84105 }
85106
86- const deferred = createDeferred < InterpreterInformation > ( ) ;
87- this . cache . set ( interpreterPath , deferred ) ;
88- return ( priority === EnvironmentInfoServiceQueuePriority . High
89- ? this . workerPool . addToQueue ( env , QueuePosition . Front )
90- : this . workerPool . addToQueue ( env , QueuePosition . Back )
91- ) . then ( ( r ) => {
92- deferred . resolve ( r ) ;
93- return r ;
107+ let reason : unknown ;
108+ let r = await addToQueue ( this . workerPool , env , priority ) . catch ( ( err ) => {
109+ reason = err ;
110+ return undefined ;
94111 } ) ;
95- }
96112
97- public isInfoProvided ( interpreterPath : string ) : boolean {
98- const result = this . cache . get ( interpreterPath ) ;
99- return ! ! ( result && result . completed ) ;
113+ if ( r === undefined ) {
114+ // Even though env kind is not conda, it can still be a conda environment
115+ // as complete env info may not be available at this time.
116+ const isCondaEnv = env . kind === PythonEnvKind . Conda || ( await isCondaEnvironment ( env . executable . filename ) ) ;
117+ if ( isCondaEnv ) {
118+ traceInfo (
119+ `Validating ${ env . executable . filename } normally failed with error, falling back to using conda run: (${ reason } )` ,
120+ ) ;
121+ if ( this . condaRunWorkerPool === undefined ) {
122+ // Create a separate queue for validation using conda, so getting environment info for
123+ // other types of environment aren't blocked on conda.
124+ this . condaRunWorkerPool = createRunningWorkerPool <
125+ PythonEnvInfo ,
126+ InterpreterInformation | undefined
127+ > ( buildEnvironmentInfoUsingCondaRun ) ;
128+ }
129+ r = await addToQueue ( this . condaRunWorkerPool , env , priority ) . catch ( ( err ) => {
130+ traceError ( err ) ;
131+ return undefined ;
132+ } ) ;
133+ } else if ( reason ) {
134+ traceError ( reason ) ;
135+ }
136+ }
137+ return r ;
100138 }
101139}
102140
141+ function addToQueue (
142+ workerPool : IWorkerPool < PythonEnvInfo , InterpreterInformation | undefined > ,
143+ env : PythonEnvInfo ,
144+ priority : EnvironmentInfoServiceQueuePriority | undefined ,
145+ ) {
146+ return priority === EnvironmentInfoServiceQueuePriority . High
147+ ? workerPool . addToQueue ( env , QueuePosition . Front )
148+ : workerPool . addToQueue ( env , QueuePosition . Back ) ;
149+ }
150+
103151let envInfoService : IEnvironmentInfoService | undefined ;
104152export function getEnvironmentInfoService ( disposables ?: IDisposableRegistry ) : IEnvironmentInfoService {
105153 if ( envInfoService === undefined ) {
0 commit comments