From 6ec461c5eab0655a689fb12e556841818dda9c36 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 11 Apr 2025 08:28:14 -0700 Subject: [PATCH 01/45] Add command --- .../Commands/Tool/Runx/ToolRunxCommand.cs | 25 ++++++++++ .../Tool/Runx/ToolRunxCommandParser.cs | 46 +++++++++++++++++++ .../dotnet/Commands/Tool/ToolCommandParser.cs | 2 + 3 files changed, 73 insertions(+) create mode 100644 src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs create mode 100644 src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs new file mode 100644 index 000000000000..405aa8c40b41 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.CommandFactory; +using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; +using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.ToolManifest; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; +using Microsoft.DotNet.Cli.ToolPackage; +namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; + +internal class ToolRunxCommand(ParseResult result) : CommandBase(result) +{ + private readonly string _toolCommandName = result.GetValue(ToolRunxCommandParser.CommandNameArgument); + private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunxCommandParser.CommandArgument); + public bool _allowRollForward = result.GetValue(ToolRunxCommandParser.RollForwardOption); + + public override int Execute() + { + var tempDir = new DirectoryPath(PathUtilities.CreateTempSubdirectory()); + return 0; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs new file mode 100644 index 000000000000..21b6a509cdf9 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; + +internal static class ToolRunxCommandParser +{ + public static readonly CliArgument CommandNameArgument = new("commandName") + { + HelpName = CliCommandStrings.CommandNameArgumentName, + Description = CliCommandStrings.CommandNameArgumentDescription + }; + + public static readonly CliArgument> CommandArgument = new("toolArguments") + { + Description = "arguments forwarded to the tool" + }; + + public static readonly CliOption RollForwardOption = new("--allow-roll-forward") + { + Description = CliCommandStrings.RollForwardOptionDescription, + Arity = ArgumentArity.Zero + }; + + private static readonly CliCommand Command = ConstructCommand(); + + public static CliCommand GetCommand() + { + return Command; + } + + private static CliCommand ConstructCommand() + { + CliCommand command = new("run", CliCommandStrings.ToolRunCommandDescription); + + command.Arguments.Add(CommandNameArgument); + command.Arguments.Add(CommandArgument); + command.Options.Add(RollForwardOption); + + command.SetAction((parseResult) => new ToolRunxCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs index afc8ef9fb707..532fdbf93de2 100644 --- a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs @@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.Commands.Tool.List; using Microsoft.DotNet.Cli.Commands.Tool.Restore; using Microsoft.DotNet.Cli.Commands.Tool.Run; +using Microsoft.DotNet.Cli.Commands.Tool.Runx; using Microsoft.DotNet.Cli.Commands.Tool.Search; using Microsoft.DotNet.Cli.Commands.Tool.Uninstall; using Microsoft.DotNet.Cli.Commands.Tool.Update; @@ -37,6 +38,7 @@ private static Command ConstructCommand() command.Subcommands.Add(ToolRunCommandParser.GetCommand()); command.Subcommands.Add(ToolSearchCommandParser.GetCommand()); command.Subcommands.Add(ToolRestoreCommandParser.GetCommand()); + command.Subcommands.Add(ToolRunxCommandParser.GetCommand()); command.SetAction((parseResult) => parseResult.HandleMissingCommand()); From a36b14b2d84b54fe3ba4755bfbe76a6c4e93ad41 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 14:44:06 -0700 Subject: [PATCH 02/45] Add logic for acquisition and running --- .../Commands/Tool/Runx/ToolRunxCommand.cs | 29 +++++++++++++++++-- .../Tool/Runx/ToolRunxCommandParser.cs | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs index 405aa8c40b41..2f1292a3bb45 100644 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs @@ -14,12 +14,35 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; internal class ToolRunxCommand(ParseResult result) : CommandBase(result) { private readonly string _toolCommandName = result.GetValue(ToolRunxCommandParser.CommandNameArgument); - private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunxCommandParser.CommandArgument); - public bool _allowRollForward = result.GetValue(ToolRunxCommandParser.RollForwardOption); public override int Execute() { + PackageLocation packageLocation = new PackageLocation(); + PackageId packageId = new PackageId(_toolCommandName); + var tempDir = new DirectoryPath(PathUtilities.CreateTempSubdirectory()); - return 0; + + // Acquire package + + ToolPackageStoreAndQuery toolPackageStoreAndQuery = ToolPackageFactory.CreateConcreteToolPackageStore(tempDir); + ToolPackageDownloader toolPackageDownloader = new ToolPackageDownloader(toolPackageStoreAndQuery); + ToolPackageUninstaller toolPackageUninstaller = new ToolPackageUninstaller(toolPackageStoreAndQuery); + + IToolPackage toolPackage = toolPackageStoreAndQuery.EnumeratePackageVersions(packageId).FirstOrDefault() + ?? toolPackageDownloader.InstallPackage(packageLocation, packageId); + + // Run package + + DotnetToolsCommandResolver dotnetToolsCommandResolver = new DotnetToolsCommandResolver(toolPackageStoreAndQuery.Root.ToString()); + CommandSpec commandSpec = dotnetToolsCommandResolver.Resolve(new CommandResolverArguments() + { + // since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet- + CommandName = $"dotnet-{_toolCommandName}", + CommandArguments = new string[] { }, + }); + + var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); + + return result.ExitCode; } } diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs index 21b6a509cdf9..427b4f04d91a 100644 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs @@ -33,7 +33,7 @@ public static CliCommand GetCommand() private static CliCommand ConstructCommand() { - CliCommand command = new("run", CliCommandStrings.ToolRunCommandDescription); + CliCommand command = new("runx", "TODO: Run and execute remote tool"); command.Arguments.Add(CommandNameArgument); command.Arguments.Add(CommandArgument); From 2f2784461a5a57295ac85c3b44e737a467cd85d1 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 16:41:15 -0700 Subject: [PATCH 03/45] Execute tool --- .../dotnet/Commands/Tool/Runx/ToolRunxCommand.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs index 2f1292a3bb45..b68143ef272c 100644 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs @@ -14,10 +14,10 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; internal class ToolRunxCommand(ParseResult result) : CommandBase(result) { private readonly string _toolCommandName = result.GetValue(ToolRunxCommandParser.CommandNameArgument); + private readonly IEnumerable _toolArguments = result.GetValue(ToolRunxCommandParser.CommandArgument); public override int Execute() { - PackageLocation packageLocation = new PackageLocation(); PackageId packageId = new PackageId(_toolCommandName); var tempDir = new DirectoryPath(PathUtilities.CreateTempSubdirectory()); @@ -28,17 +28,18 @@ public override int Execute() ToolPackageDownloader toolPackageDownloader = new ToolPackageDownloader(toolPackageStoreAndQuery); ToolPackageUninstaller toolPackageUninstaller = new ToolPackageUninstaller(toolPackageStoreAndQuery); - IToolPackage toolPackage = toolPackageStoreAndQuery.EnumeratePackageVersions(packageId).FirstOrDefault() - ?? toolPackageDownloader.InstallPackage(packageLocation, packageId); + PackageLocation packageLocation = new PackageLocation(rootConfigDirectory: toolPackageStoreAndQuery.Root); + + IToolPackage toolPackage = toolPackageDownloader.InstallPackage(packageLocation, packageId, isGlobalTool: true); // Run package - DotnetToolsCommandResolver dotnetToolsCommandResolver = new DotnetToolsCommandResolver(toolPackageStoreAndQuery.Root.ToString()); + DotnetToolsCommandResolver dotnetToolsCommandResolver = new DotnetToolsCommandResolver(toolPackage.PackageDirectory.Value); CommandSpec commandSpec = dotnetToolsCommandResolver.Resolve(new CommandResolverArguments() { // since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet- - CommandName = $"dotnet-{_toolCommandName}", - CommandArguments = new string[] { }, + CommandName = _toolCommandName.StartsWith("dotnet-") ? _toolCommandName : $"dotnet-{_toolCommandName}", + CommandArguments = _toolArguments, }); var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); From 9cc3c783ab862766086e27b6195f017386cb83ea Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 16:42:02 -0700 Subject: [PATCH 04/45] Load package if installed --- src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs index b68143ef272c..3bbd062ff604 100644 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs @@ -30,7 +30,8 @@ public override int Execute() PackageLocation packageLocation = new PackageLocation(rootConfigDirectory: toolPackageStoreAndQuery.Root); - IToolPackage toolPackage = toolPackageDownloader.InstallPackage(packageLocation, packageId, isGlobalTool: true); + IToolPackage toolPackage = toolPackageStoreAndQuery.EnumeratePackageVersions(packageId).FirstOrDefault() + ?? toolPackageDownloader.InstallPackage(packageLocation, packageId, isGlobalTool: true); // Run package From 1322829dba6cd7530822e4a958c942a02184f4c3 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 19:09:06 -0700 Subject: [PATCH 05/45] tool-run: --from-source --- .../Commands/Tool/Run/ToolRunCommand.cs | 36 +++++++++++++ .../Commands/Tool/Run/ToolRunCommandParser.cs | 3 ++ .../Commands/Tool/Runx/ToolRunxCommand.cs | 50 ------------------- .../Tool/Runx/ToolRunxCommandParser.cs | 46 ----------------- .../dotnet/Commands/Tool/ToolCommandParser.cs | 2 - .../dotnet/ToolManifest/ToolManifestFinder.cs | 2 +- 6 files changed, 40 insertions(+), 99 deletions(-) delete mode 100644 src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs delete mode 100644 src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 5a8a7fb7721a..8d43fd96cd12 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -6,7 +6,9 @@ using System.CommandLine; using Microsoft.DotNet.Cli.CommandFactory; using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; +using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.ToolManifest; +using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; using Microsoft.Extensions.EnvironmentAbstractions; @@ -22,7 +24,11 @@ internal class ToolRunCommand( private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunCommandParser.CommandArgument); public bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); private readonly ToolManifestFinder _toolManifest = toolManifest ?? new ToolManifestFinder(new DirectoryPath(Directory.GetCurrentDirectory())); + private readonly bool _fromSource = result.GetValue(ToolRunCommandParser.FromSourceOption); + private readonly ToolInstallLocalInstaller _toolInstaller = new(result); + private readonly IToolManifestEditor _toolManifestEditor = new ToolManifestEditor(); + private readonly ILocalToolsResolverCache _localToolsResolverCache = new LocalToolsResolverCache(); public override int Execute() { CommandSpec commandspec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() @@ -33,6 +39,11 @@ public override int Execute() }, _allowRollForward); + if (commandspec == null && _fromSource) + { + commandspec = GetRemoteCommandSpec(); + } + if (commandspec == null) { throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); @@ -41,4 +52,29 @@ public override int Execute() var result = CommandFactoryUsingResolver.Create(commandspec).Execute(); return result.ExitCode; } + + public CommandSpec GetRemoteCommandSpec() + { + FilePath manifestFile = _toolManifest.FindFirst(true); + PackageId packageId = new(_toolCommandName); + + IToolPackage toolPackage = _toolInstaller.Install(manifestFile, packageId); + + _toolManifestEditor.Add( + manifestFile, + toolPackage.Id, + toolPackage.Version, + [toolPackage.Command.Name], + _allowRollForward); + + _localToolsResolverCache.SaveToolPackage( + toolPackage, + _toolInstaller.TargetFrameworkToInstall); + + return _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() + { + CommandName = $"dotnet-{toolPackage.Command.Name}", + CommandArguments = _forwardArgument, + }, _allowRollForward); + } } diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 62902224054f..419dc8f1d778 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -26,6 +26,8 @@ internal static class ToolRunCommandParser Arity = ArgumentArity.Zero }; + public static readonly Option FromSourceOption = new("--from-source"); + private static readonly Command Command = ConstructCommand(); public static Command GetCommand() @@ -40,6 +42,7 @@ private static Command ConstructCommand() command.Arguments.Add(CommandNameArgument); command.Arguments.Add(CommandArgument); command.Options.Add(RollForwardOption); + command.Options.Add(FromSourceOption); command.SetAction((parseResult) => new ToolRunCommand(parseResult).Execute()); diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs deleted file mode 100644 index 3bbd062ff604..000000000000 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommand.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.CommandLine; -using Microsoft.DotNet.Cli.CommandFactory; -using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; -using Microsoft.DotNet.Cli.Commands.Tool.Install; -using Microsoft.DotNet.Cli.ToolManifest; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.Extensions.EnvironmentAbstractions; -using Microsoft.DotNet.Cli.ToolPackage; -namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; - -internal class ToolRunxCommand(ParseResult result) : CommandBase(result) -{ - private readonly string _toolCommandName = result.GetValue(ToolRunxCommandParser.CommandNameArgument); - private readonly IEnumerable _toolArguments = result.GetValue(ToolRunxCommandParser.CommandArgument); - - public override int Execute() - { - PackageId packageId = new PackageId(_toolCommandName); - - var tempDir = new DirectoryPath(PathUtilities.CreateTempSubdirectory()); - - // Acquire package - - ToolPackageStoreAndQuery toolPackageStoreAndQuery = ToolPackageFactory.CreateConcreteToolPackageStore(tempDir); - ToolPackageDownloader toolPackageDownloader = new ToolPackageDownloader(toolPackageStoreAndQuery); - ToolPackageUninstaller toolPackageUninstaller = new ToolPackageUninstaller(toolPackageStoreAndQuery); - - PackageLocation packageLocation = new PackageLocation(rootConfigDirectory: toolPackageStoreAndQuery.Root); - - IToolPackage toolPackage = toolPackageStoreAndQuery.EnumeratePackageVersions(packageId).FirstOrDefault() - ?? toolPackageDownloader.InstallPackage(packageLocation, packageId, isGlobalTool: true); - - // Run package - - DotnetToolsCommandResolver dotnetToolsCommandResolver = new DotnetToolsCommandResolver(toolPackage.PackageDirectory.Value); - CommandSpec commandSpec = dotnetToolsCommandResolver.Resolve(new CommandResolverArguments() - { - // since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet- - CommandName = _toolCommandName.StartsWith("dotnet-") ? _toolCommandName : $"dotnet-{_toolCommandName}", - CommandArguments = _toolArguments, - }); - - var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); - - return result.ExitCode; - } -} diff --git a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs deleted file mode 100644 index 427b4f04d91a..000000000000 --- a/src/Cli/dotnet/Commands/Tool/Runx/ToolRunxCommandParser.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.CommandLine; - -namespace Microsoft.DotNet.Cli.Commands.Tool.Runx; - -internal static class ToolRunxCommandParser -{ - public static readonly CliArgument CommandNameArgument = new("commandName") - { - HelpName = CliCommandStrings.CommandNameArgumentName, - Description = CliCommandStrings.CommandNameArgumentDescription - }; - - public static readonly CliArgument> CommandArgument = new("toolArguments") - { - Description = "arguments forwarded to the tool" - }; - - public static readonly CliOption RollForwardOption = new("--allow-roll-forward") - { - Description = CliCommandStrings.RollForwardOptionDescription, - Arity = ArgumentArity.Zero - }; - - private static readonly CliCommand Command = ConstructCommand(); - - public static CliCommand GetCommand() - { - return Command; - } - - private static CliCommand ConstructCommand() - { - CliCommand command = new("runx", "TODO: Run and execute remote tool"); - - command.Arguments.Add(CommandNameArgument); - command.Arguments.Add(CommandArgument); - command.Options.Add(RollForwardOption); - - command.SetAction((parseResult) => new ToolRunxCommand(parseResult).Execute()); - - return command; - } -} diff --git a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs index 532fdbf93de2..afc8ef9fb707 100644 --- a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs @@ -8,7 +8,6 @@ using Microsoft.DotNet.Cli.Commands.Tool.List; using Microsoft.DotNet.Cli.Commands.Tool.Restore; using Microsoft.DotNet.Cli.Commands.Tool.Run; -using Microsoft.DotNet.Cli.Commands.Tool.Runx; using Microsoft.DotNet.Cli.Commands.Tool.Search; using Microsoft.DotNet.Cli.Commands.Tool.Uninstall; using Microsoft.DotNet.Cli.Commands.Tool.Update; @@ -38,7 +37,6 @@ private static Command ConstructCommand() command.Subcommands.Add(ToolRunCommandParser.GetCommand()); command.Subcommands.Add(ToolSearchCommandParser.GetCommand()); command.Subcommands.Add(ToolRestoreCommandParser.GetCommand()); - command.Subcommands.Add(ToolRunxCommandParser.GetCommand()); command.SetAction((parseResult) => parseResult.HandleMissingCommand()); diff --git a/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs b/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs index d7889b0a4532..a235bcd2d227 100644 --- a/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs +++ b/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs @@ -191,7 +191,7 @@ public FilePath FindFirst(bool createIfNotFound = false) /* The --create-manifest-if-needed will use the following priority to choose the folder where the tool manifest goes: - 1. Walk up the directory tree searching for one that has a.git subfolder + 1. Walk up the directory tree searching for one that has a .git subfolder 2. Walk up the directory tree searching for one that has a .sln(x)/git file in it 3. Use the current working directory */ From 2b2e18ca3c03eafb39e2d453ffa1e7b9a61c6550 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 21:32:31 -0700 Subject: [PATCH 06/45] Save tool to temp directory --- .../Commands/Tool/Run/ToolRunCommand.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 8d43fd96cd12..b2937addd5b9 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -26,7 +26,6 @@ internal class ToolRunCommand( private readonly ToolManifestFinder _toolManifest = toolManifest ?? new ToolManifestFinder(new DirectoryPath(Directory.GetCurrentDirectory())); private readonly bool _fromSource = result.GetValue(ToolRunCommandParser.FromSourceOption); - private readonly ToolInstallLocalInstaller _toolInstaller = new(result); private readonly IToolManifestEditor _toolManifestEditor = new ToolManifestEditor(); private readonly ILocalToolsResolverCache _localToolsResolverCache = new LocalToolsResolverCache(); public override int Execute() @@ -41,7 +40,7 @@ public override int Execute() if (commandspec == null && _fromSource) { - commandspec = GetRemoteCommandSpec(); + return ExecuteFromSource(); } if (commandspec == null) @@ -53,11 +52,15 @@ public override int Execute() return result.ExitCode; } - public CommandSpec GetRemoteCommandSpec() + public int ExecuteFromSource() { + string tempDirectory = PathUtilities.CreateTempSubdirectory(); FilePath manifestFile = _toolManifest.FindFirst(true); PackageId packageId = new(_toolCommandName); + ToolInstallLocalInstaller _toolInstaller = new(_parseResult, new ToolPackageDownloader( + store: new ToolPackageStoreAndQuery(new DirectoryPath(tempDirectory)))); + IToolPackage toolPackage = _toolInstaller.Install(manifestFile, packageId); _toolManifestEditor.Add( @@ -71,10 +74,21 @@ public CommandSpec GetRemoteCommandSpec() toolPackage, _toolInstaller.TargetFrameworkToInstall); - return _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() + CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() { CommandName = $"dotnet-{toolPackage.Command.Name}", CommandArguments = _forwardArgument, }, _allowRollForward); + + if (commandSpec == null) + { + throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); + } + + var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); + + _toolManifestEditor.Remove(manifestFile, toolPackage.Id); + + return result.ExitCode; } } From 7706c72adcd76fb228a635a4acac7dccaec32fcc Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 14 Apr 2025 21:55:50 -0700 Subject: [PATCH 07/45] Update translations --- src/Cli/dotnet/Commands/CliCommandStrings.resx | 3 +++ src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs | 6 +++++- src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf | 5 +++++ src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf | 5 +++++ 15 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index ede0617ae9d2..c8e4da977886 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2476,4 +2476,7 @@ To display a value, specify the corresponding command-line option without provid Recursively add projects' ReferencedProjects to solution + + Executes a tool from source without permanently installing it. + diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 419dc8f1d778..a0d5e1a3523d 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -26,7 +26,11 @@ internal static class ToolRunCommandParser Arity = ArgumentArity.Zero }; - public static readonly Option FromSourceOption = new("--from-source"); + public static readonly Option FromSourceOption = new("--from-source") + { + Description = CliCommandStrings.ToolRunFromSourceOptionDescription, + Arity = ArgumentArity.Zero + }; private static readonly Command Command = ConstructCommand(); diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 40a1e5189fa6..b5bcf1eb9a74 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index c795c89be56b..9809782c494d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 87c250c83c14..edc7aefffeda 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index ef30f2a8ef9c..b1e762249afe 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 66e863b40a8a..39ece4c0b692 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index b1bc5a8d953d..9c4be8023c40 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index b40650d304bc..2b2cbabd978a 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 8e34a1a7e43f..0520bb161820 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 0b308fd9d0f7..077537be235e 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 15be059276e5..f84bbd230b4c 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 0b7b2addb199..b61a53943b40 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index fd53a87098be..aca7faa291b3 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 20c06fd3cd4a..9b698cca8387 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -3137,6 +3137,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org From b9a03d2034af4d49ef99aa345a35ada14934197c Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 15 Apr 2025 12:54:26 -0700 Subject: [PATCH 08/45] Update cli snapshots --- .../bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh | 2 +- .../pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 | 1 + .../zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index b4041b1e123c..6f0dbed8b489 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1729,7 +1729,7 @@ _testhost_tool_run() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--allow-roll-forward --help" + opts="--allow-roll-forward --from-source --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index 3d96499b00d8..2c70382518b9 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1057,6 +1057,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { 'testhost;tool;run' { $staticCompletions = @( [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") + [CompletionResult]::new('--from-source', '--from-source', [CompletionResultType]::ParameterName, "Executes a tool from source without permanently installing it. ") [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index a35e334962a1..f26f4307f9fa 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1127,6 +1127,7 @@ _testhost() { (run) _arguments "${_arguments_options[@]}" : \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ + '--from-source[Executes a tool from source without permanently installing it. ]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':commandName -- The command name of the tool to run.: ' \ From da3e28e81cff3174721ace257cad2d8b93f352c3 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 15 Apr 2025 18:52:25 -0700 Subject: [PATCH 09/45] Address pr comments --- .../dotnet/Commands/Tool/Run/ToolRunCommand.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index b2937addd5b9..95d442c16745 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -30,7 +30,7 @@ internal class ToolRunCommand( private readonly ILocalToolsResolverCache _localToolsResolverCache = new LocalToolsResolverCache(); public override int Execute() { - CommandSpec commandspec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() + CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() { // since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet- CommandName = $"dotnet-{_toolCommandName}", @@ -38,17 +38,17 @@ public override int Execute() }, _allowRollForward); - if (commandspec == null && _fromSource) + if (commandSpec == null && _fromSource && UserAgreedToExecuteFromSource()) { return ExecuteFromSource(); } - if (commandspec == null) + if (commandSpec == null) { throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); } - var result = CommandFactoryUsingResolver.Create(commandspec).Execute(); + var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); return result.ExitCode; } @@ -91,4 +91,11 @@ public int ExecuteFromSource() return result.ExitCode; } + + private bool UserAgreedToExecuteFromSource() + { + // TODO: Use a better way to ask for user input + Console.WriteLine("Tool will be run from source. Accept? [yn]") + return Console.ReadLine() == 'y'; + } } From 3349a733a9a39814ff827851b4fd83637a96ed6c Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 15 Apr 2025 19:06:53 -0700 Subject: [PATCH 10/45] Fix typo --- src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 95d442c16745..f444eafe27b2 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -95,7 +95,7 @@ public int ExecuteFromSource() private bool UserAgreedToExecuteFromSource() { // TODO: Use a better way to ask for user input - Console.WriteLine("Tool will be run from source. Accept? [yn]") + Console.WriteLine("Tool will be run from source. Accept? [yn]"); return Console.ReadLine() == 'y'; } } From dd13c5358f2f8bce85f6736e9ac12233c80ad159 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 15 Apr 2025 19:25:23 -0700 Subject: [PATCH 11/45] Fix typo --- src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index f444eafe27b2..08d24dd9f90c 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -96,6 +96,6 @@ private bool UserAgreedToExecuteFromSource() { // TODO: Use a better way to ask for user input Console.WriteLine("Tool will be run from source. Accept? [yn]"); - return Console.ReadLine() == 'y'; + return Console.ReadLine() == "y"; } } From 0ea66962a2e2edb40572fd353e53e6204c078b6a Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Wed, 16 Apr 2025 17:14:45 -0700 Subject: [PATCH 12/45] Move logic to ToolRunFromSourceCommand.cs --- .../Commands/Tool/Run/ToolRunCommand.cs | 62 ++------------ .../Commands/Tool/Run/ToolRunCommandParser.cs | 1 + .../Tool/Run/ToolRunFromSourceCommand.cs | 82 +++++++++++++++++++ .../ToolManifest/IToolManifestEditor.cs | 2 +- 4 files changed, 92 insertions(+), 55 deletions(-) create mode 100644 src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 08d24dd9f90c..3cb94a0e8b93 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -7,6 +7,7 @@ using Microsoft.DotNet.Cli.CommandFactory; using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.NuGetPackageDownloader; using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; @@ -16,18 +17,15 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Run; internal class ToolRunCommand( ParseResult result, - LocalToolsCommandResolver localToolsCommandResolver = null, - ToolManifestFinder toolManifest = null) : CommandBase(result) + LocalToolsCommandResolver localToolsCommandResolver = null) : CommandBase(result) { private readonly string _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); - private readonly LocalToolsCommandResolver _localToolsCommandResolver = localToolsCommandResolver ?? new LocalToolsCommandResolver(); private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunCommandParser.CommandArgument); - public bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); - private readonly ToolManifestFinder _toolManifest = toolManifest ?? new ToolManifestFinder(new DirectoryPath(Directory.GetCurrentDirectory())); private readonly bool _fromSource = result.GetValue(ToolRunCommandParser.FromSourceOption); - private readonly IToolManifestEditor _toolManifestEditor = new ToolManifestEditor(); - private readonly ILocalToolsResolverCache _localToolsResolverCache = new LocalToolsResolverCache(); + private readonly LocalToolsCommandResolver _localToolsCommandResolver = localToolsCommandResolver ?? new LocalToolsCommandResolver(); + public bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); + public override int Execute() { CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() @@ -38,9 +36,10 @@ public override int Execute() }, _allowRollForward); - if (commandSpec == null && _fromSource && UserAgreedToExecuteFromSource()) + if (commandSpec == null && _fromSource) { - return ExecuteFromSource(); + // Reroute to ToolRunFromSourceCommand + return new ToolRunFromSourceCommand(_parseResult).Execute(); } if (commandSpec == null) @@ -52,50 +51,5 @@ public override int Execute() return result.ExitCode; } - public int ExecuteFromSource() - { - string tempDirectory = PathUtilities.CreateTempSubdirectory(); - FilePath manifestFile = _toolManifest.FindFirst(true); - PackageId packageId = new(_toolCommandName); - - ToolInstallLocalInstaller _toolInstaller = new(_parseResult, new ToolPackageDownloader( - store: new ToolPackageStoreAndQuery(new DirectoryPath(tempDirectory)))); - - IToolPackage toolPackage = _toolInstaller.Install(manifestFile, packageId); - - _toolManifestEditor.Add( - manifestFile, - toolPackage.Id, - toolPackage.Version, - [toolPackage.Command.Name], - _allowRollForward); - - _localToolsResolverCache.SaveToolPackage( - toolPackage, - _toolInstaller.TargetFrameworkToInstall); - - CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() - { - CommandName = $"dotnet-{toolPackage.Command.Name}", - CommandArguments = _forwardArgument, - }, _allowRollForward); - - if (commandSpec == null) - { - throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); - } - - var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); - - _toolManifestEditor.Remove(manifestFile, toolPackage.Id); - return result.ExitCode; - } - - private bool UserAgreedToExecuteFromSource() - { - // TODO: Use a better way to ask for user input - Console.WriteLine("Tool will be run from source. Accept? [yn]"); - return Console.ReadLine() == "y"; - } } diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index a0d5e1a3523d..6dc46be1c6c8 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -4,6 +4,7 @@ #nullable disable using System.CommandLine; +using Microsoft.DotNet.Cli.Commands.Tool.Install; namespace Microsoft.DotNet.Cli.Commands.Tool.Run; diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs new file mode 100644 index 000000000000..ed0d32b1a3d6 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.CommandFactory; +using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; +using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.ToolManifest; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Run +{ + internal class ToolRunFromSourceCommand( + ParseResult result) : CommandBase(result) + { + private readonly string? _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); + private readonly IEnumerable? _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument); + private readonly bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); + + public override int Execute() + { + if (!UserAgreedToExecuteFromSource()) + { + return 1; + } + + PackageId packageId = new(_toolCommandName); + VersionRange versionRange = _parseResult.GetVersionRange(); + + string tempDirectory = PathUtilities.CreateTempSubdirectory(); + + IToolManifestFinder toolManifestFinder = new ToolManifestFinder(new(tempDirectory)); + IToolManifestEditor toolManifestEditor = new ToolManifestEditor(); + FilePath toolManifestPath = toolManifestFinder.FindFirst(true); + + ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory)); + ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery); + + IToolPackage toolPackage = toolPackageDownloader.InstallPackage( + new PackageLocation(), + packageId: packageId, + verbosity: VerbosityOptions.d, + versionRange: versionRange); + + toolManifestEditor.Add( + toolManifestPath, + packageId, + toolPackage.Version, + [toolPackage.Command.Name], + rollForward: _allowRollForward); + + LocalToolsCommandResolver localToolsCommandResolver = new(); + + CommandSpec commandSpec = localToolsCommandResolver.ResolveStrict(new() + { + CommandName = $"dotnet-{toolPackage.Command.Name}", + CommandArguments = _forwardArguments, + }, _allowRollForward); + + if (commandSpec == null) + { + throw new GracefulException( + string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName), + isUserError: false); + } + + var command = CommandFactoryUsingResolver.Create(commandSpec); + var result = command.Execute(); + + return result.ExitCode; + } + private bool UserAgreedToExecuteFromSource() + { + // TODO: Use a better way to ask for user input + Console.WriteLine("Tool will be run from source. Accept? [yn]"); + return Console.ReadKey().Key == ConsoleKey.Y; + } + } +} diff --git a/src/Cli/dotnet/ToolManifest/IToolManifestEditor.cs b/src/Cli/dotnet/ToolManifest/IToolManifestEditor.cs index 9c6f14290830..1c3047698dd2 100644 --- a/src/Cli/dotnet/ToolManifest/IToolManifestEditor.cs +++ b/src/Cli/dotnet/ToolManifest/IToolManifestEditor.cs @@ -12,7 +12,7 @@ namespace Microsoft.DotNet.Cli.ToolManifest; internal interface IToolManifestEditor { - void Add(FilePath manifest, PackageId packageId, NuGetVersion nuGetVersion, ToolCommandName[] toolCommandNames, bool RollForward = false); + void Add(FilePath manifest, PackageId packageId, NuGetVersion nuGetVersion, ToolCommandName[] toolCommandNames, bool rollForward = false); void Remove(FilePath manifest, PackageId packageId); void Edit(FilePath manifest, PackageId packageId, NuGetVersion newNuGetVersion, ToolCommandName[] newToolCommandNames); } From f689647180c40e9e87494da43331866ad3d98688 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Thu, 17 Apr 2025 11:11:53 -0700 Subject: [PATCH 13/45] Add options --- .../Commands/Tool/Run/ToolRunCommandParser.cs | 16 ++++++++++++++++ .../Tool/Run/ToolRunFromSourceCommand.cs | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 6dc46be1c6c8..5c2173498491 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -5,6 +5,7 @@ using System.CommandLine; using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.Commands.Tool.Common; namespace Microsoft.DotNet.Cli.Commands.Tool.Run; @@ -33,6 +34,14 @@ internal static class ToolRunCommandParser Arity = ArgumentArity.Zero }; + public static readonly Option FromSourceConfigFile = ToolInstallCommandParser.ConfigOption; + + public static readonly Option FromSourceSourceOption = ToolInstallCommandParser.SourceOption; + + public static readonly Option FromSourceAddSourceOption = ToolInstallCommandParser.AddSourceOption; + + public static readonly Option VerbosityOption = CommonOptions.VerbosityOption; + private static readonly Command Command = ConstructCommand(); public static Command GetCommand() @@ -48,6 +57,13 @@ private static Command ConstructCommand() command.Arguments.Add(CommandArgument); command.Options.Add(RollForwardOption); command.Options.Add(FromSourceOption); + command.Options.Add(FromSourceConfigFile); + command.Options.Add(FromSourceSourceOption); + command.Options.Add(FromSourceAddSourceOption); + command.Options.Add(VerbosityOption); + + command.Options.Add(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); + command.Options.Add(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); command.SetAction((parseResult) => new ToolRunCommand(parseResult).Execute()); diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index ed0d32b1a3d6..936ade605418 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -19,6 +19,12 @@ internal class ToolRunFromSourceCommand( private readonly string? _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); private readonly IEnumerable? _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument); private readonly bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); + private readonly string? _configFile = result.GetValue(ToolRunCommandParser.FromSourceConfigFile); + private readonly string[] _sources = result.GetValue(ToolRunCommandParser.FromSourceSourceOption) ?? []; + private readonly string[] _addSource = result.GetValue(ToolRunCommandParser.FromSourceAddSourceOption) ?? []; + private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); + private readonly bool _interactive = result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); + private readonly VerbosityOptions _verbosity = result.GetValue(ToolRunCommandParser.VerbosityOption); public override int Execute() { @@ -40,10 +46,17 @@ public override int Execute() ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery); IToolPackage toolPackage = toolPackageDownloader.InstallPackage( - new PackageLocation(), + new PackageLocation( + nugetConfig: _configFile != null ? new FilePath(_configFile) : null, + rootConfigDirectory: null, + sourceFeedOverrides: _sources, + additionalFeeds: _addSource), packageId: packageId, - verbosity: VerbosityOptions.d, - versionRange: versionRange); + verbosity: _verbosity, + versionRange: versionRange, + restoreActionConfig: new( + IgnoreFailedSources: _ignoreFailedSources, + Interactive: _interactive)); toolManifestEditor.Add( toolManifestPath, From 69cf295e5ecb395edb85a959a12797895e5ac896 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Thu, 17 Apr 2025 11:31:09 -0700 Subject: [PATCH 14/45] Fix typo --- src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs | 2 +- .../dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 5c2173498491..370a9e2d5ff1 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -33,7 +33,7 @@ internal static class ToolRunCommandParser Description = CliCommandStrings.ToolRunFromSourceOptionDescription, Arity = ArgumentArity.Zero }; - + public static readonly Option FromSourceConfigFile = ToolInstallCommandParser.ConfigOption; public static readonly Option FromSourceSourceOption = ToolInstallCommandParser.SourceOption; diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index 936ade605418..073dafe09256 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -9,6 +9,8 @@ using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; using Microsoft.Extensions.EnvironmentAbstractions; +using NuGet.Frameworks; +using NuGet.Packaging; using NuGet.Versioning; namespace Microsoft.DotNet.Cli.Commands.Tool.Run @@ -48,7 +50,7 @@ public override int Execute() IToolPackage toolPackage = toolPackageDownloader.InstallPackage( new PackageLocation( nugetConfig: _configFile != null ? new FilePath(_configFile) : null, - rootConfigDirectory: null, + rootConfigDirectory: toolManifestPath.GetDirectoryPath().GetParentPath(), sourceFeedOverrides: _sources, additionalFeeds: _addSource), packageId: packageId, @@ -58,6 +60,9 @@ public override int Execute() IgnoreFailedSources: _ignoreFailedSources, Interactive: _interactive)); + LocalToolsResolverCache localToolsResolverCache = new(); + localToolsResolverCache.SaveToolPackage(toolPackage, BundledTargetFramework.GetTargetFrameworkMoniker()); + toolManifestEditor.Add( toolManifestPath, packageId, From 623d36a8bd7955b271fed8bc21e1957b3a65d7f3 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Thu, 17 Apr 2025 12:08:24 -0700 Subject: [PATCH 15/45] Run tool --- .../Tool/Run/ToolRunFromSourceCommand.cs | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index 073dafe09256..d30039f10829 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Cli.Utils.Extensions; using Microsoft.Extensions.EnvironmentAbstractions; using NuGet.Frameworks; using NuGet.Packaging; @@ -35,13 +36,18 @@ public override int Execute() return 1; } + if (_allowRollForward) + { + _forwardArguments.Append("--allow-roll-forward"); + } + PackageId packageId = new(_toolCommandName); VersionRange versionRange = _parseResult.GetVersionRange(); string tempDirectory = PathUtilities.CreateTempSubdirectory(); - IToolManifestFinder toolManifestFinder = new ToolManifestFinder(new(tempDirectory)); - IToolManifestEditor toolManifestEditor = new ToolManifestEditor(); + ToolManifestFinder toolManifestFinder = new ToolManifestFinder(new(tempDirectory)); + ToolManifestEditor toolManifestEditor = new ToolManifestEditor(); FilePath toolManifestPath = toolManifestFinder.FindFirst(true); ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory)); @@ -56,45 +62,24 @@ public override int Execute() packageId: packageId, verbosity: _verbosity, versionRange: versionRange, + isGlobalToolRollForward: _allowRollForward, // Needed to update .runtimeconfig.json restoreActionConfig: new( IgnoreFailedSources: _ignoreFailedSources, Interactive: _interactive)); - LocalToolsResolverCache localToolsResolverCache = new(); - localToolsResolverCache.SaveToolPackage(toolPackage, BundledTargetFramework.GetTargetFrameworkMoniker()); - - toolManifestEditor.Add( - toolManifestPath, - packageId, - toolPackage.Version, - [toolPackage.Command.Name], - rollForward: _allowRollForward); - - LocalToolsCommandResolver localToolsCommandResolver = new(); - - CommandSpec commandSpec = localToolsCommandResolver.ResolveStrict(new() - { - CommandName = $"dotnet-{toolPackage.Command.Name}", - CommandArguments = _forwardArguments, - }, _allowRollForward); - - if (commandSpec == null) - { - throw new GracefulException( - string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName), - isUserError: false); - } - + CommandSpec commandSpec = MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer(toolPackage.Command.Executable.ToString(), _forwardArguments); var command = CommandFactoryUsingResolver.Create(commandSpec); var result = command.Execute(); - return result.ExitCode; } + private bool UserAgreedToExecuteFromSource() { // TODO: Use a better way to ask for user input - Console.WriteLine("Tool will be run from source. Accept? [yn]"); - return Console.ReadKey().Key == ConsoleKey.Y; + Console.Write("Tool will be run from source. Accept? [y]".Red()); + bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; + Console.WriteLine(); + return userAccepted; } } } From 1f6fc1917137d99a1adeff85602f438060543de7 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 18 Apr 2025 11:16:12 -0700 Subject: [PATCH 16/45] Simplify code and translations --- .../dotnet/Commands/CliCommandStrings.resx | 5 +++- .../Commands/Tool/Run/ToolRunCommandParser.cs | 5 ++-- .../Tool/Run/ToolRunFromSourceCommand.cs | 24 +++++-------------- .../Commands/xlf/CliCommandStrings.cs.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.de.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.es.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.fr.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.it.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.ja.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.ko.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.pl.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.ru.xlf | 5 ++++ .../Commands/xlf/CliCommandStrings.tr.xlf | 5 ++++ .../xlf/CliCommandStrings.zh-Hans.xlf | 5 ++++ .../xlf/CliCommandStrings.zh-Hant.xlf | 5 ++++ 16 files changed, 78 insertions(+), 21 deletions(-) diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index c8e4da977886..7d513ed68b23 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2479,4 +2479,7 @@ To display a value, specify the corresponding command-line option without provid Executes a tool from source without permanently installing it. - + + Tool not found in the system. Do you want to run it from source? [y/n] + + \ No newline at end of file diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 370a9e2d5ff1..7e10939d843a 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -40,7 +40,7 @@ internal static class ToolRunCommandParser public static readonly Option FromSourceAddSourceOption = ToolInstallCommandParser.AddSourceOption; - public static readonly Option VerbosityOption = CommonOptions.VerbosityOption; + public static readonly Option FromSourceVerbosityOption = CommonOptions.VerbosityOption; private static readonly Command Command = ConstructCommand(); @@ -56,11 +56,12 @@ private static Command ConstructCommand() command.Arguments.Add(CommandNameArgument); command.Arguments.Add(CommandArgument); command.Options.Add(RollForwardOption); + command.Options.Add(FromSourceOption); command.Options.Add(FromSourceConfigFile); command.Options.Add(FromSourceSourceOption); command.Options.Add(FromSourceAddSourceOption); - command.Options.Add(VerbosityOption); + command.Options.Add(FromSourceVerbosityOption); command.Options.Add(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); command.Options.Add(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index d30039f10829..ab7b622a6fc6 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -5,19 +5,12 @@ using Microsoft.DotNet.Cli.CommandFactory; using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; -using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Cli.Utils.Extensions; -using Microsoft.Extensions.EnvironmentAbstractions; -using NuGet.Frameworks; -using NuGet.Packaging; using NuGet.Versioning; namespace Microsoft.DotNet.Cli.Commands.Tool.Run { - internal class ToolRunFromSourceCommand( - ParseResult result) : CommandBase(result) + internal class ToolRunFromSourceCommand(ParseResult result) : CommandBase(result) { private readonly string? _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); private readonly IEnumerable? _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument); @@ -27,11 +20,11 @@ internal class ToolRunFromSourceCommand( private readonly string[] _addSource = result.GetValue(ToolRunCommandParser.FromSourceAddSourceOption) ?? []; private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); private readonly bool _interactive = result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); - private readonly VerbosityOptions _verbosity = result.GetValue(ToolRunCommandParser.VerbosityOption); + private readonly VerbosityOptions _verbosity = result.GetValue(ToolRunCommandParser.FromSourceVerbosityOption); public override int Execute() { - if (!UserAgreedToExecuteFromSource()) + if (!UserAgreedToRunFromSource()) { return 1; } @@ -46,17 +39,12 @@ public override int Execute() string tempDirectory = PathUtilities.CreateTempSubdirectory(); - ToolManifestFinder toolManifestFinder = new ToolManifestFinder(new(tempDirectory)); - ToolManifestEditor toolManifestEditor = new ToolManifestEditor(); - FilePath toolManifestPath = toolManifestFinder.FindFirst(true); - ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory)); ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery); IToolPackage toolPackage = toolPackageDownloader.InstallPackage( new PackageLocation( - nugetConfig: _configFile != null ? new FilePath(_configFile) : null, - rootConfigDirectory: toolManifestPath.GetDirectoryPath().GetParentPath(), + nugetConfig: _configFile != null ? new(_configFile) : null, sourceFeedOverrides: _sources, additionalFeeds: _addSource), packageId: packageId, @@ -73,10 +61,10 @@ public override int Execute() return result.ExitCode; } - private bool UserAgreedToExecuteFromSource() + private bool UserAgreedToRunFromSource() { // TODO: Use a better way to ask for user input - Console.Write("Tool will be run from source. Accept? [y]".Red()); + Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; Console.WriteLine(); return userAccepted; diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index b5bcf1eb9a74..ba9ae46da843 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index 9809782c494d..00ec0d4bad5b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index edc7aefffeda..0f0756192609 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index b1e762249afe..0aa127a3c1d5 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 39ece4c0b692..323ea1f90954 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 9c4be8023c40..c14743164236 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 2b2cbabd978a..d17bba9b88a1 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 0520bb161820..e7bd97637f27 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 077537be235e..d0b1492b15d8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index f84bbd230b4c..0a122b6835da 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index b61a53943b40..dcd13605c001 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index aca7faa291b3..fcc252551250 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 9b698cca8387..786be56f6065 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -3142,6 +3142,11 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Executes a tool from source without permanently installing it. + + Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found in the system. Do you want to run it from source? [y/n] + + Search dotnet tools in nuget.org Search dotnet tools in nuget.org From aebf4211966c17d35e8568e833e142bb565fd3b1 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 18 Apr 2025 11:59:36 -0700 Subject: [PATCH 17/45] Update completions --- .../dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs | 3 +++ .../DotnetCliSnapshotTests.VerifyCompletions.verified.sh | 9 ++++++++- ...DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 | 7 +++++++ ...DotnetCliSnapshotTests.VerifyCompletions.verified.zsh | 7 +++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index ab7b622a6fc6..cc7effa81c0e 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -57,6 +57,9 @@ public override int Execute() CommandSpec commandSpec = MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer(toolPackage.Command.Executable.ToString(), _forwardArguments); var command = CommandFactoryUsingResolver.Create(commandSpec); + + Console.WriteLine('-' * Console.WindowWidth); + var result = command.Execute(); return result.ExitCode; } diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index 6f0dbed8b489..f8e731d43556 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1729,13 +1729,20 @@ _testhost_tool_run() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--allow-roll-forward --from-source --help" + opts="--allow-roll-forward --from-source --configfile --source --add-source --verbosity --ignore-failed-sources --interactive --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) return fi + case $prev in + --verbosity|-v) + COMPREPLY=( $(compgen -W "d detailed diag diagnostic m minimal n normal q quiet" -- "$cur") ) + return + ;; + esac + COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) } diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index 2c70382518b9..8c068a48e38d 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1058,6 +1058,13 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { $staticCompletions = @( [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") [CompletionResult]::new('--from-source', '--from-source', [CompletionResultType]::ParameterName, "Executes a tool from source without permanently installing it. ") + [CompletionResult]::new('--configfile', '--configfile', [CompletionResultType]::ParameterName, "The NuGet configuration file to use.") + [CompletionResult]::new('--source', '--source', [CompletionResultType]::ParameterName, "Replace all NuGet package sources to use during installation with these.") + [CompletionResult]::new('--add-source', '--add-source', [CompletionResultType]::ParameterName, "Add an additional NuGet package source to use during installation.") + [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") + [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") + [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") + [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index f26f4307f9fa..7bb613aab0c4 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1128,6 +1128,13 @@ _testhost() { _arguments "${_arguments_options[@]}" : \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ '--from-source[Executes a tool from source without permanently installing it. ]' \ + '--configfile=[The NuGet configuration file to use.]:FILE: ' \ + '*--source=[Replace all NuGet package sources to use during installation with these.]:SOURCE: ' \ + '*--add-source=[Add an additional NuGet package source to use during installation.]:ADDSOURCE: ' \ + '--verbosity=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ + '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ + '--ignore-failed-sources[Treat package source failures as warnings.]' \ + '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':commandName -- The command name of the tool to run.: ' \ From dda7732524ddb8dd8c24cb6b68349598065dbfb2 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 18 Apr 2025 15:38:23 -0700 Subject: [PATCH 18/45] Add --interactive option --- src/Cli/dotnet/CliStrings.resx | 6 ++++++ .../Commands/Tool/Run/ToolRunCommandParser.cs | 8 +++++++- .../Tool/Run/ToolRunFromSourceCommand.cs | 19 ++++++++++++++----- src/Cli/dotnet/CommonOptions.cs | 14 ++++++++++++++ src/Cli/dotnet/xlf/CliStrings.cs.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.de.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.es.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.fr.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.it.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.ja.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.ko.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.pl.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.ru.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.tr.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 10 ++++++++++ src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 10 ++++++++++ 17 files changed, 171 insertions(+), 6 deletions(-) diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx index 1acd6a165830..f3c6c1721464 100644 --- a/src/Cli/dotnet/CliStrings.resx +++ b/src/Cli/dotnet/CliStrings.resx @@ -812,4 +812,10 @@ For a list of locations searched, specify the "-d" option before the tool name.< Cannot specify --version when the package argument already contains a version. {Locked="--version"} + + Overrides confirmation prompt with "yes" value. + + + Overrides confirmation prompt with "no" value. + diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 7e10939d843a..d670092712f5 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -4,6 +4,7 @@ #nullable disable using System.CommandLine; +using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.Commands.Tool.Common; @@ -42,6 +43,10 @@ internal static class ToolRunCommandParser public static readonly Option FromSourceVerbosityOption = CommonOptions.VerbosityOption; + public static readonly Option FromSourceInteractiveOption = CommonOptions.InteractiveOption(); + + public static readonly Option FromSourceYesOption = CommonOptions.YesOption; + private static readonly Command Command = ConstructCommand(); public static Command GetCommand() @@ -62,9 +67,10 @@ private static Command ConstructCommand() command.Options.Add(FromSourceSourceOption); command.Options.Add(FromSourceAddSourceOption); command.Options.Add(FromSourceVerbosityOption); + command.Options.Add(FromSourceInteractiveOption); + command.Options.Add(FromSourceYesOption); command.Options.Add(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); - command.Options.Add(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); command.SetAction((parseResult) => new ToolRunCommand(parseResult).Execute()); diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs index cc7effa81c0e..b7c0fe411d66 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs @@ -13,14 +13,15 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Run internal class ToolRunFromSourceCommand(ParseResult result) : CommandBase(result) { private readonly string? _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); - private readonly IEnumerable? _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument); + private readonly IEnumerable _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument) ?? Enumerable.Empty(); private readonly bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); private readonly string? _configFile = result.GetValue(ToolRunCommandParser.FromSourceConfigFile); private readonly string[] _sources = result.GetValue(ToolRunCommandParser.FromSourceSourceOption) ?? []; private readonly string[] _addSource = result.GetValue(ToolRunCommandParser.FromSourceAddSourceOption) ?? []; private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); - private readonly bool _interactive = result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption); + private readonly bool _interactive = result.GetValue(ToolRunCommandParser.FromSourceInteractiveOption); private readonly VerbosityOptions _verbosity = result.GetValue(ToolRunCommandParser.FromSourceVerbosityOption); + private readonly bool _yes = result.GetValue(ToolRunCommandParser.FromSourceYesOption); public override int Execute() { @@ -57,19 +58,27 @@ public override int Execute() CommandSpec commandSpec = MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer(toolPackage.Command.Executable.ToString(), _forwardArguments); var command = CommandFactoryUsingResolver.Create(commandSpec); - - Console.WriteLine('-' * Console.WindowWidth); - var result = command.Execute(); return result.ExitCode; } private bool UserAgreedToRunFromSource() { + if (_yes) + { + return true; + } + + if (!_interactive) + { + return false; + } + // TODO: Use a better way to ask for user input Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; Console.WriteLine(); + Console.WriteLine(new string('-', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); return userAccepted; } } diff --git a/src/Cli/dotnet/CommonOptions.cs b/src/Cli/dotnet/CommonOptions.cs index fe784d6757a1..9b30acead1f5 100644 --- a/src/Cli/dotnet/CommonOptions.cs +++ b/src/Cli/dotnet/CommonOptions.cs @@ -12,6 +12,20 @@ namespace Microsoft.DotNet.Cli; internal static class CommonOptions { + public static Option YesOption = + new DynamicOption("--yes", "-y") + { + Description = CliStrings.YesOptionDescription, + Arity = ArgumentArity.Zero + }; + + public static Option NoOption = + new DynamicOption("--no") + { + Description = CliStrings.NoOptionDescription, + Arity = ArgumentArity.Zero + }; + public static Option PropertiesOption = // these are all of the forms that the property switch can be understood by in MSBuild new ForwardedOption("--property", "-property", "/property", "/p", "-p", "--p") diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf index f63c632009a3..5556a619ef3a 100644 --- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf index 534ba566fc55..b61eb9e794c9 100644 --- a/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf index 0eb90c7d4778..1ad74dff56d7 100644 --- a/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf index 6a0e4c843aa7..06ce787e8ea3 100644 --- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf index e61372265e98..938d38054df3 100644 --- a/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf index c9df2114d91c..bda08e6c570d 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf index 13c743594420..0c710966e621 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 93a290b184d9..7884ed1b9898 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index 6b1844b87678..edaf90d966b1 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf index 5ae630abba78..cfeee2be3b20 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf index 8e371f35753f..e0d7a6d93c0d 100644 --- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index 1d4643fc5738..e0ebe0dbdd4f 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index da11764e28b1..cb8dc35d06f7 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -687,6 +687,11 @@ setx PATH "%PATH%;{0}" New + + Overrides confirmation prompt with "no" value. + Overrides confirmation prompt with "no" value. + + No projects found in the solution. No projects found in the solution. @@ -1172,6 +1177,11 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is An issue was encountered verifying workloads. For more information, run "dotnet workload update". {Locked="dotnet workload update"} + + Overrides confirmation prompt with "yes" value. + Overrides confirmation prompt with "yes" value. + + \ No newline at end of file From fdc016178fb77b8d8fa49d8de484052e3c11da7f Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 21 Apr 2025 09:03:00 -0700 Subject: [PATCH 19/45] Update Completion snapshots --- .../DotnetCliSnapshotTests.VerifyCompletions.verified.sh | 6 +++++- .../DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 | 4 +++- .../DotnetCliSnapshotTests.VerifyCompletions.verified.zsh | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index f8e731d43556..af29109c4e03 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1729,7 +1729,7 @@ _testhost_tool_run() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--allow-roll-forward --from-source --configfile --source --add-source --verbosity --ignore-failed-sources --interactive --help" + opts="--allow-roll-forward --from-source --configfile --source --add-source --verbosity --interactive --yes --ignore-failed-sources --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) @@ -1741,6 +1741,10 @@ _testhost_tool_run() { COMPREPLY=( $(compgen -W "d detailed diag diagnostic m minimal n normal q quiet" -- "$cur") ) return ;; + --yes|-y) + COMPREPLY=( $(compgen -W "(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" -- "$cur") ) + return + ;; esac COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index 8c068a48e38d..d4a9fc1993ed 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1063,8 +1063,10 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { [CompletionResult]::new('--add-source', '--add-source', [CompletionResultType]::ParameterName, "Add an additional NuGet package source to use during installation.") [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") - [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") + [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") + [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") + [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index 7bb613aab0c4..6cd73dd43356 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1133,8 +1133,10 @@ _testhost() { '*--add-source=[Add an additional NuGet package source to use during installation.]:ADDSOURCE: ' \ '--verbosity=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ - '--ignore-failed-sources[Treat package source failures as warnings.]' \ '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ + '--yes[Overrides confirmation prompt with \"yes\" value. ]' \ + '-y[Overrides confirmation prompt with \"yes\" value. ]' \ + '--ignore-failed-sources[Treat package source failures as warnings.]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':commandName -- The command name of the tool to run.: ' \ From 1beb4bbfa7a3e408f276b4ff2ea192429017d4e2 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 21 Apr 2025 14:32:27 -0700 Subject: [PATCH 20/45] tool-exec --- .../ToolExecuteCommand.cs} | 28 ++++---- .../Tool/Execute/ToolExecuteCommandParser.cs | 64 +++++++++++++++++++ .../Tool/Install/ParseResultExtension.cs | 5 +- .../Commands/Tool/Run/ToolRunCommand.cs | 7 -- .../Commands/Tool/Run/ToolRunCommandParser.cs | 29 +-------- .../dotnet/Commands/Tool/ToolCommandParser.cs | 2 + 6 files changed, 86 insertions(+), 49 deletions(-) rename src/Cli/dotnet/Commands/Tool/{Run/ToolRunFromSourceCommand.cs => Execute/ToolExecuteCommand.cs} (77%) create mode 100644 src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs similarity index 77% rename from src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs rename to src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index b7c0fe411d66..38481bb0b795 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunFromSourceCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -6,26 +6,27 @@ using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.ToolPackage; +using NuGet.Packaging.Core; using NuGet.Versioning; -namespace Microsoft.DotNet.Cli.Commands.Tool.Run +namespace Microsoft.DotNet.Cli.Commands.Tool.Execute { - internal class ToolRunFromSourceCommand(ParseResult result) : CommandBase(result) + internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) { - private readonly string? _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); - private readonly IEnumerable _forwardArguments = result.GetValue(ToolRunCommandParser.CommandArgument) ?? Enumerable.Empty(); - private readonly bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); - private readonly string? _configFile = result.GetValue(ToolRunCommandParser.FromSourceConfigFile); - private readonly string[] _sources = result.GetValue(ToolRunCommandParser.FromSourceSourceOption) ?? []; - private readonly string[] _addSource = result.GetValue(ToolRunCommandParser.FromSourceAddSourceOption) ?? []; + private readonly PackageIdentity? _packageToolIdentityArgument = result.GetValue(ToolExecuteCommandParser.PackageIdentityArgument); + private readonly IEnumerable _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty(); + private readonly bool _allowRollForward = result.GetValue(ToolExecuteCommandParser.RollForwardOption); + private readonly string? _configFile = result.GetValue(ToolExecuteCommandParser.ConfigOption); + private readonly string[] _sources = result.GetValue(ToolExecuteCommandParser.SourceOption) ?? []; + private readonly string[] _addSource = result.GetValue(ToolExecuteCommandParser.AddSourceOption) ?? []; private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); - private readonly bool _interactive = result.GetValue(ToolRunCommandParser.FromSourceInteractiveOption); - private readonly VerbosityOptions _verbosity = result.GetValue(ToolRunCommandParser.FromSourceVerbosityOption); - private readonly bool _yes = result.GetValue(ToolRunCommandParser.FromSourceYesOption); + private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); + private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); + private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); public override int Execute() { - if (!UserAgreedToRunFromSource()) + if (!UserAgreedToRunFromSource() || _packageToolIdentityArgument is null) { return 1; } @@ -35,7 +36,8 @@ public override int Execute() _forwardArguments.Append("--allow-roll-forward"); } - PackageId packageId = new(_toolCommandName); + PackageId packageId = new PackageId(_packageToolIdentityArgument.Id); + VersionRange versionRange = _parseResult.GetVersionRange(); string tempDirectory = PathUtilities.CreateTempSubdirectory(); diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs new file mode 100644 index 000000000000..04d1698737ab --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.Text; +using Microsoft.DotNet.Cli.Commands.Tool.Install; +using NuGet.Packaging.Core; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Execute +{ + internal static class ToolExecuteCommandParser + + { + public static readonly Argument PackageIdentityArgument = ToolInstallCommandParser.PackageIdentityArgument; + + public static readonly Argument> CommandArgument = new("commandArguments") + { + Description = "arguments forwarded to the tool" + }; + + public static readonly Option RollForwardOption = ToolInstallCommandParser.RollForwardOption; + public static readonly Option PrereleaseOption = ToolInstallCommandParser.PrereleaseOption; + public static readonly Option ConfigOption = ToolInstallCommandParser.ConfigOption; + public static readonly Option SourceOption = ToolInstallCommandParser.SourceOption; + public static readonly Option AddSourceOption = ToolInstallCommandParser.AddSourceOption; + public static readonly Option IgnoreFailedSourcesOption = ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption; + public static readonly Option InteractiveOption = CommonOptions.InteractiveOption(); + public static readonly Option YesOption = CommonOptions.YesOption; + public static readonly Option VerbosityOption = ToolInstallCommandParser.VerbosityOption; + + + public static readonly Command Command = ConstructCommand(); + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("execute", "Execute a tool command from source"); + + command.Aliases.Add("exec"); + + command.Arguments.Add(PackageIdentityArgument); + command.Arguments.Add(CommandArgument); + + command.Options.Add(RollForwardOption); + command.Options.Add(PrereleaseOption); + command.Options.Add(ConfigOption); + command.Options.Add(SourceOption); + command.Options.Add(AddSourceOption); + command.Options.Add(IgnoreFailedSourcesOption); + command.Options.Add(InteractiveOption); + command.Options.Add(YesOption); + command.Options.Add(VerbosityOption); + + command.SetAction((parseResult) => new ToolExecuteCommand(parseResult).Execute()); + + return command; + } + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs index 33d08add9800..e44684f5bc07 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs @@ -13,8 +13,11 @@ internal static class ParseResultExtension { public static VersionRange GetVersionRange(this ParseResult parseResult) { - string packageVersion = parseResult.GetValue(ToolInstallCommandParser.PackageIdentityArgument)?.Version?.ToString() ?? + string packageVersion = + parseResult.GetValue(CommonArguments.PackageIdentityArgument(false))?.Version?.ToString() ?? + parseResult.GetValue(CommonArguments.PackageIdentityArgument(true))?.Version?.ToString() ?? parseResult.GetValue(ToolInstallCommandParser.VersionOption); + bool prerelease = parseResult.GetValue(ToolInstallCommandParser.PrereleaseOption); if (!string.IsNullOrEmpty(packageVersion) && prerelease) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 3cb94a0e8b93..b8bb976b0bbc 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -21,7 +21,6 @@ internal class ToolRunCommand( { private readonly string _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunCommandParser.CommandArgument); - private readonly bool _fromSource = result.GetValue(ToolRunCommandParser.FromSourceOption); private readonly LocalToolsCommandResolver _localToolsCommandResolver = localToolsCommandResolver ?? new LocalToolsCommandResolver(); public bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); @@ -36,12 +35,6 @@ public override int Execute() }, _allowRollForward); - if (commandSpec == null && _fromSource) - { - // Reroute to ToolRunFromSourceCommand - return new ToolRunFromSourceCommand(_parseResult).Execute(); - } - if (commandSpec == null) { throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index d670092712f5..6b1baa929728 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -29,24 +29,6 @@ internal static class ToolRunCommandParser Arity = ArgumentArity.Zero }; - public static readonly Option FromSourceOption = new("--from-source") - { - Description = CliCommandStrings.ToolRunFromSourceOptionDescription, - Arity = ArgumentArity.Zero - }; - - public static readonly Option FromSourceConfigFile = ToolInstallCommandParser.ConfigOption; - - public static readonly Option FromSourceSourceOption = ToolInstallCommandParser.SourceOption; - - public static readonly Option FromSourceAddSourceOption = ToolInstallCommandParser.AddSourceOption; - - public static readonly Option FromSourceVerbosityOption = CommonOptions.VerbosityOption; - - public static readonly Option FromSourceInteractiveOption = CommonOptions.InteractiveOption(); - - public static readonly Option FromSourceYesOption = CommonOptions.YesOption; - private static readonly Command Command = ConstructCommand(); public static Command GetCommand() @@ -60,17 +42,8 @@ private static Command ConstructCommand() command.Arguments.Add(CommandNameArgument); command.Arguments.Add(CommandArgument); - command.Options.Add(RollForwardOption); - - command.Options.Add(FromSourceOption); - command.Options.Add(FromSourceConfigFile); - command.Options.Add(FromSourceSourceOption); - command.Options.Add(FromSourceAddSourceOption); - command.Options.Add(FromSourceVerbosityOption); - command.Options.Add(FromSourceInteractiveOption); - command.Options.Add(FromSourceYesOption); - command.Options.Add(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); + command.Options.Add(RollForwardOption); command.SetAction((parseResult) => new ToolRunCommand(parseResult).Execute()); diff --git a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs index afc8ef9fb707..0392bde15d3f 100644 --- a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs @@ -4,6 +4,7 @@ #nullable disable using System.CommandLine; +using Microsoft.DotNet.Cli.Commands.Tool.Execute; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.Commands.Tool.List; using Microsoft.DotNet.Cli.Commands.Tool.Restore; @@ -37,6 +38,7 @@ private static Command ConstructCommand() command.Subcommands.Add(ToolRunCommandParser.GetCommand()); command.Subcommands.Add(ToolSearchCommandParser.GetCommand()); command.Subcommands.Add(ToolRestoreCommandParser.GetCommand()); + command.Subcommands.Add(ToolExecuteCommandParser.GetCommand()); command.SetAction((parseResult) => parseResult.HandleMissingCommand()); From 37f00f9caee54705d01041ce5a3db6a28b24269c Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 21 Apr 2025 15:52:30 -0700 Subject: [PATCH 21/45] Update Completions --- ...napshotTests.VerifyCompletions.verified.sh | 48 ++++++++++++++----- ...apshotTests.VerifyCompletions.verified.ps1 | 31 ++++++++---- ...apshotTests.VerifyCompletions.verified.zsh | 36 ++++++++++---- 3 files changed, 82 insertions(+), 33 deletions(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index af29109c4e03..effd274f0841 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1584,7 +1584,7 @@ _testhost_tool() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="install uninstall update list run search restore --help" + opts="install uninstall update list run search restore execute --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) @@ -1627,6 +1627,11 @@ _testhost_tool() { return ;; + (execute) + _testhost_tool_execute $(($1+1)) + return + ;; + esac COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) @@ -1729,24 +1734,13 @@ _testhost_tool_run() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--allow-roll-forward --from-source --configfile --source --add-source --verbosity --interactive --yes --ignore-failed-sources --help" + opts="--allow-roll-forward --help" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) return fi - case $prev in - --verbosity|-v) - COMPREPLY=( $(compgen -W "d detailed diag diagnostic m minimal n normal q quiet" -- "$cur") ) - return - ;; - --yes|-y) - COMPREPLY=( $(compgen -W "(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" -- "$cur") ) - return - ;; - esac - COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) } @@ -1792,6 +1786,34 @@ _testhost_tool_restore() { } +_testhost_tool_execute() { + + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + COMPREPLY=() + + opts="--allow-roll-forward --prerelease --configfile --source --add-source --ignore-failed-sources --interactive --yes --verbosity --help" + + if [[ $COMP_CWORD == "$1" ]]; then + COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) + return + fi + + case $prev in + --yes|-y) + COMPREPLY=( $(compgen -W "(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" -- "$cur") ) + return + ;; + --verbosity|-v) + COMPREPLY=( $(compgen -W "d detailed diag diagnostic m minimal n normal q quiet" -- "$cur") ) + return + ;; + esac + + COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) +} + + _testhost_vstest() { cur="${COMP_WORDS[COMP_CWORD]}" diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index d4a9fc1993ed..e91e5398feb2 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -959,6 +959,8 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, "Run a local tool. Note that this command cannot be used to run a global tool. ") [CompletionResult]::new('search', 'search', [CompletionResultType]::ParameterValue, "Search dotnet tools in nuget.org") [CompletionResult]::new('restore', 'restore', [CompletionResultType]::ParameterValue, "Restore tools defined in the local tool manifest.") + [CompletionResult]::new('execute', 'execute', [CompletionResultType]::ParameterValue, "Execute a tool command from source") + [CompletionResult]::new('execute', 'exec', [CompletionResultType]::ParameterValue, "Execute a tool command from source") ) $completions += $staticCompletions break @@ -1057,16 +1059,6 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { 'testhost;tool;run' { $staticCompletions = @( [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") - [CompletionResult]::new('--from-source', '--from-source', [CompletionResultType]::ParameterName, "Executes a tool from source without permanently installing it. ") - [CompletionResult]::new('--configfile', '--configfile', [CompletionResultType]::ParameterName, "The NuGet configuration file to use.") - [CompletionResult]::new('--source', '--source', [CompletionResultType]::ParameterName, "Replace all NuGet package sources to use during installation with these.") - [CompletionResult]::new('--add-source', '--add-source', [CompletionResultType]::ParameterName, "Add an additional NuGet package source to use during installation.") - [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") - [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") - [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") - [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") - [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") - [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") ) @@ -1102,6 +1094,25 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { $completions += $staticCompletions break } + 'testhost;tool;execute' { + $staticCompletions = @( + [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") + [CompletionResult]::new('--prerelease', '--prerelease', [CompletionResultType]::ParameterName, "Include pre-release packages.") + [CompletionResult]::new('--configfile', '--configfile', [CompletionResultType]::ParameterName, "The NuGet configuration file to use.") + [CompletionResult]::new('--source', '--source', [CompletionResultType]::ParameterName, "Replace all NuGet package sources to use during installation with these.") + [CompletionResult]::new('--add-source', '--add-source', [CompletionResultType]::ParameterName, "Add an additional NuGet package source to use during installation.") + [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") + [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") + [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") + [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") + [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") + [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") + [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") + ) + $completions += $staticCompletions + break + } 'testhost;vstest' { $staticCompletions = @( [CompletionResult]::new('--Platform', '--Platform', [CompletionResultType]::ParameterName, "--Platform") diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index 6cd73dd43356..ee7ed1f5713b 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1127,16 +1127,6 @@ _testhost() { (run) _arguments "${_arguments_options[@]}" : \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ - '--from-source[Executes a tool from source without permanently installing it. ]' \ - '--configfile=[The NuGet configuration file to use.]:FILE: ' \ - '*--source=[Replace all NuGet package sources to use during installation with these.]:SOURCE: ' \ - '*--add-source=[Add an additional NuGet package source to use during installation.]:ADDSOURCE: ' \ - '--verbosity=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ - '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ - '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ - '--yes[Overrides confirmation prompt with \"yes\" value. ]' \ - '-y[Overrides confirmation prompt with \"yes\" value. ]' \ - '--ignore-failed-sources[Treat package source failures as warnings.]' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':commandName -- The command name of the tool to run.: ' \ @@ -1169,6 +1159,25 @@ _testhost() { '-h[Show command line help.]' \ && ret=0 ;; + (execute) + _arguments "${_arguments_options[@]}" : \ + '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ + '--prerelease[Include pre-release packages.]' \ + '--configfile=[The NuGet configuration file to use.]:FILE: ' \ + '*--source=[Replace all NuGet package sources to use during installation with these.]:SOURCE: ' \ + '*--add-source=[Add an additional NuGet package source to use during installation.]:ADDSOURCE: ' \ + '--ignore-failed-sources[Treat package source failures as warnings.]' \ + '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ + '--yes[Overrides confirmation prompt with \"yes\" value. ]' \ + '-y[Overrides confirmation prompt with \"yes\" value. ]' \ + '--verbosity=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ + '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ + '--help[Show command line help.]' \ + '-h[Show command line help.]' \ + ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.: ' \ + '*::commandArguments -- arguments forwarded to the tool: ' \ + && ret=0 + ;; esac ;; esac @@ -1795,6 +1804,7 @@ _testhost__tool_commands() { 'run:Run a local tool. Note that this command cannot be used to run a global tool. ' \ 'search:Search dotnet tools in nuget.org' \ 'restore:Restore tools defined in the local tool manifest.' \ + 'execute:Execute a tool command from source' \ ) _describe -t commands 'testhost tool commands' commands "$@" } @@ -1841,6 +1851,12 @@ _testhost__tool__restore_commands() { _describe -t commands 'testhost tool restore commands' commands "$@" } +(( $+functions[_testhost__tool__execute_commands] )) || +_testhost__tool__execute_commands() { + local commands; commands=() + _describe -t commands 'testhost tool execute commands' commands "$@" +} + (( $+functions[_testhost__vstest_commands] )) || _testhost__vstest_commands() { local commands; commands=() From 5ccd294bc2b3eeeae4c6e1300d8602d3caa31fac Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 22 Apr 2025 12:02:30 -0700 Subject: [PATCH 22/45] Update cli snapshots --- ...netCliSnapshotTests.VerifyCompletions.verified.sh | 1 + ...etCliSnapshotTests.VerifyCompletions.verified.ps1 | 4 ++++ ...etCliSnapshotTests.VerifyCompletions.verified.zsh | 12 +++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index effd274f0841..3cd7853e1ea9 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1793,6 +1793,7 @@ _testhost_tool_execute() { COMPREPLY=() opts="--allow-roll-forward --prerelease --configfile --source --add-source --ignore-failed-sources --interactive --yes --verbosity --help" + opts="$opts $(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" if [[ $COMP_CWORD == "$1" ]]; then COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index e91e5398feb2..d5e7835e5305 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1111,6 +1111,10 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { [CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.") ) $completions += $staticCompletions + $text = $commandAst.ToString() + $dotnetCompleteResults = @(dotnet complete --position $cursorPosition "$text") | Where-Object { $_ -NotMatch "^-|^/" } + $dynamicCompletions = $dotnetCompleteResults | Foreach-Object { [CompletionResult]::new($_, $_, [CompletionResultType]::ParameterValue, $_) } + $completions += $dynamicCompletions break } 'testhost;vstest' { diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index ee7ed1f5713b..626e84a79874 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1174,9 +1174,19 @@ _testhost() { '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ - ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.: ' \ + ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.:->dotnet_dynamic_complete' \ '*::commandArguments -- arguments forwarded to the tool: ' \ && ret=0 + case $state in + (dotnet_dynamic_complete) + local completions=() + local result=$(dotnet complete -- "${original_args[@]}") + for line in ${(f)result}; do + completions+=(${(q)line}) + done + _describe 'completions' $completions && ret=0 + ;; + esac ;; esac ;; From e07a46bf2efe65454e4ff7edfc60e80905d0a4ba Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 22 Apr 2025 16:20:47 -0700 Subject: [PATCH 23/45] Add version option --- .../Commands/Tool/Execute/ToolExecuteCommand.cs | 1 + .../Tool/Execute/ToolExecuteCommandParser.cs | 2 ++ .../Commands/Tool/Install/ParseResultExtension.cs | 14 ++++++++++---- .../Commands/Tool/Install/ToolInstallCommand.cs | 11 ----------- ...tCliSnapshotTests.VerifyCompletions.verified.sh | 2 +- ...CliSnapshotTests.VerifyCompletions.verified.ps1 | 1 + ...CliSnapshotTests.VerifyCompletions.verified.zsh | 1 + 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 38481bb0b795..25805418b60b 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -23,6 +23,7 @@ internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); + private readonly bool _prerelease = result.GetValue(ToolExecuteCommandParser.PrereleaseOption); public override int Execute() { diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index 04d1698737ab..085f715d99d3 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -20,6 +20,7 @@ internal static class ToolExecuteCommandParser Description = "arguments forwarded to the tool" }; + public static readonly Option VersionOption = ToolInstallCommandParser.VersionOption; public static readonly Option RollForwardOption = ToolInstallCommandParser.RollForwardOption; public static readonly Option PrereleaseOption = ToolInstallCommandParser.PrereleaseOption; public static readonly Option ConfigOption = ToolInstallCommandParser.ConfigOption; @@ -46,6 +47,7 @@ private static Command ConstructCommand() command.Arguments.Add(PackageIdentityArgument); command.Arguments.Add(CommandArgument); + command.Options.Add(VersionOption); command.Options.Add(RollForwardOption); command.Options.Add(PrereleaseOption); command.Options.Add(ConfigOption); diff --git a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs index e44684f5bc07..b79d3bffbde4 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs @@ -13,10 +13,16 @@ internal static class ParseResultExtension { public static VersionRange GetVersionRange(this ParseResult parseResult) { - string packageVersion = - parseResult.GetValue(CommonArguments.PackageIdentityArgument(false))?.Version?.ToString() ?? - parseResult.GetValue(CommonArguments.PackageIdentityArgument(true))?.Version?.ToString() ?? - parseResult.GetValue(ToolInstallCommandParser.VersionOption); + var packageVersionFromIdentityArgument = parseResult.GetValue(ToolInstallCommandParser.PackageIdentityArgument)?.Version?.ToString(); + var packageVersionFromVersionOption = parseResult.GetValue(ToolInstallCommandParser.VersionOption); + + // Check that only one of these has a value + if (!string.IsNullOrEmpty(packageVersionFromIdentityArgument) && !string.IsNullOrEmpty(packageVersionFromVersionOption)) + { + throw new GracefulException(CliStrings.PackageIdentityArgumentVersionOptionConflict); + } + + string packageVersion = packageVersionFromIdentityArgument ?? packageVersionFromVersionOption; bool prerelease = parseResult.GetValue(ToolInstallCommandParser.PrereleaseOption); diff --git a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommand.cs b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommand.cs index 61557ebc884f..9d24cfabe7c0 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommand.cs @@ -21,15 +21,6 @@ internal class ToolInstallCommand( private readonly string _framework = parseResult.GetValue(ToolInstallCommandParser.FrameworkOption); - internal static void EnsureNoConflictPackageIdentityVersionOption(ParseResult parseResult) - { - if (!string.IsNullOrEmpty(parseResult.GetValue(ToolInstallCommandParser.PackageIdentityArgument)?.Version?.ToString()) && - !string.IsNullOrEmpty(parseResult.GetValue(ToolInstallCommandParser.VersionOption))) - { - throw new GracefulException(CliStrings.PackageIdentityArgumentVersionOptionConflict); - } - } - public override int Execute() { ToolAppliedOption.EnsureNoConflictGlobalLocalToolPathOption( @@ -39,8 +30,6 @@ public override int Execute() ToolAppliedOption.EnsureToolManifestAndOnlyLocalFlagCombination( _parseResult); - EnsureNoConflictPackageIdentityVersionOption(_parseResult); - if (_global || !string.IsNullOrWhiteSpace(_toolPath)) { return (_toolInstallGlobalOrToolPathCommand ?? new ToolInstallGlobalOrToolPathCommand(_parseResult)).Execute(); diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index 3cd7853e1ea9..fef8c96b9382 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1792,7 +1792,7 @@ _testhost_tool_execute() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--allow-roll-forward --prerelease --configfile --source --add-source --ignore-failed-sources --interactive --yes --verbosity --help" + opts="--version --allow-roll-forward --prerelease --configfile --source --add-source --ignore-failed-sources --interactive --yes --verbosity --help" opts="$opts $(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" if [[ $COMP_CWORD == "$1" ]]; then diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index d5e7835e5305..0afb131bd3d4 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1096,6 +1096,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { } 'testhost;tool;execute' { $staticCompletions = @( + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, "The version of the tool package to install.") [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") [CompletionResult]::new('--prerelease', '--prerelease', [CompletionResultType]::ParameterName, "Include pre-release packages.") [CompletionResult]::new('--configfile', '--configfile', [CompletionResultType]::ParameterName, "The NuGet configuration file to use.") diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index 626e84a79874..c169d58e12f5 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1161,6 +1161,7 @@ _testhost() { ;; (execute) _arguments "${_arguments_options[@]}" : \ + '--version=[The version of the tool package to install.]:VERSION: ' \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ '--prerelease[Include pre-release packages.]' \ '--configfile=[The NuGet configuration file to use.]:FILE: ' \ From eae9ad8fb12a58de74514c632aa0b6bedf4702f5 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 22 Apr 2025 16:37:14 -0700 Subject: [PATCH 24/45] Pretty divider line --- src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 25805418b60b..3dd80e2747f4 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -81,7 +81,7 @@ private bool UserAgreedToRunFromSource() Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; Console.WriteLine(); - Console.WriteLine(new string('-', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); + Console.WriteLine(new string('─', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); return userAccepted; } } From 9fd3045d98db03c3062973988fa6e9937e603d21 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Thu, 24 Apr 2025 16:26:28 -0700 Subject: [PATCH 25/45] Address pr feedback --- src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index b8bb976b0bbc..7ca9f6a20729 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -17,12 +17,13 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Run; internal class ToolRunCommand( ParseResult result, - LocalToolsCommandResolver localToolsCommandResolver = null) : CommandBase(result) + LocalToolsCommandResolver localToolsCommandResolver = null, + ToolManifestFinder toolManifest = null) : CommandBase(result) { private readonly string _toolCommandName = result.GetValue(ToolRunCommandParser.CommandNameArgument); private readonly IEnumerable _forwardArgument = result.GetValue(ToolRunCommandParser.CommandArgument); - private readonly LocalToolsCommandResolver _localToolsCommandResolver = localToolsCommandResolver ?? new LocalToolsCommandResolver(); + private readonly LocalToolsCommandResolver _localToolsCommandResolver = localToolsCommandResolver ?? new LocalToolsCommandResolver(toolManifest); public bool _allowRollForward = result.GetValue(ToolRunCommandParser.RollForwardOption); public override int Execute() From fd1cc469d5b7ded3ec94c7e526c80daa526c4da2 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Mon, 28 Apr 2025 15:39:33 -0700 Subject: [PATCH 26/45] Remove prompt for normal and quiter verbosities --- .../Commands/Tool/Execute/ToolExecuteCommand.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 3dd80e2747f4..da2b48ddc2ad 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -80,8 +80,17 @@ private bool UserAgreedToRunFromSource() // TODO: Use a better way to ask for user input Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; - Console.WriteLine(); - Console.WriteLine(new string('─', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); + if (_verbosity >= VerbosityOptions.detailed) + { + Console.WriteLine(); + Console.WriteLine(new String('-', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); + } + else + { + // Clear the line + Console.Write("\r" + new string(' ', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length + 1) + "\r"); + } + return userAccepted; } } From d15b933cafe51165c944e13e9b06911e247b0dbf Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Tue, 29 Apr 2025 09:45:05 -0700 Subject: [PATCH 27/45] Store in nuget cache? --- src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index da2b48ddc2ad..08e79709dbb1 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -6,6 +6,7 @@ using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.ToolPackage; +using NuGet.Common; using NuGet.Packaging.Core; using NuGet.Versioning; @@ -41,7 +42,7 @@ public override int Execute() VersionRange versionRange = _parseResult.GetVersionRange(); - string tempDirectory = PathUtilities.CreateTempSubdirectory(); + string tempDirectory = NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp); ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory)); ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery); @@ -80,6 +81,7 @@ private bool UserAgreedToRunFromSource() // TODO: Use a better way to ask for user input Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; + if (_verbosity >= VerbosityOptions.detailed) { Console.WriteLine(); From 48c5699926cc8ca6b0d2c7981e9d91acd6684fd9 Mon Sep 17 00:00:00 2001 From: Marc Paine Date: Thu, 5 Jun 2025 18:03:31 -0700 Subject: [PATCH 28/45] Update based on PR feedback. --- .../dotnet/Commands/CliCommandStrings.resx | 15 ++++++++--- .../Tool/Execute/ToolExecuteCommand.cs | 9 ++++++- .../Tool/Execute/ToolExecuteCommandParser.cs | 4 +-- .../Commands/Tool/Run/ToolRunCommand.cs | 2 -- .../Commands/Tool/Run/ToolRunCommandParser.cs | 6 +---- .../Commands/xlf/CliCommandStrings.cs.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.de.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.es.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.fr.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.it.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.ja.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.ko.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.pl.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.ru.xlf | 25 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.tr.xlf | 25 +++++++++++++++---- .../xlf/CliCommandStrings.zh-Hans.xlf | 25 +++++++++++++++---- .../xlf/CliCommandStrings.zh-Hant.xlf | 25 +++++++++++++++---- src/Cli/dotnet/CommonOptions.cs | 7 ------ 19 files changed, 283 insertions(+), 85 deletions(-) diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index 7d513ed68b23..da29a86a39bd 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2052,6 +2052,9 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. + + Arguments forwarded to the tool + Search dotnet tools in nuget.org @@ -2476,10 +2479,16 @@ To display a value, specify the corresponding command-line option without provid Recursively add projects' ReferencedProjects to solution - - Executes a tool from source without permanently installing it. + + Executes a tool from source without permanently installing it. + + + Missing package ID - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + + + Run from source approval denied by the user \ No newline at end of file diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 08e79709dbb1..6e7fdb4e9606 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -6,6 +6,7 @@ using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; using NuGet.Common; using NuGet.Packaging.Core; using NuGet.Versioning; @@ -28,11 +29,17 @@ internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) public override int Execute() { - if (!UserAgreedToRunFromSource() || _packageToolIdentityArgument is null) + if (_packageToolIdentityArgument is null) { + // System.CommandLine will throw an error if the argument is not provided, but we can still check here for clarity. return 1; } + if (!UserAgreedToRunFromSource()) + { + throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); + } + if (_allowRollForward) { _forwardArguments.Append("--allow-roll-forward"); diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index 085f715d99d3..8ab1f8fa0e02 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -17,7 +17,7 @@ internal static class ToolExecuteCommandParser public static readonly Argument> CommandArgument = new("commandArguments") { - Description = "arguments forwarded to the tool" + Description = CliCommandStrings.ToolRunArguementsDescription }; public static readonly Option VersionOption = ToolInstallCommandParser.VersionOption; @@ -40,7 +40,7 @@ public static Command GetCommand() private static Command ConstructCommand() { - Command command = new("execute", "Execute a tool command from source"); + Command command = new("execute", CliCommandStrings.ToolExecuteCommandDescription); command.Aliases.Add("exec"); diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 7ca9f6a20729..822c0826ee2f 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -44,6 +44,4 @@ public override int Execute() var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); return result.ExitCode; } - - } diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index 6b1baa929728..b12437c1cbe0 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -4,9 +4,6 @@ #nullable disable using System.CommandLine; -using Microsoft.DotNet.Cli; -using Microsoft.DotNet.Cli.Commands.Tool.Install; -using Microsoft.DotNet.Cli.Commands.Tool.Common; namespace Microsoft.DotNet.Cli.Commands.Tool.Run; @@ -20,7 +17,7 @@ internal static class ToolRunCommandParser public static readonly Argument> CommandArgument = new("toolArguments") { - Description = "arguments forwarded to the tool" + Description = CliCommandStrings.ToolRunArguementsDescription }; public static readonly Option RollForwardOption = new("--allow-roll-forward") @@ -42,7 +39,6 @@ private static Command ConstructCommand() command.Arguments.Add(CommandNameArgument); command.Arguments.Add(CommandArgument); - command.Options.Add(RollForwardOption); command.SetAction((parseResult) => new ToolRunCommand(parseResult).Execute()); diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index ba9ae46da843..5a4726d94c72 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index 00ec0d4bad5b..e2066416652e 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 0f0756192609..a3a1904986dc 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 0aa127a3c1d5..4aec711c1b73 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 323ea1f90954..305ffd3b03f1 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index c14743164236..21ff3ca69722 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index d17bba9b88a1..98b23faa0fb5 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index e7bd97637f27..9fd0c367433f 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index d0b1492b15d8..4b51c0fd2c6a 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 0a122b6835da..1521e353653d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index dcd13605c001..3ca8e9054a9b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index fcc252551250..e64819b6e7ef 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 786be56f6065..7fa13572bd71 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -2926,6 +2926,16 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Executes a tool from source without permanently installing it. + Executes a tool from source without permanently installing it. + + + + Missing package ID + Missing package ID + + Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. @@ -3132,19 +3142,24 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. + + Arguments forwarded to the tool + Arguments forwarded to the tool + + Run a local tool. Note that this command cannot be used to run a global tool. Run a local tool. Note that this command cannot be used to run a global tool. - - Executes a tool from source without permanently installing it. - Executes a tool from source without permanently installing it. + + Run from source approval denied by the user + Run from source approval denied by the user - Tool not found in the system. Do you want to run it from source? [y/n] - Tool not found in the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] + Tool not found on the system. Do you want to run it from source? [y/n] diff --git a/src/Cli/dotnet/CommonOptions.cs b/src/Cli/dotnet/CommonOptions.cs index 9b30acead1f5..c33b84664910 100644 --- a/src/Cli/dotnet/CommonOptions.cs +++ b/src/Cli/dotnet/CommonOptions.cs @@ -19,13 +19,6 @@ internal static class CommonOptions Arity = ArgumentArity.Zero }; - public static Option NoOption = - new DynamicOption("--no") - { - Description = CliStrings.NoOptionDescription, - Arity = ArgumentArity.Zero - }; - public static Option PropertiesOption = // these are all of the forms that the property switch can be understood by in MSBuild new ForwardedOption("--property", "-property", "/property", "/p", "-p", "--p") From 729fe497feee063d6bf20fb5c556ce0118d157b2 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 9 Jun 2025 13:25:56 -0400 Subject: [PATCH 29/45] Update strings --- src/Cli/dotnet/CliStrings.resx | 3 --- src/Cli/dotnet/Commands/CliCommandStrings.resx | 4 ++-- .../dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs | 2 +- src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf | 2 +- src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf | 2 +- src/Cli/dotnet/xlf/CliStrings.cs.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.de.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.es.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.fr.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.it.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.ja.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.ko.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.pl.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.ru.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.tr.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 5 ----- src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 5 ----- 30 files changed, 17 insertions(+), 85 deletions(-) diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx index f3c6c1721464..214d2486907d 100644 --- a/src/Cli/dotnet/CliStrings.resx +++ b/src/Cli/dotnet/CliStrings.resx @@ -815,7 +815,4 @@ For a list of locations searched, specify the "-d" option before the tool name.< Overrides confirmation prompt with "yes" value. - - Overrides confirmation prompt with "no" value. - diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index da29a86a39bd..fc7e01606bbb 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2052,7 +2052,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - + Arguments forwarded to the tool @@ -2491,4 +2491,4 @@ To display a value, specify the corresponding command-line option without provid Run from source approval denied by the user - \ No newline at end of file + diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index 8ab1f8fa0e02..e03bd5b3291c 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -17,7 +17,7 @@ internal static class ToolExecuteCommandParser public static readonly Argument> CommandArgument = new("commandArguments") { - Description = CliCommandStrings.ToolRunArguementsDescription + Description = CliCommandStrings.ToolRunArgumentsDescription }; public static readonly Option VersionOption = ToolInstallCommandParser.VersionOption; diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs index b12437c1cbe0..05d085926580 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommandParser.cs @@ -17,7 +17,7 @@ internal static class ToolRunCommandParser public static readonly Argument> CommandArgument = new("toolArguments") { - Description = CliCommandStrings.ToolRunArguementsDescription + Description = CliCommandStrings.ToolRunArgumentsDescription }; public static readonly Option RollForwardOption = new("--allow-roll-forward") diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 5a4726d94c72..763090389e42 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index e2066416652e..63f94832d04f 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index a3a1904986dc..777a35cf2ff7 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 4aec711c1b73..5d286d038395 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 305ffd3b03f1..3426b8ef894b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 21ff3ca69722..4f86569fb0ae 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 98b23faa0fb5..27eb5fc18ff7 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 9fd0c367433f..18512c8c8a63 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 4b51c0fd2c6a..5842ba14d80d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 1521e353653d..4c6581ce52f9 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 3ca8e9054a9b..c1a75d3f4a60 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index e64819b6e7ef..3b4e37d8cac4 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 7fa13572bd71..e4904644f52c 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -3142,7 +3142,7 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Path to the manifest file. - + Arguments forwarded to the tool Arguments forwarded to the tool diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf index 5556a619ef3a..f250f6da228d 100644 --- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf index b61eb9e794c9..88c7f5edab74 100644 --- a/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf index 1ad74dff56d7..cf93a4ee87fc 100644 --- a/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf index 06ce787e8ea3..1150e15af09d 100644 --- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf index 938d38054df3..ea9e6d4de305 100644 --- a/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf index bda08e6c570d..1891d3dcc0ac 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf index 0c710966e621..f7ff9a0fedaa 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 7884ed1b9898..53b673eb513b 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index edaf90d966b1..2f2cf8213cc1 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf index cfeee2be3b20..7f8ebd8090f6 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf index e0d7a6d93c0d..a7fdd0073644 100644 --- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index e0ebe0dbdd4f..4a76bba083d5 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index cb8dc35d06f7..c37f2ba57bd1 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -687,11 +687,6 @@ setx PATH "%PATH%;{0}" New - - Overrides confirmation prompt with "no" value. - Overrides confirmation prompt with "no" value. - - No projects found in the solution. No projects found in the solution. From 4c9b74727afbe5d6d13db38ecde509b53d3d98d0 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 9 Jun 2025 14:36:40 -0400 Subject: [PATCH 30/45] Make package identity argument work better with nullability --- .../Package/Add/PackageAddCommandParser.cs | 2 +- .../Commands/Tool/Execute/ToolExecuteCommand.cs | 8 +------- .../Tool/Execute/ToolExecuteCommandParser.cs | 2 +- .../Tool/Install/ToolInstallCommandParser.cs | 2 +- .../Tool/Update/ToolUpdateCommandParser.cs | 2 +- src/Cli/dotnet/CommonArguments.cs | 14 ++++++++++++-- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Cli/dotnet/Commands/Package/Add/PackageAddCommandParser.cs b/src/Cli/dotnet/Commands/Package/Add/PackageAddCommandParser.cs index 03fd93676143..d2603cdf8aaf 100644 --- a/src/Cli/dotnet/Commands/Package/Add/PackageAddCommandParser.cs +++ b/src/Cli/dotnet/Commands/Package/Add/PackageAddCommandParser.cs @@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Cli.Commands.Package.Add; internal static class PackageAddCommandParser { - public static readonly Argument CmdPackageArgument = CommonArguments.PackageIdentityArgument(true) + public static readonly Argument CmdPackageArgument = CommonArguments.RequiredPackageIdentityArgument() .AddCompletions((context) => { // we should take --prerelease flags into account for version completion diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 6e7fdb4e9606..bd007d1108ef 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Execute { internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) { - private readonly PackageIdentity? _packageToolIdentityArgument = result.GetValue(ToolExecuteCommandParser.PackageIdentityArgument); + private readonly PackageIdentity _packageToolIdentityArgument = result.GetRequiredValue(ToolExecuteCommandParser.PackageIdentityArgument); private readonly IEnumerable _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty(); private readonly bool _allowRollForward = result.GetValue(ToolExecuteCommandParser.RollForwardOption); private readonly string? _configFile = result.GetValue(ToolExecuteCommandParser.ConfigOption); @@ -29,12 +29,6 @@ internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) public override int Execute() { - if (_packageToolIdentityArgument is null) - { - // System.CommandLine will throw an error if the argument is not provided, but we can still check here for clarity. - return 1; - } - if (!UserAgreedToRunFromSource()) { throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index e03bd5b3291c..81c39eba85b4 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Execute internal static class ToolExecuteCommandParser { - public static readonly Argument PackageIdentityArgument = ToolInstallCommandParser.PackageIdentityArgument; + public static readonly Argument PackageIdentityArgument = ToolInstallCommandParser.PackageIdentityArgument; public static readonly Argument> CommandArgument = new("commandArguments") { diff --git a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs index 0e554ded38e6..f802596ed045 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallCommandParser.cs @@ -12,7 +12,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Install; internal static class ToolInstallCommandParser { - public static readonly Argument PackageIdentityArgument = CommonArguments.PackageIdentityArgument(); + public static readonly Argument PackageIdentityArgument = CommonArguments.RequiredPackageIdentityArgument(); public static readonly Option VersionOption = new("--version") { diff --git a/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs index 3d8ebee80bbc..3a261c75edcb 100644 --- a/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateCommandParser.cs @@ -10,7 +10,7 @@ namespace Microsoft.DotNet.Cli.Commands.Tool.Update; internal static class ToolUpdateCommandParser { - public static readonly Argument PackageIdentityArgument = CommonArguments.PackageIdentityArgument(requireArgument: false); + public static readonly Argument PackageIdentityArgument = CommonArguments.OptionalPackageIdentityArgument(); public static readonly Option UpdateAllOption = ToolAppliedOption.UpdateAllOption; diff --git a/src/Cli/dotnet/CommonArguments.cs b/src/Cli/dotnet/CommonArguments.cs index ceaddfd7a89b..af04e3dead9d 100644 --- a/src/Cli/dotnet/CommonArguments.cs +++ b/src/Cli/dotnet/CommonArguments.cs @@ -11,15 +11,25 @@ namespace Microsoft.DotNet.Cli { internal class CommonArguments { - public static DynamicArgument PackageIdentityArgument(bool requireArgument = true) => + public static DynamicArgument OptionalPackageIdentityArgument() => new("packageId") { HelpName = "PACKAGE_ID", Description = CliStrings.PackageIdentityArgumentDescription, CustomParser = (ArgumentResult argumentResult) => ParsePackageIdentityWithVersionSeparator(argumentResult.Tokens[0]?.Value), - Arity = requireArgument ? ArgumentArity.ExactlyOne : ArgumentArity.ZeroOrOne, + Arity = ArgumentArity.ZeroOrOne, }; + public static DynamicArgument RequiredPackageIdentityArgument() => + new("packageId") + { + HelpName = "PACKAGE_ID", + Description = CliStrings.PackageIdentityArgumentDescription, + CustomParser = (ArgumentResult argumentResult) => ParsePackageIdentityWithVersionSeparator(argumentResult.Tokens[0]?.Value), + Arity = ArgumentArity.ExactlyOne, + }; + + private static PackageIdentity? ParsePackageIdentityWithVersionSeparator(string? packageIdentity, char versionSeparator = '@') { if (string.IsNullOrEmpty(packageIdentity)) From 6fab085af421525fa398522a3ec80b78023b8c94 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 9 Jun 2025 18:55:34 -0400 Subject: [PATCH 31/45] Factor out some tool restore functionality into separate class --- .../Tool/Restore/ToolPackageRestorer.cs | 166 ++++++++++++++++++ .../Tool/Restore/ToolRestoreCommand.cs | 128 ++------------ 2 files changed, 177 insertions(+), 117 deletions(-) create mode 100644 src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs new file mode 100644 index 000000000000..36cf8c31c7f0 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.DotNet.Cli.NuGetPackageDownloader; +using Microsoft.DotNet.Cli.ToolManifest; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; +using NuGet.Commands; +using NuGet.Frameworks; +using NuGet.Versioning; +using static Microsoft.DotNet.Cli.Commands.Tool.Restore.ToolRestoreCommand; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Restore; + +internal class ToolPackageRestorer +{ + private readonly IToolPackageDownloader _toolPackageDownloader; + private readonly string[] _additionalSources; + private readonly string[] _overrideSources; + private readonly VerbosityOptions _verbosity; + private readonly RestoreActionConfig _restoreActionConfig; + + private readonly ILocalToolsResolverCache _localToolsResolverCache; + private readonly IFileSystem _fileSystem; + + + + public ToolPackageRestorer(IToolPackageDownloader toolPackageDownloader, + string[] additionalSources, + string[] overrideSources, + VerbosityOptions verbosity, + RestoreActionConfig restoreActionConfig, + ILocalToolsResolverCache? localToolsResolverCache = null, + IFileSystem? fileSystem = null) + { + _toolPackageDownloader = toolPackageDownloader; + _additionalSources = additionalSources; + _overrideSources = overrideSources; + _verbosity = verbosity; + _restoreActionConfig = restoreActionConfig; + + _localToolsResolverCache = localToolsResolverCache ?? new LocalToolsResolverCache(); + _fileSystem = fileSystem ?? new FileSystemWrapper(); + } + + public ToolRestoreResult InstallPackages( + ToolManifestPackage package, + FilePath? configFile) + { + string targetFramework = BundledTargetFramework.GetTargetFrameworkMoniker(); + + if (PackageHasBeenRestored(package, targetFramework)) + { + return ToolRestoreResult.Success( + saveToCache: [], + message: string.Format( + CliCommandStrings.RestoreSuccessful, package.PackageId, + package.Version.ToNormalizedString(), string.Join(", ", package.CommandNames))); + } + + try + { + IToolPackage toolPackage = + _toolPackageDownloader.InstallPackage( + new PackageLocation( + nugetConfig: configFile, + additionalFeeds: _additionalSources, + sourceFeedOverrides: _overrideSources, + rootConfigDirectory: package.FirstEffectDirectory), + package.PackageId, + verbosity: _verbosity, + ToVersionRangeWithOnlyOneVersion(package.Version), + targetFramework, + restoreActionConfig: _restoreActionConfig + ); + + if (!ManifestCommandMatchesActualInPackage(package.CommandNames, [toolPackage.Command])) + { + return ToolRestoreResult.Failure( + string.Format(CliCommandStrings.CommandsMismatch, + JoinBySpaceWithQuote(package.CommandNames.Select(c => c.Value.ToString())), + package.PackageId, + toolPackage.Command.Name)); + } + + return ToolRestoreResult.Success( + saveToCache: + [(new RestoredCommandIdentifier( + toolPackage.Id, + toolPackage.Version, + NuGetFramework.Parse(targetFramework), + Constants.AnyRid, + toolPackage.Command.Name), + toolPackage.Command)], + message: string.Format( + CliCommandStrings.RestoreSuccessful, + package.PackageId, + package.Version.ToNormalizedString(), + string.Join(" ", package.CommandNames))); + } + catch (ToolPackageException e) + { + return ToolRestoreResult.Failure(package.PackageId, e); + } + } + + private static bool ManifestCommandMatchesActualInPackage( + ToolCommandName[] commandsFromManifest, + IReadOnlyList toolPackageCommands) + { + ToolCommandName[] commandsFromPackage = [.. toolPackageCommands.Select(t => t.Name)]; + foreach (var command in commandsFromManifest) + { + if (!commandsFromPackage.Contains(command)) + { + return false; + } + } + + foreach (var command in commandsFromPackage) + { + if (!commandsFromManifest.Contains(command)) + { + return false; + } + } + + return true; + } + + public bool PackageHasBeenRestored( + ToolManifestPackage package, + string targetFramework) + { + var sampleRestoredCommandIdentifierOfThePackage = new RestoredCommandIdentifier( + package.PackageId, + package.Version, + NuGetFramework.Parse(targetFramework), + Constants.AnyRid, + package.CommandNames.First()); + + return _localToolsResolverCache.TryLoad( + sampleRestoredCommandIdentifierOfThePackage, + out var toolCommand) + && _fileSystem.File.Exists(toolCommand.Executable.Value); + } + + private static string JoinBySpaceWithQuote(IEnumerable objects) + { + return string.Join(" ", objects.Select(o => $"\"{o.ToString()}\"")); + } + + private static VersionRange ToVersionRangeWithOnlyOneVersion(NuGetVersion version) + { + return new VersionRange( + version, + includeMinVersion: true, + maxVersion: version, + includeMaxVersion: true); + } +} + diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs index 465d598d81e2..039e7d6ddb1e 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs @@ -103,10 +103,19 @@ public override int Execute() return 0; } + var toolPackageRestorer = new ToolPackageRestorer( + _toolPackageDownloader, + _sources, + overrideSources: [], + _verbosity, + _restoreActionConfig, + _localToolsResolverCache, + _fileSystem); + ToolRestoreResult[] toolRestoreResults = [.. packagesFromManifest .AsEnumerable() - .Select(package => InstallPackages(package, configFile))]; + .Select(package => toolPackageRestorer.InstallPackages(package, configFile))]; Dictionary downloaded = toolRestoreResults.SelectMany(result => result.SaveToCache) @@ -119,66 +128,6 @@ [.. packagesFromManifest return PrintConclusionAndReturn(toolRestoreResults); } - private ToolRestoreResult InstallPackages( - ToolManifestPackage package, - FilePath? configFile) - { - string targetFramework = BundledTargetFramework.GetTargetFrameworkMoniker(); - - if (PackageHasBeenRestored(package, targetFramework)) - { - return ToolRestoreResult.Success( - saveToCache: [], - message: string.Format( - CliCommandStrings.RestoreSuccessful, package.PackageId, - package.Version.ToNormalizedString(), string.Join(", ", package.CommandNames))); - } - - try - { - IToolPackage toolPackage = - _toolPackageDownloader.InstallPackage( - new PackageLocation( - nugetConfig: configFile, - additionalFeeds: _sources, - rootConfigDirectory: package.FirstEffectDirectory), - package.PackageId, - verbosity: _verbosity, - ToVersionRangeWithOnlyOneVersion(package.Version), - targetFramework, - restoreActionConfig: _restoreActionConfig - ); - - if (!ManifestCommandMatchesActualInPackage(package.CommandNames, [toolPackage.Command])) - { - return ToolRestoreResult.Failure( - string.Format(CliCommandStrings.CommandsMismatch, - JoinBySpaceWithQuote(package.CommandNames.Select(c => c.Value.ToString())), - package.PackageId, - toolPackage.Command.Name)); - } - - return ToolRestoreResult.Success( - saveToCache: - [(new RestoredCommandIdentifier( - toolPackage.Id, - toolPackage.Version, - NuGetFramework.Parse(targetFramework), - Constants.AnyRid, - toolPackage.Command.Name), - toolPackage.Command)], - message: string.Format( - CliCommandStrings.RestoreSuccessful, - package.PackageId, - package.Version.ToNormalizedString(), - string.Join(" ", package.CommandNames))); - } - catch (ToolPackageException e) - { - return ToolRestoreResult.Failure(package.PackageId, e); - } - } - private int PrintConclusionAndReturn(ToolRestoreResult[] toolRestoreResults) { if (toolRestoreResults.Any(r => !r.IsSuccess)) @@ -214,47 +163,6 @@ private int PrintConclusionAndReturn(ToolRestoreResult[] toolRestoreResults) } } - private static bool ManifestCommandMatchesActualInPackage( - ToolCommandName[] commandsFromManifest, - IReadOnlyList toolPackageCommands) - { - ToolCommandName[] commandsFromPackage = [.. toolPackageCommands.Select(t => t.Name)]; - foreach (var command in commandsFromManifest) - { - if (!commandsFromPackage.Contains(command)) - { - return false; - } - } - - foreach (var command in commandsFromPackage) - { - if (!commandsFromManifest.Contains(command)) - { - return false; - } - } - - return true; - } - - private bool PackageHasBeenRestored( - ToolManifestPackage package, - string targetFramework) - { - var sampleRestoredCommandIdentifierOfThePackage = new RestoredCommandIdentifier( - package.PackageId, - package.Version, - NuGetFramework.Parse(targetFramework), - Constants.AnyRid, - package.CommandNames.First()); - - return _localToolsResolverCache.TryLoad( - sampleRestoredCommandIdentifierOfThePackage, - out var toolCommand) - && _fileSystem.File.Exists(toolCommand.Executable.Value); - } - private FilePath? GetCustomManifestFileLocation() { string customFile = _parseResult.GetValue(ToolRestoreCommandParser.ToolManifestOption); @@ -292,21 +200,7 @@ private static void EnsureNoCommandNameCollision(Dictionary objects) - { - return string.Join(" ", objects.Select(o => $"\"{o.ToString()}\"")); - } - - private static VersionRange ToVersionRangeWithOnlyOneVersion(NuGetVersion version) - { - return new VersionRange( - version, - includeMinVersion: true, - maxVersion: version, - includeMaxVersion: true); - } - - private struct ToolRestoreResult + public struct ToolRestoreResult { public (RestoredCommandIdentifier, ToolCommand)[] SaveToCache { get; } public bool IsSuccess { get; } From 790d2cfb3ae2798fa4e22b851e8730e2504180a3 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 9 Jun 2025 19:07:51 -0400 Subject: [PATCH 32/45] Simplify ToolRestoreResult There doesn't seem to be a reason to have SaveToCache be a list --- .../Commands/Tool/Restore/ToolPackageRestorer.cs | 8 ++++---- .../Commands/Tool/Restore/ToolRestoreCommand.cs | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs index 36cf8c31c7f0..56ddad784be7 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs @@ -47,7 +47,7 @@ public ToolPackageRestorer(IToolPackageDownloader toolPackageDownloader, _fileSystem = fileSystem ?? new FileSystemWrapper(); } - public ToolRestoreResult InstallPackages( + public ToolRestoreResult InstallPackage( ToolManifestPackage package, FilePath? configFile) { @@ -56,7 +56,7 @@ public ToolRestoreResult InstallPackages( if (PackageHasBeenRestored(package, targetFramework)) { return ToolRestoreResult.Success( - saveToCache: [], + saveToCache: null, message: string.Format( CliCommandStrings.RestoreSuccessful, package.PackageId, package.Version.ToNormalizedString(), string.Join(", ", package.CommandNames))); @@ -89,13 +89,13 @@ public ToolRestoreResult InstallPackages( return ToolRestoreResult.Success( saveToCache: - [(new RestoredCommandIdentifier( + (new RestoredCommandIdentifier( toolPackage.Id, toolPackage.Version, NuGetFramework.Parse(targetFramework), Constants.AnyRid, toolPackage.Command.Name), - toolPackage.Command)], + toolPackage.Command), message: string.Format( CliCommandStrings.RestoreSuccessful, package.PackageId, diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs index 039e7d6ddb1e..e5e5cb867de1 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs @@ -115,11 +115,12 @@ public override int Execute() ToolRestoreResult[] toolRestoreResults = [.. packagesFromManifest .AsEnumerable() - .Select(package => toolPackageRestorer.InstallPackages(package, configFile))]; + .Select(package => toolPackageRestorer.InstallPackage(package, configFile))]; Dictionary downloaded = - toolRestoreResults.SelectMany(result => result.SaveToCache) - .ToDictionary(pair => pair.Item1, pair => pair.Item2); + toolRestoreResults.Select(result => result.SaveToCache) + .Where(item => item is not null) + .ToDictionary(pair => pair.Value.Item1, pair => pair.Value.Item2); EnsureNoCommandNameCollision(downloaded); @@ -202,12 +203,12 @@ private static void EnsureNoCommandNameCollision(Dictionary Date: Mon, 9 Jun 2025 19:47:05 -0400 Subject: [PATCH 33/45] Look for local tools first with dotnet tool exec --- .../Tool/Execute/ToolExecuteCommand.cs | 69 ++++++++++++++++--- .../Commands/Tool/Run/ToolRunCommand.cs | 14 ++-- .../dotnet/ToolManifest/ToolManifestFinder.cs | 28 ++++++++ 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index bd007d1108ef..09ca92b9d29f 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -5,15 +5,24 @@ using Microsoft.DotNet.Cli.CommandFactory; using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.Commands.Tool.Restore; +using Microsoft.DotNet.Cli.Commands.Tool.Run; +using Microsoft.DotNet.Cli.Extensions; +using Microsoft.DotNet.Cli.NuGetPackageDownloader; +using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Cli.Utils.Extensions; + +using Microsoft.Extensions.EnvironmentAbstractions; using NuGet.Common; using NuGet.Packaging.Core; using NuGet.Versioning; + namespace Microsoft.DotNet.Cli.Commands.Tool.Execute { - internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) + internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolManifestFinder = null, string? currentWorkingDirectory = null) : CommandBase(result) { private readonly PackageIdentity _packageToolIdentityArgument = result.GetRequiredValue(ToolExecuteCommandParser.PackageIdentityArgument); private readonly IEnumerable _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty(); @@ -25,10 +34,60 @@ internal class ToolExecuteCommand(ParseResult result) : CommandBase(result) private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); + + // TODO: Does result.OptionValuesToBeForwarded work here? + private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader( + additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolExecuteCommandParser.GetCommand())).Item3; + + // TODO: Make sure to add these options to the command + private readonly RestoreActionConfig _restoreActionConfig = new RestoreActionConfig(DisableParallel: result.GetValue(ToolCommandRestorePassThroughOptions.DisableParallelOption), + NoCache: result.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || result.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption), + IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), + Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); + + // TODO: Use prerelease private readonly bool _prerelease = result.GetValue(ToolExecuteCommandParser.PrereleaseOption); + private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory())); + public override int Execute() { + VersionRange versionRange = _parseResult.GetVersionRange(); + PackageId packageId = new PackageId(_packageToolIdentityArgument.Id); + + // Look in local tools manifest first, but only if version is not specified + if (versionRange == null) + { + var localToolsResolverCache = new LocalToolsResolverCache(); + + if (_toolManifestFinder.TryFindPackageId(packageId, out var toolManifestPackage)) + { + var toolPackageRestorer = new ToolPackageRestorer( + _toolPackageDownloader, + _sources, + overrideSources: [], + _verbosity, + _restoreActionConfig, + localToolsResolverCache, + new FileSystemWrapper()); + + var restoreResult = toolPackageRestorer.InstallPackage(toolManifestPackage, _configFile == null ? null : new FilePath(_configFile)); + + if (!restoreResult.IsSuccess) + { + Reporter.Error.WriteLine(restoreResult.Message.Red()); + return 1; + } + + var localToolsCommandResolver = new LocalToolsCommandResolver( + _toolManifestFinder, + localToolsResolverCache); + + return ToolRunCommand.ExecuteCommand(localToolsCommandResolver, toolManifestPackage.CommandNames.Single().Value, _forwardArguments, _allowRollForward); + } + } + + if (!UserAgreedToRunFromSource()) { throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); @@ -39,16 +98,10 @@ public override int Execute() _forwardArguments.Append("--allow-roll-forward"); } - PackageId packageId = new PackageId(_packageToolIdentityArgument.Id); - - VersionRange versionRange = _parseResult.GetVersionRange(); string tempDirectory = NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp); - ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory)); - ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery); - - IToolPackage toolPackage = toolPackageDownloader.InstallPackage( + IToolPackage toolPackage = _toolPackageDownloader.InstallPackage( new PackageLocation( nugetConfig: _configFile != null ? new(_configFile) : null, sourceFeedOverrides: _sources, diff --git a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs index 822c0826ee2f..ee0e2aa63f46 100644 --- a/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs @@ -28,17 +28,21 @@ internal class ToolRunCommand( public override int Execute() { - CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments() + return ExecuteCommand(_localToolsCommandResolver, _toolCommandName, _forwardArgument, _allowRollForward); + } + public static int ExecuteCommand(LocalToolsCommandResolver commandResolver, string toolCommandName, IEnumerable argumentsToForward, bool allowRollForward) + { + CommandSpec commandSpec = commandResolver.ResolveStrict(new CommandResolverArguments() { // since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet- - CommandName = $"dotnet-{_toolCommandName}", - CommandArguments = _forwardArgument, + CommandName = $"dotnet-{toolCommandName}", + CommandArguments = argumentsToForward, - }, _allowRollForward); + }, allowRollForward); if (commandSpec == null) { - throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false); + throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, toolCommandName)], isUserError: false); } var result = CommandFactoryUsingResolver.Create(commandSpec).Execute(); diff --git a/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs b/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs index a235bcd2d227..6cbde572af90 100644 --- a/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs +++ b/src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs @@ -132,6 +132,34 @@ public bool TryFind(ToolCommandName toolCommandName, out ToolManifestPackage too return false; } + public bool TryFindPackageId(PackageId packageId, out ToolManifestPackage toolManifestPackage) + { + toolManifestPackage = default; + foreach ((FilePath possibleManifest, DirectoryPath correspondingDirectory) in + EnumerateDefaultAllPossibleManifests()) + { + if (!_fileSystem.File.Exists(possibleManifest.Value)) + { + continue; + } + (List manifestPackages, bool isRoot) = + _toolManifestEditor.Read(possibleManifest, correspondingDirectory); + foreach (var package in manifestPackages) + { + if (package.PackageId.Equals(packageId)) + { + toolManifestPackage = package; + return true; + } + } + if (isRoot) + { + return false; + } + } + return false; + } + private IEnumerable<(FilePath manifestfile, DirectoryPath manifestFileFirstEffectDirectory)> EnumerateDefaultAllPossibleManifests() { From a4ee7d186902ba4270252ac34ada785c268f484f Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 9 Jun 2025 23:30:14 -0400 Subject: [PATCH 34/45] Add method to NuGetPackageDownloader to get source with best package version --- .../INuGetPackageDownloader.cs | 4 ++++ .../NuGetPackageDownloader.cs | 13 +++++++++++-- .../MockNuGetPackageDownloader.cs | 14 ++++++++++++-- .../Install/FailingNuGetPackageInstaller.cs | 4 ++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Cli/dotnet/NugetPackageDownloader/INuGetPackageDownloader.cs b/src/Cli/dotnet/NugetPackageDownloader/INuGetPackageDownloader.cs index 93e21d486e91..a5e54ba06bb9 100644 --- a/src/Cli/dotnet/NugetPackageDownloader/INuGetPackageDownloader.cs +++ b/src/Cli/dotnet/NugetPackageDownloader/INuGetPackageDownloader.cs @@ -39,4 +39,8 @@ Task> GetLatestPackageVersions(PackageId packageId, Task GetBestPackageVersionAsync(PackageId packageId, VersionRange versionRange, PackageSourceLocation packageSourceLocation = null); + + Task<(NuGetVersion version, PackageSource source)> GetBestPackageVersionAndSourceAsync(PackageId packageId, + VersionRange versionRange, + PackageSourceLocation packageSourceLocation = null); } diff --git a/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs b/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs index 3de046a03122..8ac89af40212 100644 --- a/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs +++ b/src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs @@ -614,14 +614,23 @@ public async Task GetBestPackageVersionAsync(PackageId packageId, return versionRange.MinVersion; } + return (await GetBestPackageVersionAndSourceAsync(packageId, versionRange, packageSourceLocation) + .ConfigureAwait(false)) + .version; + } + + public async Task<(NuGetVersion version, PackageSource source)> GetBestPackageVersionAndSourceAsync(PackageId packageId, + VersionRange versionRange, + PackageSourceLocation packageSourceLocation = null) + { CancellationToken cancellationToken = CancellationToken.None; IPackageSearchMetadata packageMetadata; IEnumerable packagesSources = LoadNuGetSources(packageId, packageSourceLocation); - (_, packageMetadata) = await GetMatchingVersionInternalAsync(packageId.ToString(), packagesSources, + (var source, packageMetadata) = await GetMatchingVersionInternalAsync(packageId.ToString(), packagesSources, versionRange, cancellationToken).ConfigureAwait(false); - return packageMetadata.Identity.Version; + return (packageMetadata.Identity.Version, source); } private async Task<(PackageSource, IPackageSearchMetadata)> GetPackageMetadataAsync(string packageIdentifier, diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs index ff1a37dc9e69..e99e96e5a740 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs @@ -130,10 +130,17 @@ public Task GetLatestPackageVersion(PackageId packageId, PackageSo } public Task GetBestPackageVersionAsync(PackageId packageId, VersionRange versionRange, PackageSourceLocation packageSourceLocation = null) + { + return GetBestPackageVersionAndSourceAsync(packageId, versionRange, packageSourceLocation) + .ContinueWith(t => t.Result.version, TaskContinuationOptions.OnlyOnRanToCompletion); + } + + public Task<(NuGetVersion version, PackageSource source)> GetBestPackageVersionAndSourceAsync(PackageId packageId, + VersionRange versionRange,PackageSourceLocation packageSourceLocation = null) { if (!ShouldFindPackage(packageId, packageSourceLocation)) { - return Task.FromException(new NuGetPackageNotFoundException(string.Format(CliStrings.IsNotFoundInNuGetFeeds, packageId, MOCK_FEEDS_TEXT))); + return Task.FromException<(NuGetVersion version, PackageSource source)>(new NuGetPackageNotFoundException(string.Format(CliStrings.IsNotFoundInNuGetFeeds, packageId, MOCK_FEEDS_TEXT))); } var bestVersion = versionRange.FindBestMatch(_packageVersions); @@ -141,7 +148,10 @@ public Task GetBestPackageVersionAsync(PackageId packageId, Versio { bestVersion = versionRange.MinVersion; } - return Task.FromResult(bestVersion); + + var source = new PackageSource("http://mock-url", "MockSource"); + + return Task.FromResult((bestVersion, source)); } diff --git a/test/dotnet.Tests/CommandTests/Workload/Install/FailingNuGetPackageInstaller.cs b/test/dotnet.Tests/CommandTests/Workload/Install/FailingNuGetPackageInstaller.cs index 298e19ab7d22..1c1471d91790 100644 --- a/test/dotnet.Tests/CommandTests/Workload/Install/FailingNuGetPackageInstaller.cs +++ b/test/dotnet.Tests/CommandTests/Workload/Install/FailingNuGetPackageInstaller.cs @@ -42,6 +42,10 @@ public Task> ExtractPackageAsync(string packagePath, Directo public Task GetLatestPackageVersion(PackageId packageId, PackageSourceLocation packageSourceLocation = null, bool includePreview = false) => throw new NotImplementedException(); public Task> GetLatestPackageVersions(PackageId packageId, int numberOfResults, PackageSourceLocation packageSourceLocation = null, bool includePreview = false) => throw new NotImplementedException(); public Task GetBestPackageVersionAsync(PackageId packageId, VersionRange versionRange, PackageSourceLocation packageSourceLocation = null) => throw new NotImplementedException(); + + public Task<(NuGetVersion version, PackageSource source)> GetBestPackageVersionAndSourceAsync(PackageId packageId, + VersionRange versionRange, PackageSourceLocation packageSourceLocation = null) => throw new NotImplementedException(); + public Task GetPackageUrl(PackageId packageId, NuGetVersion packageVersion, PackageSourceLocation packageSourceLocation = null, From fac59a8b10bec0560831ae39555c57fe60681da4 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 10 Jun 2025 07:05:16 -0400 Subject: [PATCH 35/45] Updates to interface to support tool exec GetNuGetVersion now returns the package source, and add method to check if tool is downloaded --- .../ToolInstallGlobalOrToolPathCommand.cs | 3 +- .../ToolPackage/IToolPackageDownloader.cs | 9 ++- .../ToolPackage/ToolPackageDownloaderBase.cs | 59 +++++++++++++++---- .../dotnet/ToolPackage/ToolPackageInstance.cs | 2 +- .../ToolPackageDownloaderTests.cs | 6 +- .../ToolPackageDownloaderMock.cs | 8 ++- 6 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs index 1107e8558214..429eea05069a 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs @@ -241,9 +241,8 @@ private NuGetVersion GetBestMatchNugetVersion(PackageId packageId, VersionRange packageId: packageId, versionRange: versionRange, verbosity: _verbosity, - isGlobalTool: true, restoreActionConfig: restoreActionConfig - ); + ).version; } private static bool ToolVersionAlreadyInstalled(IToolPackage oldPackageNullable, NuGetVersion nuGetVersion) diff --git a/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs b/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs index 767fc2f2e86f..3bc6b1d83707 100644 --- a/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs +++ b/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs @@ -4,6 +4,7 @@ #nullable disable using Microsoft.DotNet.Cli.NuGetPackageDownloader; +using NuGet.Configuration; using NuGet.Versioning; namespace Microsoft.DotNet.Cli.ToolPackage; @@ -21,12 +22,16 @@ IToolPackage InstallPackage(PackageLocation packageLocation, RestoreActionConfig restoreActionConfig = null ); - NuGetVersion GetNuGetVersion( + (NuGetVersion version, PackageSource source) GetNuGetVersion( PackageLocation packageLocation, PackageId packageId, VerbosityOptions verbosity, VersionRange versionRange = null, - bool isGlobalTool = false, RestoreActionConfig restoreActionConfig = null ); + + bool IsLocalToolDownloaded( + PackageId packageId, + NuGetVersion packageVersion, + string targetFramework = null); } diff --git a/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs b/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs index 062ed393bee5..c3322e4bef27 100644 --- a/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs +++ b/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json.Linq; using NuGet.Client; using NuGet.Commands; +using NuGet.Commands.Restore; using NuGet.Common; using NuGet.Configuration; using NuGet.ContentModel; @@ -272,10 +273,50 @@ protected virtual void DownloadTool( DownloadAndExtractPackage(packageId, nugetPackageDownloader, packageDownloadDir.Value, packageVersion, packageSourceLocation, includeUnlisted: givenSpecificVersion); } - CreateAssetFile(packageId, packageVersion, packageDownloadDir, Path.Combine(assetFileDirectory.Value, "project.assets.json"), _runtimeJsonPath, targetFramework); + CreateAssetFile(packageId, packageVersion, packageDownloadDir, Path.Combine(assetFileDirectory.Value, ToolPackageInstance.AssetsFileName), _runtimeJsonPath, targetFramework); // Also download RID-specific package if needed + var ridSpecificPackage = ResolveRidSpecificPackage(packageId, packageVersion, packageDownloadDir, assetFileDirectory); + if (ridSpecificPackage != null) + { + if (!IsPackageInstalled(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, packageDownloadDir.Value)) + { + DownloadAndExtractPackage(new PackageId(ridSpecificPackage.Id), nugetPackageDownloader, packageDownloadDir.Value, ridSpecificPackage.Version, packageSourceLocation, includeUnlisted: true); + } + + CreateAssetFile(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, packageDownloadDir, Path.Combine(assetFileDirectory.Value, ToolPackageInstance.RidSpecificPackageAssetsFileName), _runtimeJsonPath, targetFramework); + } + } + + public bool IsLocalToolDownloaded( + PackageId packageId, + NuGetVersion packageVersion, + string? targetFramework = null) + { + if (!IsPackageInstalled(packageId, packageVersion, _localToolDownloadDir.Value)) + { + return false; + } + CreateAssetFile(packageId, packageVersion, _localToolDownloadDir, Path.Combine(_localToolAssetDir.Value, ToolPackageInstance.AssetsFileName), _runtimeJsonPath, targetFramework); + + var ridSpecificPackage = ResolveRidSpecificPackage(packageId, packageVersion, _localToolDownloadDir, _localToolAssetDir); + if (ridSpecificPackage != null) + { + return IsPackageInstalled(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, _localToolDownloadDir.Value); + } + else + { + return true; + } + } + + private PackageIdentity? ResolveRidSpecificPackage(PackageId packageId, + NuGetVersion packageVersion, + DirectoryPath packageDownloadDir, + DirectoryPath assetFileDirectory) + { var toolConfiguration = GetToolConfiguration(packageId, packageDownloadDir, assetFileDirectory); + if (toolConfiguration.RidSpecificPackages?.Any() == true) { var runtimeGraph = JsonRuntimeFormat.ReadRuntimeGraph(_runtimeJsonPath); @@ -288,16 +329,11 @@ protected virtual void DownloadTool( var resolvedPackage = toolConfiguration.RidSpecificPackages[bestRuntimeIdentifier]; - if (!IsPackageInstalled(new PackageId(resolvedPackage.Id), resolvedPackage.Version, packageDownloadDir.Value)) - { - DownloadAndExtractPackage(new PackageId(resolvedPackage.Id), nugetPackageDownloader, packageDownloadDir.Value, resolvedPackage.Version, packageSourceLocation, includeUnlisted: true); - } - - CreateAssetFile(new PackageId(resolvedPackage.Id), resolvedPackage.Version, packageDownloadDir, Path.Combine(assetFileDirectory.Value, ToolPackageInstance.RidSpecificPackageAssetsFileName), _runtimeJsonPath, targetFramework); + return resolvedPackage; } - } - + return null; + } protected void UpdateRuntimeConfig( ToolPackageInstance toolPackageInstance @@ -320,12 +356,11 @@ ToolPackageInstance toolPackageInstance } } - public virtual NuGetVersion GetNuGetVersion( + public virtual (NuGetVersion version, PackageSource source) GetNuGetVersion( PackageLocation packageLocation, PackageId packageId, VerbosityOptions verbosity, VersionRange? versionRange = null, - bool isGlobalTool = false, RestoreActionConfig? restoreActionConfig = null) { if (versionRange == null) @@ -346,6 +381,6 @@ public virtual NuGetVersion GetNuGetVersion( additionalSourceFeeds: packageLocation.AdditionalFeeds, basePath: _currentWorkingDirectory); - return nugetPackageDownloader.GetBestPackageVersionAsync(packageId, versionRange, packageSourceLocation).GetAwaiter().GetResult(); + return nugetPackageDownloader.GetBestPackageVersionAndSourceAsync(packageId, versionRange, packageSourceLocation).GetAwaiter().GetResult(); } } diff --git a/src/Cli/dotnet/ToolPackage/ToolPackageInstance.cs b/src/Cli/dotnet/ToolPackage/ToolPackageInstance.cs index ca03522dbf2e..d17874fdb2c8 100644 --- a/src/Cli/dotnet/ToolPackage/ToolPackageInstance.cs +++ b/src/Cli/dotnet/ToolPackage/ToolPackageInstance.cs @@ -37,7 +37,7 @@ internal class ToolPackageInstance : IToolPackage private IFileSystem _fileSystem; - private const string AssetsFileName = "project.assets.json"; + public const string AssetsFileName = "project.assets.json"; public const string RidSpecificPackageAssetsFileName = "project.assets.ridpackage.json"; private const string ToolSettingsFileName = "DotnetToolSettings.xml"; diff --git a/test/Microsoft.DotNet.PackageInstall.Tests/ToolPackageDownloaderTests.cs b/test/Microsoft.DotNet.PackageInstall.Tests/ToolPackageDownloaderTests.cs index 299593c6e202..32f6f731397a 100644 --- a/test/Microsoft.DotNet.PackageInstall.Tests/ToolPackageDownloaderTests.cs +++ b/test/Microsoft.DotNet.PackageInstall.Tests/ToolPackageDownloaderTests.cs @@ -167,8 +167,7 @@ public void GivenAllButNoPackageVersionItReturnLatestStableVersion(bool testMock var package = downloader.GetNuGetVersion( new PackageLocation(nugetConfig: testDir.WithFile("NuGet.config")), packageId: TestPackageId, - verbosity: TestVerbosity, - isGlobalTool: true); + verbosity: TestVerbosity).version; package.OriginalVersion.Should().Be(TestPackageVersion); } @@ -194,8 +193,7 @@ public void GivenASpecificVersionGetCorrectVersion(bool testMockBehaviorIsInSync additionalFeeds: new[] { emptySource }), packageId: TestPackageId, verbosity: TestVerbosity, - versionRange: VersionRange.Parse(requestedVersion), - isGlobalTool: true); + versionRange: VersionRange.Parse(requestedVersion)).version; package.OriginalVersion.Should().Be(expectedVersion); } diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs index e6f0d0e1265c..d672c82e7b29 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs @@ -10,6 +10,7 @@ using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; using Microsoft.Extensions.EnvironmentAbstractions; +using NuGet.Configuration; using NuGet.Frameworks; using NuGet.Versioning; @@ -309,12 +310,11 @@ private static bool ExcludeOtherFeeds(FilePath nugetConfig, MockFeed f) || (f.Type == MockFeedType.ExplicitNugetConfig && f.Uri == nugetConfig.Value); } - public NuGetVersion GetNuGetVersion( + public (NuGetVersion version, PackageSource source) GetNuGetVersion( PackageLocation packageLocation, PackageId packageId, VerbosityOptions verbosity, VersionRange versionRange = null, - bool isGlobalTool = false, RestoreActionConfig restoreActionConfig = null) { versionRange = VersionRange.Parse(versionRange?.OriginalString ?? "*"); @@ -331,9 +331,11 @@ public NuGetVersion GetNuGetVersion( packageLocation.RootConfigDirectory, packageLocation.SourceFeedOverrides); - return NuGetVersion.Parse(feedPackage.Version); + return (NuGetVersion.Parse(feedPackage.Version), new PackageSource("http://mock-feed", "MockFeed")); } + public bool IsLocalToolDownloaded(PackageId packageId, NuGetVersion packageVersion, string targetFramework = null) => throw new NotImplementedException(); + private class TestToolPackage : IToolPackage { public PackageId Id { get; set; } From 321fd59e591711ad66c398045b77b7924b9cf577 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 10 Jun 2025 16:28:47 -0400 Subject: [PATCH 36/45] Prompt for tool exec only if tool hasn't been downloaded before --- src/Cli/dotnet/CliStrings.resx | 2 +- .../LocalToolsCommandResolver.cs | 28 +------- .../dotnet/Commands/CliCommandStrings.resx | 2 +- .../Tool/Execute/ToolExecuteCommand.cs | 70 ++++++++++++------- .../Tool/Execute/ToolExecuteCommandParser.cs | 2 + .../Tool/Install/ParseResultExtension.cs | 2 + .../Commands/Tool/ToolCommandSpecCreator.cs | 47 +++++++++++++ .../Commands/xlf/CliCommandStrings.cs.xlf | 4 +- .../Commands/xlf/CliCommandStrings.de.xlf | 4 +- .../Commands/xlf/CliCommandStrings.es.xlf | 4 +- .../Commands/xlf/CliCommandStrings.fr.xlf | 4 +- .../Commands/xlf/CliCommandStrings.it.xlf | 4 +- .../Commands/xlf/CliCommandStrings.ja.xlf | 4 +- .../Commands/xlf/CliCommandStrings.ko.xlf | 4 +- .../Commands/xlf/CliCommandStrings.pl.xlf | 4 +- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 4 +- .../Commands/xlf/CliCommandStrings.ru.xlf | 4 +- .../Commands/xlf/CliCommandStrings.tr.xlf | 4 +- .../xlf/CliCommandStrings.zh-Hans.xlf | 4 +- .../xlf/CliCommandStrings.zh-Hant.xlf | 4 +- .../ToolPackage/IToolPackageDownloader.cs | 5 +- .../ToolPackage/ToolPackageDownloaderBase.cs | 26 +++++-- src/Cli/dotnet/xlf/CliStrings.cs.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.de.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.es.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.fr.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.it.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.ja.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.ko.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.pl.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.ru.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.tr.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 4 +- src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 4 +- .../ToolPackageDownloaderMock.cs | 2 +- 36 files changed, 175 insertions(+), 115 deletions(-) create mode 100644 src/Cli/dotnet/Commands/Tool/ToolCommandSpecCreator.cs diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx index 214d2486907d..8e915a928d53 100644 --- a/src/Cli/dotnet/CliStrings.resx +++ b/src/Cli/dotnet/CliStrings.resx @@ -317,7 +317,7 @@ More than one command is defined for the tool. - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." The tool does not support the current architecture or operating system ({0}). Supported runtimes: {1} diff --git a/src/Cli/dotnet/CommandFactory/CommandResolution/LocalToolsCommandResolver.cs b/src/Cli/dotnet/CommandFactory/CommandResolution/LocalToolsCommandResolver.cs index d9845c0aea06..ac22545eddec 100644 --- a/src/Cli/dotnet/CommandFactory/CommandResolution/LocalToolsCommandResolver.cs +++ b/src/Cli/dotnet/CommandFactory/CommandResolution/LocalToolsCommandResolver.cs @@ -3,6 +3,7 @@ #nullable disable +using Microsoft.DotNet.Cli.Commands.Tool; using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; @@ -91,31 +92,8 @@ private CommandSpec GetPackageCommandSpecUsingMuxer(CommandResolverArguments arg toolCommandName.ToString())); } - if (toolCommand.Runner == "dotnet") - { - if (toolManifestPackage.RollForward || allowRollForward) - { - arguments.CommandArguments = ["--allow-roll-forward", .. arguments.CommandArguments]; - } - - return MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer( - toolCommand.Executable.Value, - arguments.CommandArguments); - } - else if (toolCommand.Runner == "executable") - { - var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart( - arguments.CommandArguments); - - return new CommandSpec( - toolCommand.Executable.Value, - escapedArgs); - } - else - { - throw new GracefulException(string.Format(CliStrings.ToolSettingsUnsupportedRunner, - toolCommand.Name, toolCommand.Runner)); - } + return ToolCommandSpecCreator.CreateToolCommandSpec(toolCommand.Name.Value, toolCommand.Executable.Value, toolCommand.Runner, + toolManifestPackage.RollForward || allowRollForward, arguments.CommandArguments); } else { diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index fc7e01606bbb..4ac2de1ef0eb 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2486,7 +2486,7 @@ To display a value, specify the corresponding command-line option without provid Missing package ID - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] Run from source approval denied by the user diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 09ca92b9d29f..1a6e3af319d7 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -16,6 +16,7 @@ using Microsoft.Extensions.EnvironmentAbstractions; using NuGet.Common; +using NuGet.Configuration; using NuGet.Packaging.Core; using NuGet.Versioning; @@ -87,40 +88,54 @@ public override int Execute() } } + var packageLocation = new PackageLocation( + nugetConfig: _configFile != null ? new(_configFile) : null, + sourceFeedOverrides: _sources, + additionalFeeds: _addSource); - if (!UserAgreedToRunFromSource()) - { - throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); - } + var restoreActionConfig = new RestoreActionConfig( + IgnoreFailedSources: _ignoreFailedSources, + Interactive: _interactive); - if (_allowRollForward) - { - _forwardArguments.Append("--allow-roll-forward"); - } + (var bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, restoreActionConfig); + IToolPackage toolPackage; - string tempDirectory = NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp); + // TODO: Add framework argument + if (!_toolPackageDownloader.TryGetDownloadedTool(packageId, bestVersion, targetFramework: null, out toolPackage)) + { + if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource)) + { + // TODO: Refactor this to print a better message, and probably a different message depending on whether the user selected no + // or whether interactive mode was off + throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); + } - IToolPackage toolPackage = _toolPackageDownloader.InstallPackage( - new PackageLocation( + // We've already determined which source we will use and displayed that in a confirmation message to the user. + // So set the package location here to override the source feeds to just the source we already resolved to. + // This does mean that we won't work with feeds that have a primary package but where the RID-specific packages are on + // other feeds, but this is probably OK. + var downloadPackageLocation = new PackageLocation( nugetConfig: _configFile != null ? new(_configFile) : null, - sourceFeedOverrides: _sources, - additionalFeeds: _addSource), - packageId: packageId, - verbosity: _verbosity, - versionRange: versionRange, - isGlobalToolRollForward: _allowRollForward, // Needed to update .runtimeconfig.json - restoreActionConfig: new( - IgnoreFailedSources: _ignoreFailedSources, - Interactive: _interactive)); + sourceFeedOverrides: [packageSource.Source], + additionalFeeds: _addSource); + + toolPackage = _toolPackageDownloader.InstallPackage( + downloadPackageLocation, + packageId: packageId, + verbosity: _verbosity, + versionRange: new VersionRange(bestVersion, true, bestVersion, true), + isGlobalToolRollForward: false, + restoreActionConfig: restoreActionConfig); + } - CommandSpec commandSpec = MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer(toolPackage.Command.Executable.ToString(), _forwardArguments); + var commandSpec = ToolCommandSpecCreator.CreateToolCommandSpec(toolPackage.Command.Name.Value, toolPackage.Command.Executable.Value, toolPackage.Command.Runner, _allowRollForward, _forwardArguments); var command = CommandFactoryUsingResolver.Create(commandSpec); var result = command.Execute(); return result.ExitCode; } - private bool UserAgreedToRunFromSource() + private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version, PackageSource source) { if (_yes) { @@ -132,19 +147,22 @@ private bool UserAgreedToRunFromSource() return false; } - // TODO: Use a better way to ask for user input - Console.Write(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt); + // TODO: Use a better way to ask for user input + // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? + string promptMessage = string.Format(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt, packageId, version.ToString(), source.Source); + + Console.Write(promptMessage); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; if (_verbosity >= VerbosityOptions.detailed) { Console.WriteLine(); - Console.WriteLine(new String('-', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length)); + Console.WriteLine(new String('-', promptMessage.Length)); } else { // Clear the line - Console.Write("\r" + new string(' ', CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt.Length + 1) + "\r"); + Console.Write("\r" + new string(' ', promptMessage.Length + 1) + "\r"); } return userAccepted; diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index 81c39eba85b4..88554f4418c5 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -58,6 +58,8 @@ private static Command ConstructCommand() command.Options.Add(YesOption); command.Options.Add(VerbosityOption); + // TODO: Framework? + command.SetAction((parseResult) => new ToolExecuteCommand(parseResult).Execute()); return command; diff --git a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs index b79d3bffbde4..9b485abbcffe 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs @@ -36,6 +36,8 @@ public static VersionRange GetVersionRange(this ParseResult parseResult) if (prerelease) { + // TODO: This is probably broken if you try to specify --prerelease together with a version. Should that be allowed? + // It seems like it would make sense to specify a version of something like 2.* and want to allow prerelease versions. packageVersion = "*-*"; } diff --git a/src/Cli/dotnet/Commands/Tool/ToolCommandSpecCreator.cs b/src/Cli/dotnet/Commands/Tool/ToolCommandSpecCreator.cs new file mode 100644 index 000000000000..375e9ca20397 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/ToolCommandSpecCreator.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.Text; +using Microsoft.DotNet.Cli.CommandFactory; +using Microsoft.DotNet.Cli.CommandFactory.CommandResolution; +using Microsoft.DotNet.Cli.ToolManifest; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Commands.Tool +{ + internal class ToolCommandSpecCreator + { + public static CommandSpec CreateToolCommandSpec(string toolName, string toolExecutable, string toolRunner, bool allowRollForward, IEnumerable commandArguments) + { + if (toolRunner == "dotnet") + { + if (allowRollForward) + { + commandArguments = ["--allow-roll-forward", .. commandArguments]; + } + + return MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer( + toolExecutable, + commandArguments); + } + else if (toolRunner == "executable") + { + var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart( + commandArguments); + + return new CommandSpec( + toolExecutable, + escapedArgs); + } + else + { + throw new GracefulException(string.Format(CliStrings.ToolSettingsUnsupportedRunner, + toolName, toolRunner)); + } + } + } +} diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 763090389e42..3093c80cf90d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index 63f94832d04f..fc3418d28a59 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 777a35cf2ff7..d74cd26ac9f8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 5d286d038395..90c38a4cd508 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 3426b8ef894b..5751a93ef3f8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 4f86569fb0ae..39e7c2cdc00b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 27eb5fc18ff7..7f72811cd758 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 18512c8c8a63..d70ec3018013 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 5842ba14d80d..f1c9a3c113cd 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 4c6581ce52f9..61a092c2f9ee 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index c1a75d3f4a60..a7b5b283273c 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index 3b4e37d8cac4..b745b1f2dd08 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index e4904644f52c..e2de1217e78b 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -3158,8 +3158,8 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl - Tool not found on the system. Do you want to run it from source? [y/n] - Tool not found on the system. Do you want to run it from source? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] diff --git a/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs b/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs index 3bc6b1d83707..9d2a881250ba 100644 --- a/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs +++ b/src/Cli/dotnet/ToolPackage/IToolPackageDownloader.cs @@ -30,8 +30,9 @@ IToolPackage InstallPackage(PackageLocation packageLocation, RestoreActionConfig restoreActionConfig = null ); - bool IsLocalToolDownloaded( + bool TryGetDownloadedTool( PackageId packageId, NuGetVersion packageVersion, - string targetFramework = null); + string targetFramework, + out IToolPackage toolPackage); } diff --git a/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs b/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs index c3322e4bef27..9e45f2308ae2 100644 --- a/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs +++ b/src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs @@ -288,13 +288,15 @@ protected virtual void DownloadTool( } } - public bool IsLocalToolDownloaded( + public bool TryGetDownloadedTool( PackageId packageId, NuGetVersion packageVersion, - string? targetFramework = null) + string targetFramework, + out IToolPackage? toolPackage) { if (!IsPackageInstalled(packageId, packageVersion, _localToolDownloadDir.Value)) { + toolPackage = null; return false; } CreateAssetFile(packageId, packageVersion, _localToolDownloadDir, Path.Combine(_localToolAssetDir.Value, ToolPackageInstance.AssetsFileName), _runtimeJsonPath, targetFramework); @@ -302,12 +304,22 @@ public bool IsLocalToolDownloaded( var ridSpecificPackage = ResolveRidSpecificPackage(packageId, packageVersion, _localToolDownloadDir, _localToolAssetDir); if (ridSpecificPackage != null) { - return IsPackageInstalled(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, _localToolDownloadDir.Value); - } - else - { - return true; + if (!IsPackageInstalled(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, _localToolDownloadDir.Value)) + { + toolPackage = null; + return false; + } + CreateAssetFile(new PackageId(ridSpecificPackage.Id), ridSpecificPackage.Version, _localToolDownloadDir, + Path.Combine(_localToolAssetDir.Value, ToolPackageInstance.RidSpecificPackageAssetsFileName), _runtimeJsonPath, targetFramework); } + + toolPackage = new ToolPackageInstance(id: packageId, + version: packageVersion, + packageDirectory: _localToolDownloadDir, + assetsJsonParentDirectory: _localToolAssetDir, + fileSystem: _fileSystem); + return true; + } private PackageIdentity? ResolveRidSpecificPackage(PackageId packageId, diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf index f250f6da228d..396856cdcffd 100644 --- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf index 88c7f5edab74..1690a105b041 100644 --- a/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf index cf93a4ee87fc..9d7873bc0541 100644 --- a/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf index 1150e15af09d..c5f3168077e9 100644 --- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf index ea9e6d4de305..6f59a4b0bc1e 100644 --- a/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf index 1891d3dcc0ac..50251a085637 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf index f7ff9a0fedaa..c3e0895f0c3c 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 53b673eb513b..9fb38670ba74 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index 2f2cf8213cc1..aa469cb2f3bf 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf index 7f8ebd8090f6..331ee9258476 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf index a7fdd0073644..804364591bdb 100644 --- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index 4a76bba083d5..9a34782be7f3 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index c37f2ba57bd1..50dec21fa806 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -1078,8 +1078,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is - Command '{0}' uses unsupported runner '{1}'." - Command '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." + Tool '{0}' uses unsupported runner '{1}'." diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs index d672c82e7b29..fc1920ce5312 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageDownloaderMock.cs @@ -334,7 +334,7 @@ private static bool ExcludeOtherFeeds(FilePath nugetConfig, MockFeed f) return (NuGetVersion.Parse(feedPackage.Version), new PackageSource("http://mock-feed", "MockFeed")); } - public bool IsLocalToolDownloaded(PackageId packageId, NuGetVersion packageVersion, string targetFramework = null) => throw new NotImplementedException(); + public bool TryGetDownloadedTool(PackageId packageId, NuGetVersion packageVersion, string targetFramework, out IToolPackage toolPackage) => throw new NotImplementedException(); private class TestToolPackage : IToolPackage { From 56cc63a8915df47ea33d6de0e569342e6b13f5cd Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 10 Jun 2025 17:33:52 -0400 Subject: [PATCH 37/45] Improve dotnet tool exec UI --- .../dotnet/Commands/CliCommandStrings.resx | 12 +++++--- .../Tool/Execute/ToolExecuteCommand.cs | 30 ++++++++----------- .../Commands/xlf/CliCommandStrings.cs.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.de.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.es.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.fr.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.it.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.ja.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.ko.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.pl.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.ru.xlf | 27 ++++++++++------- .../Commands/xlf/CliCommandStrings.tr.xlf | 27 ++++++++++------- .../xlf/CliCommandStrings.zh-Hans.xlf | 27 ++++++++++------- .../xlf/CliCommandStrings.zh-Hant.xlf | 27 ++++++++++------- 15 files changed, 242 insertions(+), 151 deletions(-) diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index 4ac2de1ef0eb..52a6229e3648 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2485,10 +2485,14 @@ To display a value, specify the corresponding command-line option without provid Missing package ID - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] - - Run from source approval denied by the user + + Tool package download canceled + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 1a6e3af319d7..82b45a6fa856 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -46,9 +46,6 @@ internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolMa IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); - // TODO: Use prerelease - private readonly bool _prerelease = result.GetValue(ToolExecuteCommandParser.PrereleaseOption); - private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory())); public override int Execute() @@ -106,9 +103,15 @@ public override int Execute() { if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource)) { - // TODO: Refactor this to print a better message, and probably a different message depending on whether the user selected no - // or whether interactive mode was off - throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true); + if (_interactive) + { + // TODO: Should we return an exit code that indicates the user canceled the operation? + throw new GracefulException(CliCommandStrings.ToolDownloadCanceled, isUserError: true); + } + else + { + throw new GracefulException(CliCommandStrings.ToolDownloadNeedsConfirmation, isUserError: true); + } } // We've already determined which source we will use and displayed that in a confirmation message to the user. @@ -149,21 +152,14 @@ private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version // TODO: Use a better way to ask for user input // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? - string promptMessage = string.Format(CliCommandStrings.ToolRunFromSourceUserConfirmationPrompt, packageId, version.ToString(), source.Source); + string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt + " ", packageId, version.ToString(), source.Source); Console.Write(promptMessage); bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; - if (_verbosity >= VerbosityOptions.detailed) - { - Console.WriteLine(); - Console.WriteLine(new String('-', promptMessage.Length)); - } - else - { - // Clear the line - Console.Write("\r" + new string(' ', promptMessage.Length + 1) + "\r"); - } + Console.WriteLine(); + // TODO: Do we want a separator like this? Seems like it's meant to separate the output of the tool from the prompt. + //Console.WriteLine(new String('-', promptMessage.Length + 2)); return userAccepted; } diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 3093c80cf90d..408e91734cf3 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index fc3418d28a59..ec753951dde0 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index d74cd26ac9f8..40e9a46f9b04 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 90c38a4cd508..03767fba5c3d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 5751a93ef3f8..51795815c595 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 39e7c2cdc00b..24ecd6605478 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 7f72811cd758..12245675cc92 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index d70ec3018013..997f778f8423 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index f1c9a3c113cd..b8d70a5c022e 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 61a092c2f9ee..89507fc97999 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index a7b5b283273c..fa170752851a 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index b745b1f2dd08..6791c400b918 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index e2de1217e78b..d92ecb7cf043 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -2926,6 +2926,23 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Tool package download canceled + Tool package download canceled + + + + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + Tool package {0}@{1} will be downloaded from source {2}. +Proceed? [y/n] + + + + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + + Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. @@ -3152,16 +3169,6 @@ If you would like to create a manifest, use the `--create-manifest-if-needed` fl Run a local tool. Note that this command cannot be used to run a global tool. - - Run from source approval denied by the user - Run from source approval denied by the user - - - - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - Tool package {0}@{1} will be downloaded from source {2}. Proceed? [y/n] - - Search dotnet tools in nuget.org Search dotnet tools in nuget.org From 68f06385f5609b6b035efb1ea7fa5b5af8759488 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 11:14:17 -0400 Subject: [PATCH 38/45] Apply code review feedback --- .../Tool/Execute/ToolExecuteCommand.cs | 234 +++++++++--------- .../Tool/Execute/ToolExecuteCommandParser.cs | 88 ++++--- .../Tool/Install/ParseResultExtension.cs | 2 - .../Tool/Restore/ToolPackageRestorer.cs | 4 - .../Tool/Restore/ToolRestoreCommand.cs | 4 +- .../Commands/Tool/ToolCommandSpecCreator.cs | 55 ++-- .../dotnet/ToolPackage/ToolPackageFactory.cs | 2 +- 7 files changed, 187 insertions(+), 202 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 82b45a6fa856..51e7e8a71f66 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -21,147 +21,149 @@ using NuGet.Versioning; -namespace Microsoft.DotNet.Cli.Commands.Tool.Execute +namespace Microsoft.DotNet.Cli.Commands.Tool.Execute; + +internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolManifestFinder = null, string? currentWorkingDirectory = null) : CommandBase(result) { - internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolManifestFinder = null, string? currentWorkingDirectory = null) : CommandBase(result) + const int ERROR_CANCELLED = 1223; // Windows error code for "Operation canceled by user" + + private readonly PackageIdentity _packageToolIdentityArgument = result.GetRequiredValue(ToolExecuteCommandParser.PackageIdentityArgument); + private readonly IEnumerable _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty(); + private readonly bool _allowRollForward = result.GetValue(ToolExecuteCommandParser.RollForwardOption); + private readonly string? _configFile = result.GetValue(ToolExecuteCommandParser.ConfigOption); + private readonly string[] _sources = result.GetValue(ToolExecuteCommandParser.SourceOption) ?? []; + private readonly string[] _addSource = result.GetValue(ToolExecuteCommandParser.AddSourceOption) ?? []; + private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); + private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); + private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); + private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); + + // TODO: Does result.OptionValuesToBeForwarded work here? + private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader( + additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolExecuteCommandParser.GetCommand())).downloader; + + // TODO: Make sure to add these options to the command + private readonly RestoreActionConfig _restoreActionConfig = new RestoreActionConfig(DisableParallel: result.GetValue(ToolCommandRestorePassThroughOptions.DisableParallelOption), + NoCache: result.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || result.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption), + IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), + Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); + + private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory())); + + public override int Execute() { - private readonly PackageIdentity _packageToolIdentityArgument = result.GetRequiredValue(ToolExecuteCommandParser.PackageIdentityArgument); - private readonly IEnumerable _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty(); - private readonly bool _allowRollForward = result.GetValue(ToolExecuteCommandParser.RollForwardOption); - private readonly string? _configFile = result.GetValue(ToolExecuteCommandParser.ConfigOption); - private readonly string[] _sources = result.GetValue(ToolExecuteCommandParser.SourceOption) ?? []; - private readonly string[] _addSource = result.GetValue(ToolExecuteCommandParser.AddSourceOption) ?? []; - private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); - private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); - private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); - private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); - - // TODO: Does result.OptionValuesToBeForwarded work here? - private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader( - additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolExecuteCommandParser.GetCommand())).Item3; - - // TODO: Make sure to add these options to the command - private readonly RestoreActionConfig _restoreActionConfig = new RestoreActionConfig(DisableParallel: result.GetValue(ToolCommandRestorePassThroughOptions.DisableParallelOption), - NoCache: result.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || result.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption), - IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), - Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); - - private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory())); - - public override int Execute() + VersionRange versionRange = _parseResult.GetVersionRange(); + PackageId packageId = new PackageId(_packageToolIdentityArgument.Id); + + // Look in local tools manifest first, but only if version is not specified + if (versionRange == null) { - VersionRange versionRange = _parseResult.GetVersionRange(); - PackageId packageId = new PackageId(_packageToolIdentityArgument.Id); + var localToolsResolverCache = new LocalToolsResolverCache(); - // Look in local tools manifest first, but only if version is not specified - if (versionRange == null) + if (_toolManifestFinder.TryFindPackageId(packageId, out var toolManifestPackage)) { - var localToolsResolverCache = new LocalToolsResolverCache(); - - if (_toolManifestFinder.TryFindPackageId(packageId, out var toolManifestPackage)) + var toolPackageRestorer = new ToolPackageRestorer( + _toolPackageDownloader, + _sources, + overrideSources: [], + _verbosity, + _restoreActionConfig, + localToolsResolverCache, + new FileSystemWrapper()); + + var restoreResult = toolPackageRestorer.InstallPackage(toolManifestPackage, _configFile == null ? null : new FilePath(_configFile)); + + if (!restoreResult.IsSuccess) { - var toolPackageRestorer = new ToolPackageRestorer( - _toolPackageDownloader, - _sources, - overrideSources: [], - _verbosity, - _restoreActionConfig, - localToolsResolverCache, - new FileSystemWrapper()); - - var restoreResult = toolPackageRestorer.InstallPackage(toolManifestPackage, _configFile == null ? null : new FilePath(_configFile)); - - if (!restoreResult.IsSuccess) - { - Reporter.Error.WriteLine(restoreResult.Message.Red()); - return 1; - } - - var localToolsCommandResolver = new LocalToolsCommandResolver( - _toolManifestFinder, - localToolsResolverCache); - - return ToolRunCommand.ExecuteCommand(localToolsCommandResolver, toolManifestPackage.CommandNames.Single().Value, _forwardArguments, _allowRollForward); + Reporter.Error.WriteLine(restoreResult.Message.Red()); + return 1; } + + var localToolsCommandResolver = new LocalToolsCommandResolver( + _toolManifestFinder, + localToolsResolverCache); + + return ToolRunCommand.ExecuteCommand(localToolsCommandResolver, toolManifestPackage.CommandNames.Single().Value, _forwardArguments, _allowRollForward); } + } - var packageLocation = new PackageLocation( - nugetConfig: _configFile != null ? new(_configFile) : null, - sourceFeedOverrides: _sources, - additionalFeeds: _addSource); + var packageLocation = new PackageLocation( + nugetConfig: _configFile != null ? new(_configFile) : null, + sourceFeedOverrides: _sources, + additionalFeeds: _addSource); - var restoreActionConfig = new RestoreActionConfig( - IgnoreFailedSources: _ignoreFailedSources, - Interactive: _interactive); + var restoreActionConfig = new RestoreActionConfig( + IgnoreFailedSources: _ignoreFailedSources, + Interactive: _interactive); - (var bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, restoreActionConfig); + (var bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, restoreActionConfig); - IToolPackage toolPackage; + IToolPackage toolPackage; - // TODO: Add framework argument - if (!_toolPackageDownloader.TryGetDownloadedTool(packageId, bestVersion, targetFramework: null, out toolPackage)) + // TODO: Add framework argument + if (!_toolPackageDownloader.TryGetDownloadedTool(packageId, bestVersion, targetFramework: null, out toolPackage)) + { + if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource)) { - if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource)) + if (_interactive) { - if (_interactive) - { - // TODO: Should we return an exit code that indicates the user canceled the operation? - throw new GracefulException(CliCommandStrings.ToolDownloadCanceled, isUserError: true); - } - else - { - throw new GracefulException(CliCommandStrings.ToolDownloadNeedsConfirmation, isUserError: true); - } + Reporter.Error.WriteLine(CliCommandStrings.ToolDownloadCanceled.Red().Bold()); + return ERROR_CANCELLED; + } + else + { + Reporter.Error.WriteLine(CliCommandStrings.ToolDownloadNeedsConfirmation.Red().Bold()); + return 1; } - - // We've already determined which source we will use and displayed that in a confirmation message to the user. - // So set the package location here to override the source feeds to just the source we already resolved to. - // This does mean that we won't work with feeds that have a primary package but where the RID-specific packages are on - // other feeds, but this is probably OK. - var downloadPackageLocation = new PackageLocation( - nugetConfig: _configFile != null ? new(_configFile) : null, - sourceFeedOverrides: [packageSource.Source], - additionalFeeds: _addSource); - - toolPackage = _toolPackageDownloader.InstallPackage( - downloadPackageLocation, - packageId: packageId, - verbosity: _verbosity, - versionRange: new VersionRange(bestVersion, true, bestVersion, true), - isGlobalToolRollForward: false, - restoreActionConfig: restoreActionConfig); } - var commandSpec = ToolCommandSpecCreator.CreateToolCommandSpec(toolPackage.Command.Name.Value, toolPackage.Command.Executable.Value, toolPackage.Command.Runner, _allowRollForward, _forwardArguments); - var command = CommandFactoryUsingResolver.Create(commandSpec); - var result = command.Execute(); - return result.ExitCode; + // We've already determined which source we will use and displayed that in a confirmation message to the user. + // So set the package location here to override the source feeds to just the source we already resolved to. + // This does mean that we won't work with feeds that have a primary package but where the RID-specific packages are on + // other feeds, but this is probably OK. + var downloadPackageLocation = new PackageLocation( + nugetConfig: _configFile != null ? new(_configFile) : null, + sourceFeedOverrides: [packageSource.Source], + additionalFeeds: _addSource); + + toolPackage = _toolPackageDownloader.InstallPackage( + downloadPackageLocation, + packageId: packageId, + verbosity: _verbosity, + versionRange: new VersionRange(bestVersion, true, bestVersion, true), + isGlobalToolRollForward: false, + restoreActionConfig: restoreActionConfig); } - private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version, PackageSource source) + var commandSpec = ToolCommandSpecCreator.CreateToolCommandSpec(toolPackage.Command.Name.Value, toolPackage.Command.Executable.Value, toolPackage.Command.Runner, _allowRollForward, _forwardArguments); + var command = CommandFactoryUsingResolver.Create(commandSpec); + var result = command.Execute(); + return result.ExitCode; + } + + private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version, PackageSource source) + { + if (_yes) { - if (_yes) - { - return true; - } + return true; + } - if (!_interactive) - { - return false; - } + if (!_interactive) + { + return false; + } - // TODO: Use a better way to ask for user input - // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? - string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt + " ", packageId, version.ToString(), source.Source); + // TODO: Use a better way to ask for user input + // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? + string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt + " ", packageId, version.ToString(), source.Source); - Console.Write(promptMessage); - bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; + Console.Write(promptMessage); + bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; - Console.WriteLine(); - // TODO: Do we want a separator like this? Seems like it's meant to separate the output of the tool from the prompt. - //Console.WriteLine(new String('-', promptMessage.Length + 2)); + Console.WriteLine(); + // TODO: Do we want a separator like this? Seems like it's meant to separate the output of the tool from the prompt. + //Console.WriteLine(new String('-', promptMessage.Length + 2)); - return userAccepted; - } + return userAccepted; } } diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index 88554f4418c5..a30123472c46 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -1,68 +1,64 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.CommandLine; -using System.Text; using Microsoft.DotNet.Cli.Commands.Tool.Install; using NuGet.Packaging.Core; -namespace Microsoft.DotNet.Cli.Commands.Tool.Execute +namespace Microsoft.DotNet.Cli.Commands.Tool.Execute; + +internal static class ToolExecuteCommandParser + { - internal static class ToolExecuteCommandParser + public static readonly Argument PackageIdentityArgument = ToolInstallCommandParser.PackageIdentityArgument; + public static readonly Argument> CommandArgument = new("commandArguments") { - public static readonly Argument PackageIdentityArgument = ToolInstallCommandParser.PackageIdentityArgument; - - public static readonly Argument> CommandArgument = new("commandArguments") - { - Description = CliCommandStrings.ToolRunArgumentsDescription - }; + Description = CliCommandStrings.ToolRunArgumentsDescription + }; - public static readonly Option VersionOption = ToolInstallCommandParser.VersionOption; - public static readonly Option RollForwardOption = ToolInstallCommandParser.RollForwardOption; - public static readonly Option PrereleaseOption = ToolInstallCommandParser.PrereleaseOption; - public static readonly Option ConfigOption = ToolInstallCommandParser.ConfigOption; - public static readonly Option SourceOption = ToolInstallCommandParser.SourceOption; - public static readonly Option AddSourceOption = ToolInstallCommandParser.AddSourceOption; - public static readonly Option IgnoreFailedSourcesOption = ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption; - public static readonly Option InteractiveOption = CommonOptions.InteractiveOption(); - public static readonly Option YesOption = CommonOptions.YesOption; - public static readonly Option VerbosityOption = ToolInstallCommandParser.VerbosityOption; + public static readonly Option VersionOption = ToolInstallCommandParser.VersionOption; + public static readonly Option RollForwardOption = ToolInstallCommandParser.RollForwardOption; + public static readonly Option PrereleaseOption = ToolInstallCommandParser.PrereleaseOption; + public static readonly Option ConfigOption = ToolInstallCommandParser.ConfigOption; + public static readonly Option SourceOption = ToolInstallCommandParser.SourceOption; + public static readonly Option AddSourceOption = ToolInstallCommandParser.AddSourceOption; + public static readonly Option IgnoreFailedSourcesOption = ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption; + public static readonly Option InteractiveOption = CommonOptions.InteractiveOption(); + public static readonly Option YesOption = CommonOptions.YesOption; + public static readonly Option VerbosityOption = ToolInstallCommandParser.VerbosityOption; - public static readonly Command Command = ConstructCommand(); - public static Command GetCommand() - { - return Command; - } + public static readonly Command Command = ConstructCommand(); + public static Command GetCommand() + { + return Command; + } - private static Command ConstructCommand() - { - Command command = new("execute", CliCommandStrings.ToolExecuteCommandDescription); + private static Command ConstructCommand() + { + Command command = new("execute", CliCommandStrings.ToolExecuteCommandDescription); - command.Aliases.Add("exec"); + command.Aliases.Add("exec"); - command.Arguments.Add(PackageIdentityArgument); - command.Arguments.Add(CommandArgument); + command.Arguments.Add(PackageIdentityArgument); + command.Arguments.Add(CommandArgument); - command.Options.Add(VersionOption); - command.Options.Add(RollForwardOption); - command.Options.Add(PrereleaseOption); - command.Options.Add(ConfigOption); - command.Options.Add(SourceOption); - command.Options.Add(AddSourceOption); - command.Options.Add(IgnoreFailedSourcesOption); - command.Options.Add(InteractiveOption); - command.Options.Add(YesOption); - command.Options.Add(VerbosityOption); + command.Options.Add(VersionOption); + command.Options.Add(RollForwardOption); + command.Options.Add(PrereleaseOption); + command.Options.Add(ConfigOption); + command.Options.Add(SourceOption); + command.Options.Add(AddSourceOption); + command.Options.Add(IgnoreFailedSourcesOption); + command.Options.Add(InteractiveOption); + command.Options.Add(YesOption); + command.Options.Add(VerbosityOption); - // TODO: Framework? + // TODO: Framework? - command.SetAction((parseResult) => new ToolExecuteCommand(parseResult).Execute()); + command.SetAction((parseResult) => new ToolExecuteCommand(parseResult).Execute()); - return command; - } + return command; } } diff --git a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs index 9b485abbcffe..b79d3bffbde4 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ParseResultExtension.cs @@ -36,8 +36,6 @@ public static VersionRange GetVersionRange(this ParseResult parseResult) if (prerelease) { - // TODO: This is probably broken if you try to specify --prerelease together with a version. Should that be allowed? - // It seems like it would make sense to specify a version of something like 2.* and want to allow prerelease versions. packageVersion = "*-*"; } diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs index 56ddad784be7..614919fa62d7 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs @@ -1,15 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; -using System.Text; using Microsoft.DotNet.Cli.NuGetPackageDownloader; using Microsoft.DotNet.Cli.ToolManifest; using Microsoft.DotNet.Cli.ToolPackage; using Microsoft.DotNet.Cli.Utils; using Microsoft.Extensions.EnvironmentAbstractions; -using NuGet.Commands; using NuGet.Frameworks; using NuGet.Versioning; using static Microsoft.DotNet.Cli.Commands.Tool.Restore.ToolRestoreCommand; diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs index e5e5cb867de1..b8c9a6a56625 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs @@ -120,7 +120,7 @@ [.. packagesFromManifest Dictionary downloaded = toolRestoreResults.Select(result => result.SaveToCache) .Where(item => item is not null) - .ToDictionary(pair => pair.Value.Item1, pair => pair.Value.Item2); + .ToDictionary(pair => pair.Value.restoredCommandIdentifier, pair => pair.Value.toolCommand); EnsureNoCommandNameCollision(downloaded); @@ -203,7 +203,7 @@ private static void EnsureNoCommandNameCollision(Dictionary commandArguments) { - public static CommandSpec CreateToolCommandSpec(string toolName, string toolExecutable, string toolRunner, bool allowRollForward, IEnumerable commandArguments) + if (toolRunner == "dotnet") { - if (toolRunner == "dotnet") + if (allowRollForward) { - if (allowRollForward) - { - commandArguments = ["--allow-roll-forward", .. commandArguments]; - } - - return MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer( - toolExecutable, - commandArguments); + commandArguments = ["--allow-roll-forward", .. commandArguments]; } - else if (toolRunner == "executable") - { - var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart( - commandArguments); - return new CommandSpec( - toolExecutable, - escapedArgs); - } - else - { - throw new GracefulException(string.Format(CliStrings.ToolSettingsUnsupportedRunner, - toolName, toolRunner)); - } + return MuxerCommandSpecMaker.CreatePackageCommandSpecUsingMuxer( + toolExecutable, + commandArguments); + } + else if (toolRunner == "executable") + { + var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart( + commandArguments); + + return new CommandSpec( + toolExecutable, + escapedArgs); + } + else + { + throw new GracefulException(string.Format(CliStrings.ToolSettingsUnsupportedRunner, + toolName, toolRunner)); } } } diff --git a/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs b/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs index 7cc0a63af369..2e5b3c05ad12 100644 --- a/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs +++ b/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs @@ -10,7 +10,7 @@ namespace Microsoft.DotNet.Cli.ToolPackage; internal static class ToolPackageFactory { - public static (IToolPackageStore, IToolPackageStoreQuery, IToolPackageDownloader) CreateToolPackageStoresAndDownloader( + public static (IToolPackageStore packageStore, IToolPackageStoreQuery packageStoreQuery, IToolPackageDownloader downloader) CreateToolPackageStoresAndDownloader( DirectoryPath? nonGlobalLocation = null, IEnumerable additionalRestoreArguments = null, string runtimeJsonPathForTests = null) { ToolPackageStoreAndQuery toolPackageStore = CreateConcreteToolPackageStore(nonGlobalLocation); From cde3627e57367748e035132d1664b217fcce6cb9 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 15:39:09 -0400 Subject: [PATCH 39/45] Fix exception handling in mock package downloader --- .../MockNuGetPackageDownloader.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs index e99e96e5a740..99cacfd68eb1 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockNuGetPackageDownloader.cs @@ -129,10 +129,9 @@ public Task GetLatestPackageVersion(PackageId packageId, PackageSo return Task.FromResult(_packageVersions.Max()); } - public Task GetBestPackageVersionAsync(PackageId packageId, VersionRange versionRange, PackageSourceLocation packageSourceLocation = null) + public async Task GetBestPackageVersionAsync(PackageId packageId, VersionRange versionRange, PackageSourceLocation packageSourceLocation = null) { - return GetBestPackageVersionAndSourceAsync(packageId, versionRange, packageSourceLocation) - .ContinueWith(t => t.Result.version, TaskContinuationOptions.OnlyOnRanToCompletion); + return (await GetBestPackageVersionAndSourceAsync(packageId, versionRange, packageSourceLocation)).version; } public Task<(NuGetVersion version, PackageSource source)> GetBestPackageVersionAndSourceAsync(PackageId packageId, From 2e33374d2a5b2685b80cdcc34f989cdf499093dc Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 15:58:58 -0400 Subject: [PATCH 40/45] Improve confirmation prompt and other text updates --- src/Cli/dotnet/CliStrings.resx | 2 +- .../dotnet/Commands/CliCommandStrings.resx | 17 ++++++--- .../Tool/Execute/ToolExecuteCommand.cs | 36 +++++++++++++++---- .../Commands/xlf/CliCommandStrings.cs.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.de.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.es.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.fr.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.it.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.ja.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.ko.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.pl.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.pt-BR.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.ru.xlf | 26 +++++++++----- .../Commands/xlf/CliCommandStrings.tr.xlf | 26 +++++++++----- .../xlf/CliCommandStrings.zh-Hans.xlf | 26 +++++++++----- .../xlf/CliCommandStrings.zh-Hant.xlf | 26 +++++++++----- src/Cli/dotnet/xlf/CliStrings.cs.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.de.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.es.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.fr.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.it.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.ja.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.ko.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.pl.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.ru.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.tr.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 4 +-- src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 4 +-- 29 files changed, 303 insertions(+), 142 deletions(-) diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx index 8e915a928d53..3c2602e01069 100644 --- a/src/Cli/dotnet/CliStrings.resx +++ b/src/Cli/dotnet/CliStrings.resx @@ -813,6 +813,6 @@ For a list of locations searched, specify the "-d" option before the tool name.< {Locked="--version"} - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index 52a6229e3648..8c09c6f50191 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2482,17 +2482,26 @@ To display a value, specify the corresponding command-line option without provid Executes a tool from source without permanently installing it. - - Missing package ID - Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? + + + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + + + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + Please type '{0}' for yes or '{1}' for no. Tool package download canceled Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. + {Locked="--yes"} diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 51e7e8a71f66..86c70a57eb94 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -155,15 +155,37 @@ private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version // TODO: Use a better way to ask for user input // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? - string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt + " ", packageId, version.ToString(), source.Source); + string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt, packageId, version.ToString(), source.Source); - Console.Write(promptMessage); - bool userAccepted = Console.ReadKey().Key == ConsoleKey.Y; + static string AddPromptOptions(string message) + { + return $"{message} [{CliCommandStrings.ConfirmationPromptYesValue}/{CliCommandStrings.ConfirmationPromptNoValue}] ({CliCommandStrings.ConfirmationPromptYesValue}): "; + } + + Console.Write(AddPromptOptions(promptMessage)); + + static bool KeyMatches(ConsoleKeyInfo pressedKey, string valueKey) + { + // Apparently you can't do invariant case insensitive comparison on a char directly, so we have to convert it to a string. + // The resource string should be a single character, but we take the first character just to be sure. + return pressedKey.KeyChar.ToString().ToLowerInvariant().Equals( + valueKey.ToLowerInvariant().Substring(0, 1)); + } - Console.WriteLine(); - // TODO: Do we want a separator like this? Seems like it's meant to separate the output of the tool from the prompt. - //Console.WriteLine(new String('-', promptMessage.Length + 2)); + while (true) + { + var key = Console.ReadKey(); + Console.WriteLine(); + if (key.Key == ConsoleKey.Enter || KeyMatches(key, CliCommandStrings.ConfirmationPromptYesValue)) + { + return true; + } + if (key.Key == ConsoleKey.Escape || KeyMatches(key, CliCommandStrings.ConfirmationPromptNoValue)) + { + return false; + } - return userAccepted; + Console.Write(AddPromptOptions(string.Format(CliCommandStrings.ConfirmationPromptInvalidChoiceMessage, CliCommandStrings.ConfirmationPromptYesValue, CliCommandStrings.ConfirmationPromptNoValue))); + } } } diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index 408e91734cf3..cb8e9bb5c167 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index ec753951dde0..f9163e30b48d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 40e9a46f9b04..1e743b625fd1 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 03767fba5c3d..9380312957fd 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 51795815c595..5a2ba78614b4 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 24ecd6605478..5333ec620730 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 12245675cc92..07b40c42db65 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 997f778f8423..a321eefe4d16 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index b8d70a5c022e..bc3827d77af7 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 89507fc97999..0b38c9e41e97 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index fa170752851a..7fef08597364 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index 6791c400b918..bd68495d70c8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index d92ecb7cf043..2a1b6d1e747d 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -925,6 +925,21 @@ dotnet.config is a name don't translate. The NuGet configuration file. If specified, only the settings from this file will be used. If not specified, the hierarchy of configuration files from the current directory will be used. For more information, see https://docs.microsoft.com/nuget/consume-packages/configuring-nuget-behavior + + Please type '{0}' for yes or '{1}' for no. + Please type '{0}' for yes or '{1}' for no. + + + + n + n + For a command line connfirmation prompt, this is the key that should be pressed for "no", ie to cancel the operation. + + + y + y + For a command line connfirmation prompt, this is the key that should be pressed for "yes", ie to agree. + Console is already in batching mode. Console is already in batching mode. @@ -2933,26 +2948,21 @@ Your project targets multiple frameworks. Specify which framework to run using ' Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package {0}@{1} will be downloaded from source {2}. -Proceed? [y/n] +Proceed? Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. Tool package download needs confirmation. Run in interactive mode or use the "--yes" command-line option to confirm. - + {Locked="--yes"} Executes a tool from source without permanently installing it. Executes a tool from source without permanently installing it. - - Missing package ID - Missing package ID - - Add an additional NuGet package source to use during installation. Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf index 396856cdcffd..1c8c8cbd3aa1 100644 --- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf index 1690a105b041..48e28dc2f122 100644 --- a/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf index 9d7873bc0541..d011db54ac18 100644 --- a/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf index c5f3168077e9..cde571e660dd 100644 --- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf index 6f59a4b0bc1e..022a9c52b0a4 100644 --- a/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf index 50251a085637..71e0d244691a 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf index c3e0895f0c3c..b1f57d8eb913 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 9fb38670ba74..03bad9be7fe9 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index aa469cb2f3bf..d814bb7ba5bf 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf index 331ee9258476..a1ae8bb56d19 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf index 804364591bdb..42e59a4b6e79 100644 --- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index 9a34782be7f3..e5f3ee1f738a 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index 50dec21fa806..c97ebe73ef02 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Overrides confirmation prompt with "yes" value. - Overrides confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. + Suppresses confirmation prompt with "yes" value. From cb66e95aa68d4fac607ca05eddc42f72a7f97f50 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 16:39:20 -0400 Subject: [PATCH 41/45] Address TODOs --- .../Tool/Execute/ToolExecuteCommand.cs | 22 +++++-------------- .../Tool/Execute/ToolExecuteCommandParser.cs | 12 +++++----- .../Tool/Install/ToolInstallLocalInstaller.cs | 2 +- .../Tool/Restore/ToolRestoreCommand.cs | 3 +-- .../Tool/Update/ToolUpdateLocalCommand.cs | 3 +-- .../dotnet/ToolPackage/ToolPackageFactory.cs | 2 +- 6 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs index 86c70a57eb94..909947f2316d 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs @@ -33,20 +33,15 @@ internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolMa private readonly string? _configFile = result.GetValue(ToolExecuteCommandParser.ConfigOption); private readonly string[] _sources = result.GetValue(ToolExecuteCommandParser.SourceOption) ?? []; private readonly string[] _addSource = result.GetValue(ToolExecuteCommandParser.AddSourceOption) ?? []; - private readonly bool _ignoreFailedSources = result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption); private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption); private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption); + private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader().downloader; - // TODO: Does result.OptionValuesToBeForwarded work here? - private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader( - additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolExecuteCommandParser.GetCommand())).downloader; - - // TODO: Make sure to add these options to the command private readonly RestoreActionConfig _restoreActionConfig = new RestoreActionConfig(DisableParallel: result.GetValue(ToolCommandRestorePassThroughOptions.DisableParallelOption), NoCache: result.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || result.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption), IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), - Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); + Interactive: result.GetValue(ToolExecuteCommandParser.InteractiveOption)); private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory())); @@ -92,15 +87,12 @@ public override int Execute() sourceFeedOverrides: _sources, additionalFeeds: _addSource); - var restoreActionConfig = new RestoreActionConfig( - IgnoreFailedSources: _ignoreFailedSources, - Interactive: _interactive); - - (var bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, restoreActionConfig); + (var bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, _restoreActionConfig); IToolPackage toolPackage; - // TODO: Add framework argument + // TargetFramework is null, which means to use the current framework. Global tools can override the target framework to use (or select assets for), + // but we don't support this for local or one-shot tools. if (!_toolPackageDownloader.TryGetDownloadedTool(packageId, bestVersion, targetFramework: null, out toolPackage)) { if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource)) @@ -132,7 +124,7 @@ public override int Execute() verbosity: _verbosity, versionRange: new VersionRange(bestVersion, true, bestVersion, true), isGlobalToolRollForward: false, - restoreActionConfig: restoreActionConfig); + restoreActionConfig: _restoreActionConfig); } var commandSpec = ToolCommandSpecCreator.CreateToolCommandSpec(toolPackage.Command.Name.Value, toolPackage.Command.Executable.Value, toolPackage.Command.Runner, _allowRollForward, _forwardArguments); @@ -153,8 +145,6 @@ private bool UserAgreedToRunFromSource(PackageId packageId, NuGetVersion version return false; } - // TODO: Use a better way to ask for user input - // TODO: How to localize y/n and interpret keys correctly? Does Spectre.Console handle this? string promptMessage = string.Format(CliCommandStrings.ToolDownloadConfirmationPrompt, packageId, version.ToString(), source.Source); static string AddPromptOptions(string message) diff --git a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs index a30123472c46..21aeff66040e 100644 --- a/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommandParser.cs @@ -23,7 +23,6 @@ internal static class ToolExecuteCommandParser public static readonly Option ConfigOption = ToolInstallCommandParser.ConfigOption; public static readonly Option SourceOption = ToolInstallCommandParser.SourceOption; public static readonly Option AddSourceOption = ToolInstallCommandParser.AddSourceOption; - public static readonly Option IgnoreFailedSourcesOption = ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption; public static readonly Option InteractiveOption = CommonOptions.InteractiveOption(); public static readonly Option YesOption = CommonOptions.YesOption; public static readonly Option VerbosityOption = ToolInstallCommandParser.VerbosityOption; @@ -45,18 +44,19 @@ private static Command ConstructCommand() command.Arguments.Add(CommandArgument); command.Options.Add(VersionOption); + command.Options.Add(YesOption); + command.Options.Add(InteractiveOption); command.Options.Add(RollForwardOption); command.Options.Add(PrereleaseOption); command.Options.Add(ConfigOption); command.Options.Add(SourceOption); command.Options.Add(AddSourceOption); - command.Options.Add(IgnoreFailedSourcesOption); - command.Options.Add(InteractiveOption); - command.Options.Add(YesOption); + command.Options.Add(ToolCommandRestorePassThroughOptions.DisableParallelOption); + command.Options.Add(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption); + command.Options.Add(ToolCommandRestorePassThroughOptions.NoCacheOption); + command.Options.Add(ToolCommandRestorePassThroughOptions.NoHttpCacheOption); command.Options.Add(VerbosityOption); - // TODO: Framework? - command.SetAction((parseResult) => new ToolExecuteCommand(parseResult).Execute()); return command; diff --git a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallLocalInstaller.cs b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallLocalInstaller.cs index ad4985e42f3c..0307b3abfda6 100644 --- a/src/Cli/dotnet/Commands/Tool/Install/ToolInstallLocalInstaller.cs +++ b/src/Cli/dotnet/Commands/Tool/Install/ToolInstallLocalInstaller.cs @@ -39,7 +39,7 @@ public ToolInstallLocalInstaller( IToolPackageStoreQuery, IToolPackageDownloader downloader) toolPackageStoresAndDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader( - additionalRestoreArguments: parseResult.OptionValuesToBeForwarded(ToolInstallCommandParser.GetCommand()), runtimeJsonPathForTests: runtimeJsonPathForTests); + runtimeJsonPathForTests: runtimeJsonPathForTests); _toolPackageDownloader = toolPackageDownloader ?? toolPackageStoresAndDownloader.downloader; _restoreActionConfig = restoreActionConfig; diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs index b8c9a6a56625..978bc9c1bdd7 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolRestoreCommand.cs @@ -43,8 +43,7 @@ public ToolRestoreCommand( (IToolPackageStore, IToolPackageStoreQuery, IToolPackageDownloader downloader) toolPackageStoresAndInstaller - = ToolPackageFactory.CreateToolPackageStoresAndDownloader( - additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolRestoreCommandParser.GetCommand())); + = ToolPackageFactory.CreateToolPackageStoresAndDownloader(); _toolPackageDownloader = toolPackageStoresAndInstaller.downloader; } else diff --git a/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateLocalCommand.cs b/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateLocalCommand.cs index 4636f43c027b..8d9a132655f5 100644 --- a/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateLocalCommand.cs +++ b/src/Cli/dotnet/Commands/Tool/Update/ToolUpdateLocalCommand.cs @@ -38,8 +38,7 @@ public ToolUpdateLocalCommand( (IToolPackageStore, IToolPackageStoreQuery, IToolPackageDownloader downloader) toolPackageStoresAndDownloader - = ToolPackageFactory.CreateToolPackageStoresAndDownloader( - additionalRestoreArguments: parseResult.OptionValuesToBeForwarded(ToolUpdateCommandParser.GetCommand())); + = ToolPackageFactory.CreateToolPackageStoresAndDownloader(); _toolPackageDownloader = toolPackageStoresAndDownloader.downloader; } else diff --git a/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs b/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs index 2e5b3c05ad12..c55726f4e217 100644 --- a/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs +++ b/src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.DotNet.Cli.ToolPackage; internal static class ToolPackageFactory { public static (IToolPackageStore packageStore, IToolPackageStoreQuery packageStoreQuery, IToolPackageDownloader downloader) CreateToolPackageStoresAndDownloader( - DirectoryPath? nonGlobalLocation = null, IEnumerable additionalRestoreArguments = null, string runtimeJsonPathForTests = null) + DirectoryPath? nonGlobalLocation = null, string runtimeJsonPathForTests = null) { ToolPackageStoreAndQuery toolPackageStore = CreateConcreteToolPackageStore(nonGlobalLocation); var toolPackageDownloader = new ToolPackageDownloader(toolPackageStore, runtimeJsonPathForTests); From 4bbafef715a2808270374293b5e70c1581406f4b Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 16:44:18 -0400 Subject: [PATCH 42/45] Update CLI snapshots --- ...tCliSnapshotTests.VerifyCompletions.verified.sh | 2 +- ...CliSnapshotTests.VerifyCompletions.verified.ps1 | 12 +++++++----- ...CliSnapshotTests.VerifyCompletions.verified.zsh | 14 ++++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh index fef8c96b9382..a9d26bb79ad3 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh +++ b/test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh @@ -1792,7 +1792,7 @@ _testhost_tool_execute() { prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() - opts="--version --allow-roll-forward --prerelease --configfile --source --add-source --ignore-failed-sources --interactive --yes --verbosity --help" + opts="--version --yes --interactive --allow-roll-forward --prerelease --configfile --source --add-source --disable-parallel --ignore-failed-sources --no-http-cache --verbosity --help" opts="$opts $(${COMP_WORDS[0]} complete --position ${COMP_POINT} ${COMP_LINE} 2>/dev/null | tr '\n' ' ')" if [[ $COMP_CWORD == "$1" ]]; then diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index 0afb131bd3d4..5f6742410953 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -959,8 +959,8 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, "Run a local tool. Note that this command cannot be used to run a global tool. ") [CompletionResult]::new('search', 'search', [CompletionResultType]::ParameterValue, "Search dotnet tools in nuget.org") [CompletionResult]::new('restore', 'restore', [CompletionResultType]::ParameterValue, "Restore tools defined in the local tool manifest.") - [CompletionResult]::new('execute', 'execute', [CompletionResultType]::ParameterValue, "Execute a tool command from source") - [CompletionResult]::new('execute', 'exec', [CompletionResultType]::ParameterValue, "Execute a tool command from source") + [CompletionResult]::new('execute', 'execute', [CompletionResultType]::ParameterValue, "Executes a tool from source without permanently installing it.") + [CompletionResult]::new('execute', 'exec', [CompletionResultType]::ParameterValue, "Executes a tool from source without permanently installing it.") ) $completions += $staticCompletions break @@ -1097,15 +1097,17 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { 'testhost;tool;execute' { $staticCompletions = @( [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, "The version of the tool package to install.") + [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Suppresses confirmation prompt with `"yes`" value.") + [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Suppresses confirmation prompt with `"yes`" value.") + [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") [CompletionResult]::new('--prerelease', '--prerelease', [CompletionResultType]::ParameterName, "Include pre-release packages.") [CompletionResult]::new('--configfile', '--configfile', [CompletionResultType]::ParameterName, "The NuGet configuration file to use.") [CompletionResult]::new('--source', '--source', [CompletionResultType]::ParameterName, "Replace all NuGet package sources to use during installation with these.") [CompletionResult]::new('--add-source', '--add-source', [CompletionResultType]::ParameterName, "Add an additional NuGet package source to use during installation.") + [CompletionResult]::new('--disable-parallel', '--disable-parallel', [CompletionResultType]::ParameterName, "Prevent restoring multiple projects in parallel.") [CompletionResult]::new('--ignore-failed-sources', '--ignore-failed-sources', [CompletionResultType]::ParameterName, "Treat package source failures as warnings.") - [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") - [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") - [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Overrides confirmation prompt with `"yes`" value. ") + [CompletionResult]::new('--no-http-cache', '--no-http-cache', [CompletionResultType]::ParameterName, "Do not cache packages and http requests.") [CompletionResult]::new('--verbosity', '--verbosity', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") [CompletionResult]::new('--verbosity', '-v', [CompletionResultType]::ParameterName, "Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].") [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.") diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index c169d58e12f5..f42384bdc318 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1130,7 +1130,7 @@ _testhost() { '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':commandName -- The command name of the tool to run.: ' \ - '*::toolArguments -- arguments forwarded to the tool: ' \ + '*::toolArguments -- Arguments forwarded to the tool: ' \ && ret=0 ;; (search) @@ -1162,21 +1162,23 @@ _testhost() { (execute) _arguments "${_arguments_options[@]}" : \ '--version=[The version of the tool package to install.]:VERSION: ' \ + '--yes[Suppresses confirmation prompt with \"yes\" value.]' \ + '-y[Suppresses confirmation prompt with \"yes\" value.]' \ + '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ '--prerelease[Include pre-release packages.]' \ '--configfile=[The NuGet configuration file to use.]:FILE: ' \ '*--source=[Replace all NuGet package sources to use during installation with these.]:SOURCE: ' \ '*--add-source=[Add an additional NuGet package source to use during installation.]:ADDSOURCE: ' \ + '--disable-parallel[Prevent restoring multiple projects in parallel.]' \ '--ignore-failed-sources[Treat package source failures as warnings.]' \ - '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ - '--yes[Overrides confirmation prompt with \"yes\" value. ]' \ - '-y[Overrides confirmation prompt with \"yes\" value. ]' \ + '--no-http-cache[Do not cache packages and http requests.]' \ '--verbosity=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '-v=[Set the MSBuild verbosity level. Allowed values are q\[uiet\], m\[inimal\], n\[ormal\], d\[etailed\], and diag\[nostic\].]:LEVEL:((d\:"d" detailed\:"detailed" diag\:"diag" diagnostic\:"diagnostic" m\:"m" minimal\:"minimal" n\:"n" normal\:"normal" q\:"q" quiet\:"quiet" ))' \ '--help[Show command line help.]' \ '-h[Show command line help.]' \ ':packageId -- Package reference in the form of a package identifier like '\''Newtonsoft.Json'\'' or package identifier and version separated by '\''@'\'' like '\''Newtonsoft.Json@13.0.3'\''.:->dotnet_dynamic_complete' \ - '*::commandArguments -- arguments forwarded to the tool: ' \ + '*::commandArguments -- Arguments forwarded to the tool: ' \ && ret=0 case $state in (dotnet_dynamic_complete) @@ -1815,7 +1817,7 @@ _testhost__tool_commands() { 'run:Run a local tool. Note that this command cannot be used to run a global tool. ' \ 'search:Search dotnet tools in nuget.org' \ 'restore:Restore tools defined in the local tool manifest.' \ - 'execute:Execute a tool command from source' \ + 'execute:Executes a tool from source without permanently installing it.' \ ) _describe -t commands 'testhost tool commands' commands "$@" } From 1d611735e0ad7263d429540f2a5874e940a9bfb9 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 16:53:16 -0400 Subject: [PATCH 43/45] Update --yes option description --- src/Cli/dotnet/CliStrings.resx | 2 +- src/Cli/dotnet/xlf/CliStrings.cs.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.de.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.es.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.fr.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.it.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.ja.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.ko.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.pl.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.ru.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.tr.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf | 4 ++-- src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Cli/dotnet/CliStrings.resx b/src/Cli/dotnet/CliStrings.resx index 3c2602e01069..eedd5a24b57f 100644 --- a/src/Cli/dotnet/CliStrings.resx +++ b/src/Cli/dotnet/CliStrings.resx @@ -813,6 +813,6 @@ For a list of locations searched, specify the "-d" option before the tool name.< {Locked="--version"} - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.cs.xlf b/src/Cli/dotnet/xlf/CliStrings.cs.xlf index 1c8c8cbd3aa1..447b05aa9fbd 100644 --- a/src/Cli/dotnet/xlf/CliStrings.cs.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.cs.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.de.xlf b/src/Cli/dotnet/xlf/CliStrings.de.xlf index 48e28dc2f122..ab866cdf329c 100644 --- a/src/Cli/dotnet/xlf/CliStrings.de.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.de.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.es.xlf b/src/Cli/dotnet/xlf/CliStrings.es.xlf index d011db54ac18..e9e1ebc6ba2d 100644 --- a/src/Cli/dotnet/xlf/CliStrings.es.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.es.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.fr.xlf b/src/Cli/dotnet/xlf/CliStrings.fr.xlf index cde571e660dd..84d4d542133e 100644 --- a/src/Cli/dotnet/xlf/CliStrings.fr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.fr.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.it.xlf b/src/Cli/dotnet/xlf/CliStrings.it.xlf index 022a9c52b0a4..9b01c10ee105 100644 --- a/src/Cli/dotnet/xlf/CliStrings.it.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.it.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.ja.xlf b/src/Cli/dotnet/xlf/CliStrings.ja.xlf index 71e0d244691a..c80d97d256a3 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ja.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ja.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.ko.xlf b/src/Cli/dotnet/xlf/CliStrings.ko.xlf index b1f57d8eb913..1cc16ba3b829 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ko.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ko.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.pl.xlf b/src/Cli/dotnet/xlf/CliStrings.pl.xlf index 03bad9be7fe9..24d82b496a03 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pl.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pl.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf index d814bb7ba5bf..984ccf035489 100644 --- a/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.ru.xlf b/src/Cli/dotnet/xlf/CliStrings.ru.xlf index a1ae8bb56d19..ec120eadb61b 100644 --- a/src/Cli/dotnet/xlf/CliStrings.ru.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.ru.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.tr.xlf b/src/Cli/dotnet/xlf/CliStrings.tr.xlf index 42e59a4b6e79..0ee97839c2a6 100644 --- a/src/Cli/dotnet/xlf/CliStrings.tr.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.tr.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf index e5f3ee1f738a..43585298531a 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hans.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." diff --git a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf index c97ebe73ef02..835e4fa4fbb6 100644 --- a/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/xlf/CliStrings.zh-Hant.xlf @@ -1173,8 +1173,8 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is {Locked="dotnet workload update"} - Suppresses confirmation prompt with "yes" value. - Suppresses confirmation prompt with "yes" value. + Accept all confirmation prompts using "yes." + Accept all confirmation prompts using "yes." From ccde6b0f23e0c920072a5b826d942231fac49270 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 16:53:53 -0400 Subject: [PATCH 44/45] Apply code review feedback Co-authored-by: Michael Yanni --- .../Tool/Restore/ToolPackageRestorer.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs index 614919fa62d7..b1c3b3f4ed52 100644 --- a/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs +++ b/src/Cli/dotnet/Commands/Tool/Restore/ToolPackageRestorer.cs @@ -109,23 +109,7 @@ private static bool ManifestCommandMatchesActualInPackage( IReadOnlyList toolPackageCommands) { ToolCommandName[] commandsFromPackage = [.. toolPackageCommands.Select(t => t.Name)]; - foreach (var command in commandsFromManifest) - { - if (!commandsFromPackage.Contains(command)) - { - return false; - } - } - - foreach (var command in commandsFromPackage) - { - if (!commandsFromManifest.Contains(command)) - { - return false; - } - } - - return true; +return !commandsFromManifest.Any(cmd => !commandsFromPackage.Contains(cmd)) && !commandsFromPackage.Any(cmd => !commandsFromManifest.Contains(cmd)); } public bool PackageHasBeenRestored( From b0800286faeaa3f367aa30a8a7aa4132798d416a Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 11 Jun 2025 21:07:28 -0400 Subject: [PATCH 45/45] Update CLI snapshots --- .../DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 | 4 ++-- .../zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 index 5f6742410953..0c5628dd5e25 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 +++ b/test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1 @@ -1097,8 +1097,8 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock { 'testhost;tool;execute' { $staticCompletions = @( [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, "The version of the tool package to install.") - [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Suppresses confirmation prompt with `"yes`" value.") - [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Suppresses confirmation prompt with `"yes`" value.") + [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, "Accept all confirmation prompts using `"yes.`"") + [CompletionResult]::new('--yes', '-y', [CompletionResultType]::ParameterName, "Accept all confirmation prompts using `"yes.`"") [CompletionResult]::new('--interactive', '--interactive', [CompletionResultType]::ParameterName, "Allows the command to stop and wait for user input or action (for example to complete authentication).") [CompletionResult]::new('--allow-roll-forward', '--allow-roll-forward', [CompletionResultType]::ParameterName, "Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn`'t installed.") [CompletionResult]::new('--prerelease', '--prerelease', [CompletionResultType]::ParameterName, "Include pre-release packages.") diff --git a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh index f42384bdc318..c7069ebc1e57 100644 --- a/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh +++ b/test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh @@ -1162,8 +1162,8 @@ _testhost() { (execute) _arguments "${_arguments_options[@]}" : \ '--version=[The version of the tool package to install.]:VERSION: ' \ - '--yes[Suppresses confirmation prompt with \"yes\" value.]' \ - '-y[Suppresses confirmation prompt with \"yes\" value.]' \ + '--yes[Accept all confirmation prompts using \"yes.\"]' \ + '-y[Accept all confirmation prompts using \"yes.\"]' \ '--interactive[Allows the command to stop and wait for user input or action (for example to complete authentication).]' \ '--allow-roll-forward[Allow a .NET tool to roll forward to newer versions of the .NET runtime if the runtime it targets isn'\''t installed.]' \ '--prerelease[Include pre-release packages.]' \