Skip to content

Commit 3e509b8

Browse files
author
Kartik Raj
committed
Add API to contribute a new locator
1 parent 65852fa commit 3e509b8

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

src/client/pythonEnvironments/base/locators.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
import { chain } from '../../common/utils/async';
55
import { Disposables } from '../../common/utils/resourceLifecycle';
6-
import { PythonEnvInfo } from './info';
76
import {
7+
BasicEnvInfo,
88
ILocator,
99
IPythonEnvsIterator,
1010
isProgressEvent,
@@ -59,10 +59,10 @@ export function combineIterators<I>(iterators: IPythonEnvsIterator<I>[]): IPytho
5959
*
6060
* Events and iterator results are combined.
6161
*/
62-
export class Locators<I = PythonEnvInfo> extends PythonEnvsWatchers implements ILocator<I> {
62+
export class Locators<I = BasicEnvInfo> extends PythonEnvsWatchers implements ILocator<I> {
6363
constructor(
6464
// The locators will be watched as well as iterated.
65-
private readonly locators: ReadonlyArray<ILocator<I>>,
65+
private locators: ILocator<I>[],
6666
) {
6767
super(locators);
6868
}
@@ -71,4 +71,9 @@ export class Locators<I = PythonEnvInfo> extends PythonEnvsWatchers implements I
7171
const iterators = this.locators.map((loc) => loc.iterEnvs(query));
7272
return combineIterators(iterators);
7373
}
74+
75+
public addLocator(locator: ILocator<I>): void {
76+
this.locators = [...this.locators, locator];
77+
this.addWatcher(locator);
78+
}
7479
}

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

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,48 @@
33

44
// eslint-disable-next-line max-classes-per-file
55
import { Uri } from 'vscode';
6+
import { ILocatorClass } from '../../../apiTypes';
67
import { IDisposable } from '../../../common/types';
78
import { iterEmpty } from '../../../common/utils/async';
89
import { getURIFilter } from '../../../common/utils/misc';
910
import { Disposables } from '../../../common/utils/resourceLifecycle';
11+
import { CustomLocator } from '../../converter';
1012
import { PythonEnvInfo } from '../info';
11-
import { ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
13+
import { BasicEnvInfo, ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
1214
import { combineIterators, Locators } from '../locators';
1315
import { LazyResourceBasedLocator } from './common/resourceBasedLocator';
1416

1517
/**
1618
* A wrapper around all locators used by the extension.
1719
*/
1820

19-
export class ExtensionLocators<I = PythonEnvInfo> extends Locators<I> {
21+
export class ExtensionLocators extends Locators<BasicEnvInfo> {
2022
constructor(
2123
// These are expected to be low-level locators (e.g. system).
22-
private readonly nonWorkspace: ILocator<I>[],
24+
private nonWorkspace: ILocator<BasicEnvInfo>[],
2325
// This is expected to be a locator wrapping any found in
2426
// the workspace (i.e. WorkspaceLocators).
25-
private readonly workspace: ILocator<I>,
27+
private workspace: WorkspaceLocators,
2628
) {
2729
super([...nonWorkspace, workspace]);
2830
}
2931

30-
public iterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<I> {
31-
const iterators: IPythonEnvsIterator<I>[] = [this.workspace.iterEnvs(query)];
32+
public iterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<BasicEnvInfo> {
33+
const iterators: IPythonEnvsIterator<BasicEnvInfo>[] = [this.workspace.iterEnvs(query)];
3234
if (!query?.searchLocations?.doNotIncludeNonRooted) {
3335
iterators.push(...this.nonWorkspace.map((loc) => loc.iterEnvs(query)));
3436
}
3537
return combineIterators(iterators);
3638
}
39+
40+
public addNewLocator(LocatorClass: ILocatorClass, isWorkspace: boolean): void {
41+
if (isWorkspace) {
42+
this.workspace.addNewLocator(LocatorClass);
43+
}
44+
if (!isWorkspace) {
45+
this.nonWorkspace = [...this.nonWorkspace, new CustomLocator(new LocatorClass())];
46+
}
47+
}
3748
}
3849
type WorkspaceLocatorFactoryResult<I> = ILocator<I> & Partial<IDisposable>;
3950
type WorkspaceLocatorFactory<I = PythonEnvInfo> = (root: Uri) => WorkspaceLocatorFactoryResult<I>[];
@@ -52,12 +63,15 @@ type WatchRootsFunc = (args: WatchRootsArgs) => IDisposable;
5263
* The factories are used to produce the locators for each workspace folder.
5364
*/
5465

55-
export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocator<I> {
56-
private readonly locators: Record<RootURI, [ILocator<I>, IDisposable]> = {};
66+
export class WorkspaceLocators extends LazyResourceBasedLocator<BasicEnvInfo> {
67+
private readonly locators: Record<RootURI, [Locators<BasicEnvInfo>, IDisposable]> = {};
5768

5869
private readonly roots: Record<RootURI, Uri> = {};
5970

60-
constructor(private readonly watchRoots: WatchRootsFunc, private readonly factories: WorkspaceLocatorFactory<I>[]) {
71+
constructor(
72+
private readonly watchRoots: WatchRootsFunc,
73+
private readonly factory: WorkspaceLocatorFactory<BasicEnvInfo>,
74+
) {
6175
super();
6276
}
6377

@@ -69,7 +83,7 @@ export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocat
6983
roots.forEach((root) => this.removeRoot(root));
7084
}
7185

72-
protected doIterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<I> {
86+
protected doIterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<BasicEnvInfo> {
7387
const iterators = Object.keys(this.locators).map((key) => {
7488
if (query?.searchLocations !== undefined) {
7589
const root = this.roots[key];
@@ -78,7 +92,7 @@ export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocat
7892
// Ignore any requests for global envs.
7993
if (!query.searchLocations.roots.some(filter)) {
8094
// This workspace folder did not match the query, so skip it!
81-
return iterEmpty<I>();
95+
return iterEmpty<BasicEnvInfo>();
8296
}
8397
}
8498
// The query matches or was not location-specific.
@@ -107,15 +121,13 @@ export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocat
107121

108122
private addRoot(root: Uri): void {
109123
// Create the root's locator, wrapping each factory-generated locator.
110-
const locators: ILocator<I>[] = [];
124+
const locators: ILocator<BasicEnvInfo>[] = [];
111125
const disposables = new Disposables();
112-
this.factories.forEach((create) => {
113-
create(root).forEach((loc) => {
114-
locators.push(loc);
115-
if (loc.dispose !== undefined) {
116-
disposables.push(loc as IDisposable);
117-
}
118-
});
126+
this.factory(root).forEach((loc) => {
127+
locators.push(loc);
128+
if (loc.dispose !== undefined) {
129+
disposables.push(loc as IDisposable);
130+
}
119131
});
120132
const locator = new Locators(locators);
121133
// Cache it.
@@ -133,6 +145,16 @@ export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocat
133145
);
134146
}
135147

148+
public addNewLocator(LocatorClass: ILocatorClass): void {
149+
Object.keys(this.roots).forEach((key) => {
150+
const root = this.roots[key];
151+
const newLocator = new LocatorClass(root.fsPath);
152+
const convertedLocator: ILocator<BasicEnvInfo> = new CustomLocator(newLocator);
153+
const [locators] = this.locators[key];
154+
locators.addLocator(convertedLocator);
155+
});
156+
}
157+
136158
private removeRoot(root: Uri): void {
137159
const key = root.toString();
138160
const found = this.locators[key];

src/client/pythonEnvironments/base/watchers.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ export class PythonEnvsWatchers implements IPythonEnvsWatcher, IDisposable {
3030
public async dispose(): Promise<void> {
3131
await this.disposables.dispose();
3232
}
33+
34+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
35+
protected addWatcher(w: IPythonEnvsWatcher) {
36+
const disposable = w.onChanged((e) => this.watcher.fire(e));
37+
this.disposables.push(disposable);
38+
}
3339
}

src/client/pythonEnvironments/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ async function createLocator(
106106
// This is shared.
107107
): Promise<IDiscoveryAPI> {
108108
// Create the low-level locators.
109-
let locators: ILocator<BasicEnvInfo> = new ExtensionLocators<BasicEnvInfo>(
109+
let locators: ILocator<BasicEnvInfo> = new ExtensionLocators(
110110
// Here we pull the locators together.
111111
createNonWorkspaceLocators(ext),
112112
createWorkspaceLocator(ext),
@@ -177,10 +177,10 @@ function watchRoots(args: WatchRootsArgs): IDisposable {
177177
});
178178
}
179179

180-
function createWorkspaceLocator(ext: ExtensionState): WorkspaceLocators<BasicEnvInfo> {
181-
const locators = new WorkspaceLocators<BasicEnvInfo>(watchRoots, [
182-
(root: vscode.Uri) => [new WorkspaceVirtualEnvironmentLocator(root.fsPath), new PoetryLocator(root.fsPath)],
183-
// Add an ILocator factory func here for each kind of workspace-rooted locator.
180+
function createWorkspaceLocator(ext: ExtensionState): WorkspaceLocators {
181+
const locators = new WorkspaceLocators(watchRoots, (root: vscode.Uri) => [
182+
new WorkspaceVirtualEnvironmentLocator(root.fsPath),
183+
new PoetryLocator(root.fsPath),
184184
]);
185185
ext.disposables.push(locators);
186186
return locators;

0 commit comments

Comments
 (0)