|
// 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.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.Configuration;
using NuGet.Versioning;
namespace Microsoft.DotNet.Cli.Commands.Tool.Execute;
internal sealed class ToolExecuteCommand : CommandBase<ToolExecuteCommandDefinitionBase>
{
private readonly PackageIdentityWithRange _packageToolIdentityArgument;
private readonly IEnumerable<string> _forwardArguments;
private readonly bool _allowRollForward;
private readonly string? _configFile;
private readonly string[] _sources;
private readonly string[] _addSource;
private readonly VerbosityOptions _verbosity;
private readonly IToolPackageDownloader _toolPackageDownloader = ToolPackageFactory.CreateToolPackageStoresAndDownloader().downloader;
private readonly RestoreActionConfig _restoreActionConfig;
private readonly ToolManifestFinder _toolManifestFinder;
public ToolExecuteCommand(ParseResult result, ToolManifestFinder? toolManifestFinder = null, string? currentWorkingDirectory = null)
: base(result)
{
_packageToolIdentityArgument = result.GetValue(Definition.PackageIdentityArgument);
_forwardArguments = result.GetValue(Definition.CommandArgument) ?? [];
_allowRollForward = result.GetValue(Definition.RollForwardOption);
_configFile = result.GetValue(Definition.ConfigOption);
_sources = result.GetValue(Definition.SourceOption) ?? [];
_addSource = result.GetValue(Definition.AddSourceOption) ?? [];
_verbosity = result.GetValue(Definition.VerbosityOption);
_restoreActionConfig = Definition.RestoreOptions.ToRestoreActionConfig(result);
_toolManifestFinder = toolManifestFinder ?? new ToolManifestFinder(new DirectoryPath(currentWorkingDirectory ?? Directory.GetCurrentDirectory()));
}
public override int Execute()
{
var versionRange = VersionRangeUtilities.GetVersionRange(
_packageToolIdentityArgument.VersionRange?.OriginalString,
_parseResult.GetValue(Definition.VersionOption),
_parseResult.GetValue(Definition.PrereleaseOption));
PackageId packageId = new PackageId(_packageToolIdentityArgument.Id);
var toolLocationActivity = Activities.Source.StartActivity("find-tool");
toolLocationActivity?.SetTag("tool.package.id", packageId.ToString());
toolLocationActivity?.SetTag("tool.package.version", versionRange?.ToString() ?? "latest");
// 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))
{
toolLocationActivity?.SetTag("tool.exec.kind", "local");
toolLocationActivity?.Stop();
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;
}
if (restoreResult.SaveToCache is not null)
{
localToolsResolverCache.Save(new Dictionary<RestoredCommandIdentifier, ToolCommand>
{
{ restoreResult.SaveToCache.Value.restoredCommandIdentifier, restoreResult.SaveToCache.Value.toolCommand }
});
}
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 bestVersion, var packageSource) = _toolPackageDownloader.GetNuGetVersion(packageLocation, packageId, _verbosity, versionRange, _restoreActionConfig);
toolLocationActivity?.SetTag("tool.exec.kind", "one-shot");
toolLocationActivity?.Stop();
// 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, verbosity: _verbosity, out var toolPackage))
{
// We've already determined which source we will use and will use it to download the package.
// 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,
packageSourceOverrides: [packageSource]);
toolPackage = _toolPackageDownloader.InstallPackage(
downloadPackageLocation,
packageId: packageId,
verbosity: _verbosity,
versionRange: new VersionRange(bestVersion, true, bestVersion, true),
isGlobalToolRollForward: false,
restoreActionConfig: _restoreActionConfig);
}
using var toolExecuteActivity = Activities.Source.StartActivity("execute-tool");
toolExecuteActivity?.SetTag("tool.package.id", packageId.ToString());
toolExecuteActivity?.SetTag("tool.package.version", toolPackage.Version.ToString());
toolExecuteActivity?.SetTag("tool.runner", toolPackage.Command.Runner);
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;
}
}
|