4
4
import { Event } from 'vscode' ;
5
5
import { traceInfo } from '../../../../logging' ;
6
6
import { reportInterpretersChanged } from '../../../../proposedApi' ;
7
- import { arePathsSame , pathExists } from '../../../common/externalDependencies' ;
7
+ import { arePathsSame , getFileInfo , pathExists } from '../../../common/externalDependencies' ;
8
8
import { PythonEnvInfo } from '../../info' ;
9
9
import { areSameEnv , getEnvPath } from '../../info/env' ;
10
10
import {
@@ -33,18 +33,19 @@ export interface IEnvsCollectionCache {
33
33
/**
34
34
* Adds environment to cache.
35
35
*/
36
- addEnv ( env : PythonEnvInfo , hasCompleteInfo ?: boolean ) : void ;
36
+ addEnv ( env : PythonEnvInfo , hasLatestInfo ?: boolean ) : void ;
37
37
38
38
/**
39
39
* Return cached environment information for a given path if it exists and
40
- * has complete info , otherwise return `undefined`.
40
+ * is up to date , otherwise return `undefined`.
41
41
*
42
42
* @param path - Python executable path or path to environment
43
43
*/
44
- getCompleteInfo ( path : string ) : PythonEnvInfo | undefined ;
44
+ getLatestInfo ( path : string ) : Promise < PythonEnvInfo | undefined > ;
45
45
46
46
/**
47
- * Writes the content of the in-memory cache to persistent storage.
47
+ * Writes the content of the in-memory cache to persistent storage. It is assumed
48
+ * all envs have upto date info when this is called.
48
49
*/
49
50
flush ( ) : Promise < void > ;
50
51
@@ -60,7 +61,7 @@ export interface IEnvsCollectionCache {
60
61
clearCache ( ) : Promise < void > ;
61
62
}
62
63
63
- export type PythonEnvCompleteInfo = { hasCompleteInfo ?: boolean } & PythonEnvInfo ;
64
+ export type PythonEnvLatestInfo = { hasLatestInfo ?: boolean } & PythonEnvInfo ;
64
65
65
66
interface IPersistentStorage {
66
67
load ( ) : Promise < PythonEnvInfo [ ] > ;
@@ -72,7 +73,7 @@ interface IPersistentStorage {
72
73
*/
73
74
export class PythonEnvInfoCache extends PythonEnvsWatcher < PythonEnvCollectionChangedEvent >
74
75
implements IEnvsCollectionCache {
75
- private envs : PythonEnvCompleteInfo [ ] = [ ] ;
76
+ private envs : PythonEnvLatestInfo [ ] = [ ] ;
76
77
77
78
constructor ( private readonly persistentStorage : IPersistentStorage ) {
78
79
super ( ) ;
@@ -103,10 +104,11 @@ export class PythonEnvInfoCache extends PythonEnvsWatcher<PythonEnvCollectionCha
103
104
return this . envs ;
104
105
}
105
106
106
- public addEnv ( env : PythonEnvCompleteInfo , hasCompleteInfo ?: boolean ) : void {
107
+ public addEnv ( env : PythonEnvLatestInfo , hasLatestInfo ?: boolean ) : void {
107
108
const found = this . envs . find ( ( e ) => areSameEnv ( e , env ) ) ;
108
- if ( hasCompleteInfo ) {
109
- env . hasCompleteInfo = true ;
109
+ if ( hasLatestInfo ) {
110
+ env . hasLatestInfo = true ;
111
+ this . flush ( false ) . ignoreErrors ( ) ;
110
112
}
111
113
if ( ! found ) {
112
114
this . envs . push ( env ) ;
@@ -133,26 +135,33 @@ export class PythonEnvInfoCache extends PythonEnvsWatcher<PythonEnvCollectionCha
133
135
}
134
136
}
135
137
136
- public getCompleteInfo ( path : string ) : PythonEnvInfo | undefined {
138
+ public async getLatestInfo ( path : string ) : Promise < PythonEnvInfo | undefined > {
137
139
// `path` can either be path to environment or executable path
138
- let env = this . envs . find ( ( e ) => arePathsSame ( e . location , path ) ) ;
139
- if ( env ?. hasCompleteInfo ) {
140
+ const env = this . envs . find ( ( e ) => arePathsSame ( e . location , path ) ) ?? this . envs . find ( ( e ) => areSameEnv ( e , path ) ) ;
141
+ if ( env ?. hasLatestInfo ) {
140
142
return env ;
141
143
}
142
- env = this . envs . find ( ( e ) => areSameEnv ( e , path ) ) ;
143
- return env ?. hasCompleteInfo ? env : undefined ;
144
+ if ( env && ( env ?. hasLatestInfo || ( await validateInfo ( env ) ) ) ) {
145
+ return env ;
146
+ }
147
+ return undefined ;
144
148
}
145
149
146
150
public async clearAndReloadFromStorage ( ) : Promise < void > {
147
151
this . envs = await this . persistentStorage . load ( ) ;
152
+ this . envs . forEach ( ( e ) => {
153
+ e . hasLatestInfo = false ;
154
+ } ) ;
148
155
}
149
156
150
- public async flush ( ) : Promise < void > {
157
+ public async flush ( allEnvsHaveLatestInfo = true ) : Promise < void > {
151
158
if ( this . envs . length ) {
152
159
traceInfo ( 'Environments added to cache' , JSON . stringify ( this . envs ) ) ;
153
- this . envs . forEach ( ( e ) => {
154
- e . hasCompleteInfo = true ;
155
- } ) ;
160
+ if ( allEnvsHaveLatestInfo ) {
161
+ this . envs . forEach ( ( e ) => {
162
+ e . hasLatestInfo = true ;
163
+ } ) ;
164
+ }
156
165
await this . persistentStorage . store ( this . envs ) ;
157
166
}
158
167
}
@@ -167,6 +176,16 @@ export class PythonEnvInfoCache extends PythonEnvsWatcher<PythonEnvCollectionCha
167
176
}
168
177
}
169
178
179
+ async function validateInfo ( env : PythonEnvInfo ) {
180
+ const { ctime, mtime } = await getFileInfo ( env . executable . filename ) ;
181
+ if ( ctime === env . executable . ctime && mtime === env . executable . mtime ) {
182
+ return true ;
183
+ }
184
+ env . executable . ctime = ctime ;
185
+ env . executable . mtime = mtime ;
186
+ return false ;
187
+ }
188
+
170
189
/**
171
190
* Build a cache of PythonEnvInfo that is ready to use.
172
191
*/
0 commit comments