11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4+ // tslint:disable-next-line:no-single-line-block-comment
5+ /* eslint-disable max-classes-per-file */
6+
47import { cloneDeep } from 'lodash' ;
58import { PythonEnvInfo } from './info' ;
6- import { areSameEnv } from './info/env' ;
9+ import {
10+ areSameEnv ,
11+ getEnvExecutable ,
12+ haveSameExecutables ,
13+ } from './info/env' ;
14+
15+ /**
16+ * A simple in-memory store of Python envs.
17+ */
18+ export class PythonEnvsCache {
19+ private envs : PythonEnvInfo [ ] = [ ] ;
20+
21+ private byExecutable : Record < string , PythonEnvInfo > | undefined ;
22+
23+ constructor ( envs ?: PythonEnvInfo [ ] ) {
24+ if ( envs !== undefined ) {
25+ this . setEnvs ( envs ) ;
26+ }
27+ }
28+
29+ /**
30+ * Provide a copy of the cached envs.
31+ */
32+ public getEnvs ( ) : PythonEnvInfo [ ] {
33+ return cloneDeep ( this . envs ) ;
34+ }
35+
36+ /**
37+ * Replace the set of cached envs with the given set.
38+ *
39+ * If the given envs are the same as the cached ones
40+ * then the existing are left in place.
41+ *
42+ * @returns - `true` if the cached envs were actually replaced
43+ */
44+ public setEnvs ( envs : PythonEnvInfo [ ] ) : boolean {
45+ // We *could* compare additional properties, but checking
46+ // the executables is good enough for now.
47+ if ( haveSameExecutables ( this . envs , envs ) ) {
48+ return false ;
49+ }
50+ this . envs = cloneDeep ( envs ) ;
51+ this . byExecutable = undefined ;
52+ return true ;
53+ }
54+
55+ /**
56+ * Find the matching env in the cache, if any.
57+ */
58+ public lookUp (
59+ query : string | Partial < PythonEnvInfo > ,
60+ ) : PythonEnvInfo | undefined {
61+ const executable = getEnvExecutable ( query ) ;
62+ if ( executable === '' ) {
63+ return undefined ;
64+ }
65+ if ( this . byExecutable === undefined ) {
66+ this . byExecutable = { } ;
67+ for ( const env of this . envs ) {
68+ this . byExecutable [ env . executable . filename ] = env ;
69+ }
70+ }
71+ return this . byExecutable [ executable ] ;
72+ }
73+
74+ public filter ( match : ( env : PythonEnvInfo ) => boolean | undefined ) : PythonEnvInfo [ ] {
75+ const matched = this . envs . filter ( match ) ;
76+ return cloneDeep ( matched ) ;
77+ }
78+ }
779
880/**
981 * Represents the environment info cache to be used by the cache locator.
@@ -60,7 +132,7 @@ type CompleteEnvInfoFunction = (envInfo: PythonEnvInfo) => boolean;
60132export class PythonEnvInfoCache implements IEnvsCache {
61133 private initialized = false ;
62134
63- private envsList : PythonEnvInfo [ ] | undefined ;
135+ private inMemory : PythonEnvsCache | undefined ;
64136
65137 private persistentStorage : IPersistentStorage | undefined ;
66138
@@ -77,28 +149,27 @@ export class PythonEnvInfoCache implements IEnvsCache {
77149 this . initialized = true ;
78150 if ( this . getPersistentStorage !== undefined ) {
79151 this . persistentStorage = this . getPersistentStorage ( ) ;
80- this . envsList = await this . persistentStorage . load ( ) ;
152+ const envs = await this . persistentStorage . load ( ) ;
153+ if ( envs !== undefined ) {
154+ this . setAllEnvs ( envs ) ;
155+ }
81156 }
82157 }
83158
84159 public getAllEnvs ( ) : PythonEnvInfo [ ] | undefined {
85- return cloneDeep ( this . envsList ) ;
160+ return this . inMemory ?. getEnvs ( ) ;
86161 }
87162
88163 public setAllEnvs ( envs : PythonEnvInfo [ ] ) : void {
89- this . envsList = cloneDeep ( envs ) ;
164+ this . inMemory = new PythonEnvsCache ( envs ) ;
90165 }
91166
92167 public filterEnvs ( query : Partial < PythonEnvInfo > ) : PythonEnvInfo [ ] | undefined {
93- if ( this . envsList === undefined ) {
94- return undefined ;
95- }
96- const result = this . envsList . filter ( ( info ) => areSameEnv ( info , query ) ) ;
97- return cloneDeep ( result ) ;
168+ return this . inMemory ?. filter ( ( info ) => areSameEnv ( info , query ) ) ;
98169 }
99170
100171 public async flush ( ) : Promise < void > {
101- const completeEnvs = this . envsList ?. filter ( this . isComplete ) ;
172+ const completeEnvs = this . inMemory ?. filter ( this . isComplete ) ;
102173
103174 if ( completeEnvs ?. length ) {
104175 await this . persistentStorage ?. store ( completeEnvs ) ;
0 commit comments