Skip to content

Commit 7c06c11

Browse files
flying-sheepCopilot
andauthored
fix: try extensionId first in register{Environment,Package}Manager (microsoft#1484)
Fixes microsoft#1483 This improves both debug and production behavior as it no longer relies on fragile stack walking (e.g. if one extension ID is a substring of another, the stack walking could fail) cc @StellaHuang95 --------- Co-authored-by: Copilot <copilot@github.com>
1 parent 6b40729 commit 7c06c11

3 files changed

Lines changed: 24 additions & 28 deletions

File tree

api/src/main.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -896,9 +896,8 @@ export interface PythonEnvironmentManagerRegistrationApi {
896896
*
897897
* @param manager Environment Manager implementation to register.
898898
* @param options Optional registration options.
899-
* @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
900-
* automatic extension detection fails, such as during F5 debugging where the extension's file path
901-
* does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
899+
* @param options.extensionId The extension ID of the calling extension. When this is not specified,
900+
* or when the specified extension cannot be found, the extension ID will be automatically detected.
902901
* @returns A disposable that can be used to unregister the environment manager.
903902
* @see {@link EnvironmentManager}
904903
*/
@@ -1005,9 +1004,8 @@ export interface PythonPackageManagerRegistrationApi {
10051004
*
10061005
* @param manager Package Manager implementation to register.
10071006
* @param options Optional registration options.
1008-
* @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
1009-
* automatic extension detection fails, such as during F5 debugging where the extension's file path
1010-
* does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
1007+
* @param options.extensionId The extension ID of the calling extension. When this is not specified,
1008+
* or when the specified extension cannot be found, the extension ID will be automatically detected.
10111009
* @returns A disposable that can be used to unregister the package manager.
10121010
* @see {@link PackageManager}
10131011
*/

src/api.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import {
4+
import type {
55
Disposable,
66
Event,
77
FileChangeType,
@@ -890,9 +890,8 @@ export interface PythonEnvironmentManagerRegistrationApi {
890890
*
891891
* @param manager Environment Manager implementation to register.
892892
* @param options Optional registration options.
893-
* @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
894-
* automatic extension detection fails, such as during F5 debugging where the extension's file path
895-
* does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
893+
* @param options.extensionId The extension ID of the calling extension. When this is not specified,
894+
* or when the specified extension cannot be found, the extension ID will be automatically detected.
896895
* @returns A disposable that can be used to unregister the environment manager.
897896
* @see {@link EnvironmentManager}
898897
*/
@@ -999,9 +998,8 @@ export interface PythonPackageManagerRegistrationApi {
999998
*
1000999
* @param manager Package Manager implementation to register.
10011000
* @param options Optional registration options.
1002-
* @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
1003-
* automatic extension detection fails, such as during F5 debugging where the extension's file path
1004-
* does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
1001+
* @param options.extensionId The extension ID of the calling extension. When this is not specified,
1002+
* or when the specified extension cannot be found, the extension ID will be automatically detected.
10051003
* @returns A disposable that can be used to unregister the package manager.
10061004
* @see {@link PackageManager}
10071005
*/

src/common/utils/frameUtils.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,28 @@ function getFrameData(): FrameData[] {
2222
}
2323

2424
function getPathFromFrame(frame: FrameData): string {
25-
if (frame.filePath && frame.filePath.startsWith('file://')) {
25+
if (frame.filePath?.startsWith('file://')) {
2626
return Uri.parse(frame.filePath).fsPath;
2727
}
2828
return frame.filePath;
2929
}
3030

31-
export function getCallingExtension(extensionIdHint?: string): string {
31+
export function getCallingExtension(extensionId?: string): string {
3232
const pythonExts = [ENVS_EXTENSION_ID, PYTHON_EXTENSION_ID];
3333
const extensions = allExtensions();
34+
35+
// Use the provided extensionId when available.
36+
// Only accept if it matches an actually loaded extension so we can always return something.
37+
if (extensionId) {
38+
const hintExt = extensions.find((ext) => ext.id === extensionId);
39+
if (hintExt) {
40+
traceVerbose(`Using provided extensionId: ${extensionId}`);
41+
return extensionId;
42+
}
43+
traceWarn(`Provided extensionId '${extensionId}' not found in loaded extensions, ignoring`);
44+
}
45+
46+
// Search the stack as a fallback when no extensionId is provided
3447
const otherExts = extensions.filter((ext) => !pythonExts.includes(ext.id));
3548
const frames = getFrameData();
3649

@@ -94,19 +107,6 @@ export function getCallingExtension(extensionIdHint?: string): string {
94107
}
95108
}
96109

97-
// Use the provided extensionId hint as a fallback (e.g., during F5 debugging where
98-
// stack-based detection fails because the file path doesn't contain the extension ID).
99-
// Only accept the hint if it matches an actually loaded extension for safety.
100-
if (extensionIdHint) {
101-
const hintExt = extensions.find((ext) => ext.id === extensionIdHint);
102-
if (hintExt) {
103-
traceVerbose(`Using provided extensionId hint: ${extensionIdHint}`);
104-
extensionIdCache.set(cacheKey, extensionIdHint);
105-
return extensionIdHint;
106-
}
107-
traceWarn(`Provided extensionId hint '${extensionIdHint}' not found in loaded extensions, ignoring`);
108-
}
109-
110110
// Fallback - we're likely being called from Python extension or built-in managers
111111
traceWarn(
112112
`Could not determine calling extension from stack frames. ` +

0 commit comments

Comments
 (0)