Skip to content

Commit 5070566

Browse files
authored
Hide progress messages when creating env or installing packages (#25174)
#25143 Hides progress when tools use components from Python extension
1 parent 7d8ac2f commit 5070566

File tree

7 files changed

+111
-61
lines changed

7 files changed

+111
-61
lines changed

src/client/chat/createVirtualEnvTool.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { traceError, traceVerbose, traceWarn } from '../logging';
4343
import { StopWatch } from '../common/utils/stopWatch';
4444
import { useEnvExtension } from '../envExt/api.internal';
4545
import { PythonEnvironment } from '../envExt/types';
46+
import { hideEnvCreation } from '../pythonEnvironments/creation/provider/hideEnvCreation';
4647

4748
interface ICreateVirtualEnvToolParams extends IResourceReference {
4849
packageList?: string[]; // Added only becausewe have ability to create a virtual env with list of packages same tool within the in Python Env extension.
@@ -86,6 +87,7 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
8687
const interpreterPathService = this.serviceContainer.get<IInterpreterPathService>(IInterpreterPathService);
8788
const disposables = new DisposableStore();
8889
try {
90+
disposables.add(hideEnvCreation());
8991
const interpreterChanged = new Promise<void>((resolve) => {
9092
disposables.add(interpreterPathService.onDidChange(() => resolve()));
9193
});

src/client/chat/installPackagesTool.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ export class InstallPackagesTool implements LanguageModelTool<IInstallPackageArg
9393
throw new Error(`Installer ${installerType} not supported for the environment type: ${installerType}`);
9494
}
9595
for (const packageName of options.input.packageList) {
96-
await installer.installModule(packageName, resourcePath, token, undefined, { installAsProcess: true });
96+
await installer.installModule(packageName, resourcePath, token, undefined, {
97+
installAsProcess: true,
98+
hideProgress: true,
99+
});
97100
}
98101
// format and return
99102
const resultMessage = `Successfully installed ${packagePlurality}: ${options.input.packageList.join(', ')}`;

src/client/common/installer/moduleInstaller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
130130
// Display progress indicator if we have ability to cancel this operation from calling code.
131131
// This is required as its possible the installation can take a long time.
132132
// (i.e. if installation takes a long time in terminal or like, a progress indicator is necessary to let user know what is being waited on).
133-
if (cancel) {
133+
if (cancel && !options?.hideProgress) {
134134
const shell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
135135
const options: ProgressOptions = {
136136
location: ProgressLocation.Notification,

src/client/common/installer/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@ export enum ModuleInstallFlags {
8383

8484
export type InstallOptions = {
8585
installAsProcess?: boolean;
86+
hideProgress?: boolean;
8687
};

src/client/pythonEnvironments/creation/provider/condaCreationProvider.ts

Lines changed: 48 additions & 35 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 { CancellationToken, ProgressLocation, WorkspaceFolder } from 'vscode';
4+
import { CancellationToken, CancellationTokenSource, ProgressLocation, WorkspaceFolder } from 'vscode';
55
import * as path from 'path';
66
import { Commands, PVSC_EXTENSION_ID } from '../../../common/constants';
77
import { traceError, traceInfo, traceLog } from '../../../logging';
@@ -35,6 +35,8 @@ import {
3535
CreateEnvironmentResult,
3636
CreateEnvironmentProvider,
3737
} from '../proposed.createEnvApis';
38+
import { shouldDisplayEnvCreationProgress } from './hideEnvCreation';
39+
import { noop } from '../../../common/utils/misc';
3840

3941
function generateCommandArgs(version?: string, options?: CreateEnvironmentOptions): string[] {
4042
let addGitIgnore = true;
@@ -261,6 +263,50 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
261263
}
262264
}
263265

266+
const createEnvInternal = async (progress: CreateEnvironmentProgress, token: CancellationToken) => {
267+
progress.report({
268+
message: CreateEnv.statusStarting,
269+
});
270+
271+
let envPath: string | undefined;
272+
try {
273+
sendTelemetryEvent(EventName.ENVIRONMENT_CREATING, undefined, {
274+
environmentType: 'conda',
275+
pythonVersion: version,
276+
});
277+
if (workspace) {
278+
envPath = await createCondaEnv(
279+
workspace,
280+
getExecutableCommand(conda),
281+
generateCommandArgs(version, options),
282+
progress,
283+
token,
284+
);
285+
286+
if (envPath) {
287+
return { path: envPath, workspaceFolder: workspace };
288+
}
289+
290+
throw new Error('Failed to create conda environment. See Output > Python for more info.');
291+
} else {
292+
throw new Error('A workspace is needed to create conda environment');
293+
}
294+
} catch (ex) {
295+
traceError(ex);
296+
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
297+
return { error: ex as Error };
298+
}
299+
};
300+
301+
if (!shouldDisplayEnvCreationProgress()) {
302+
const token = new CancellationTokenSource();
303+
try {
304+
return await createEnvInternal({ report: noop }, token.token);
305+
} finally {
306+
token.dispose();
307+
}
308+
}
309+
264310
return withProgress(
265311
{
266312
location: ProgressLocation.Notification,
@@ -270,40 +316,7 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
270316
async (
271317
progress: CreateEnvironmentProgress,
272318
token: CancellationToken,
273-
): Promise<CreateEnvironmentResult | undefined> => {
274-
progress.report({
275-
message: CreateEnv.statusStarting,
276-
});
277-
278-
let envPath: string | undefined;
279-
try {
280-
sendTelemetryEvent(EventName.ENVIRONMENT_CREATING, undefined, {
281-
environmentType: 'conda',
282-
pythonVersion: version,
283-
});
284-
if (workspace) {
285-
envPath = await createCondaEnv(
286-
workspace,
287-
getExecutableCommand(conda),
288-
generateCommandArgs(version, options),
289-
progress,
290-
token,
291-
);
292-
293-
if (envPath) {
294-
return { path: envPath, workspaceFolder: workspace };
295-
}
296-
297-
throw new Error('Failed to create conda environment. See Output > Python for more info.');
298-
} else {
299-
throw new Error('A workspace is needed to create conda environment');
300-
}
301-
} catch (ex) {
302-
traceError(ex);
303-
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
304-
return { error: ex as Error };
305-
}
306-
},
319+
): Promise<CreateEnvironmentResult | undefined> => createEnvInternal(progress, token),
307320
);
308321
}
309322

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { Disposable } from 'vscode';
5+
6+
const envCreationTracker: Disposable[] = [];
7+
8+
export function hideEnvCreation(): Disposable {
9+
const disposable = new Disposable(() => {
10+
const index = envCreationTracker.indexOf(disposable);
11+
if (index > -1) {
12+
envCreationTracker.splice(index, 1);
13+
}
14+
});
15+
envCreationTracker.push(disposable);
16+
return disposable;
17+
}
18+
19+
export function shouldDisplayEnvCreationProgress(): boolean {
20+
return envCreationTracker.length === 0;
21+
}

src/client/pythonEnvironments/creation/provider/venvCreationProvider.ts

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33

44
import * as os from 'os';
5-
import { CancellationToken, ProgressLocation, WorkspaceFolder } from 'vscode';
5+
import { CancellationToken, CancellationTokenSource, ProgressLocation, WorkspaceFolder } from 'vscode';
66
import { Commands, PVSC_EXTENSION_ID } from '../../../common/constants';
77
import { createVenvScript } from '../../../common/process/internal/scripts';
88
import { execObservable } from '../../../common/process/rawProcessApis';
@@ -31,6 +31,8 @@ import {
3131
CreateEnvironmentOptions,
3232
CreateEnvironmentResult,
3333
} from '../proposed.createEnvApis';
34+
import { shouldDisplayEnvCreationProgress } from './hideEnvCreation';
35+
import { noop } from '../../../common/utils/misc';
3436

3537
interface IVenvCommandArgs {
3638
argv: string[];
@@ -333,6 +335,36 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
333335
}
334336

335337
const args = generateCommandArgs(installInfo, addGitIgnore);
338+
const createEnvInternal = async (progress: CreateEnvironmentProgress, token: CancellationToken) => {
339+
progress.report({
340+
message: CreateEnv.statusStarting,
341+
});
342+
343+
let envPath: string | undefined;
344+
try {
345+
if (interpreter && workspace) {
346+
envPath = await createVenv(workspace, interpreter, args, progress, token);
347+
if (envPath) {
348+
return { path: envPath, workspaceFolder: workspace };
349+
}
350+
throw new Error('Failed to create virtual environment. See Output > Python for more info.');
351+
}
352+
throw new Error('Failed to create virtual environment. Either interpreter or workspace is undefined.');
353+
} catch (ex) {
354+
traceError(ex);
355+
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
356+
return { error: ex as Error };
357+
}
358+
};
359+
360+
if (!shouldDisplayEnvCreationProgress()) {
361+
const token = new CancellationTokenSource();
362+
try {
363+
return await createEnvInternal({ report: noop }, token.token);
364+
} finally {
365+
token.dispose();
366+
}
367+
}
336368

337369
return withProgress(
338370
{
@@ -343,29 +375,7 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
343375
async (
344376
progress: CreateEnvironmentProgress,
345377
token: CancellationToken,
346-
): Promise<CreateEnvironmentResult | undefined> => {
347-
progress.report({
348-
message: CreateEnv.statusStarting,
349-
});
350-
351-
let envPath: string | undefined;
352-
try {
353-
if (interpreter && workspace) {
354-
envPath = await createVenv(workspace, interpreter, args, progress, token);
355-
if (envPath) {
356-
return { path: envPath, workspaceFolder: workspace };
357-
}
358-
throw new Error('Failed to create virtual environment. See Output > Python for more info.');
359-
}
360-
throw new Error(
361-
'Failed to create virtual environment. Either interpreter or workspace is undefined.',
362-
);
363-
} catch (ex) {
364-
traceError(ex);
365-
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
366-
return { error: ex as Error };
367-
}
368-
},
378+
): Promise<CreateEnvironmentResult | undefined> => createEnvInternal(progress, token),
369379
);
370380
}
371381

0 commit comments

Comments
 (0)