Skip to content

Commit

Permalink
Do not go beyond the root when searching for a previously installed t…
Browse files Browse the repository at this point in the history
…ool Fixes #40655 (#40800)

Fixes #40655

dotnet tool install currently looks for a previously installed tools manifest. It reads manifests it finds in looking for one that has the manifest it's trying to install but does not check whether that manifest 'isRoot', which means it keeps going outside the root.

We don't use a tool beyond the root, which means we can't install then use a tool as would be expected.
  • Loading branch information
Forgind authored Jul 23, 2024
1 parent 58d1cf7 commit 2cc1c05
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/Cli/Microsoft.DotNet.Cli.Utils/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Command(Process process, bool trimtrailingNewlines = false)

public CommandResult Execute()
{
return Execute(_ => { });
return Execute(null);
}
public CommandResult Execute(Action<Process> processStarted)
{
Expand Down
18 changes: 16 additions & 2 deletions src/Cli/dotnet/ToolManifest/ToolManifestFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,32 @@ public IReadOnlyList<FilePath> FindByPackageId(PackageId packageId)
{
var result = new List<FilePath>();
bool findAnyManifest = false;
DirectoryPath? rootPath = null;
foreach ((FilePath possibleManifest,
DirectoryPath correspondingDirectory)
in EnumerateDefaultAllPossibleManifests())
{
if (rootPath is not null)
{
if (!correspondingDirectory.Value.Equals(rootPath.Value))
{
break;
}
}

if (_fileSystem.File.Exists(possibleManifest.Value))
{
findAnyManifest = true;
if (_toolManifestEditor.Read(possibleManifest, correspondingDirectory).content
.Any(t => t.PackageId.Equals(packageId)))
(List<ToolManifestPackage> content, bool isRoot) = _toolManifestEditor.Read(possibleManifest, correspondingDirectory);
if (content.Any(t => t.PackageId.Equals(packageId)))
{
result.Add(possibleManifest);
}

if (isRoot)
{
rootPath = correspondingDirectory;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Cli/dotnet/ToolPackage/ToolPackageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ namespace Microsoft.DotNet.ToolPackage
internal static class ToolPackageFactory
{
public static (IToolPackageStore, IToolPackageStoreQuery, IToolPackageDownloader) CreateToolPackageStoresAndDownloader(
DirectoryPath? nonGlobalLocation = null, IEnumerable<string> additionalRestoreArguments = null)
DirectoryPath? nonGlobalLocation = null, IEnumerable<string> additionalRestoreArguments = null, string runtimeJsonPathForTests = null)
{
ToolPackageStoreAndQuery toolPackageStore = CreateConcreteToolPackageStore(nonGlobalLocation);
var toolPackageDownloader = new ToolPackageDownloader(toolPackageStore);
var toolPackageDownloader = new ToolPackageDownloader(toolPackageStore, runtimeJsonPathForTests);

return (toolPackageStore, toolPackageStore, toolPackageDownloader);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public ToolInstallLocalCommand(
IToolManifestFinder toolManifestFinder = null,
IToolManifestEditor toolManifestEditor = null,
ILocalToolsResolverCache localToolsResolverCache = null,
IReporter reporter = null
IReporter reporter = null,
string runtimeJsonPathForTests = null
)
: base(parseResult)
{
Expand All @@ -54,7 +55,7 @@ public ToolInstallLocalCommand(
new ToolManifestFinder(new DirectoryPath(Directory.GetCurrentDirectory()));
_toolManifestEditor = toolManifestEditor ?? new ToolManifestEditor();
_localToolsResolverCache = localToolsResolverCache ?? new LocalToolsResolverCache();
_toolLocalPackageInstaller = new ToolInstallLocalInstaller(parseResult, toolPackageDownloader);
_toolLocalPackageInstaller = new ToolInstallLocalInstaller(parseResult, toolPackageDownloader, runtimeJsonPathForTests);
_toolPackageDownloader = toolPackageDownloader;
_allowRollForward = parseResult.GetValue(ToolInstallCommandParser.RollForwardOption);
_allowPackageDowngrade = parseResult.GetValue(ToolInstallCommandParser.AllowPackageDowngradeOption);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ internal class ToolInstallLocalInstaller

public ToolInstallLocalInstaller(
ParseResult parseResult,
IToolPackageDownloader toolPackageDownloader = null)
IToolPackageDownloader toolPackageDownloader = null,
string runtimeJsonPathForTests = null)
{
_parseResult = parseResult;
_packageVersion = parseResult.GetValue(ToolInstallCommandParser.VersionOption);
Expand All @@ -38,7 +39,7 @@ public ToolInstallLocalInstaller(
IToolPackageStoreQuery,
IToolPackageDownloader downloader) toolPackageStoresAndDownloader
= ToolPackageFactory.CreateToolPackageStoresAndDownloader(
additionalRestoreArguments: parseResult.OptionValuesToBeForwarded(ToolInstallCommandParser.GetCommand()));
additionalRestoreArguments: parseResult.OptionValuesToBeForwarded(ToolInstallCommandParser.GetCommand()), runtimeJsonPathForTests: runtimeJsonPathForTests);
_toolPackageStore = toolPackageStoresAndDownloader.store;
_toolPackageDownloader = toolPackageDownloader ?? toolPackageStoresAndDownloader.downloader;

Expand Down
2 changes: 1 addition & 1 deletion src/Cli/dotnet/commands/dotnet-tool/run/ToolRunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public override int Execute()
CommandName = $"dotnet-{_toolCommandName}",
CommandArguments = _forwardArgument,

}, _allowRollForward); ;
}, _allowRollForward);

if (commandspec == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ internal static class ToolsetUtils
/// <returns></returns>
internal static string GetRuntimeGraphFilePath()
{
string dotnetRoot = TestContext.Current.ToolsetUnderTest.DotNetRoot;

DirectoryInfo sdksDir = new(Path.Combine(dotnetRoot, "sdk"));

var lastWrittenSdk = sdksDir.EnumerateDirectories().OrderByDescending(di => di.LastWriteTime).First();

return lastWrittenSdk.GetFiles("RuntimeIdentifierGraph.json").Single().FullName;
return TestContext.GetRuntimeGraphFilePath();
}

internal static IManifestPicker RidGraphManifestPicker { get; } = new RidGraphManifestPicker(GetRuntimeGraphFilePath());
Expand Down
11 changes: 11 additions & 0 deletions test/Microsoft.NET.TestFramework/TestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ public static TestContext Current

public const string LatestRuntimePatchForNetCoreApp2_0 = "2.0.9";

public static string GetRuntimeGraphFilePath()
{
string dotnetRoot = TestContext.Current.ToolsetUnderTest.DotNetRoot;

DirectoryInfo sdksDir = new(Path.Combine(dotnetRoot, "sdk"));

var lastWrittenSdk = sdksDir.EnumerateDirectories().OrderByDescending(di => di.LastWriteTime).First();

return lastWrittenSdk.GetFiles("RuntimeIdentifierGraph.json").Single().FullName;
}

public void AddTestEnvironmentVariables(IDictionary<string, string> environment)
{
environment["DOTNET_MULTILEVEL_LOOKUP"] = "0";
Expand Down
37 changes: 36 additions & 1 deletion test/dotnet.Tests/CommandTests/ToolInstallCommandTests.cs
Original file line number Diff line number Diff line change
@@ -1,17 +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.IO;
using System.Linq;
using System.Reflection;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Tool.Install;
using Microsoft.DotNet.Tools.Tool.Run;
using LocalizableStrings = Microsoft.DotNet.Tools.Tool.Install.LocalizableStrings;
using Parser = Microsoft.DotNet.Cli.Parser;

namespace Microsoft.DotNet.Tests.Commands.Tool
{
public class ToolInstallCommandTests
public class ToolInstallCommandTests : SdkTest
{
private const string PackageId = "global.tool.console.demo";

public ToolInstallCommandTests(ITestOutputHelper log) : base(log)
{
}

[Fact]
public void WhenRunWithBothGlobalAndToolPathShowErrorMessage()
{
Expand All @@ -28,6 +36,33 @@ public void WhenRunWithBothGlobalAndToolPathShowErrorMessage()
"--global --tool-path"));
}

[Fact]
public void WhenRunWithRoot()
{
Directory.CreateDirectory("/tmp/folder/sub");
var directory = Directory.GetCurrentDirectory();
var ridGraphPath = TestContext.GetRuntimeGraphFilePath();
try
{
Directory.SetCurrentDirectory("/tmp/folder");

new DotnetNewCommand(Log, "tool-manifest").WithCustomHive("/tmp/folder").WithWorkingDirectory("/tmp/folder").Execute().Should().Pass();
var parseResult = Parser.Instance.Parse("tool install dotnetsay");
new ToolInstallLocalCommand(parseResult, runtimeJsonPathForTests: ridGraphPath).Execute().Should().Be(0);

Directory.SetCurrentDirectory("/tmp/folder/sub");
new DotnetNewCommand(Log, "tool-manifest").WithCustomHive("/tmp/folder/sub").WithWorkingDirectory("/tmp/folder/sub").Execute().Should().Pass();
parseResult = Parser.Instance.Parse("tool install dotnetsay");
new ToolInstallLocalCommand(parseResult, runtimeJsonPathForTests: ridGraphPath).Execute().Should().Be(0);

new ToolRunCommand(Parser.Instance.Parse($"tool run dotnetsay")).Execute().Should().Be(0);
}
finally
{
Directory.SetCurrentDirectory(directory);
}
}

[Fact]
public void WhenRunWithBothGlobalAndLocalShowErrorMessage()
{
Expand Down

0 comments on commit 2cc1c05

Please sign in to comment.