Skip to content

Commit e2332d8

Browse files
committed
Add capability supported helper methods
1 parent 01bc9db commit e2332d8

9 files changed

Lines changed: 73 additions & 65 deletions

File tree

‎src/capabilities.ts‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ export type PackageManagerCapability = (typeof packageCapabilityKeys)[number];
7777
type ManagerCapability = EnvironmentManagerCapability | PackageManagerCapability;
7878

7979
/** General feature support, not a guarantee that a particular operation will succeed. */
80-
export type Support =
81-
| { readonly supported: true }
82-
| { readonly supported: false; readonly reason: string };
80+
export type Support = { readonly supported: true } | { readonly supported: false; readonly reason: string };
8381

8482
/** Context for a support query. Operation arguments and request validation are intentionally excluded. */
8583
export interface CapabilityContext {
@@ -94,6 +92,18 @@ export type CapabilityCheck = (context: CapabilityContext) => Promise<Support>;
9492
/** Every capability key must be advertised as a read-only, noninteractive check; there are no defaults. */
9593
export type Capabilities<C extends ManagerCapability> = Readonly<Record<C, CapabilityCheck>>;
9694

95+
/** A capability check that always reports support. Use for unconditionally supported operations. */
96+
export const supportedCapability: CapabilityCheck = async () => ({ supported: true });
97+
98+
/**
99+
* A capability check that always reports the generic "not implemented" reason. Use when a manager
100+
* has no reason more specific than "unsupported"; otherwise return a custom `{ supported: false, reason }`.
101+
*/
102+
export const unsupportedCapability: CapabilityCheck = async () => ({
103+
supported: false,
104+
reason: l10n.t('Capability not implemented'),
105+
});
106+
97107
/**
98108
* Resolves environment-manager support without invoking the operation or prompting.
99109
* @param manager Manager whose advertised capabilities are queried.

‎src/managers/builtin/inlineScript/envManager.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
ResolveEnvironmentContext,
3333
SetEnvironmentScope,
3434
} from '../../../api';
35-
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability } from '../../../capabilities';
35+
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability, supportedCapability } from '../../../capabilities';
3636
import {
3737
CONDA_MANAGER_ID,
3838
INLINE_SCRIPT_MANAGER_ID,
@@ -288,7 +288,7 @@ export class InlineScriptEnvManager implements EnvironmentManager, Disposable {
288288
supported: false,
289289
reason: l10n.t('Inline-script environments do not support resolving interpreter or environment URIs.'),
290290
}),
291-
'environments.remove': async () => ({ supported: true }),
291+
'environments.remove': supportedCapability,
292292
'environments.remove.headless': async (context) =>
293293
resolveEnvironmentManagerCapability(this, 'environments.remove', context),
294294
'environments.create': async ({ scope }) => {

‎src/managers/builtin/pipPackageManager.ts‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
PythonEnvironment,
2424
PythonEnvironmentApi,
2525
} from '../../api';
26-
import { Capabilities, PackageManagerCapability } from '../../capabilities';
26+
import { Capabilities, PackageManagerCapability, supportedCapability } from '../../capabilities';
2727
import { showErrorMessageWithLogs } from '../../common/errors/utils';
2828
import { PythonVersion } from '../../common/pythonVersion';
2929
import { showErrorMessage, withProgress } from '../../common/window.apis';
@@ -53,15 +53,15 @@ import { VenvManager } from './venvManager';
5353
export class PipPackageManager implements PackageManager, Disposable {
5454
readonly capabilities: Capabilities<PackageManagerCapability> = {
5555
...requiredPackageCapabilities,
56-
'packages.list.skipCache': async () => ({ supported: true }),
57-
'packages.manage.install': async () => ({ supported: true }),
58-
'packages.manage.uninstall': async () => ({ supported: true }),
59-
'packages.manage.upgrade': async () => ({ supported: true }),
60-
'packages.manage.headless': async () => ({ supported: true }),
61-
'packages.manage.showSkipOption': async () => ({ supported: true }),
62-
'packages.availableVersions': async () => ({ supported: true }),
56+
'packages.list.skipCache': supportedCapability,
57+
'packages.manage.install': supportedCapability,
58+
'packages.manage.uninstall': supportedCapability,
59+
'packages.manage.upgrade': supportedCapability,
60+
'packages.manage.headless': supportedCapability,
61+
'packages.manage.showSkipOption': supportedCapability,
62+
'packages.availableVersions': supportedCapability,
6363
// Dependency roots are best-effort classification, not exact user install intent.
64-
'packages.direct': async () => ({ supported: true }),
64+
'packages.direct': supportedCapability,
6565
};
6666

6767
private readonly _onDidChangePackages = new EventEmitter<DidChangePackagesEventArgs>();

‎src/managers/builtin/sysPythonManager.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
ResolveEnvironmentContext,
1818
SetEnvironmentScope,
1919
} from '../../api';
20-
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability } from '../../capabilities';
20+
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability, supportedCapability } from '../../capabilities';
2121
import { SysManagerStrings } from '../../common/localize';
2222
import { createDeferred, Deferred } from '../../common/utils/deferred';
2323
import { normalizePath } from '../../common/utils/pathUtils';
@@ -39,7 +39,7 @@ import { installPythonWithUv, promptInstallPythonViaUv, selectPythonVersionToIns
3939
export class SysPythonManager implements EnvironmentManager {
4040
readonly capabilities: Capabilities<EnvironmentManagerCapability> = {
4141
...requiredEnvironmentCapabilities,
42-
'environments.create': async () => ({ supported: true }),
42+
'environments.create': supportedCapability,
4343
'environments.create.quick': async () => ({
4444
supported: false,
4545
reason: l10n.t('Installing a global Python requires interactive version selection.'),

‎src/managers/builtin/venvManager.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
ResolveEnvironmentContext,
2121
SetEnvironmentScope,
2222
} from '../../api';
23-
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability } from '../../capabilities';
23+
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability, supportedCapability } from '../../capabilities';
2424
import { executeCommand } from '../../common/command.api';
2525
import { PYTHON_EXTENSION_ID } from '../../common/constants';
2626
import { VenvManagerStrings } from '../../common/localize';
@@ -55,12 +55,12 @@ import {
5555
export class VenvManager implements EnvironmentManager {
5656
readonly capabilities: Capabilities<EnvironmentManagerCapability> = {
5757
...requiredEnvironmentCapabilities,
58-
'environments.create': async () => ({ supported: true }),
58+
'environments.create': supportedCapability,
5959
'environments.create.quick': async (context) =>
6060
resolveEnvironmentManagerCapability(this, 'environments.create', context),
6161
'environments.create.additionalPackages': async (context) =>
6262
resolveEnvironmentManagerCapability(this, 'environments.create', context),
63-
'environments.remove': async () => ({ supported: true }),
63+
'environments.remove': supportedCapability,
6464
'environments.remove.headless': async (context) =>
6565
resolveEnvironmentManagerCapability(this, 'environments.remove', context),
6666
};
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import type { Capabilities, EnvironmentManagerCapability, PackageManagerCapability } from '../../capabilities';
4+
import { Capabilities, EnvironmentManagerCapability, PackageManagerCapability, supportedCapability } from '../../capabilities';
55

66
/**
77
* Every environment manager implements these operations; spread into a manager's `capabilities`
8-
* to advertise them without repeating the same `{ supported: true }` checks.
8+
* to advertise them without repeating the same `supportedCapability` checks.
99
*/
1010
export const requiredEnvironmentCapabilities: Pick<
1111
Capabilities<EnvironmentManagerCapability>,
1212
'environments.list' | 'environments.refresh' | 'environments.resolve' | 'environments.getSelected' | 'environments.setSelected'
1313
> = {
14-
'environments.list': async () => ({ supported: true }),
15-
'environments.refresh': async () => ({ supported: true }),
16-
'environments.resolve': async () => ({ supported: true }),
17-
'environments.getSelected': async () => ({ supported: true }),
18-
'environments.setSelected': async () => ({ supported: true }),
14+
'environments.list': supportedCapability,
15+
'environments.refresh': supportedCapability,
16+
'environments.resolve': supportedCapability,
17+
'environments.getSelected': supportedCapability,
18+
'environments.setSelected': supportedCapability,
1919
};
2020

2121
/**
2222
* Every package manager implements these operations; spread into a manager's `capabilities`
23-
* to advertise them without repeating the same `{ supported: true }` checks.
23+
* to advertise them without repeating the same `supportedCapability` checks.
2424
*/
2525
export const requiredPackageCapabilities: Pick<
2626
Capabilities<PackageManagerCapability>,
2727
'packages.list' | 'packages.refresh' | 'packages.manage'
2828
> = {
29-
'packages.list': async () => ({ supported: true }),
30-
'packages.refresh': async () => ({ supported: true }),
31-
'packages.manage': async () => ({ supported: true }),
29+
'packages.list': supportedCapability,
30+
'packages.refresh': supportedCapability,
31+
'packages.manage': supportedCapability,
3232
};

‎src/managers/conda/condaEnvManager.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
ResolveEnvironmentContext,
2020
SetEnvironmentScope,
2121
} from '../../api';
22-
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability } from '../../capabilities';
22+
import { Capabilities, EnvironmentManagerCapability, resolveEnvironmentManagerCapability, supportedCapability } from '../../capabilities';
2323
import { CondaStrings } from '../../common/localize';
2424
import { traceError, traceInfo } from '../../common/logging';
2525
import { StopWatch } from '../../common/stopWatch';
@@ -57,12 +57,12 @@ import {
5757
export class CondaEnvManager implements EnvironmentManager, Disposable {
5858
readonly capabilities: Capabilities<EnvironmentManagerCapability> = {
5959
...requiredEnvironmentCapabilities,
60-
'environments.create': async () => ({ supported: true }),
60+
'environments.create': supportedCapability,
6161
'environments.create.quick': async (context) =>
6262
resolveEnvironmentManagerCapability(this, 'environments.create', context),
6363
'environments.create.additionalPackages': async (context) =>
6464
resolveEnvironmentManagerCapability(this, 'environments.create', context),
65-
'environments.remove': async () => ({ supported: true }),
65+
'environments.remove': supportedCapability,
6666
'environments.remove.headless': async (context) =>
6767
resolveEnvironmentManagerCapability(this, 'environments.remove', context),
6868
};

‎src/managers/conda/condaPackageManager.ts‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
PythonEnvironment,
2424
PythonEnvironmentApi,
2525
} from '../../api';
26-
import { Capabilities, PackageManagerCapability } from '../../capabilities';
26+
import { Capabilities, PackageManagerCapability, supportedCapability } from '../../capabilities';
2727
import { showErrorMessageWithLogs } from '../../common/errors/utils';
2828
import { CondaStrings } from '../../common/localize';
2929
import { withProgress } from '../../common/window.apis';
@@ -44,13 +44,13 @@ import { getCommonCondaPackagesToInstall } from './condaUtils';
4444
export class CondaPackageManager implements PackageManager, Disposable {
4545
readonly capabilities: Capabilities<PackageManagerCapability> = {
4646
...requiredPackageCapabilities,
47-
'packages.list.skipCache': async () => ({ supported: true }),
48-
'packages.manage.install': async () => ({ supported: true }),
49-
'packages.manage.uninstall': async () => ({ supported: true }),
50-
'packages.manage.upgrade': async () => ({ supported: true }),
51-
'packages.manage.headless': async () => ({ supported: true }),
52-
'packages.manage.showSkipOption': async () => ({ supported: true }),
53-
'packages.availableVersions': async () => ({ supported: true }),
47+
'packages.list.skipCache': supportedCapability,
48+
'packages.manage.install': supportedCapability,
49+
'packages.manage.uninstall': supportedCapability,
50+
'packages.manage.upgrade': supportedCapability,
51+
'packages.manage.headless': supportedCapability,
52+
'packages.manage.showSkipOption': supportedCapability,
53+
'packages.availableVersions': supportedCapability,
5454
'packages.direct': async () => ({
5555
supported: false,
5656
reason: l10n.t('Conda does not classify direct and transitive packages.'),

‎src/test/capabilityFixtures.ts‎

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,31 @@
77
* constants into their fake managers instead of repeating the full key list.
88
*/
99

10-
import type { Capabilities, EnvironmentManagerCapability, PackageManagerCapability } from '../capabilities';
11-
12-
const supported = async () => ({ supported: true }) as const;
10+
import { Capabilities, EnvironmentManagerCapability, PackageManagerCapability, supportedCapability } from '../capabilities';
1311

1412
export const allSupportedEnvironmentCapabilities: Capabilities<EnvironmentManagerCapability> = {
15-
'environments.list': supported,
16-
'environments.refresh': supported,
17-
'environments.resolve': supported,
18-
'environments.getSelected': supported,
19-
'environments.setSelected': supported,
20-
'environments.create': supported,
21-
'environments.create.quick': supported,
22-
'environments.create.additionalPackages': supported,
23-
'environments.remove': supported,
24-
'environments.remove.headless': supported,
13+
'environments.list': supportedCapability,
14+
'environments.refresh': supportedCapability,
15+
'environments.resolve': supportedCapability,
16+
'environments.getSelected': supportedCapability,
17+
'environments.setSelected': supportedCapability,
18+
'environments.create': supportedCapability,
19+
'environments.create.quick': supportedCapability,
20+
'environments.create.additionalPackages': supportedCapability,
21+
'environments.remove': supportedCapability,
22+
'environments.remove.headless': supportedCapability,
2523
};
2624

2725
export const allSupportedPackageCapabilities: Capabilities<PackageManagerCapability> = {
28-
'packages.list': supported,
29-
'packages.list.skipCache': supported,
30-
'packages.refresh': supported,
31-
'packages.manage': supported,
32-
'packages.manage.install': supported,
33-
'packages.manage.uninstall': supported,
34-
'packages.manage.upgrade': supported,
35-
'packages.manage.headless': supported,
36-
'packages.manage.showSkipOption': supported,
37-
'packages.direct': supported,
38-
'packages.availableVersions': supported,
26+
'packages.list': supportedCapability,
27+
'packages.list.skipCache': supportedCapability,
28+
'packages.refresh': supportedCapability,
29+
'packages.manage': supportedCapability,
30+
'packages.manage.install': supportedCapability,
31+
'packages.manage.uninstall': supportedCapability,
32+
'packages.manage.upgrade': supportedCapability,
33+
'packages.manage.headless': supportedCapability,
34+
'packages.manage.showSkipOption': supportedCapability,
35+
'packages.direct': supportedCapability,
36+
'packages.availableVersions': supportedCapability,
3937
};

0 commit comments

Comments
 (0)