-
Notifications
You must be signed in to change notification settings - Fork 299
/
Copy pathcondaService.ts
107 lines (104 loc) · 4.07 KB
/
condaService.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import { inject, injectable, named } from 'inversify';
import { SemVer } from 'semver';
import { Memento } from 'vscode';
import { IPythonApiProvider } from '../../api/types';
import { IFileSystem } from '../platform/types';
import { GLOBAL_MEMENTO, IMemento } from '../types';
import { createDeferredFromPromise } from '../utils/async';
const CACHEKEY_FOR_CONDA_INFO = 'CONDA_INFORMATION_CACHE';
@injectable()
export class CondaService {
private _file?: string;
private _version?: SemVer;
private _previousVersionCall?: Promise<SemVer | undefined>;
private _previousFileCall?: Promise<string | undefined>;
constructor(
@inject(IPythonApiProvider) private readonly pythonApi: IPythonApiProvider,
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly globalState: Memento,
@inject(IFileSystem) private readonly fs: IFileSystem
) {}
async getCondaVersion() {
if (this._version) {
return this._version;
}
if (this._previousVersionCall) {
return this._previousVersionCall;
}
const promise = async () => {
const latestInfo = this.pythonApi
.getApi()
.then((api) => (api.getCondaVersion ? api.getCondaVersion() : undefined));
void latestInfo.then((version) => {
this._version = version;
void this.updateCache();
});
const cachedInfo = createDeferredFromPromise(this.getCachedInformation());
await Promise.race([cachedInfo, latestInfo]);
if (cachedInfo.completed && cachedInfo.value?.version) {
return (this._version = cachedInfo.value.version);
}
return latestInfo;
};
this._previousVersionCall = promise();
return this._previousVersionCall;
}
async getCondaFile() {
if (this._file) {
return this._file;
}
if (this._previousFileCall) {
return this._previousFileCall;
}
const promise = async () => {
const latestInfo = this.pythonApi
.getApi()
.then((api) => (api.getCondaFile ? api.getCondaFile() : undefined));
void latestInfo.then((file) => {
this._file = file;
void this.updateCache();
});
const cachedInfo = createDeferredFromPromise(this.getCachedInformation());
await Promise.race([cachedInfo, latestInfo]);
if (cachedInfo.completed && cachedInfo.value?.file) {
return (this._file = cachedInfo.value.file);
}
return latestInfo;
};
this._previousFileCall = promise();
return this._previousFileCall;
}
private async updateCache() {
if (!this._file || !this._version) {
return;
}
const fileHash = this._file.toLowerCase() === 'conda' ? '' : await this.fs.getFileHash(this._file);
await this.globalState.update(CACHEKEY_FOR_CONDA_INFO, {
version: this._version.raw,
file: this._file,
fileHash
});
}
/**
* If the last modified date of the conda file is the same as when we last checked,
* then we can assume the version is the same.
* Even if not, we'll update this with the latest information.
*/
private async getCachedInformation(): Promise<{ version: SemVer; file: string } | undefined> {
const cachedInfo = this.globalState.get<{ version: string; file: string; fileHash: string } | undefined>(
CACHEKEY_FOR_CONDA_INFO,
undefined
);
if (!cachedInfo) {
return;
}
const fileHash = cachedInfo.file.toLowerCase() === 'conda' ? '' : await this.fs.getFileHash(cachedInfo.file);
if (cachedInfo.fileHash === fileHash) {
return {
version: new SemVer(cachedInfo.version),
file: cachedInfo.file
};
}
}
}