From 595003df3852329e913f432dc5d239fdb64b3f43 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Tue, 2 Jan 2024 16:34:09 -0800 Subject: [PATCH 01/30] Prepare for 2.0.1 --- sample/package-lock.json | 4 ++-- sample/yarn.lock | 4 ++-- vscode-dotnet-runtime-extension/CHANGELOG.md | 13 +++++++++++++ vscode-dotnet-runtime-extension/package-lock.json | 4 ++-- vscode-dotnet-runtime-extension/package.json | 2 +- vscode-dotnet-sdk-extension/package-lock.json | 4 ++-- vscode-dotnet-sdk-extension/package.json | 2 +- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sample/package-lock.json b/sample/package-lock.json index 405a80ec4a..e5f05d7664 100644 --- a/sample/package-lock.json +++ b/sample/package-lock.json @@ -35,7 +35,7 @@ }, "../vscode-dotnet-runtime-extension": { "name": "vscode-dotnet-runtime", - "version": "2.0.0", + "version": "2.0.1", "license": "MIT", "dependencies": { "axios": "^1.3.4", @@ -128,7 +128,7 @@ } }, "../vscode-dotnet-sdk-extension": { - "version": "2.0.0", + "version": "2.0.1", "license": "MIT", "dependencies": { "@types/chai": "4.2.22", diff --git a/sample/yarn.lock b/sample/yarn.lock index 6943604fb8..036a582564 100644 --- a/sample/yarn.lock +++ b/sample/yarn.lock @@ -1832,7 +1832,7 @@ "vscode-dotnet-runtime@file:../vscode-dotnet-runtime-extension": "resolved" "file:../vscode-dotnet-runtime-extension" - "version" "2.0.0" + "version" "2.0.1" dependencies: "axios" "^1.3.4" "axios-cache-interceptor" "^1.0.1" @@ -1860,7 +1860,7 @@ "vscode-dotnet-sdk@file:../vscode-dotnet-sdk-extension": "resolved" "file:../vscode-dotnet-sdk-extension" - "version" "2.0.0" + "version" "2.0.1" dependencies: "@types/chai" "4.2.22" "@types/chai-as-promised" "^7.1.4" diff --git a/vscode-dotnet-runtime-extension/CHANGELOG.md b/vscode-dotnet-runtime-extension/CHANGELOG.md index 0fd064292d..b604b1f183 100644 --- a/vscode-dotnet-runtime-extension/CHANGELOG.md +++ b/vscode-dotnet-runtime-extension/CHANGELOG.md @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. ## [Unreleased] +## [2.0.1] - 2023-09-18 + +Fixes several key bugs with installing .NET: + +- Ubuntu Installs would fail for the first time on 18.04. +- The extension would print ... forever after installation failure. +- The extension would fail to read Ubuntu directories properly if PMC was installed in certain scenarios. +- GitHub Forms is now added. +- Corrects behavior on our unknown Ubuntu Versions by estimating the correct behavior for known versions. +- Improve timeout error handling +- Catch bug in the caching library we use to prevent it from failing to cache +- Several other key issues. + ## [2.0.0] - 2023-09-18 The '.NET Runtime Install Tool' has been renamed to the '.NET Install Tool.' diff --git a/vscode-dotnet-runtime-extension/package-lock.json b/vscode-dotnet-runtime-extension/package-lock.json index 19c9170317..5086f95b43 100644 --- a/vscode-dotnet-runtime-extension/package-lock.json +++ b/vscode-dotnet-runtime-extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-dotnet-runtime", - "version": "2.0.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-dotnet-runtime", - "version": "2.0.0", + "version": "2.0.1", "license": "MIT", "dependencies": { "axios": "^1.3.4", diff --git a/vscode-dotnet-runtime-extension/package.json b/vscode-dotnet-runtime-extension/package.json index 0c4d18346f..c2b426b46d 100644 --- a/vscode-dotnet-runtime-extension/package.json +++ b/vscode-dotnet-runtime-extension/package.json @@ -13,7 +13,7 @@ "description": "This extension installs and manages different versions of the .NET SDK and Runtime.", "appInsightsKey": "02dc18e0-7494-43b2-b2a3-18ada5fcb522", "icon": "images/dotnetIcon.png", - "version": "2.0.0", + "version": "2.0.1", "publisher": "ms-dotnettools", "engines": { "vscode": "^1.74.0" diff --git a/vscode-dotnet-sdk-extension/package-lock.json b/vscode-dotnet-sdk-extension/package-lock.json index 8711c294e3..32b2bd0789 100644 --- a/vscode-dotnet-sdk-extension/package-lock.json +++ b/vscode-dotnet-sdk-extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-dotnet-sdk", - "version": "2.0.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-dotnet-sdk", - "version": "2.0.0", + "version": "2.0.1", "license": "MIT", "dependencies": { "@types/chai": "4.2.22", diff --git a/vscode-dotnet-sdk-extension/package.json b/vscode-dotnet-sdk-extension/package.json index 7dc9ac279f..5075ba90d9 100644 --- a/vscode-dotnet-sdk-extension/package.json +++ b/vscode-dotnet-sdk-extension/package.json @@ -13,7 +13,7 @@ "description": "This extension installs and manages different versions of the .NET SDK.", "appInsightsKey": "02dc18e0-7494-43b2-b2a3-18ada5fcb522", "icon": "images/dotnetIcon.png", - "version": "2.0.0", + "version": "2.0.1", "publisher": "ms-dotnettools", "engines": { "vscode": "^1.74.0" From 2b8e3fa13732a837073b43651714ce0d5b20ea33 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 10:27:30 -0800 Subject: [PATCH 02/30] Add symlink reading so we can resolve the global path to its true value to tell the install type of msft pmc or distro feed --- .../distro-data/distro-support.json | 16 ++++++++++++++++ .../src/Acquisition/GenericDistroSDKProvider.ts | 14 ++++++++++++++ .../src/Acquisition/IDistroDotnetSDKProvider.ts | 2 ++ .../src/Acquisition/RedHatDistroSDKProvider.ts | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/vscode-dotnet-runtime-library/distro-data/distro-support.json b/vscode-dotnet-runtime-library/distro-data/distro-support.json index a70748fe82..c4df64a12c 100644 --- a/vscode-dotnet-runtime-library/distro-data/distro-support.json +++ b/vscode-dotnet-runtime-library/distro-data/distro-support.json @@ -59,6 +59,14 @@ "commandParts": ["-l", "{packageName}"] } ], + "readSymLinkCommand": + [ + { + "runUnderSudo": false, + "commandRoot": "readlink", + "commandParts": ["-f", "{path}"] + } + ], "expectedDistroFeedInstallDirectory" : "/usr/lib/dotnet", "expectedMicrosoftFeedInstallDirectory" : "/usr/share/dotnet", "installedSDKVersionsCommand": @@ -255,6 +263,14 @@ ] } ], + "readSymLinkCommand": + [ + { + "runUnderSudo": false, + "commandRoot": "readlink", + "commandParts": ["-f", "{path}"] + } + ], "expectedDistroFeedInstallDirectory": "/usr/lib64/dotnet/dotnet", "expectedMicrosoftFeedInstallDirectory": "", "installedSDKVersionsCommand": [ diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index 2a9070911a..b0198d1023 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -13,6 +13,8 @@ import { IDistroDotnetSDKProvider } from './IDistroDotnetSDKProvider'; export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider { + protected resolvePathAsSymlink = true; + public async installDotnet(fullySpecifiedVersion : string, installType : LinuxInstallType): Promise { await this.injectPMCFeed(fullySpecifiedVersion, installType); @@ -37,6 +39,18 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider { commandResult[0] = commandResult[0].trim(); } + + if(commandResult && this.resolvePathAsSymlink) + { + let symLinkReadCommand = this.myDistroCommands(this.readSymbolicLinkCommandKey); + symLinkReadCommand = CommandExecutor.replaceSubstringsInCommands(symLinkReadCommand, this.missingPathKey, commandResult[0]); + const resolvedPath = (await this.commandRunner.executeMultipleCommands(symLinkReadCommand))[0]; + if(resolvedPath) + { + return resolvedPath.trim(); + } + } + return commandResult[0]; } diff --git a/vscode-dotnet-runtime-library/src/Acquisition/IDistroDotnetSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/IDistroDotnetSDKProvider.ts index 4b3141fcc4..120b936011 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/IDistroDotnetSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/IDistroDotnetSDKProvider.ts @@ -43,6 +43,7 @@ export abstract class IDistroDotnetSDKProvider { protected searchCommandKey = 'searchCommand'; protected updateCommandKey = 'updateCommand'; protected packageLookupCommandKey = 'packageLookupCommand'; + protected readSymbolicLinkCommandKey = 'readSymLinkCommand'; protected currentInstallPathCommandKey = 'currentInstallPathCommand'; protected isInstalledCommandKey = 'isInstalledCommand'; protected expectedMicrosoftFeedInstallDirKey = 'expectedMicrosoftFeedInstallDirectory'; @@ -51,6 +52,7 @@ export abstract class IDistroDotnetSDKProvider { protected installedRuntimeVersionsCommandKey = 'installedRuntimeVersionsCommand'; protected currentInstallVersionCommandKey = 'currentInstallationVersionCommand'; protected missingPackageNameKey = '{packageName}'; + protected missingPathKey = '{path}'; protected distroVersionsKey = 'versions'; protected versionKey = 'version'; diff --git a/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts index 5d33acd437..4580ce6c0d 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts @@ -3,12 +3,22 @@ * The .NET Foundation licenses this file to you under the MIT license. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ +import { ICommandExecutor } from '../Utils/ICommandExecutor'; +import { IUtilityContext } from '../Utils/IUtilityContext'; import { GenericDistroSDKProvider } from './GenericDistroSDKProvider'; +import { IAcquisitionWorkerContext } from './IAcquisitionWorkerContext'; import { LinuxInstallType } from './LinuxInstallType'; +import { DistroVersionPair } from './LinuxVersionResolver'; /* tslint:disable:no-any */ export class RedHatDistroSDKProvider extends GenericDistroSDKProvider { + constructor(distroVersion : DistroVersionPair, context : IAcquisitionWorkerContext, utilContext : IUtilityContext, executor : ICommandExecutor | null = null) + { + super(distroVersion, context, utilContext, executor); + this.resolvePathAsSymlink = false; + } + protected myVersionDetails() : any { const distroVersions = this.distroJson[this.distroVersion.distro][this.distroVersionsKey]; From 45d8df923dc2040a4baf4b884f3e7f572395e69a Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 11:13:38 -0800 Subject: [PATCH 03/30] expect symlink on ubuntu test only --- .../src/test/unit/LinuxDistroTests.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts b/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts index 61ae4af852..43bebe2452 100644 --- a/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts +++ b/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts @@ -104,7 +104,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`; if(shouldRun) { await provider.getInstalledGlobalDotnetPathIfExists(installType); - assert.equal(mockExecutor.attemptedCommand, 'which dotnet'); + assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet'); } }).timeout(standardTimeoutTime); From 058f56ec4ca0cf169b4f44ec2dab692255461653 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 11:19:58 -0800 Subject: [PATCH 04/30] dotnet/dotnet is the resolved path, which is expected. use the root dir instead for install comparison --- .../src/Acquisition/GenericDistroSDKProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index b0198d1023..4d26a9ad78 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -47,7 +47,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider const resolvedPath = (await this.commandRunner.executeMultipleCommands(symLinkReadCommand))[0]; if(resolvedPath) { - return resolvedPath.trim(); + return path.dirname(resolvedPath.trim()); } } From 83d2d7d8efc7b2d7fda20103bb535a8d7a7512fc Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 11:32:41 -0800 Subject: [PATCH 05/30] Sanitize extension name to match vscode sudo prompt name requirements --- vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts index 7d98b3bb49..344c463210 100644 --- a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts +++ b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts @@ -86,7 +86,9 @@ Please install the .NET SDK manually by following https://learn.microsoft.com/en return new Promise((resolve, reject) => { // The '.' character is not allowed for sudo-prompt so we use 'NET' - const options = { name: `${this.context?.acquisitionContext?.requestingExtensionId} On behalf of NET Install Tool` }; + let sanitizedCallerName = this.context?.acquisitionContext?.requestingExtensionId?.replace(/[^0-9a-z]/gi, ''); // Remove non-alphanumerics per OS requirements + sanitizedCallerName = sanitizedCallerName?.substring(0, 69); // 70 Characters is the maximum limit we can use for the prompt. + const options = { name: `${sanitizedCallerName ?? '.NET Install Tool'}` }; exec((fullCommandString), options, (error?: any, stdout?: any, stderr?: any) => { let commandResultString = ''; From e626f291e36cbcc14a82bc3b98816ede77be1d05 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 13:24:43 -0800 Subject: [PATCH 06/30] improve logic for detecting update and add update msg --- .../src/Acquisition/LinuxVersionResolver.ts | 12 ++++++++++-- .../src/EventStream/EventStreamEvents.ts | 4 ++++ .../src/EventStream/EventType.ts | 1 + .../src/EventStream/OutputChannelObserver.ts | 5 +++++ .../src/Utils/CommandExecutor.ts | 2 ++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 71762baa5c..1814e963ac 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -9,7 +9,8 @@ import { DotnetAcquisitionDistroUnknownError, DotnetConflictingLinuxInstallTypesError, - DotnetCustomLinuxInstallExistsError + DotnetCustomLinuxInstallExistsError, + DotnetUpgradedEvent } from '../EventStream/EventStreamEvents'; import { GenericDistroSDKProvider } from './GenericDistroSDKProvider' import { VersionResolver } from './VersionResolver'; @@ -67,6 +68,7 @@ export class LinuxVersionResolver protected distroSDKProvider : IDistroDotnetSDKProvider | null = null; protected commandRunner : ICommandExecutor; protected versionResolver : VersionResolver; + public okUpdateExitCode = 11188; // Arbitrary number that is not shared or used by other things we rely on as an exit code public conflictingInstallErrorMessage = `A dotnet installation was found which indicates dotnet that was installed via Microsoft package feeds. But for this distro and version, we only acquire .NET via the distro feeds. You should not mix distro feed and microsoft feed installations. To continue, please completely remove this version of dotnet to continue by following https://learn.microsoft.com/dotnet/core/install/remove-runtime-sdk-versions?pivots=os-linux. @@ -272,7 +274,9 @@ export class LinuxVersionResolver Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion))) { // We can update instead of doing an install - return (await this.distroSDKProvider!.upgradeDotnet(existingGlobalInstallSDKVersion, 'sdk')) ? '1' : '1'; + this.acquisitionContext.eventStream.post(new DotnetUpgradedEvent( + `.NET was updated by the .NET Install Tool from ${existingGlobalInstallSDKVersion} to ${fullySpecifiedDotnetVersion}, or the newest available package in the feed.`)); + return (await this.distroSDKProvider!.upgradeDotnet(existingGlobalInstallSDKVersion, 'sdk')) === '0' ? this.okUpdateExitCode : '1'; } else { @@ -310,6 +314,10 @@ export class LinuxVersionResolver { return await this.distroSDKProvider!.installDotnet(fullySpecifiedDotnetVersion, 'sdk') ? '0' : '1'; } + else if(updateOrRejectState === String(this.okUpdateExitCode)) + { + return '0'; + } return updateOrRejectState; } diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index ca02bff77b..72629c309b 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -521,6 +521,10 @@ export class CommandExecutionEvent extends DotnetCustomMessageEvent { public readonly eventName = 'CommandExecutionEvent'; } +export class CommandExecutionUserAskDialogueEvent extends DotnetCustomMessageEvent { + public readonly eventName = 'CommandExecutionUserAskDialogueEvent'; +} + export class CommandExecutionUserCompletedDialogueEvent extends DotnetCustomMessageEvent { public readonly eventName = 'CommandExecutionUserCompletedDialogueEvent'; } diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventType.ts b/vscode-dotnet-runtime-library/src/EventStream/EventType.ts index 69b1908c32..34916be58a 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventType.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventType.ts @@ -16,5 +16,6 @@ export enum EventType { DotnetAcquisitionInProgress, DotnetDebuggingMessage, DotnetTotalSuccessEvent, + DotnetUpgradedEvent, SuppressedAcquisitionError, } diff --git a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts index cd8e0113dc..a4f230af67 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts @@ -12,6 +12,7 @@ import { DotnetAcquisitionVersionError, DotnetDebuggingMessage, DotnetExistingPathResolutionCompleted, + DotnetUpgradedEvent, } from './EventStreamEvents'; import { EventType } from './EventType'; import { IEvent } from './IEvent'; @@ -116,6 +117,10 @@ export class OutputChannelObserver implements IEventStreamObserver { this.stopDownloadIndicator(); } break; + case EventType.DotnetUpgradedEvent: + const upgradeMessage = event as DotnetUpgradedEvent; + this.outputChannel.appendLine(`${upgradeMessage.eventMessage}:`); + break; case EventType.DotnetDebuggingMessage: const loggedMessage = event as DotnetDebuggingMessage; this.outputChannel.appendLine(loggedMessage.message); diff --git a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts index 344c463210..cd97fbfbd2 100644 --- a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts +++ b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts @@ -89,6 +89,8 @@ Please install the .NET SDK manually by following https://learn.microsoft.com/en let sanitizedCallerName = this.context?.acquisitionContext?.requestingExtensionId?.replace(/[^0-9a-z]/gi, ''); // Remove non-alphanumerics per OS requirements sanitizedCallerName = sanitizedCallerName?.substring(0, 69); // 70 Characters is the maximum limit we can use for the prompt. const options = { name: `${sanitizedCallerName ?? '.NET Install Tool'}` }; + + this.context?.eventStream.post(new CommandExecutionUserAskDialogueEvent(`Prompting user for command ${fullCommandString} under sudo.`)); exec((fullCommandString), options, (error?: any, stdout?: any, stderr?: any) => { let commandResultString = ''; From 03d7a78def281d0739e7414357bccd3771751b59 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 13:30:59 -0800 Subject: [PATCH 07/30] Improve logging messages so we can tell if users click thru the sudo prompts --- .../src/Acquisition/DotnetCoreAcquisitionWorker.ts | 2 +- .../src/Acquisition/LinuxVersionResolver.ts | 2 +- .../src/EventStream/EventStreamEvents.ts | 4 ++++ vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/DotnetCoreAcquisitionWorker.ts b/vscode-dotnet-runtime-library/src/Acquisition/DotnetCoreAcquisitionWorker.ts index 98695ba7ba..e3268dc81b 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/DotnetCoreAcquisitionWorker.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/DotnetCoreAcquisitionWorker.ts @@ -308,7 +308,7 @@ export class DotnetCoreAcquisitionWorker implements IDotnetCoreAcquisitionWorker this.context.eventStream.post(new DotnetBeginGlobalInstallerExecution(`Beginning to run installer for ${installKey} in ${os.platform()}.`)) const installerResult = await installer.installSDK(); - this.context.eventStream.post(new DotnetCompletedGlobalInstallerExecution(`Beginning to run installer for ${installKey} in ${os.platform()}.`)) + this.context.eventStream.post(new DotnetCompletedGlobalInstallerExecution(`Completed installer for ${installKey} in ${os.platform()}.`)) if(installerResult !== '0') { diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 1814e963ac..7982d3ddf8 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -318,7 +318,7 @@ export class LinuxVersionResolver { return '0'; } - return updateOrRejectState; + return String(updateOrRejectState); } /** diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index 72629c309b..141eb3c30a 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -537,6 +537,10 @@ export class DotnetVersionParseEvent extends DotnetCustomMessageEvent { public readonly eventName = 'DotnetVersionParseEvent'; } +export class DotnetUpgradedEvent extends DotnetCustomMessageEvent { + public readonly eventName = 'DotnetUpgradedEvent'; +} + export abstract class DotnetFileEvent extends DotnetAcquisitionMessage { constructor(public readonly eventMessage: string, public readonly time: string, public readonly file: string) { super(); } diff --git a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts index cd97fbfbd2..6dab55b410 100644 --- a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts +++ b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts @@ -17,6 +17,7 @@ import { CommandExecutionStdError, CommandExecutionStdOut, CommandExecutionUnderSudoEvent, + CommandExecutionUserAskDialogueEvent, CommandExecutionUserCompletedDialogueEvent, DotnetAlternativeCommandFoundEvent, DotnetCommandNotFoundEvent, From 0cc90b707e4fb38ecf12ad2a3e6b869a34e2bc36 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 13:40:55 -0800 Subject: [PATCH 08/30] capture update stauts instead of output --- .../src/Acquisition/GenericDistroSDKProvider.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index 4d26a9ad78..c4bbe1d800 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -77,11 +77,15 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider public async upgradeDotnet(versionToUpgrade : string, installType : LinuxInstallType): Promise { + const oldReturnStatusSetting = this.commandRunner.returnStatus; + this.commandRunner.returnStatus = true; + let command = this.myDistroCommands(this.updateCommandKey); const sdkPackage = await this.myDotnetVersionPackageName(versionToUpgrade, installType); command = CommandExecutor.replaceSubstringsInCommands(command, this.missingPackageNameKey, sdkPackage); const commandResult = (await this.commandRunner.executeMultipleCommands(command))[0]; + this.commandRunner.returnStatus = oldReturnStatusSetting; return commandResult[0]; } From abc5f1e1de286fcee868c6ee967505ad4f1290a2 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 13:54:54 -0800 Subject: [PATCH 09/30] Make update message show up only if updating not if we are repaiting packages --- .../src/Acquisition/LinuxVersionResolver.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 7982d3ddf8..9826c86278 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -252,7 +252,7 @@ export class LinuxVersionResolver * @returns 0 if we can proceed. Will throw if a conflicting install exists. If we can update, it will do the update and return 1. * A string is returned in case we want to make this return more info about the update. */ - private async UpdateOrRejectIfVersionRequestDoesNotRequireInstall(fullySpecifiedDotnetVersion : string, existingInstall : string | null) + private async UpdateOrRejectIfVersionRequestDoesNotRequireInstall(fullySpecifiedDotnetVersion : string, existingInstall : string | null) : Promise { await this.Initialize(); @@ -262,6 +262,8 @@ export class LinuxVersionResolver if(existingGlobalInstallSDKVersion && Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) === Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion))) { + const isPatchUpgrade = Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion)); + if(Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion))) { // We shouldn't downgrade to a lower patch @@ -270,13 +272,15 @@ export class LinuxVersionResolver this.acquisitionContext.eventStream.post(err); throw err.error; } - else if(await this.distroSDKProvider!.dotnetPackageExistsOnSystem(fullySpecifiedDotnetVersion, 'sdk') || - Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion))) + else if(await this.distroSDKProvider!.dotnetPackageExistsOnSystem(fullySpecifiedDotnetVersion, 'sdk') || isPatchUpgrade) { // We can update instead of doing an install this.acquisitionContext.eventStream.post(new DotnetUpgradedEvent( - `.NET was updated by the .NET Install Tool from ${existingGlobalInstallSDKVersion} to ${fullySpecifiedDotnetVersion}, or the newest available package in the feed.`)); - return (await this.distroSDKProvider!.upgradeDotnet(existingGlobalInstallSDKVersion, 'sdk')) === '0' ? this.okUpdateExitCode : '1'; + isPatchUpgrade ? + `Updating .NET: Current Version: ${existingGlobalInstallSDKVersion} to ${fullySpecifiedDotnetVersion}.` + : + `Repairing .NET Packages for ${existingGlobalInstallSDKVersion}.`)); + return (await this.distroSDKProvider!.upgradeDotnet(existingGlobalInstallSDKVersion, 'sdk')) === '0' ? String(this.okUpdateExitCode) : '1'; } else { From 77ee7245523f779685f1fcf6ecbdc833f0c59420 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 14:08:22 -0800 Subject: [PATCH 10/30] Explicitly add event stream to clarify constructor args --- vscode-dotnet-runtime-extension/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-extension/src/extension.ts b/vscode-dotnet-runtime-extension/src/extension.ts index 43f4753028..a9ee32295f 100644 --- a/vscode-dotnet-runtime-extension/src/extension.ts +++ b/vscode-dotnet-runtime-extension/src/extension.ts @@ -254,7 +254,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE return { storagePath: context.globalStoragePath, extensionState: context.globalState, - eventStream, + eventStream: eventStream, installationValidator: new InstallationValidator(eventStream), timeoutSeconds: resolvedTimeoutSeconds, installDirectoryProvider: isRuntimeInstall ? new RuntimeInstallationDirectoryProvider(context.globalStoragePath): new SdkInstallationDirectoryProvider(context.globalStoragePath), From 0067911da4c77438164f82d90fe72bfbef7b6182 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 14:17:43 -0800 Subject: [PATCH 11/30] add a log message for when we start running install validation on linux --- .../src/Acquisition/LinuxVersionResolver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 9826c86278..232ea162d1 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -256,6 +256,7 @@ export class LinuxVersionResolver { await this.Initialize(); + this.acquisitionContext.eventStream.post(new DotnetInstallLinuxChecks(`Checking to see if we should install, update, or cancel...`)); if(existingInstall) { const existingGlobalInstallSDKVersion = await this.distroSDKProvider!.getInstalledGlobalDotnetVersionIfExists(); From 30fbdca9edaf857f6ad09ecc0db219673e79d5e8 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 14:19:07 -0800 Subject: [PATCH 12/30] Add InstallLinuxChecksEvent (I forgot to save lol) --- .../src/Acquisition/LinuxVersionResolver.ts | 1 + .../src/EventStream/EventStreamEvents.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 232ea162d1..bbd250a4a2 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -10,6 +10,7 @@ import DotnetAcquisitionDistroUnknownError, DotnetConflictingLinuxInstallTypesError, DotnetCustomLinuxInstallExistsError, + DotnetInstallLinuxChecks, DotnetUpgradedEvent } from '../EventStream/EventStreamEvents'; import { GenericDistroSDKProvider } from './GenericDistroSDKProvider' diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index 141eb3c30a..b334cfc838 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -541,6 +541,10 @@ export class DotnetUpgradedEvent extends DotnetCustomMessageEvent { public readonly eventName = 'DotnetUpgradedEvent'; } +export class DotnetInstallLinuxChecks extends DotnetCustomMessageEvent { + public readonly eventName = 'DotnetInstallLinuxChecks'; +} + export abstract class DotnetFileEvent extends DotnetAcquisitionMessage { constructor(public readonly eventMessage: string, public readonly time: string, public readonly file: string) { super(); } From 5198673f27d66012f02b885ddc7468d0f6bb44c1 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 14:35:05 -0800 Subject: [PATCH 13/30] DO not allow feature band downgrades --- .../src/Acquisition/LinuxVersionResolver.ts | 3 ++- .../src/EventStream/EventStreamEvents.ts | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index bbd250a4a2..112b5f8a7d 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -266,7 +266,8 @@ export class LinuxVersionResolver { const isPatchUpgrade = Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion)); - if(Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion))) + if(Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion)) + || Number(this.versionResolver.getFeatureBandFromVersion(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getFeatureBandFromVersion(fullySpecifiedDotnetVersion))) { // We shouldn't downgrade to a lower patch const err = new DotnetCustomLinuxInstallExistsError(new Error(`An installation of ${fullySpecifiedDotnetVersion} was requested but ${existingGlobalInstallSDKVersion} is already available.`), diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index b334cfc838..fa3f7c430c 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -402,7 +402,7 @@ export class DotnetExistingPathResolutionCompleted extends DotnetAcquisitionSucc } export abstract class DotnetAcquisitionMessage extends IEvent { - public readonly type = EventType.DotnetAcquisitionMessage; + public type = EventType.DotnetAcquisitionMessage; public getProperties(): { [key: string]: string } | undefined { return undefined; @@ -539,6 +539,11 @@ export class DotnetVersionParseEvent extends DotnetCustomMessageEvent { export class DotnetUpgradedEvent extends DotnetCustomMessageEvent { public readonly eventName = 'DotnetUpgradedEvent'; + constructor(eventMsg : string) + { + super(eventMsg); + this.type = EventType.DotnetUpgradedEvent; + } } export class DotnetInstallLinuxChecks extends DotnetCustomMessageEvent { From 8a8f367cc036cd2c00ec6ded115e367fe45fd6cc Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 15:02:14 -0800 Subject: [PATCH 14/30] Add telemetry to tell if the user did not ever interact with the installer: --- .../src/Acquisition/WinMacGlobalInstaller.ts | 8 ++++++++ .../src/EventStream/EventStreamEvents.ts | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts index 9d6a8e4302..85ef8cddb2 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts @@ -15,6 +15,8 @@ import { DotnetConflictingGlobalWindowsInstallError, DotnetFileIntegrityCheckEvent, DotnetUnexpectedInstallerOSError, + NetInstallerBeginExecutionEvent, + NetInstallerEndExecutionEvent, OSXOpenNotAvailableError, SuppressedAcquisitionError } from '../EventStream/EventStreamEvents'; @@ -225,9 +227,11 @@ Please correct your PATH variable or make sure the 'open' utility is installed s workingCommand = CommandExecutor.makeCommand(`open`, [`-W`, `${path.resolve(installerPath)}`]); } + this.acquisitionContext.eventStream.post(new NetInstallerBeginExecutionEvent(`The OS X .NET Installer has been launched.`)); const commandResult = await this.commandRunner.execute( workingCommand ); + this.acquisitionContext.eventStream.post(new NetInstallerEndExecutionEvent(`The OS X .NET Installer has closed.`)); this.commandRunner.returnStatus = false; return commandResult[0]; @@ -240,9 +244,13 @@ Please correct your PATH variable or make sure the 'open' utility is installed s { commandOptions = [`/quiet`, `/install`, `/norestart`]; } + + this.acquisitionContext.eventStream.post(new NetInstallerBeginExecutionEvent(`The Windows .NET Installer has been launched.`)); const commandResult = await this.commandRunner.execute( CommandExecutor.makeCommand(command, commandOptions) ); + this.acquisitionContext.eventStream.post(new NetInstallerEndExecutionEvent(`The Windows .NET Installer has closed.`)); + this.commandRunner.returnStatus = false; return commandResult[0]; } diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index fa3f7c430c..a42f6306d0 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -546,6 +546,15 @@ export class DotnetUpgradedEvent extends DotnetCustomMessageEvent { } } +export class NetInstallerBeginExecutionEvent extends DotnetCustomMessageEvent { + public readonly eventName = 'NetInstallerBeginExecutionEvent'; +} + +export class NetInstallerEndExecutionEvent extends DotnetCustomMessageEvent { + public readonly eventName = 'NetInstallerEndExecutionEvent'; +} + + export class DotnetInstallLinuxChecks extends DotnetCustomMessageEvent { public readonly eventName = 'DotnetInstallLinuxChecks'; } From e468c21a087a292b30d0dda316214ec31f92f839 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 15:19:35 -0800 Subject: [PATCH 15/30] Fix bug where api change caused command line exit code parsing to split a string array --- .../src/Acquisition/WinMacGlobalInstaller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts index 85ef8cddb2..f85124eb72 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts @@ -234,7 +234,7 @@ Please correct your PATH variable or make sure the 'open' utility is installed s this.acquisitionContext.eventStream.post(new NetInstallerEndExecutionEvent(`The OS X .NET Installer has closed.`)); this.commandRunner.returnStatus = false; - return commandResult[0]; + return commandResult; } else { @@ -252,7 +252,7 @@ Please correct your PATH variable or make sure the 'open' utility is installed s this.acquisitionContext.eventStream.post(new NetInstallerEndExecutionEvent(`The Windows .NET Installer has closed.`)); this.commandRunner.returnStatus = false; - return commandResult[0]; + return commandResult; } } From 188e53cd4a3e95f0f7bd14af653d637b79c65306 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 15:44:22 -0800 Subject: [PATCH 16/30] Dont count cancelled installs as failures (excluding sudo prompt) --- .../src/Acquisition/WinMacGlobalInstaller.ts | 8 ++++ .../src/EventStream/EventStreamEvents.ts | 36 ++++++++++++++--- .../src/EventStream/EventType.ts | 1 + .../src/EventStream/OutputChannelObserver.ts | 39 ++++++++++++------- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts index f85124eb72..48c61b3d8f 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts @@ -109,6 +109,14 @@ We cannot verify .NET is safe to download at this time. Please try again later.` { return '0'; // These statuses are a success, we don't want to throw. } + else if(installerResult === '1602') + { + // Special code for when user cancels the install + const err = new DotnetInstallCancelledByUserError(new Error( + `The install of .NET was cancelled by the user. Aborting.`), getInstallKeyFromContext(this.acquisitionContext.acquisitionContext)); + this.acquisitionContext.eventStream.post(err); + throw err.error; + } else { return installerResult; diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index a42f6306d0..af448a3970 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -131,6 +131,28 @@ export abstract class DotnetNonAcquisitionError extends IEvent { } } +export abstract class DotnetInstallExpectedAbort extends IEvent { + public readonly type = EventType.DotnetInstallExpectedAbort; + public isError = true; + + /** + * + * @param error The error that triggered, so the call stack, etc. can be analyzed. + * @param installKey For acquisition errors, you MUST include this install key. For commands unrelated to acquiring or managing a specific dotnet version, you + * have the option to leave this parameter null. If it is NULL during acquisition the extension CANNOT properly manage what it has finished installing or not. + */ + constructor(public readonly error: Error, public readonly installKey: string | null) + { + super(); + } + + public getProperties(telemetry = false): { [key: string]: string } | undefined { + return {ErrorName : this.error.name, + ErrorMessage : this.error.message, + StackTrace : this.error.stack ? TelemetryUtilities.HashAllPaths(this.error.stack) : '', + InstallKey : this.installKey ?? 'null'}; + } +} export class SuppressedAcquisitionError extends IEvent { public readonly eventName = 'SuppressedAcquisitionError'; @@ -217,7 +239,7 @@ export class DotnetFeatureBandDoesNotExistError extends DotnetAcquisitionError { public readonly eventName = 'DotnetFeatureBandDoesNotExistError'; } -export class DotnetWSLSecurityError extends DotnetAcquisitionError { +export class DotnetWSLSecurityError extends DotnetInstallExpectedAbort { public readonly eventName = 'DotnetWSLSecurityError'; } @@ -247,10 +269,14 @@ export class DotnetAcquisitionScriptError extends DotnetAcquisitionVersionError public readonly eventName = 'DotnetAcquisitionScriptError'; } -export class DotnetConflictingGlobalWindowsInstallError extends DotnetAcquisitionError { +export class DotnetConflictingGlobalWindowsInstallError extends DotnetInstallExpectedAbort { public readonly eventName = 'DotnetConflictingGlobalWindowsInstallError'; } +export class DotnetInstallCancelledByUserError extends DotnetInstallExpectedAbort { + public readonly eventName = 'DotnetInstallCancelledByUserError'; +} + export class DotnetDebuggingMessage extends IEvent { public readonly eventName = 'DotnetDebuggingMessage'; public readonly type = EventType.DotnetDebuggingMessage; @@ -293,11 +319,11 @@ export class DotnetVersionResolutionError extends DotnetAcquisitionVersionError public readonly eventName = 'DotnetVersionResolutionError'; } -export class DotnetConflictingLinuxInstallTypesError extends DotnetAcquisitionVersionError { +export class DotnetConflictingLinuxInstallTypesError extends DotnetInstallExpectedAbort { public readonly eventName = 'DotnetConflictingLinuxInstallTypesError'; } -export class DotnetCustomLinuxInstallExistsError extends DotnetAcquisitionVersionError { +export class DotnetCustomLinuxInstallExistsError extends DotnetInstallExpectedAbort { public readonly eventName = 'DotnetCustomLinuxInstallExistsError'; } @@ -338,7 +364,7 @@ export class DotnetInstallationValidationError extends DotnetAcquisitionVersionE } } -export class DotnetAcquisitionDistroUnknownError extends DotnetAcquisitionError { +export class DotnetAcquisitionDistroUnknownError extends DotnetInstallExpectedAbort { public readonly eventName = 'DotnetAcquisitionDistroUnknownError'; public getProperties(telemetry = false): { [key: string]: string } | undefined { diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventType.ts b/vscode-dotnet-runtime-library/src/EventStream/EventType.ts index 34916be58a..ac2b4d1907 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventType.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventType.ts @@ -18,4 +18,5 @@ export enum EventType { DotnetTotalSuccessEvent, DotnetUpgradedEvent, SuppressedAcquisitionError, + DotnetInstallExpectedAbort } diff --git a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts index a4f230af67..259fed4974 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts @@ -12,6 +12,7 @@ import { DotnetAcquisitionVersionError, DotnetDebuggingMessage, DotnetExistingPathResolutionCompleted, + DotnetInstallExpectedAbort, DotnetUpgradedEvent, } from './EventStreamEvents'; import { EventType } from './EventType'; @@ -99,23 +100,18 @@ export class OutputChannelObserver implements IEventStreamObserver { case EventType.DotnetAcquisitionError: const error = event as DotnetAcquisitionError; this.outputChannel.appendLine(' Error!'); - if (error instanceof DotnetAcquisitionVersionError) { - this.outputChannel.appendLine(`Failed to download .NET ${error.installKey}:`); - } + this.outputChannel.appendLine(`Failed to download .NET ${error.installKey}:`); this.outputChannel.appendLine(error.error.message); this.outputChannel.appendLine(''); - if(error.installKey && error.installKey !== 'null') - { - this.inProgressVersionDone(error.installKey); - } + this.updateDownloadIndicators(error.installKey); + break; + case EventType.DotnetInstallExpectedAbort: + const abortEvent = event as DotnetInstallExpectedAbort; + this.outputChannel.appendLine(`Cancelled Installation of .NET ${abortEvent.installKey}.`); + this.outputChannel.appendLine(abortEvent.error.message); - if (this.inProgressDownloads.length > 0) { - const errorVersionString = this.inProgressDownloads.join(', '); - this.outputChannel.append(`Still downloading .NET version(s) ${errorVersionString} ...`); - } else { - this.stopDownloadIndicator(); - } + this.updateDownloadIndicators(abortEvent.installKey); break; case EventType.DotnetUpgradedEvent: const upgradeMessage = event as DotnetUpgradedEvent; @@ -132,6 +128,23 @@ export class OutputChannelObserver implements IEventStreamObserver { // Nothing to dispose } + private updateDownloadIndicators(installKey : string | null | undefined) + { + if(installKey && installKey !== 'null') + { + this.inProgressVersionDone(installKey); + } + + if (this.inProgressDownloads.length > 0) + { + const errorVersionString = this.inProgressDownloads.join(', '); + this.outputChannel.append(`Still downloading .NET version(s) ${errorVersionString} ...`); + } + else { + this.stopDownloadIndicator(); + } + } + private startDownloadIndicator() { this.downloadProgressInterval = setInterval(() => this.outputChannel.append('.'), 1000); } From cd3f6ef52b2261d57dc6dea8ce9fa811c9604c81 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 3 Jan 2024 15:48:30 -0800 Subject: [PATCH 17/30] Working windows cancellation message --- .../src/Acquisition/WinMacGlobalInstaller.ts | 3 ++- .../src/EventStream/OutputChannelObserver.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts index 48c61b3d8f..f87d0c9595 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/WinMacGlobalInstaller.ts @@ -14,6 +14,7 @@ import { CommandExecutor } from '../Utils/CommandExecutor'; import { DotnetConflictingGlobalWindowsInstallError, DotnetFileIntegrityCheckEvent, + DotnetInstallCancelledByUserError as DotnetInstallCancelledByUser, DotnetUnexpectedInstallerOSError, NetInstallerBeginExecutionEvent, NetInstallerEndExecutionEvent, @@ -112,7 +113,7 @@ We cannot verify .NET is safe to download at this time. Please try again later.` else if(installerResult === '1602') { // Special code for when user cancels the install - const err = new DotnetInstallCancelledByUserError(new Error( + const err = new DotnetInstallCancelledByUser(new Error( `The install of .NET was cancelled by the user. Aborting.`), getInstallKeyFromContext(this.acquisitionContext.acquisitionContext)); this.acquisitionContext.eventStream.post(err); throw err.error; diff --git a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts index 259fed4974..811c7d1f99 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/OutputChannelObserver.ts @@ -9,7 +9,6 @@ import { DotnetAcquisitionError, DotnetAcquisitionInProgress, DotnetAcquisitionStarted, - DotnetAcquisitionVersionError, DotnetDebuggingMessage, DotnetExistingPathResolutionCompleted, DotnetInstallExpectedAbort, From db5116ed64ec9e46f25242de33d2eac62f02c2d9 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 11:57:28 -0800 Subject: [PATCH 18/30] Check command results element instead of the array for truthiness as the old version is a bug --- .../src/Acquisition/GenericDistroSDKProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index c4bbe1d800..31abef56ed 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -40,7 +40,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider commandResult[0] = commandResult[0].trim(); } - if(commandResult && this.resolvePathAsSymlink) + if(!commandResult[0] && this.resolvePathAsSymlink) { let symLinkReadCommand = this.myDistroCommands(this.readSymbolicLinkCommandKey); symLinkReadCommand = CommandExecutor.replaceSubstringsInCommands(symLinkReadCommand, this.missingPathKey, commandResult[0]); From 0276319b487a6b6bf3187eb9146251c7ad65bd37 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 12:01:22 -0800 Subject: [PATCH 19/30] Merge w fixed branch --- .../src/Acquisition/GenericDistroSDKProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index 31abef56ed..62164efd4e 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -40,7 +40,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider commandResult[0] = commandResult[0].trim(); } - if(!commandResult[0] && this.resolvePathAsSymlink) + if(commandResult[0] && this.resolvePathAsSymlink) { let symLinkReadCommand = this.myDistroCommands(this.readSymbolicLinkCommandKey); symLinkReadCommand = CommandExecutor.replaceSubstringsInCommands(symLinkReadCommand, this.missingPathKey, commandResult[0]); From 98dd51cd08d59e5ed838d73fd5f23e2c00d12185 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 12:05:05 -0800 Subject: [PATCH 20/30] return null to match the spec for the api -- even if it is not a behavioral change --- .../src/Acquisition/GenericDistroSDKProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index 62164efd4e..47bdffa076 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -51,7 +51,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider } } - return commandResult[0]; + return commandResult[0] ?? null; } public async dotnetPackageExistsOnSystem(fullySpecifiedDotnetVersion : string, installType : LinuxInstallType) : Promise From fef303970cca1fbf21cbe10ecf4709aa9b8fa54e Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 12:46:40 -0800 Subject: [PATCH 21/30] Add a special message for password prompt reject and dont consider it a failure in telemetry, and so we dont print error! on cancellation --- .../src/EventStream/EventStreamEvents.ts | 4 ++++ .../src/Utils/CommandExecutor.ts | 9 +++++++++ .../src/Utils/ErrorHandler.ts | 15 ++++++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts index af448a3970..bf43b7e107 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/EventStreamEvents.ts @@ -559,6 +559,10 @@ export class CommandExecutionUnderSudoEvent extends DotnetCustomMessageEvent { public readonly eventName = 'CommandExecutionUnderSudoEvent'; } +export class CommandExecutionUserRejectedPasswordRequest extends DotnetInstallExpectedAbort { + public readonly eventName = 'CommandExecutionUserRejectedPasswordRequest'; +} + export class DotnetVersionParseEvent extends DotnetCustomMessageEvent { public readonly eventName = 'DotnetVersionParseEvent'; } diff --git a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts index 6dab55b410..36f9b3eb8c 100644 --- a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts +++ b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts @@ -19,6 +19,7 @@ import { CommandExecutionUnderSudoEvent, CommandExecutionUserAskDialogueEvent, CommandExecutionUserCompletedDialogueEvent, + CommandExecutionUserRejectedPasswordRequest, DotnetAlternativeCommandFoundEvent, DotnetCommandNotFoundEvent, DotnetWSLSecurityError @@ -114,6 +115,14 @@ ${stderr}`)); this.context?.eventStream.post(new CommandExecutionUserCompletedDialogueEvent(`The command ${fullCommandString} failed to run under sudo.`)); if(terminalFailure) { + if(error.code === 126) + { + const err = new CommandExecutionUserRejectedPasswordRequest(new Error(`Cancelling .NET Install, as command ${fullCommandString} failed. +The user refused the password prompt.`), + getInstallKeyFromContext(this.context?.acquisitionContext!)); + this.context?.eventStream.post(err); + throw err.error; + } reject(error); } else diff --git a/vscode-dotnet-runtime-library/src/Utils/ErrorHandler.ts b/vscode-dotnet-runtime-library/src/Utils/ErrorHandler.ts index 13e768f7a2..5673bc7331 100644 --- a/vscode-dotnet-runtime-library/src/Utils/ErrorHandler.ts +++ b/vscode-dotnet-runtime-library/src/Utils/ErrorHandler.ts @@ -7,6 +7,8 @@ import * as open from 'open'; import { DotnetCommandFailed, DotnetCommandSucceeded, + DotnetInstallCancelledByUserError, + DotnetInstallExpectedAbort, DotnetNotInstallRelatedCommandFailed } from '../EventStream/EventStreamEvents'; import { getInstallKeyFromContext } from '../Utils/InstallKeyGenerator'; @@ -62,11 +64,14 @@ export async function callWithErrorHandling(callback: () => T, context: IIssu catch (caughtError) { const error = caughtError as Error; - context.eventStream.post(isAcquisitionError ? - new DotnetCommandFailed(error, context.commandName, getInstallKeyFromContext(acquireContext?.acquisitionContext)) : - // The output observer will keep track of installs and we don't want a non-install failure to make it think it should -=1 from the no. of installs - new DotnetNotInstallRelatedCommandFailed(error, context.commandName) - ); + if(!(error instanceof DotnetInstallExpectedAbort) && error && error.constructor && error.constructor.name !== 'UserCancelledError') + { + context.eventStream.post(isAcquisitionError ? + new DotnetCommandFailed(error, context.commandName, getInstallKeyFromContext(acquireContext?.acquisitionContext)) : + // The output observer will keep track of installs and we don't want a non-install failure to make it think it should -=1 from the no. of installs + new DotnetNotInstallRelatedCommandFailed(error, context.commandName) + ); + } if (context.errorConfiguration === AcquireErrorConfiguration.DisplayAllErrorPopups) { From f6d006eb0c4ca5ec759c9728fc930e5b888d3fe2 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 12:53:50 -0800 Subject: [PATCH 22/30] Dont color status bar red on cancellation --- .../src/EventStream/StatusBarObserver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vscode-dotnet-runtime-library/src/EventStream/StatusBarObserver.ts b/vscode-dotnet-runtime-library/src/EventStream/StatusBarObserver.ts index a4b1b9e647..bcb2a82af5 100644 --- a/vscode-dotnet-runtime-library/src/EventStream/StatusBarObserver.ts +++ b/vscode-dotnet-runtime-library/src/EventStream/StatusBarObserver.ts @@ -23,6 +23,7 @@ export class StatusBarObserver implements IEventStreamObserver { this.setAndShowStatusBar('$(cloud-download) Downloading .NET...', this.showLogCommand, '', 'Downloading .NET...'); break; case EventType.DotnetAcquisitionCompleted: + case EventType.DotnetInstallExpectedAbort: this.resetAndHideStatusBar(); break; case EventType.DotnetAcquisitionError: From ef29a912a4da0dccb3cab006ee187d9a35f44ae3 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 13:07:31 -0800 Subject: [PATCH 23/30] Respond to linter --- .../src/extension.ts | 24 +++++++++---------- .../src/Acquisition/LinuxVersionResolver.ts | 9 +++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/vscode-dotnet-runtime-extension/src/extension.ts b/vscode-dotnet-runtime-extension/src/extension.ts index a9ee32295f..7d475d0e05 100644 --- a/vscode-dotnet-runtime-extension/src/extension.ts +++ b/vscode-dotnet-runtime-extension/src/extension.ts @@ -106,7 +106,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE showLogCommand: `${commandPrefix}.${commandKeys.showAcquisitionLog}`, packageJson } as IEventStreamContext; - const [eventStream, outputChannel, loggingObserver, eventStreamObservers, telemetryObserver] = registerEventStream(eventStreamContext, vsCodeExtensionContext, utilContext); + const [globalEventStream, outputChannel, loggingObserver, eventStreamObservers, telemetryObserver] = registerEventStream(eventStreamContext, vsCodeExtensionContext, utilContext); // Setting up command-shared classes for Runtime & SDK Acquisition @@ -125,8 +125,8 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE const dotnetAcquireRegistration = vscode.commands.registerCommand(`${commandPrefix}.${commandKeys.acquire}`, async (commandContext: IDotnetAcquireContext) => { let fullyResolvedVersion = ''; const dotnetPath = await callWithErrorHandling>(async () => { - eventStream.post(new DotnetRuntimeAcquisitionStarted(commandContext.requestingExtensionId)); - eventStream.post(new DotnetAcquisitionRequested(commandContext.version, commandContext.requestingExtensionId)); + globalEventStream.post(new DotnetRuntimeAcquisitionStarted(commandContext.requestingExtensionId)); + globalEventStream.post(new DotnetAcquisitionRequested(commandContext.version, commandContext.requestingExtensionId)); runtimeAcquisitionWorker.setAcquisitionContext(commandContext); telemetryObserver?.setAcquisitionContext(runtimeContext, commandContext); @@ -154,7 +154,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE }, runtimeIssueContextFunctor(commandContext.errorConfiguration, 'acquire', commandContext.version), commandContext.requestingExtensionId, runtimeContext); const installKey = runtimeAcquisitionWorker.getInstallKey(fullyResolvedVersion); - eventStream.post(new DotnetRuntimeAcquisitionTotalSuccessEvent(commandContext.version, installKey, commandContext.requestingExtensionId ?? '', dotnetPath?.dotnetPath ?? '')); + globalEventStream.post(new DotnetRuntimeAcquisitionTotalSuccessEvent(commandContext.version, installKey, commandContext.requestingExtensionId ?? '', dotnetPath?.dotnetPath ?? '')); return dotnetPath; }); @@ -167,8 +167,8 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE const pathResult = callWithErrorHandling(async () => { - eventStream.post(new DotnetSDKAcquisitionStarted(commandContext.requestingExtensionId)); - eventStream.post(new DotnetAcquisitionRequested(commandContext.version, commandContext.requestingExtensionId)); + globalEventStream.post(new DotnetSDKAcquisitionStarted(commandContext.requestingExtensionId)); + globalEventStream.post(new DotnetAcquisitionRequested(commandContext.version, commandContext.requestingExtensionId)); const existingPath = await resolveExistingPathIfExists(existingPathConfigWorker, commandContext); if(existingPath) @@ -196,7 +196,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE const dotnetAcquireStatusRegistration = vscode.commands.registerCommand(`${commandPrefix}.${commandKeys.acquireStatus}`, async (commandContext: IDotnetAcquireContext) => { const pathResult = callWithErrorHandling(async () => { - eventStream.post(new DotnetAcquisitionStatusRequested(commandContext.version, commandContext.requestingExtensionId)); + globalEventStream.post(new DotnetAcquisitionStatusRequested(commandContext.version, commandContext.requestingExtensionId)); const resolvedVersion = await runtimeVersionResolver.getFullRuntimeVersion(commandContext.version); const dotnetPath = await runtimeAcquisitionWorker.acquireStatus(resolvedVersion, true); return dotnetPath; @@ -220,7 +220,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE const result = cp.spawnSync(commandContext.command, commandContext.arguments); const installer = new DotnetCoreDependencyInstaller(); if (installer.signalIndicatesMissingLinuxDependencies(result.signal!)) { - eventStream.post(new DotnetAcquisitionMissingLinuxDependencies()); + globalEventStream.post(new DotnetAcquisitionMissingLinuxDependencies()); await installer.promptLinuxDependencyInstall('Failed to run .NET runtime.'); } }, runtimeIssueContextFunctor(commandContext.errorConfiguration, 'ensureDependencies')); @@ -239,7 +239,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE const existingPath = existingPathResolver.resolveExistingPath(configResolver.getPathConfigurationValue(), commandContext.requestingExtensionId, displayWorker); if (existingPath) { - eventStream.post(new DotnetExistingPathResolutionCompleted(existingPath.dotnetPath)); + globalEventStream.post(new DotnetExistingPathResolutionCompleted(existingPath.dotnetPath)); return new Promise((resolve) => { resolve(existingPath); }); @@ -254,8 +254,8 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE return { storagePath: context.globalStoragePath, extensionState: context.globalState, - eventStream: eventStream, - installationValidator: new InstallationValidator(eventStream), + eventStream: globalEventStream, + installationValidator: new InstallationValidator(globalEventStream), timeoutSeconds: resolvedTimeoutSeconds, installDirectoryProvider: isRuntimeInstall ? new RuntimeInstallationDirectoryProvider(context.globalStoragePath): new SdkInstallationDirectoryProvider(context.globalStoragePath), proxyUrl: proxyLink, @@ -276,7 +276,7 @@ export function activate(context: vscode.ExtensionContext, extensionContext?: IE errorConfiguration: errorConfiguration || AcquireErrorConfiguration.DisplayAllErrorPopups, displayWorker, extensionConfigWorker: configResolver, - eventStream, + eventStream: globalEventStream, commandName, version, moreInfoUrl, diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index 112b5f8a7d..3bb6d0dc7c 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -184,9 +184,9 @@ export class LinuxVersionResolver case 'Red Hat Enterprise Linux': if(this.isRedHatVersion7(distroAndVersion.version)) { - const error = new DotnetAcquisitionDistroUnknownError(new Error(this.redhatUnsupportedDistroErrorMessage), getInstallKeyFromContext(this.acquireContext)); - this.acquisitionContext.eventStream.post(error); - throw error.error; + const unsupportedRhelErr = new DotnetAcquisitionDistroUnknownError(new Error(this.redhatUnsupportedDistroErrorMessage), getInstallKeyFromContext(this.acquireContext)); + this.acquisitionContext.eventStream.post(unsupportedRhelErr); + throw unsupportedRhelErr.error; } return new RedHatDistroSDKProvider(distroAndVersion, this.acquisitionContext, this.utilityContext); default: @@ -264,7 +264,8 @@ export class LinuxVersionResolver if(existingGlobalInstallSDKVersion && Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) === Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion))) { - const isPatchUpgrade = Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion)); + const isPatchUpgrade = Number(this.versionResolver.getFeatureBandPatchVersion(existingGlobalInstallSDKVersion)) < + Number(this.versionResolver.getFeatureBandPatchVersion(fullySpecifiedDotnetVersion)); if(Number(this.versionResolver.getMajorMinor(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion)) || Number(this.versionResolver.getFeatureBandFromVersion(existingGlobalInstallSDKVersion)) > Number(this.versionResolver.getFeatureBandFromVersion(fullySpecifiedDotnetVersion))) From e075c814e460dafce08aac5996f7fb51777d9b31 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 4 Jan 2024 16:09:10 -0800 Subject: [PATCH 24/30] Update 2.0.1 changelog to add new changes --- vscode-dotnet-runtime-extension/CHANGELOG.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/vscode-dotnet-runtime-extension/CHANGELOG.md b/vscode-dotnet-runtime-extension/CHANGELOG.md index b604b1f183..6fbb079b89 100644 --- a/vscode-dotnet-runtime-extension/CHANGELOG.md +++ b/vscode-dotnet-runtime-extension/CHANGELOG.md @@ -6,20 +6,27 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. ## [Unreleased] -## [2.0.1] - 2023-09-18 +## [2.0.1] - 2024-01-03 Fixes several key bugs with installing .NET: -- Ubuntu Installs would fail for the first time on 18.04. -- The extension would print ... forever after installation failure. -- The extension would fail to read Ubuntu directories properly if PMC was installed in certain scenarios. +- Ubuntu Global SDK Installs would fail for the first time on 18.04. +- The extension would print ... forever after installation failure for certain errors. +- The extension would fail to read Ubuntu directories properly for the first time if PMC was installed in certain scenarios. - GitHub Forms is now added. - Corrects behavior on our unknown Ubuntu Versions by estimating the correct behavior for known versions. - Improve timeout error handling - Catch bug in the caching library we use to prevent it from failing to cache +- Remove bug where status bar would stay red when cancelling install +- Fix bug where Linux would not update .NET SDKs properly when it could update instead of install +- Detect when a user cancels the installation in the password prompt or windows installer so we can remove the error failure message +- Adds more logging to the extension to improve diagnostics and speed to resolve github issues +- Improve installation management, so that the extension is aware that installs it manages can be deleted by external sources, to prevent it from thinking something is installed when it is no longer installed. +- Fix an issue where the uninstall command would think it could uninstall a global SDK. This is not the case. +- Improve detection logic for existing Ubuntu and RHEL installations of linux to prevent installing when it is not needed - Several other key issues. -## [2.0.0] - 2023-09-18 +## [2.0.0] - 2023-11-23 The '.NET Runtime Install Tool' has been renamed to the '.NET Install Tool.' From 94c54ea1cac32c726f142d74f5b220c0a3a1404c Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Tue, 16 Jan 2024 15:13:00 -0800 Subject: [PATCH 25/30] convert throw to rejection as the throw will cause the promise to never finish and never error properly --- vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts index 36f9b3eb8c..bd3ae5e0fc 100644 --- a/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts +++ b/vscode-dotnet-runtime-library/src/Utils/CommandExecutor.ts @@ -121,7 +121,7 @@ ${stderr}`)); The user refused the password prompt.`), getInstallKeyFromContext(this.context?.acquisitionContext!)); this.context?.eventStream.post(err); - throw err.error; + reject(err.error); } reject(error); } From 6af81276fab0c52c737f70f350f357e9a723deb5 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 17 Jan 2024 10:05:01 -0800 Subject: [PATCH 26/30] dont fail with 1 if the install already exists on linux RHEL --- .../src/Acquisition/LinuxVersionResolver.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts index d27be0ed81..73453f79f0 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/LinuxVersionResolver.ts @@ -70,6 +70,7 @@ export class LinuxVersionResolver protected commandRunner : ICommandExecutor; protected versionResolver : VersionResolver; public okUpdateExitCode = 11188; // Arbitrary number that is not shared or used by other things we rely on as an exit code + public okAlreadyExistsExitCode = 11166; public conflictingInstallErrorMessage = `A dotnet installation was found which indicates dotnet that was installed via Microsoft package feeds. But for this distro and version, we only acquire .NET via the distro feeds. You should not mix distro feed and microsoft feed installations. To continue, please completely remove this version of dotnet to continue by following https://learn.microsoft.com/dotnet/core/install/remove-runtime-sdk-versions?pivots=os-linux. @@ -289,7 +290,7 @@ export class LinuxVersionResolver else { // An existing install exists. - return '1'; + return String(this.okAlreadyExistsExitCode); } } // Additional logic to check the major.minor could be added here if we wanted to prevent installing lower major.minors if an existing install existed. @@ -322,7 +323,7 @@ export class LinuxVersionResolver { return await this.distroSDKProvider!.installDotnet(fullySpecifiedDotnetVersion, 'sdk') ? '0' : '1'; } - else if(updateOrRejectState === String(this.okUpdateExitCode)) + else if(updateOrRejectState === String(this.okUpdateExitCode) || updateOrRejectState === String(this.okAlreadyExistsExitCode)) { return '0'; } From fb7306e4ce9c259314efdd5ededc16bb74870956 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 17 Jan 2024 10:29:30 -0800 Subject: [PATCH 27/30] Read symlinks on RHEL as they apparently can become symlinks too depending on install type --- .../distro-data/distro-support.json | 2 +- .../src/Acquisition/RedHatDistroSDKProvider.ts | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/vscode-dotnet-runtime-library/distro-data/distro-support.json b/vscode-dotnet-runtime-library/distro-data/distro-support.json index c4df64a12c..747c1b182d 100644 --- a/vscode-dotnet-runtime-library/distro-data/distro-support.json +++ b/vscode-dotnet-runtime-library/distro-data/distro-support.json @@ -271,7 +271,7 @@ "commandParts": ["-f", "{path}"] } ], - "expectedDistroFeedInstallDirectory": "/usr/lib64/dotnet/dotnet", + "expectedDistroFeedInstallDirectory": "/usr/lib64/dotnet", "expectedMicrosoftFeedInstallDirectory": "", "installedSDKVersionsCommand": [ { diff --git a/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts index 4580ce6c0d..fe7bc3e344 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/RedHatDistroSDKProvider.ts @@ -16,7 +16,6 @@ export class RedHatDistroSDKProvider extends GenericDistroSDKProvider constructor(distroVersion : DistroVersionPair, context : IAcquisitionWorkerContext, utilContext : IUtilityContext, executor : ICommandExecutor | null = null) { super(distroVersion, context, utilContext, executor); - this.resolvePathAsSymlink = false; } protected myVersionDetails() : any @@ -26,17 +25,4 @@ export class RedHatDistroSDKProvider extends GenericDistroSDKProvider const versionData = distroVersions.filter((x: { [x: string]: string; }) => x[this.versionKey] === String(targetVersion)); return versionData; } - - public async getInstalledGlobalDotnetPathIfExists(installType : LinuxInstallType) : Promise - { - this.commandRunner.returnStatus = true; - const commandResult = await this.commandRunner.executeMultipleCommands(this.myDistroCommands(this.currentInstallPathCommandKey)); - this.commandRunner.returnStatus = false; - - if (commandResult[0] !== '0'){ - return ''; - } - const verboseCommandResult = await this.commandRunner.executeMultipleCommands(this.myDistroCommands(this.currentInstallPathCommandKey)); - return verboseCommandResult[0]; - } } \ No newline at end of file From ea50349147653e955baf34a10c0cd7bd410526ba Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Wed, 17 Jan 2024 11:45:23 -0800 Subject: [PATCH 28/30] RHEL: dont parse failure --- .../src/Acquisition/GenericDistroSDKProvider.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts index 47bdffa076..b620423872 100644 --- a/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts +++ b/vscode-dotnet-runtime-library/src/Acquisition/GenericDistroSDKProvider.ts @@ -35,6 +35,17 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider public async getInstalledGlobalDotnetPathIfExists(installType : LinuxInstallType) : Promise { const commandResult = await this.commandRunner.executeMultipleCommands(this.myDistroCommands(this.currentInstallPathCommandKey)); + + const oldReturnStatusSetting = this.commandRunner.returnStatus; + this.commandRunner.returnStatus = true; + const commandSignal = await this.commandRunner.executeMultipleCommands(this.myDistroCommands(this.currentInstallPathCommandKey)); + this.commandRunner.returnStatus = oldReturnStatusSetting; + + if(commandSignal[0] !== '0') // no dotnet error can be returned, dont want to try to parse this as a path + { + return null; + } + if(commandResult[0]) { commandResult[0] = commandResult[0].trim(); From 6941b5c4c5a606e9d0892261e9a3232ee799b7b9 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Thu, 18 Jan 2024 11:28:45 -0800 Subject: [PATCH 29/30] update redhat tests to read symlinks --- .../src/test/unit/RedHatDistroTests.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts b/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts index 3155c6c88a..de4782c782 100644 --- a/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts +++ b/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts @@ -53,7 +53,7 @@ suite('Red Hat For Linux Distro Logic Unit Tests', () => if(shouldRun) { const distroFeedDir = await provider.getExpectedDotnetDistroFeedInstallationDirectory(); - assert.equal(distroFeedDir, '/usr/lib64/dotnet/dotnet'); + assert.equal(distroFeedDir, '/usr/lib64/dotnet'); } }).timeout(standardTimeoutTime); @@ -104,7 +104,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`; if(shouldRun) { await provider.getInstalledGlobalDotnetPathIfExists(installType); - assert.equal(mockExecutor.attemptedCommand, 'which dotnet'); + assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet'); } }).timeout(standardTimeoutTime); From a1f03c60dfa563a681b65788a52377e26320e0b5 Mon Sep 17 00:00:00 2001 From: Noah Gilson Date: Fri, 19 Jan 2024 11:34:14 -0800 Subject: [PATCH 30/30] Use which dotnet in tests instead of the readlink for symlinks After we made it so if theres no dotnet it does not try to read a symlink which dotnet went back to being the correct result --- .../src/test/unit/LinuxDistroTests.test.ts | 2 +- .../src/test/unit/RedHatDistroTests.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts b/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts index 43bebe2452..61ae4af852 100644 --- a/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts +++ b/vscode-dotnet-runtime-library/src/test/unit/LinuxDistroTests.test.ts @@ -104,7 +104,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`; if(shouldRun) { await provider.getInstalledGlobalDotnetPathIfExists(installType); - assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet'); + assert.equal(mockExecutor.attemptedCommand, 'which dotnet'); } }).timeout(standardTimeoutTime); diff --git a/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts b/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts index de4782c782..e01a954563 100644 --- a/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts +++ b/vscode-dotnet-runtime-library/src/test/unit/RedHatDistroTests.test.ts @@ -104,7 +104,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`; if(shouldRun) { await provider.getInstalledGlobalDotnetPathIfExists(installType); - assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet'); + assert.equal(mockExecutor.attemptedCommand, 'which dotnet'); } }).timeout(standardTimeoutTime);