Skip to content

Commit 6f3e9a8

Browse files
committed
Look for local tools first with dotnet tool exec
1 parent 790d2cf commit 6f3e9a8

File tree

3 files changed

+98
-13
lines changed

3 files changed

+98
-13
lines changed

src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@
55
using Microsoft.DotNet.Cli.CommandFactory;
66
using Microsoft.DotNet.Cli.CommandFactory.CommandResolution;
77
using Microsoft.DotNet.Cli.Commands.Tool.Install;
8+
using Microsoft.DotNet.Cli.Commands.Tool.Restore;
9+
using Microsoft.DotNet.Cli.Commands.Tool.Run;
10+
using Microsoft.DotNet.Cli.Extensions;
11+
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
12+
using Microsoft.DotNet.Cli.ToolManifest;
813
using Microsoft.DotNet.Cli.ToolPackage;
914
using Microsoft.DotNet.Cli.Utils;
15+
using Microsoft.DotNet.Cli.Utils.Extensions;
16+
17+
using Microsoft.Extensions.EnvironmentAbstractions;
1018
using NuGet.Common;
1119
using NuGet.Packaging.Core;
1220
using NuGet.Versioning;
1321

22+
1423
namespace Microsoft.DotNet.Cli.Commands.Tool.Execute
1524
{
16-
internal class ToolExecuteCommand(ParseResult result) : CommandBase(result)
25+
internal class ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolManifestFinder = null, string? currentWorkingDirectory = null) : CommandBase(result)
1726
{
1827
private readonly PackageIdentity _packageToolIdentityArgument = result.GetRequiredValue(ToolExecuteCommandParser.PackageIdentityArgument);
1928
private readonly IEnumerable<string> _forwardArguments = result.GetValue(ToolExecuteCommandParser.CommandArgument) ?? Enumerable.Empty<string>();
@@ -25,10 +34,60 @@ internal class ToolExecuteCommand(ParseResult result) : CommandBase(result)
2534
private readonly bool _interactive = result.GetValue(ToolExecuteCommandParser.InteractiveOption);
2635
private readonly VerbosityOptions _verbosity = result.GetValue(ToolExecuteCommandParser.VerbosityOption);
2736
private readonly bool _yes = result.GetValue(ToolExecuteCommandParser.YesOption);
37+
38+
// TODO: Does result.OptionValuesToBeForwarded work here?
39+
private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader(
40+
additionalRestoreArguments: result.OptionValuesToBeForwarded(ToolExecuteCommandParser.GetCommand())).Item3;
41+
42+
// TODO: Make sure to add these options to the command
43+
private readonly RestoreActionConfig _restoreActionConfig = new RestoreActionConfig(DisableParallel: result.GetValue(ToolCommandRestorePassThroughOptions.DisableParallelOption),
44+
NoCache: result.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || result.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption),
45+
IgnoreFailedSources: result.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption),
46+
Interactive: result.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption));
47+
48+
// TODO: Use prerelease
2849
private readonly bool _prerelease = result.GetValue(ToolExecuteCommandParser.PrereleaseOption);
2950

