Skip to content

Commit 7e6eb78

Browse files
author
Kartik Raj
committed
Handle workspace locator factor
1 parent 3404a15 commit 7e6eb78

File tree

3 files changed

+171
-113
lines changed

3 files changed

+171
-113
lines changed

src/client/apiTypes.ts

Lines changed: 88 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ export interface EnvironmentDetails {
143143
path: string;
144144
project?: string; // Any specific project environment is created for.
145145
source: EnvSource[];
146-
};;
146+
};
147147
version: VersionInfo & {
148148
sysVersion?: string;
149-
};;
149+
};
150150
implementation?: {
151151
// `sys.implementation`
152152
name: string;
@@ -156,6 +156,92 @@ export interface EnvironmentDetails {
156156
};
157157
}
158158

159+
/**
160+
* Provider is only required to provide the `executable` key, rest are optional. So construct a type using
161+
* `EnvironmentDetails` where `executable` is the only required key.
162+
*/
163+
type EnvironmentDetailsByProvider = Partial<EnvironmentDetails> & Pick<EnvironmentDetails, 'executable'>;
164+
165+
interface IEnvironmentProvider {
166+
createLocator: ILocatorFactory;
167+
getEnvironmentDetails: (env: EnvInfo) => Promise<EnvironmentDetailsByProvider | undefined>;
168+
}
169+
170+
export type ILocatorFactory = INonWorkspaceLocatorFactory | IWorkspaceLocatorFactory;
171+
export type INonWorkspaceLocatorFactory = () => ILocatorAPI;
172+
export type IWorkspaceLocatorFactory = (root: string) => ILocatorAPI;
173+
174+
export interface ILocatorAPI {
175+
iterEnvs?(): IPythonEnvsIterator<EnvInfo>;
176+
readonly onChanged?: Event<LocatorEnvsChangedEvent>;
177+
}
178+
179+
export type EnvInfo = {
180+
envSources: EnvSource[];
181+
executablePath: string;
182+
envPath?: string;
183+
};
184+
185+
type ProviderID = string;
186+
187+
/**
188+
* These can be used when querying for a particular env.
189+
*/
190+
interface EnvironmentProviderMetadata {
191+
/**
192+
* Details about the environments the locator provides.
193+
* Useful when querying for a particular env.
194+
*/
195+
readonly environments?: EnvironmentMetaData;
196+
/**
197+
* If locator requires a workspace root to search envs within.
198+
*/
199+
readonly isWorkspaceBasedLocator: boolean;
200+
/**
201+
* An Identifier for the provider.
202+
*/
203+
readonly providerId: ProviderID;
204+
}
205+
206+
interface EnvironmentMetaData {
207+
readonly envType: EnvType;
208+
readonly envSources: EnvSource[];
209+
}
210+
211+
export interface LocatorEnvsChangedEvent {
212+
/**
213+
* Any details known about the environment which can be used for query.
214+
*/
215+
env?: EnvironmentMetaData;
216+
/**
217+
* Details about how the environment was modified.
218+
* */
219+
type: EnvChangeType;
220+
}
221+
222+
export type EnvChangeType = 'add' | 'remove' | 'update';
223+
224+
export type EnvType = KnownEnvTypes | string;
225+
226+
export enum KnownEnvTypes {
227+
VirtualEnv = 'VirtualEnv',
228+
Conda = 'Conda',
229+
Unknown = 'Unknown',
230+
Global = 'Global',
231+
}
232+
233+
export type EnvSource = KnownEnvSourceTypes | string;
234+
235+
export enum KnownEnvSourceTypes {
236+
Conda = 'Conda',
237+
Pipenv = 'PipEnv',
238+
Poetry = 'Poetry',
239+
VirtualEnv = 'VirtualEnv',
240+
Venv = 'Venv',
241+
VirtualEnvWrapper = 'VirtualEnvWrapper',
242+
Pyenv = 'Pyenv',
243+
}
244+
159245
export interface EnvironmentsChangedParams {
160246
/**
161247
* Path to environment folder or path to interpreter that uniquely identifies an environment.
@@ -263,89 +349,3 @@ export interface IProposedExtensionAPI {
263349
): Promise<Disposable>; // TODO: Disposable?? // TODO: Confirm whether this should return a promise??
264350
};
265351
}
266-
267-
/**
268-
* Provider is only expected to provide the executable key, so construct a type using `EnvironmentDetails`
269-
* where `executable` is the only necessary key.
270-
*/
271-
type EnvironmentDetailsByProvider = Omit<Partial<EnvironmentDetails>, 'executable'> &
272-
Pick<EnvironmentDetails, 'executable'>;
273-
274-
interface IEnvironmentProvider {
275-
createLocator: ILocatorFactory;
276-
getEnvironmentDetails: (env: EnvInfo) => Promise<EnvironmentDetailsByProvider | undefined>;
277-
}
278-
279-
type isRootBasedLocatorFactory = ((root: string) => ILocatorAPI);
280-
export type ILocatorFactory = (() => ILocatorAPI) | isRootBasedLocatorFactory;
281-
282-
export interface ILocatorAPI {
283-
iterEnvs?(): IPythonEnvsIterator<EnvInfo>;
284-
readonly onChanged?: Event<LocatorEnvsChangedEvent>;
285-
}
286-
287-
export type EnvInfo = {
288-
envSources: EnvSource[];
289-
executablePath: string;
290-
envPath?: string;
291-
};
292-
293-
type ProviderID = string;
294-
295-
/**
296-
* These can be used when querying for a particular env.
297-
*/
298-
interface EnvironmentProviderMetadata {
299-
/**
300-
* Details about the environments the locator provides.
301-
* Useful when querying for a particular env.
302-
*/
303-
readonly environments?: EnvironmentMetaData;
304-
/**
305-
* If locator requires a root to search envs within.
306-
*/
307-
readonly isRootBasedLocator: boolean;
308-
/**
309-
* An Identifier for the provider.
310-
*/
311-
readonly providerId: ProviderID;
312-
}
313-
314-
interface EnvironmentMetaData {
315-
readonly envType: EnvType;
316-
readonly envSources: EnvSource[];
317-
}
318-
319-
export interface LocatorEnvsChangedEvent {
320-
/**
321-
* Any details known about the environment which can be used for query.
322-
*/
323-
env?: EnvironmentMetaData;
324-
/**
325-
* Details about how the environment was modified.
326-
**/
327-
type: EnvChangeType;
328-
}
329-
330-
export type EnvChangeType = 'add' | 'remove' | 'update';
331-
332-
export type EnvType = KnownEnvTypes | string;
333-
334-
export enum KnownEnvTypes {
335-
VirtualEnv = 'VirtualEnv',
336-
Conda = 'Conda',
337-
Unknown = 'Unknown',
338-
Global = 'Global',
339-
}
340-
341-
export type EnvSource = KnownEnvSourceTypes | string;
342-
343-
export enum KnownEnvSourceTypes {
344-
Conda = 'Conda',
345-
Pipenv = 'PipEnv',
346-
Poetry = 'Poetry',
347-
VirtualEnv = 'VirtualEnv',
348-
Venv = 'Venv',
349-
VirtualEnvWrapper = 'VirtualEnvWrapper',
350-
Pyenv = 'Pyenv',
351-
}

src/client/pythonEnvironments/base/locator.ts

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
/* eslint-disable @typescript-eslint/ban-types */
12
// Copyright (c) Microsoft Corporation. All rights reserved.
23
// Licensed under the MIT License.
34

45
/* eslint-disable max-classes-per-file */
56

67
import { Event, Uri } from 'vscode';
78
import { IAsyncIterableIterator, iterEmpty } from '../../common/utils/async';
9+
import { Architecture } from '../../common/utils/platform';
810
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from './info';
911
import {
1012
BasicPythonEnvsChangedEvent,
@@ -14,7 +16,61 @@ import {
1416
PythonEnvsWatcher,
1517
} from './watcher';
1618

17-
export type ILocatorFactory = (root?: string) => ILocatorAPI;
19+
type VersionInfo = {
20+
major: number;
21+
minor: number;
22+
micro: number;
23+
releaselevel: 'alpha' | 'beta' | 'candidate' | 'final';
24+
serial: number;
25+
};
26+
27+
export interface EnvironmentDetails {
28+
executable: {
29+
path: string;
30+
run: {
31+
// Functions would only require the arguments. The env provider can internally decide on the commands.
32+
// Support option of whether to run as a process or VSCode terminal.
33+
// However note we cannot pass this into the debugger at the moment, as VSCode itself handles execution.
34+
// Gotta add support in VSCode for that, they already support that for LSP.
35+
// TODO: Gotta support this for upstream debugger
36+
exec: Function;
37+
shellExec: Function; // Only for backwards compatibility.
38+
execObservable: Function;
39+
/**
40+
* Uses a VSCode terminal.
41+
* */
42+
terminalExec: () => void;
43+
/**
44+
* Any environment variables that can be used to activate the environment, if supported.
45+
* If not provided, Python extension itself uses the other execution APIs to calculate it.
46+
*/
47+
env?: { [key: string]: string | null | undefined };
48+
};
49+
bitness?: Architecture;
50+
sysPrefix: string;
51+
};
52+
environment?: {
53+
type: EnvType;
54+
name?: string;
55+
path: string;
56+
project?: string; // Any specific project environment is created for.
57+
source: EnvSource[];
58+
};
59+
version: VersionInfo & {
60+
sysVersion?: string;
61+
};
62+
implementation?: {
63+
// `sys.implementation`
64+
name: string;
65+
version: VersionInfo & {
66+
serial: number;
67+
};
68+
};
69+
}
70+
71+
type isRootBasedLocatorFactory = (root: string) => ILocatorAPI;
72+
export type ILocatorFactory = ILocatorAPI | isRootBasedLocatorFactory;
73+
1874
export interface ILocatorAPI {
1975
iterEnvs?(): IPythonEnvsIterator<EnvInfo>;
2076
readonly onChanged?: Event<LocatorEnvsChangedEvent>;
@@ -25,46 +81,43 @@ export type EnvInfo = {
2581
executablePath: string;
2682
envPath?: string;
2783
};
28-
29-
/**
30-
* These can be used when querying for a particular env.
31-
*/
32-
interface EnvironmentProviderMetadata {
84+
interface EnvironmentMetaData {
3385
readonly envType: EnvType;
34-
readonly searchLocation?: string;
3586
readonly envSources: EnvSource[];
36-
readonly isRootBasedLocator: boolean;
3787
}
3888

39-
type EnvironmentMetaData = EnvironmentProviderMetadata;
40-
4189
export interface LocatorEnvsChangedEvent {
4290
/**
4391
* Any details known about the environment which can be used for query.
4492
*/
4593
env?: EnvironmentMetaData;
94+
/**
95+
* Details about how the environment was modified.
96+
* */
4697
type: EnvChangeType;
4798
}
4899

49100
export type EnvChangeType = 'add' | 'remove' | 'update';
50101

51-
export enum EnvType {
102+
export type EnvType = KnownEnvTypes | string;
103+
104+
export enum KnownEnvTypes {
52105
VirtualEnv = 'VirtualEnv',
53106
Conda = 'Conda',
54107
Unknown = 'Unknown',
55-
Global = 'GlobalInterpreter',
108+
Global = 'Global',
56109
}
57110

58-
export enum EnvSource {
111+
export type EnvSource = KnownEnvSourceTypes | string;
112+
113+
export enum KnownEnvSourceTypes {
59114
Conda = 'Conda',
60115
Pipenv = 'PipEnv',
61116
Poetry = 'Poetry',
62117
VirtualEnv = 'VirtualEnv',
63118
Venv = 'Venv',
64119
VirtualEnvWrapper = 'VirtualEnvWrapper',
65-
WindowsStore = 'WindowsStore',
66120
Pyenv = 'Pyenv',
67-
Custom = 'Custom',
68121
}
69122

70123
/**
@@ -229,7 +282,7 @@ export interface ILocator<I = PythonEnvInfo, E extends BasicPythonEnvsChangedEve
229282
}
230283

231284
export interface IEnvProvider {
232-
addNewLocator?(locatorFactory: ILocatorFactory, isWorkspace: boolean): void;
285+
addNewLocator?(locatorFactory: ILocatorFactory): void;
233286
}
234287

235288
interface IResolver {

src/client/pythonEnvironments/base/locators/wrappers.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,28 @@
33

44
// eslint-disable-next-line max-classes-per-file
55
import { Uri } from 'vscode';
6-
import { ILocatorFactory } from '../../../apiTypes';
6+
import { ILocatorFactory, INonWorkspaceLocatorFactory, IWorkspaceLocatorFactory } from '../../../apiTypes';
77
import { IDisposable } from '../../../common/types';
88
import { iterEmpty } from '../../../common/utils/async';
99
import { getURIFilter } from '../../../common/utils/misc';
1010
import { Disposables } from '../../../common/utils/resourceLifecycle';
1111
import { CustomLocator } from '../../converter';
1212
import { PythonEnvInfo } from '../info';
13-
import { BasicEnvInfo, ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
13+
import { BasicEnvInfo, IEnvProvider, ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
1414
import { combineIterators, Locators } from '../locators';
1515
import { LazyResourceBasedLocator } from './common/resourceBasedLocator';
1616

17+
function IsNonWorkspaceLocatorFactory(
18+
pet: IWorkspaceLocatorFactory | INonWorkspaceLocatorFactory,
19+
): pet is INonWorkspaceLocatorFactory {
20+
return pet.length === 0;
21+
}
22+
1723
/**
1824
* A wrapper around all locators used by the extension.
1925
*/
2026

21-
export class ExtensionLocators extends Locators<BasicEnvInfo> {
27+
export class ExtensionLocators extends Locators<BasicEnvInfo> implements IEnvProvider {
2228
constructor(
2329
// These are expected to be low-level locators (e.g. system).
2430
private nonWorkspace: ILocator<BasicEnvInfo>[],
@@ -37,12 +43,11 @@ export class ExtensionLocators extends Locators<BasicEnvInfo> {
3743
return combineIterators(iterators);
3844
}
3945

40-
public addNewLocator(locatorFactory: ILocatorFactory, isWorkspace: boolean): void {
41-
if (isWorkspace) {
42-
this.workspace.addNewLocator(locatorFactory);
43-
}
44-
if (!isWorkspace) {
46+
public addNewLocator(locatorFactory: ILocatorFactory): void {
47+
if (IsNonWorkspaceLocatorFactory(locatorFactory)) {
4548
this.nonWorkspace = [...this.nonWorkspace, new CustomLocator(locatorFactory())];
49+
} else {
50+
this.workspace.addNewLocator(locatorFactory);
4651
}
4752
}
4853
}
@@ -145,7 +150,7 @@ export class WorkspaceLocators extends LazyResourceBasedLocator<BasicEnvInfo> {
145150
);
146151
}
147152

148-
public addNewLocator(locatorFactory: ILocatorFactory): void {
153+
public addNewLocator(locatorFactory: IWorkspaceLocatorFactory): void {
149154
Object.keys(this.roots).forEach((key) => {
150155
const root = this.roots[key];
151156
const newLocator = locatorFactory(root.fsPath);

0 commit comments

Comments
 (0)