diff --git a/eng/Versions.props b/eng/Versions.props index ac52d1f1..ec047b38 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -14,7 +14,6 @@ release 13.0.1 - 3.2.2146 - 9.3.3 + 3.3.2180 diff --git a/global.json b/global.json index ddc6167e..ba40af30 100644 --- a/global.json +++ b/global.json @@ -1,4 +1,7 @@ { + "sdk": { + "version": "7.0.100-rc.1.22431.12" + }, "tools": { "dotnet": "7.0.100-rc.1.22431.12" }, diff --git a/src/MSBuildBinLogQuery/MSBuildBinLogQuery.csproj b/src/MSBuildBinLogQuery/MSBuildBinLogQuery.csproj index 4ffb13f3..d04254b8 100644 --- a/src/MSBuildBinLogQuery/MSBuildBinLogQuery.csproj +++ b/src/MSBuildBinLogQuery/MSBuildBinLogQuery.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/core-sdk-tasks/AzurePublisher.cs b/src/core-sdk-tasks/AzurePublisher.cs deleted file mode 100644 index c537331b..00000000 --- a/src/core-sdk-tasks/AzurePublisher.cs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#if !SOURCE_BUILD -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Auth; -using Microsoft.WindowsAzure.Storage.Blob; - -namespace Microsoft.DotNet.Cli.Build -{ - public class AzurePublisher - { - public enum Product - { - SharedFramework, - Host, - HostFxr, - Sdk, - } - - private const string s_dotnetBlobContainerName = "dotnet"; - - private string _connectionString { get; set; } - private string _containerName { get; set; } - private CloudBlobContainer _blobContainer { get; set; } - - public AzurePublisher(string accountName, string accountKey, string containerName = s_dotnetBlobContainerName) - { - _containerName = containerName; - _blobContainer = GetDotnetBlobContainer(accountName, accountKey, containerName); - } - - private CloudBlobContainer GetDotnetBlobContainer(string accountName, string accountKey, string containerName) - { - var storageCredentials = new StorageCredentials(accountName, accountKey); - var storageAccount = new CloudStorageAccount(storageCredentials, true); - return GetDotnetBlobContainer(storageAccount, containerName); - } - - private CloudBlobContainer GetDotnetBlobContainer(CloudStorageAccount storageAccount, string containerName) - { - CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); - - return blobClient.GetContainerReference(containerName); - } - - public string UploadFile(string file, Product product, string version) - { - string url = CalculateRelativePathForFile(file, product, version); - CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(url); - blob.UploadFromFileAsync(file).Wait(); - SetBlobPropertiesBasedOnFileType(blob); - return url; - } - - public void PublishStringToBlob(string blob, string content) - { - CloudBlockBlob blockBlob = _blobContainer.GetBlockBlobReference(blob); - blockBlob.UploadTextAsync(content).Wait(); - - SetBlobPropertiesBasedOnFileType(blockBlob); - } - - public void CopyBlob(string sourceBlob, string targetBlob) - { - CloudBlockBlob source = _blobContainer.GetBlockBlobReference(sourceBlob); - CloudBlockBlob target = _blobContainer.GetBlockBlobReference(targetBlob); - - // Create the empty blob - using (MemoryStream ms = new MemoryStream()) - { - target.UploadFromStreamAsync(ms).Wait(); - } - - // Copy actual blob data - target.StartCopyAsync(source).Wait(); - } - - public void SetBlobPropertiesBasedOnFileType(string path) - { - CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(path); - SetBlobPropertiesBasedOnFileType(blob); - } - - private void SetBlobPropertiesBasedOnFileType(CloudBlockBlob blockBlob) - { - if (Path.GetExtension(blockBlob.Uri.AbsolutePath.ToLower()) == ".svg") - { - blockBlob.Properties.ContentType = "image/svg+xml"; - blockBlob.Properties.CacheControl = "no-cache"; - blockBlob.SetPropertiesAsync().Wait(); - } - else if (Path.GetExtension(blockBlob.Uri.AbsolutePath.ToLower()) == ".version") - { - blockBlob.Properties.ContentType = "text/plain"; - blockBlob.Properties.CacheControl = "no-cache"; - blockBlob.SetPropertiesAsync().Wait(); - } - } - - public IEnumerable ListBlobs(Product product, string version) - { - string virtualDirectory = $"{product}/{version}"; - return ListBlobs(virtualDirectory); - } - - public IEnumerable ListBlobs(string virtualDirectory) - { - CloudBlobDirectory blobDir = _blobContainer.GetDirectoryReference(virtualDirectory); - BlobContinuationToken continuationToken = new BlobContinuationToken(); - - var blobFiles = blobDir.ListBlobsSegmentedAsync(continuationToken).Result; - return blobFiles.Results.Select(bf => bf.Uri.PathAndQuery.Replace($"/{_containerName}/", string.Empty)); - } - - public string AcquireLeaseOnBlob( - string blob, - TimeSpan? maxWaitDefault = null, - TimeSpan? delayDefault = null) - { - TimeSpan maxWait = maxWaitDefault ?? TimeSpan.FromSeconds(120); - TimeSpan delay = delayDefault ?? TimeSpan.FromMilliseconds(500); - - Stopwatch stopWatch = new Stopwatch(); - stopWatch.Start(); - - // This will throw an exception with HTTP code 409 when we cannot acquire the lease - // But we should block until we can get this lease, with a timeout (maxWaitSeconds) - while (stopWatch.ElapsedMilliseconds < maxWait.TotalMilliseconds) - { - try - { - CloudBlockBlob cloudBlob = _blobContainer.GetBlockBlobReference(blob); - Task task = cloudBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), null); - task.Wait(); - return task.Result; - } - catch (Exception e) - { - Console.WriteLine($"Retrying lease acquisition on {blob}, {e.Message}"); - Thread.Sleep(delay); - } - } - - throw new Exception($"Unable to acquire lease on {blob}"); - } - - public void ReleaseLeaseOnBlob(string blob, string leaseId) - { - CloudBlockBlob cloudBlob = _blobContainer.GetBlockBlobReference(blob); - AccessCondition ac = new AccessCondition() { LeaseId = leaseId }; - cloudBlob.ReleaseLeaseAsync(ac).Wait(); - } - - public bool IsLatestSpecifiedVersion(string version) - { - Task task = _blobContainer.GetBlockBlobReference(version).ExistsAsync(); - task.Wait(); - return task.Result; - } - - public void DropLatestSpecifiedVersion(string version) - { - CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(version); - using (MemoryStream ms = new MemoryStream()) - { - blob.UploadFromStreamAsync(ms).Wait(); - } - } - - public void CreateBlobIfNotExists(string path) - { - Task task = _blobContainer.GetBlockBlobReference(path).ExistsAsync(); - task.Wait(); - if (!task.Result) - { - CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(path); - using (MemoryStream ms = new MemoryStream()) - { - blob.UploadFromStreamAsync(ms).Wait(); - } - } - } - - public bool TryDeleteBlob(string path) - { - try - { - DeleteBlob(path); - - return true; - } - catch (Exception e) - { - Console.WriteLine($"Deleting blob {path} failed with \r\n{e.Message}"); - - return false; - } - } - - private void DeleteBlob(string path) - { - _blobContainer.GetBlockBlobReference(path).DeleteAsync().Wait(); - } - - private static string CalculateRelativePathForFile(string file, Product product, string version) - { - return $"{product}/{version}/{Path.GetFileName(file)}"; - } - } -} -#endif \ No newline at end of file diff --git a/src/core-sdk-tasks/CopyBlobsToLatest.cs b/src/core-sdk-tasks/CopyBlobsToLatest.cs deleted file mode 100644 index 734898a7..00000000 --- a/src/core-sdk-tasks/CopyBlobsToLatest.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#if !SOURCE_BUILD -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using System; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; - -namespace Microsoft.DotNet.Cli.Build -{ - public class CopyBlobsToLatest : Task - { - private const string feedRegex = @"(?https:\/\/(?[^\.-]+)(?[^\/]*)\/((?[a-zA-Z0-9+\/]*?\/\d{4}-\d{2}-\d{2})\/)?(?[^\/]+)\/(?.*\/)?)index\.json"; - - private AzurePublisher _azurePublisher; - - [Required] - public string FeedUrl { get; set; } - - [Required] - public string AccountKey { get; set; } - - [Required] - public string Channel { get; set; } - - [Required] - public string CommitHash { get; set; } - - [Required] - public string NugetVersion { get; set; } - - private string ContainerName { get; set; } - - private AzurePublisher AzurePublisherTool - { - get - { - if (_azurePublisher == null) - { - Match m = Regex.Match(FeedUrl, feedRegex); - if (m.Success) - { - string accountName = m.Groups["accountname"].Value; - string ContainerName = m.Groups["containername"].Value; - - _azurePublisher = new AzurePublisher( - accountName, - AccountKey, - ContainerName); - } - else - { - throw new Exception( - "Unable to parse expected feed. Please check ExpectedFeedUrl."); - } - } - - return _azurePublisher; - } - } - - public override bool Execute() - { - string targetFolder = $"{AzurePublisher.Product.Sdk}/{Channel}"; - - string targetVersionFile = $"{targetFolder}/{CommitHash}"; - string semaphoreBlob = $"{targetFolder}/publishSemaphore"; - AzurePublisherTool.CreateBlobIfNotExists(semaphoreBlob); - string leaseId = AzurePublisherTool.AcquireLeaseOnBlob(semaphoreBlob); - - // Prevent race conditions by dropping a version hint of what version this is. If we see this file - // and it is the same as our version then we know that a race happened where two+ builds finished - // at the same time and someone already took care of publishing and we have no work to do. - if (AzurePublisherTool.IsLatestSpecifiedVersion(targetVersionFile)) - { - AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId); - return true; - } - else - { - Regex versionFileRegex = new Regex(@"(?[\w\d]{40})"); - - // Delete old version files - AzurePublisherTool.ListBlobs(targetFolder) - .Where(s => versionFileRegex.IsMatch(s)) - .ToList() - .ForEach(f => AzurePublisherTool.TryDeleteBlob(f)); - - // Drop the version file signaling such for any race-condition builds (see above comment). - AzurePublisherTool.DropLatestSpecifiedVersion(targetVersionFile); - } - - try - { - CopyBlobs(targetFolder); - - string cliVersion = GetVersionFileContent(CommitHash, NugetVersion); - AzurePublisherTool.PublishStringToBlob($"{targetFolder}/latest.version", cliVersion); - } - finally - { - AzurePublisherTool.ReleaseLeaseOnBlob(semaphoreBlob, leaseId); - } - - return true; - } - - private void CopyBlobs(string destinationFolder) - { - Log.LogMessage("Copying blobs to {0}/{1}", ContainerName, destinationFolder); - - foreach (string blob in AzurePublisherTool.ListBlobs(AzurePublisher.Product.Sdk, NugetVersion)) - { - string targetName = Path.GetFileName(blob) - .Replace(NugetVersion, "latest"); - - string target = $"{destinationFolder}/{targetName}"; - - AzurePublisherTool.CopyBlob(blob, target); - } - } - - private string GetVersionFileContent(string commitHash, string version) - { - return $@"{commitHash}{Environment.NewLine}{version}{Environment.NewLine}"; - } - } -} -#endif diff --git a/src/core-sdk-tasks/core-sdk-tasks.csproj b/src/core-sdk-tasks/core-sdk-tasks.csproj index 9cffaa32..6ccb0e80 100644 --- a/src/core-sdk-tasks/core-sdk-tasks.csproj +++ b/src/core-sdk-tasks/core-sdk-tasks.csproj @@ -6,13 +6,12 @@ - - - + + + - - - + + diff --git a/src/dotnet-core-uninstall/Shared/Commands/ListCommandExec.cs b/src/dotnet-core-uninstall/Shared/Commands/ListCommandExec.cs index f2d9480c..3c1c81ef 100644 --- a/src/dotnet-core-uninstall/Shared/Commands/ListCommandExec.cs +++ b/src/dotnet-core-uninstall/Shared/Commands/ListCommandExec.cs @@ -33,7 +33,7 @@ private static void Execute( { Console.WriteLine(RuntimeInfo.RunningOnWindows ? LocalizableStrings.WindowsListCommandOutput : LocalizableStrings.MacListCommandOutput); - var listCommandParseResult = CommandLineConfigs.ListCommand.Parse(Environment.GetCommandLineArgs()); + var listCommandParseResult = CommandLineConfigs.ListCommand.Parse(Environment.GetCommandLineArgs().Skip(1).ToList()); var verbose = listCommandParseResult.CommandResult.GetVerbosityLevel().Equals(VerbosityLevel.Detailed) || listCommandParseResult.CommandResult.GetVerbosityLevel().Equals(VerbosityLevel.Diagnostic); diff --git a/src/dotnet-core-uninstall/Shared/Commands/UninstallHelpBuilder.cs b/src/dotnet-core-uninstall/Shared/Commands/UninstallHelpBuilder.cs index 6309ebc3..3f4604a5 100644 --- a/src/dotnet-core-uninstall/Shared/Commands/UninstallHelpBuilder.cs +++ b/src/dotnet-core-uninstall/Shared/Commands/UninstallHelpBuilder.cs @@ -9,16 +9,16 @@ namespace Microsoft.DotNet.Tools.Uninstall.Shared.Commands { public class UninstallHelpBuilder : HelpBuilder { - public UninstallHelpBuilder(IConsole console) : base(console) { } + public UninstallHelpBuilder(LocalizationResources localizationResources, int maxWidth = int.MaxValue) : base(localizationResources, maxWidth) { } - public override void Write(ICommand command) + public override void Write(HelpContext context) { - base.Write(command); - if (command.Name.Equals("dry-run") || command.Name.Equals("remove")) + base.Write(context); + if (context.Command.Name.Equals("dry-run") || context.Command.Name.Equals("remove")) { - Console.Out.Write(RuntimeInfo.RunningOnWindows ? LocalizableStrings.HelpExplainationParagraphWindows : + context.Output.Write(RuntimeInfo.RunningOnWindows ? LocalizableStrings.HelpExplainationParagraphWindows : LocalizableStrings.HelpExplainationParagraphMac); - Console.Out.Write(Environment.NewLine); + context.Output.Write(Environment.NewLine); } } } diff --git a/src/dotnet-core-uninstall/Shared/Configs/CommandLineConfigs.cs b/src/dotnet-core-uninstall/Shared/Configs/CommandLineConfigs.cs index fb941947..48dd1c5d 100644 --- a/src/dotnet-core-uninstall/Shared/Configs/CommandLineConfigs.cs +++ b/src/dotnet-core-uninstall/Shared/Configs/CommandLineConfigs.cs @@ -8,6 +8,7 @@ using System.CommandLine.Invocation; using System.CommandLine.Parsing; using System.Linq; +using System.Text.RegularExpressions; using Microsoft.DotNet.Tools.Uninstall.MacOs; using Microsoft.DotNet.Tools.Uninstall.Shared.BundleInfo; using Microsoft.DotNet.Tools.Uninstall.Shared.Commands; @@ -51,84 +52,109 @@ internal static class CommandLineConfigs public static readonly string X64OptionName = "x64"; public static readonly string X86OptionName = "x86"; - public static readonly Option UninstallAllOption = new Option( + public static readonly Option UninstallAllOption = new Option( "--all", LocalizableStrings.UninstallAllOptionDescription); - public static readonly Option UninstallAllLowerPatchesOption = new Option( + public static readonly Option UninstallAllLowerPatchesOption = new Option( "--all-lower-patches", LocalizableStrings.UninstallAllLowerPatchesOptionDescription); - public static readonly Option UninstallAllButLatestOption = new Option( + public static readonly Option UninstallAllButLatestOption = new Option( "--all-but-latest", LocalizableStrings.UninstallAllButLatestOptionDescription); - public static readonly Option UninstallAllButOption = new Option( - "--all-but", - LocalizableStrings.UninstallAllButOptionDescription) - { - Argument = new Argument> - { - Name = LocalizableStrings.UninstallAllButOptionArgumentName + public static Regex SemVer = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$"); + public static string CheckTokenIsVersion(ArgumentResult r) { + // ideally we'd parse and check a semver here, but not sure we want to take + // that dependency + var input = r.Tokens[0].Value; + if(SemVer.IsMatch(input) || Version.TryParse(input, out _)) { + r.OnlyTake(1); + return input; + } else { + r.OnlyTake(0); + r.ErrorMessage = $"Version '{input}' is not a valid SemVer version or .NET Version"; + return null; } - }; + } - public static readonly Option UninstallAllBelowOption = new Option( - "--all-below", - LocalizableStrings.UninstallAllBelowOptionDescription) - { - Argument = new Argument - { - Name = LocalizableStrings.UninstallAllBelowOptionArgumentName + public static string[] CheckTokensAreVersion(ArgumentResult r) { + // ideally we'd parse and check a semver here, but not sure we want to take + // that dependency + var parsed = new List(); + foreach(var token in r.Tokens) { + var input = token.Value; + if(SemVer.IsMatch(input) || Version.TryParse(input, out _)) { + parsed.Add(input); + } else { + r.ErrorMessage = $"Version '{input}' is not a valid SemVer version or .NET Version"; + return null; + } } - }; + r.OnlyTake(parsed.Count); + return parsed.ToArray(); + } + + public static readonly Option UninstallAllButOption = new Option( + "--all-but", + parseArgument: CheckTokensAreVersion, + description: LocalizableStrings.UninstallAllButOptionDescription) { + AllowMultipleArgumentsPerToken = true + }; - public static readonly Option UninstallAllPreviewsOption = new Option( + public static readonly Option UninstallAllBelowOption = new Option( + "--all-below", + parseArgument: CheckTokenIsVersion, + description: LocalizableStrings.UninstallAllBelowOptionDescription + ); + + public static readonly Option UninstallAllPreviewsOption = new Option( "--all-previews", LocalizableStrings.UninstallAllPreviewsOptionDescription); - public static readonly Option UninstallAllPreviewsButLatestOption = new Option( + public static readonly Option UninstallAllPreviewsButLatestOption = new Option( "--all-previews-but-latest", LocalizableStrings.UninstallAllPreviewsButLatestOptionDescription); + + private static Regex MajorMinor = new Regex(@"^\d+\.\d+$"); + public static string ParseMajorMinor(ArgumentResult r) { + var input = r.Tokens[0].Value; + if (MajorMinor.IsMatch(input)) { + return input; + } else { + r.ErrorMessage = $"The version '{input}' is not in the format Major.Minor."; + return null; + } + } - public static readonly Option UninstallMajorMinorOption = new Option( + public static readonly Option UninstallMajorMinorOption = new Option( "--major-minor", - LocalizableStrings.UninstallMajorMinorOptionDescription) - { - Argument = new Argument - { - Name = LocalizableStrings.UninstallMajorMinorOptionArgumentName - } - }; + parseArgument: ParseMajorMinor, + description: LocalizableStrings.UninstallMajorMinorOptionDescription); - public static readonly Option VerbosityOption = new Option( + public static readonly Option VerbosityOption = new Option( new[] { "--verbosity", "-v" }, - LocalizableStrings.VerbosityOptionDescription) - { - Argument = new Argument - { - Name = LocalizableStrings.VerbosityOptionArgumentName - } - }; + LocalizableStrings.VerbosityOptionDescription); - public static readonly Option ListX64Option = new Option( + public static readonly Option ListX64Option = new Option( $"--{X64OptionName}", LocalizableStrings.ListX64OptionDescription); - public static readonly Option ListX86Option = new Option( + public static readonly Option ListX86Option = new Option( $"--{X86OptionName}", LocalizableStrings.ListX86OptionDescription); - public static readonly Option VersionOption = new Option("--version") + public static readonly Option VersionOption = new Option("--version") { IsHidden = true }; - public static readonly Option YesOption = new Option( + public static readonly Option YesOption = new Option( new[] { "--yes", "-y" }, LocalizableStrings.YesOptionDescription); - public static readonly Option ForceOption = new Option( + public static readonly Option ForceOption = new Option( "--force", RuntimeInfo.RunningOnWindows ? LocalizableStrings.ForceOptionDescriptionWindows : LocalizableStrings.ForceOptionDescriptionMac); @@ -145,26 +171,26 @@ internal static class CommandLineConfigs UninstallMajorMinorOption }; - public static readonly Option[] ListBundleTypeOptions = new Option[] + public static readonly Option[] ListBundleTypeOptions = new Option[] { - new Option($"--{SdkOptionName}", LocalizableStrings.ListSdkOptionDescription), - new Option($"--{RuntimeOptionName}", LocalizableStrings.ListRuntimeOptionDescription), - new Option($"--{AspNetRuntimeOptionName}", LocalizableStrings.ListAspNetRuntimeOptionDescription), - new Option($"--{HostingBundleOptionName}", LocalizableStrings.ListHostingBundleOptionDescription) + new Option($"--{SdkOptionName}", LocalizableStrings.ListSdkOptionDescription), + new Option($"--{RuntimeOptionName}", LocalizableStrings.ListRuntimeOptionDescription), + new Option($"--{AspNetRuntimeOptionName}", LocalizableStrings.ListAspNetRuntimeOptionDescription), + new Option($"--{HostingBundleOptionName}", LocalizableStrings.ListHostingBundleOptionDescription) }; - public static readonly Option[] UninstallBundleTypeOptions = new Option[] + public static readonly Option[] UninstallBundleTypeOptions = new Option[] { - new Option($"--{SdkOptionName}", LocalizableStrings.UninstallSdkOptionDescription), - new Option($"--{RuntimeOptionName}", LocalizableStrings.UninstallRuntimeOptionDescription), - new Option($"--{AspNetRuntimeOptionName}", LocalizableStrings.UninstallAspNetRuntimeOptionDescription), - new Option($"--{HostingBundleOptionName}", LocalizableStrings.UninstallHostingBundleOptionDescription) + new Option($"--{SdkOptionName}", LocalizableStrings.UninstallSdkOptionDescription), + new Option($"--{RuntimeOptionName}", LocalizableStrings.UninstallRuntimeOptionDescription), + new Option($"--{AspNetRuntimeOptionName}", LocalizableStrings.UninstallAspNetRuntimeOptionDescription), + new Option($"--{HostingBundleOptionName}", LocalizableStrings.UninstallHostingBundleOptionDescription) }; - public static readonly Option[] ArchUninstallOptions = new Option[] + public static readonly Option[] ArchUninstallOptions = new Option[] { - new Option($"--{X64OptionName}", LocalizableStrings.UninstallX64OptionDescription), - new Option($"--{X86OptionName}", LocalizableStrings.UninstallX86OptionDescription) + new Option($"--{X64OptionName}", LocalizableStrings.UninstallX64OptionDescription), + new Option($"--{X86OptionName}", LocalizableStrings.UninstallX86OptionDescription) }; public static readonly Option[] AdditionalUninstallOptions = new Option[] @@ -232,15 +258,15 @@ static CommandLineConfigs() AssignOptionsToCommand(ListCommand, ListAuxOptions); var bundleCollector = RuntimeInfo.RunningOnWindows ? new RegistryQuery() as IBundleCollector : new FileSystemExplorer() as IBundleCollector; - ListCommand.Handler = CommandHandler.Create(ExceptionHandler.HandleException(() => ListCommandExec.Execute(bundleCollector))); - DryRunCommand.Handler = CommandHandler.Create(ExceptionHandler.HandleException(() => DryRunCommandExec.Execute(bundleCollector))); - RemoveCommand.Handler = CommandHandler.Create(ExceptionHandler.HandleException(() => UninstallCommandExec.Execute(bundleCollector))); + ListCommand.SetHandler(_ => ExceptionHandler.HandleException(() => ListCommandExec.Execute(bundleCollector))); + DryRunCommand.SetHandler(_ => ExceptionHandler.HandleException(() => DryRunCommandExec.Execute(bundleCollector))); + RemoveCommand.SetHandler(_ => ExceptionHandler.HandleException(() => UninstallCommandExec.Execute(bundleCollector))); UninstallCommandParser = new CommandLineBuilder(UninstallRootCommand) .UseDefaults() - .UseHelpBuilder(context => new UninstallHelpBuilder(context.Console)) + .UseHelpBuilder(context => new UninstallHelpBuilder(LocalizationResources.Instance)) .Build(); - CommandLineParseResult = UninstallCommandParser.Parse(Environment.GetCommandLineArgs()); + CommandLineParseResult = UninstallCommandParser.Parse(Environment.GetCommandLineArgs().Skip(1).ToList()); } public static Option GetUninstallMainOption(this CommandResult commandResult) @@ -281,7 +307,7 @@ public static BundleType GetTypeSelection(this ParseResult parseResult) var supportedBundleTypes = SupportedBundleTypeConfigs.GetSupportedBundleTypes(); var typeSelection = supportedBundleTypes - .Where(type => parseResult.ValueForOption($"--{type.OptionName}")) + .Where(type => parseResult.CommandResult.Children.FirstOrDefault(c => c is OptionResult o && o.Option.Name == type.OptionName && o.GetValueForOption(o.Option) is bool b && b) is not null) .Select(type => type.Type) .Aggregate((BundleType)0, (orSum, next) => orSum | next); @@ -294,10 +320,10 @@ public static BundleArch GetArchSelection(this ParseResult parseResult) { var archSelection = new[] { - (OptionName: X64OptionName, Arch: BundleArch.X64), - (OptionName: X86OptionName, Arch: BundleArch.X86) + (Option: ListX64Option, Arch: BundleArch.X64), + (Option: ListX86Option, Arch: BundleArch.X86) } - .Where(tuple => parseResult.ValueForOption($"--{tuple.OptionName}")) + .Where(tuple => parseResult.GetValueForOption(tuple.Option)) .Select(tuple => tuple.Arch) .Aggregate((BundleArch)0, (orSum, next) => orSum | next); diff --git a/src/dotnet-core-uninstall/Shared/Filterers/Filterer.cs b/src/dotnet-core-uninstall/Shared/Filterers/Filterer.cs index b41549a0..0da68a75 100644 --- a/src/dotnet-core-uninstall/Shared/Filterers/Filterer.cs +++ b/src/dotnet-core-uninstall/Shared/Filterers/Filterer.cs @@ -48,7 +48,7 @@ internal abstract class ArgFilterer : Filterer { public override IEnumerable Filter(ParseResult parseResult, Option option, IEnumerable bundles, BundleType typeSelection, BundleArch archSelection) { - var argValue = parseResult.ValueForOption(option); + var argValue = parseResult.GetValueForOption(option as Option); return Filter(argValue, bundles, typeSelection, archSelection); } diff --git a/src/dotnet-core-uninstall/dotnet-core-uninstall.csproj b/src/dotnet-core-uninstall/dotnet-core-uninstall.csproj index 46578c8f..5402ed6a 100644 --- a/src/dotnet-core-uninstall/dotnet-core-uninstall.csproj +++ b/src/dotnet-core-uninstall/dotnet-core-uninstall.csproj @@ -14,11 +14,11 @@ - - - - - + + + + + diff --git a/test/dotnet-core-uninstall.Tests/Shared/Configs/CommandLineConfigsTests.cs b/test/dotnet-core-uninstall.Tests/Shared/Configs/CommandLineConfigsTests.cs index b4dc31f0..08bf05c3 100644 --- a/test/dotnet-core-uninstall.Tests/Shared/Configs/CommandLineConfigsTests.cs +++ b/test/dotnet-core-uninstall.Tests/Shared/Configs/CommandLineConfigsTests.cs @@ -95,14 +95,14 @@ internal void TestListCommandReject(string command) } [Theory] - [InlineData("--all")] - [InlineData("--all-lower-patches")] - [InlineData("--all-but-latest")] + [InlineData("--all", null, true)] + [InlineData("--all-lower-patches", null, true)] + [InlineData("--all-but-latest", null, true)] [InlineData("--all-but", "2.2.300", new[] { "2.2.300" })] [InlineData("--all-but", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] [InlineData("--all-below", "2.2.300", "2.2.300")] - [InlineData("--all-previews")] - [InlineData("--all-previews-but-latest")] + [InlineData("--all-previews", null, true)] + [InlineData("--all-previews-but-latest", null, true)] [InlineData("--major-minor", "2.2", "2.2")] [InlineData("", "2.2.300", new[] { "2.2.300" })] [InlineData("", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] @@ -114,8 +114,9 @@ internal void TestRemoveCommandAccept(string option, string argValue = "", objec if (!option.Equals(string.Empty)) { - parseResult.CommandResult.OptionResult(option).Should().NotBeNull(); - parseResult.ValueForOption(option).Should().BeEquivalentTo(expected); + var optionResult = parseResult.CommandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); + parseResult.GetValueForOption(optionResult.Option).Should().BeEquivalentTo(expected); } else { @@ -129,27 +130,28 @@ internal void TestRemoveCommandAccept(string option, string argValue = "", objec } [Theory] - [InlineData("--all")] - [InlineData("--all-lower-patches")] - [InlineData("--all-but-latest")] + [InlineData("--all", null, true)] + [InlineData("--all-lower-patches", null, true)] + [InlineData("--all-but-latest", null, true)] [InlineData("--all-but", "2.2.300", new[] { "2.2.300" })] [InlineData("--all-but", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] [InlineData("--all-below", "2.2.300", "2.2.300")] - [InlineData("--all-previews")] - [InlineData("--all-previews-but-latest")] + [InlineData("--all-previews", null, true)] + [InlineData("--all-previews-but-latest", null, true)] [InlineData("--major-minor", "2.2", "2.2")] [InlineData("", "2.2.300", new[] { "2.2.300" })] [InlineData("", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] [InlineData("", "--unknown-option", new[] { "--unknown-option" })] [InlineData("", "--unknown-option argument", new[] { "--unknown-option", "argument" })] - internal void TestDryRunCommandAccept(string option, string argValue = "", object expected = null) + internal void TestDryRunCommandAccept(string option, string argValue, object expected) { var parseResult = CommandLineConfigs.UninstallRootCommand.Parse($"dry-run {option} {argValue}"); if (!option.Equals(string.Empty)) { - parseResult.CommandResult.OptionResult(option).Should().NotBeNull(); - parseResult.ValueForOption(option).Should().BeEquivalentTo(expected); + var optionResult = parseResult.CommandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); + parseResult.GetValueForOption(optionResult.Option).Should().BeEquivalentTo(expected); } else { @@ -163,14 +165,14 @@ internal void TestDryRunCommandAccept(string option, string argValue = "", objec } [Theory] - [InlineData("--all")] - [InlineData("--all-lower-patches")] - [InlineData("--all-but-latest")] + [InlineData("--all", null, true)] + [InlineData("--all-lower-patches", null, true)] + [InlineData("--all-but-latest", null, true)] [InlineData("--all-but", "2.2.300", new[] { "2.2.300" })] [InlineData("--all-but", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] [InlineData("--all-below", "2.2.300", "2.2.300")] - [InlineData("--all-previews")] - [InlineData("--all-previews-but-latest")] + [InlineData("--all-previews", null, true)] + [InlineData("--all-previews-but-latest", null, true)] [InlineData("--major-minor", "2.2", "2.2")] [InlineData("", "2.2.300", new[] { "2.2.300" })] [InlineData("", "2.2.300 3.0.100", new[] { "2.2.300", "3.0.100" })] @@ -182,8 +184,9 @@ internal void TestWhatIfCommandAccept(string option, string argValue = "", objec if (!option.Equals(string.Empty)) { - parseResult.CommandResult.OptionResult(option).Should().NotBeNull(); - parseResult.ValueForOption(option).Should().BeEquivalentTo(expected); + var optionResult = parseResult.CommandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); + parseResult.GetValueForOption(optionResult.Option).Should().BeEquivalentTo(expected); } else { @@ -422,8 +425,10 @@ internal void TestGetUninstallRemoveOptionAccept(string option, string argValue } else { + var optionResult = commandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); commandResult.GetUninstallMainOption().Name - .Should().Be(commandResult.OptionResult(option).Option.Name); + .Should().Be(optionResult.Option.Name); } } @@ -451,8 +456,10 @@ internal void TestGetUninstallDryRunOptionAccept(string option, string argValue } else { + var optionResult = commandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); commandResult.GetUninstallMainOption().Name - .Should().Be(commandResult.OptionResult(option).Option.Name); + .Should().Be(optionResult.Option.Name); } } @@ -480,8 +487,10 @@ internal void TestGetUninstallWhatIfOptionAccept(string option, string argValue } else { + var optionResult = commandResult.Children.First(c => c is OptionResult o && o.Option.Name == option.TrimStart('-')) as OptionResult; + optionResult.Should().NotBeNull(); commandResult.GetUninstallMainOption().Name - .Should().Be(commandResult.OptionResult(option).Option.Name); + .Should().Be(optionResult.Option.Name); } }