51+
private readonly ToolManifestFinder _toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory()));
52+
3053
public override int Execute()
3154
{
55+
VersionRange versionRange = _parseResult.GetVersionRange();
56+
PackageId packageId = new PackageId(_packageToolIdentityArgument.Id);
57+
58+
// Look in local tools manifest first, but only if version is not specified
59+
if (versionRange == null)
60+
{
61+
var localToolsResolverCache = new LocalToolsResolverCache();
62+
63+
if (_toolManifestFinder.TryFindPackageId(packageId, out var toolManifestPackage))
64+
{
65+
var toolPackageRestorer = new ToolPackageRestorer(
66+
_toolPackageDownloader,
67+
_sources,
68+
overrideSources: [],
69+
_verbosity,
70+
_restoreActionConfig,
71+
localToolsResolverCache,
72+
new FileSystemWrapper());
73+
74+
var restoreResult = toolPackageRestorer.InstallPackage(toolManifestPackage, _configFile == null ? null : new FilePath(_configFile));
75+
76+
if (!restoreResult.IsSuccess)
77+
{
78+
Reporter.Error.WriteLine(restoreResult.Message.Red());
79+
return 1;
80+
}
81+
82+
var localToolsCommandResolver = new LocalToolsCommandResolver(
83+
_toolManifestFinder,
84+
localToolsResolverCache);
85+
86+
return ToolRunCommand.ExecuteCommand(localToolsCommandResolver, toolManifestPackage.CommandNames.Single().Value, _forwardArguments, _allowRollForward);
87+
}
88+
}
89+
90+
3291
if (!UserAgreedToRunFromSource())
3392
{
3493
throw new GracefulException(CliCommandStrings.ToolRunFromSourceUserConfirmationFailed, isUserError: true);
@@ -39,16 +98,10 @@ public override int Execute()
3998
_forwardArguments.Append("--allow-roll-forward");
4099
}
41100

42-
PackageId packageId = new PackageId(_packageToolIdentityArgument.Id);
43-
44-
VersionRange versionRange = _parseResult.GetVersionRange();
45101

46102
string tempDirectory = NuGetEnvironment.GetFolderPath(NuGetFolderPath.Temp);
47103

48-
ToolPackageStoreAndQuery toolPackageStoreAndQuery = new(new(tempDirectory));
49-
ToolPackageDownloader toolPackageDownloader = new(toolPackageStoreAndQuery);
50-
51-
IToolPackage toolPackage = toolPackageDownloader.InstallPackage(
104+
IToolPackage toolPackage = _toolPackageDownloader.InstallPackage(
52105
new PackageLocation(
53106
nugetConfig: _configFile != null ? new(_configFile) : null,
54107
sourceFeedOverrides: _sources,

src/Cli/dotnet/Commands/Tool/Run/ToolRunCommand.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,21 @@ internal class ToolRunCommand(
2828

2929
public override int Execute()
3030
{
31-
CommandSpec commandSpec = _localToolsCommandResolver.ResolveStrict(new CommandResolverArguments()
31+
return ExecuteCommand(_localToolsCommandResolver, _toolCommandName, _forwardArgument, _allowRollForward);
32+
}
33+
public static int ExecuteCommand(LocalToolsCommandResolver commandResolver, string toolCommandName, IEnumerable<string> argumentsToForward, bool allowRollForward)
34+
{
35+
CommandSpec commandSpec = commandResolver.ResolveStrict(new CommandResolverArguments()
3236
{
3337
// since LocalToolsCommandResolver is a resolver, and all resolver input have dotnet-
34-
CommandName = $"dotnet-{_toolCommandName}",
35-
CommandArguments = _forwardArgument,
38+
CommandName = $"dotnet-{toolCommandName}",
39+
CommandArguments = argumentsToForward,
3640

37-
}, _allowRollForward);
41+
}, allowRollForward);
3842

3943
if (commandSpec == null)
4044
{
41-
throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, _toolCommandName)], isUserError: false);
45+
throw new GracefulException([string.Format(CliCommandStrings.CannotFindCommandName, toolCommandName)], isUserError: false);
4246
}
4347

4448
var result = CommandFactoryUsingResolver.Create(commandSpec).Execute();

src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,34 @@ public bool TryFind(ToolCommandName toolCommandName, out ToolManifestPackage too
132132
return false;
133133
}
134134

135+
public bool TryFindPackageId(PackageId packageId, out ToolManifestPackage toolManifestPackage)
136+
{
137+
toolManifestPackage = default;
138+
foreach ((FilePath possibleManifest, DirectoryPath correspondingDirectory) in
139+
EnumerateDefaultAllPossibleManifests())
140+
{
141+
if (!_fileSystem.File.Exists(possibleManifest.Value))
142+
{
143+
continue;
144+
}
145+
(List<ToolManifestPackage> manifestPackages, bool isRoot) =
146+
_toolManifestEditor.Read(possibleManifest, correspondingDirectory);
147+
foreach (var package in manifestPackages)
148+
{
149+
if (package.PackageId.Equals(packageId))
150+
{
151+
toolManifestPackage = package;
152+
return true;
153+
}
154+
}
155+
if (isRoot)
156+
{
157+
return false;
158+
}
159+
}
160+
return false;
161+
}
162+
135163
private IEnumerable<(FilePath manifestfile, DirectoryPath manifestFileFirstEffectDirectory)>
136164
EnumerateDefaultAllPossibleManifests()
137165
{

0 commit comments

Comments
 (0)