Skip to content

Support RID-specific .NET Tool packages #48575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ public async Task<string> DownloadPackageAsync(PackageId packageId,
string.Format(CliStrings.IsNotFoundInNuGetFeeds, packageId, source.Source));
}

var pathResolver = new VersionFolderPathResolver(downloadFolder == null || !downloadFolder.HasValue ? _packageInstallDir.Value : downloadFolder.Value.Value);
var resolvedDownloadFolder = downloadFolder == null || !downloadFolder.HasValue ? _packageInstallDir.Value : downloadFolder.Value.Value;
if (string.IsNullOrEmpty(resolvedDownloadFolder))
{
throw new ArgumentException($"Package download folder must be specified either via {nameof(NuGetPackageDownloader)} constructor or via {nameof(downloadFolder)} method argument.");
}
var pathResolver = new VersionFolderPathResolver(resolvedDownloadFolder);

string nupkgPath = pathResolver.GetPackageFilePath(packageId.ToString(), resolvedPackageVersion);
Directory.CreateDirectory(Path.GetDirectoryName(nupkgPath));

Expand Down
4 changes: 4 additions & 0 deletions src/Cli/dotnet/ToolPackage/IToolPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ internal interface IToolPackage

NuGetVersion Version { get; }

public PackageId ResolvedPackageId { get; }

public NuGetVersion ResolvedPackageVersion { get; }

DirectoryPath PackageDirectory { get; }

RestoredCommand Command { get; }
Expand Down
3 changes: 3 additions & 0 deletions src/Cli/dotnet/ToolPackage/LocalToolsResolverCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public void Save(
{
EnsureFileStorageExists();

// TODO: Save resolved package info here?

foreach (var distinctPackageIdAndRestoredCommandMap in restoredCommandMap.GroupBy(x => x.Key.PackageId))
{
PackageId distinctPackageId = distinctPackageIdAndRestoredCommandMap.Key;
Expand Down Expand Up @@ -213,5 +215,6 @@ private class CacheRow
public string Name { get; set; }
public string Runner { get; set; }
public string PathToExecutable { get; set; }
// TODO: Need resolved package info here
}
}
3 changes: 3 additions & 0 deletions src/Cli/dotnet/ToolPackage/RestoredCommandIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ internal class RestoredCommandIdentifier(
string runtimeIdentifier,
ToolCommandName commandName) : IEquatable<RestoredCommandIdentifier>
{

// TODO: What is this class and how is it different from CacheRow? Does it need to have the resolved package information?

public PackageId PackageId { get; } = packageId;
public NuGetVersion Version { get; } = version ?? throw new ArgumentException(nameof(version));
public NuGetFramework TargetFramework { get; } = targetFramework ?? throw new ArgumentException(nameof(targetFramework));
Expand Down
14 changes: 13 additions & 1 deletion src/Cli/dotnet/ToolPackage/ToolConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,21 +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 NuGet.Packaging.Core;

namespace Microsoft.DotNet.Cli.ToolPackage;

internal class ToolConfiguration
{
public ToolConfiguration(
string commandName,
string toolAssemblyEntryPoint,
string runner,
IDictionary<string, PackageIdentity> ridSpecificPackages = null,
IEnumerable<string> warnings = null)
{
if (string.IsNullOrWhiteSpace(commandName))
{
throw new ToolConfigurationException(CliStrings.ToolSettingsMissingCommandName);
}

if (string.IsNullOrWhiteSpace(toolAssemblyEntryPoint))
if (string.IsNullOrWhiteSpace(toolAssemblyEntryPoint) && ridSpecificPackages?.Any() != true)
{
throw new ToolConfigurationException(
string.Format(
Expand All @@ -28,6 +32,8 @@ public ToolConfiguration(

CommandName = commandName;
ToolAssemblyEntryPoint = toolAssemblyEntryPoint;
Runner = runner;
RidSpecificPackages = ridSpecificPackages;
Warnings = warnings ?? [];
}

Expand Down Expand Up @@ -55,7 +61,13 @@ private static void EnsureNoLeadingDot(string commandName)
}
}



public string CommandName { get; }
public string ToolAssemblyEntryPoint { get; }
public string Runner { get; }

public IDictionary<string, PackageIdentity> RidSpecificPackages { get; }

public IEnumerable<string> Warnings { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class DotNetCliTool
[XmlArrayItem("Command", IsNullable = false)]
public DotNetCliToolCommand[] Commands { get; set; }

[XmlArrayItem("RuntimeIdentifierPackage", IsNullable = false)]
public DotNetCliToolRuntimeIdentifierPackage[] RuntimeIdentifierPackages { get; set; }

[XmlAttribute(AttributeName = "Version")]
public string Version { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Xml.Serialization;

namespace Microsoft.DotNet.Cli.ToolPackage.ToolConfigurationDeserialization;

[Serializable]
[DebuggerStepThrough]
[XmlType(AnonymousType = true)]
public class DotNetCliToolRuntimeIdentifierPackage
{
[XmlAttribute]
public string RuntimeIdentifier { get; set; }

[XmlAttribute]
public string Id { get; set; }

[XmlAttribute]
public string Version { get; set; }
}
14 changes: 11 additions & 3 deletions src/Cli/dotnet/ToolPackage/ToolConfigurationDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
using System.Xml;
using System.Xml.Serialization;
using Microsoft.DotNet.Cli.ToolPackage.ToolConfigurationDeserialization;
using NuGet.Packaging.Core;

namespace Microsoft.DotNet.Cli.ToolPackage;

internal static class ToolConfigurationDeserializer
{
// The supported tool configuration schema version.
// This should match the schema version in the GenerateToolsSettingsFile task from the SDK.
private const int SupportedVersion = 1;
private const int SupportedVersion = 2;

public static ToolConfiguration Deserialize(string pathToXml)
{
Expand Down Expand Up @@ -51,7 +52,9 @@ public static ToolConfiguration Deserialize(string pathToXml)
throw new ToolConfigurationException(CliStrings.ToolSettingsMoreThanOneCommand);
}

if (dotNetCliTool.Commands[0].Runner != "dotnet")
// TODO: Should be an error if runner is empty and there aren't any RID-specific packages
var runner = dotNetCliTool.Commands[0].Runner;
if (!string.IsNullOrEmpty(runner) && runner != "dotnet" && runner != "executable")
{
throw new ToolConfigurationException(
string.Format(
Expand All @@ -60,10 +63,15 @@ public static ToolConfiguration Deserialize(string pathToXml)
dotNetCliTool.Commands[0].Runner));
}

var ridSpecificPackages = dotNetCliTool.RuntimeIdentifierPackages?.ToDictionary(p => p.RuntimeIdentifier, p => new PackageIdentity(p.Id, new NuGet.Versioning.NuGetVersion(p.Version)))
.AsReadOnly();

return new ToolConfiguration(
dotNetCliTool.Commands[0].Name,
dotNetCliTool.Commands[0].EntryPoint,
warnings);
dotNetCliTool.Commands[0].Runner,
ridSpecificPackages: ridSpecificPackages,
warnings: warnings);
}

private static List<string> GenerateWarningAccordingToVersionAttribute(DotNetCliTool dotNetCliTool)
Expand Down
Loading
Loading