-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add support for adding RIDs to runtime.json during build #50818
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| <Project Sdk="Microsoft.NET.SDK"> | ||
| <Project Sdk="Microsoft.NET.SDK"> | ||
| <!-- These are wrapper project files for packaging.--> | ||
| <PropertyGroup> | ||
| <TargetFrameworks>$(NetCoreAppToolCurrent);net472</TargetFrameworks> | ||
|
|
@@ -12,6 +12,9 @@ | |
| <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking> | ||
| <NoWarn>$(NoWarn);NU5128</NoWarn> <!-- No Dependencies--> | ||
| <PackageDescription>Provides runtime information required to resolve target framework, platform, and runtime specific implementations of .NETCore packages.</PackageDescription> | ||
|
|
||
| <!-- When building from source, ensure the RID we're building for is part of the RID graph --> | ||
| <AdditionalRuntimeIdentifiers Condition="'$(DotNetBuildFromSource)' == 'true'">$(AdditionalRuntimeIdentifiers);$(OutputRID)</AdditionalRuntimeIdentifiers> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup Condition="'$(TargetFramework)' == 'net472'"> | ||
|
|
@@ -24,11 +27,14 @@ | |
| <Compile Include="Extensions.cs" /> | ||
| <Compile Include="GenerateRuntimeGraph.cs" /> | ||
| <Compile Include="RID.cs" /> | ||
| <Compile Include="RuntimeGroupCollection.cs" /> | ||
| <Compile Include="RuntimeGroup.cs" /> | ||
| <Compile Include="RuntimeVersion.cs" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <Content Include="runtime.json" PackagePath="/" /> | ||
| <Content Condition="'$(AdditionalRuntimeIdentifiers)' == ''" Include="runtime.json" PackagePath="/" /> | ||
| <Content Condition="'$(AdditionalRuntimeIdentifiers)' != ''" Include="$(IntermediateOutputPath)runtime.json" PackagePath="/" /> | ||
| <Content Include="_._" PackagePath="lib/netstandard1.0" /> | ||
| </ItemGroup> | ||
|
|
||
|
|
@@ -38,5 +44,14 @@ | |
| <PackageReference Include="NuGet.ProjectModel" Version="$(RefOnlyNugetProjectModelVersion)" /> | ||
| </ItemGroup> | ||
|
|
||
| <Target Name="GenerateRuntimeJson" Condition="'$(AdditionalRuntimeIdentifiers)' != ''" BeforeTargets="GenerateNuspec"> | ||
| <MakeDir Directories="$(IntermediateOutputPath)" /> | ||
| <GenerateRuntimeGraph RuntimeGroups="@(RuntimeGroupWithQualifiers)" | ||
| AdditionalRuntimeIdentifiers="$(AdditionalRuntimeIdentifiers)" | ||
| AdditionalRuntimeIdentifierParent="$(AdditionalRuntimeIdentifierParent)" | ||
| RuntimeJson="$(IntermediateOutputPath)runtime.json" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider defining a property for the path to the runtime.json file. You are currently hardcoding it in two places. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do so in a follow up PR |
||
| UpdateRuntimeFiles="True" /> | ||
| </Target> | ||
|
|
||
| <Import Project="runtimeGroups.props" /> | ||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,44 @@ | ||
| // 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.Diagnostics; | ||
| using System.Text; | ||
|
|
||
| namespace Microsoft.NETCore.Platforms.BuildTasks | ||
| { | ||
| internal class RID | ||
| public class RID | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the access modifier changed because of tests depending on the RID class now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I didn't bother setting up internals visible to since this is an msbuild task and the only consumer of it is our build and tests. |
||
| { | ||
| internal const char VersionDelimiter = '.'; | ||
| internal const char ArchitectureDelimiter = '-'; | ||
| internal const char QualifierDelimiter = '-'; | ||
|
|
||
| public string BaseRID { get; set; } | ||
| public string VersionDelimiter { get; set; } | ||
| public string Version { get; set; } | ||
| public string ArchitectureDelimiter { get; set; } | ||
| public bool OmitVersionDelimiter { get; set; } | ||
| public RuntimeVersion Version { get; set; } | ||
| public string Architecture { get; set; } | ||
| public string QualifierDelimiter { get; set; } | ||
| public string Qualifier { get; set; } | ||
|
|
||
| public override string ToString() | ||
| { | ||
| StringBuilder builder = new StringBuilder(BaseRID); | ||
|
|
||
| if (HasVersion()) | ||
| if (HasVersion) | ||
| { | ||
| builder.Append(VersionDelimiter); | ||
| if (!OmitVersionDelimiter) | ||
| { | ||
| builder.Append(VersionDelimiter); | ||
| } | ||
| builder.Append(Version); | ||
| } | ||
|
|
||
| if (HasArchitecture()) | ||
| if (HasArchitecture) | ||
| { | ||
| builder.Append(ArchitectureDelimiter); | ||
| builder.Append(Architecture); | ||
| } | ||
|
|
||
| if (HasQualifier()) | ||
| if (HasQualifier) | ||
| { | ||
| builder.Append(QualifierDelimiter); | ||
| builder.Append(Qualifier); | ||
|
|
@@ -40,20 +47,153 @@ public override string ToString() | |
| return builder.ToString(); | ||
| } | ||
|
|
||
| public bool HasVersion() | ||
| private enum RIDPart : int | ||
| { | ||
| Base = 0, | ||
| Version, | ||
| Architecture, | ||
| Qualifier, | ||
| Max = Qualifier | ||
| } | ||
|
|
||
| public static RID Parse(string runtimeIdentifier) | ||
| { | ||
| string[] parts = new string[(int)RIDPart.Max + 1]; | ||
| bool omitVersionDelimiter = true; | ||
| RIDPart parseState = RIDPart.Base; | ||
|
|
||
| int partStart = 0, partLength = 0; | ||
|
|
||
| // qualifier is indistinguishable from arch so we cannot distinguish it for parsing purposes | ||
| Debug.Assert(ArchitectureDelimiter == QualifierDelimiter); | ||
|
|
||
| for (int i = 0; i < runtimeIdentifier.Length; i++) | ||
| { | ||
| char current = runtimeIdentifier[i]; | ||
| partLength = i - partStart; | ||
|
|
||
| switch (parseState) | ||
| { | ||
| case RIDPart.Base: | ||
| // treat any number as the start of the version | ||
| if (current == VersionDelimiter || (current >= '0' && current <= '9')) | ||
| { | ||
| SetPart(); | ||
| partStart = i; | ||
| if (current == VersionDelimiter) | ||
| { | ||
| omitVersionDelimiter = false; | ||
| partStart = i + 1; | ||
| } | ||
| parseState = RIDPart.Version; | ||
| } | ||
| // version might be omitted | ||
| else if (current == ArchitectureDelimiter) | ||
| { | ||
| // ensure there's no version later in the string | ||
| if (runtimeIdentifier.IndexOf(VersionDelimiter, i) != -1) | ||
| { | ||
| break; | ||
| } | ||
| SetPart(); | ||
| partStart = i + 1; // skip delimiter | ||
| parseState = RIDPart.Architecture; | ||
| } | ||
| break; | ||
| case RIDPart.Version: | ||
| if (current == ArchitectureDelimiter) | ||
| { | ||
| SetPart(); | ||
| partStart = i + 1; // skip delimiter | ||
| parseState = RIDPart.Architecture; | ||
| } | ||
| break; | ||
| case RIDPart.Architecture: | ||
| if (current == QualifierDelimiter) | ||
| { | ||
| SetPart(); | ||
| partStart = i + 1; // skip delimiter | ||
| parseState = RIDPart.Qualifier; | ||
| } | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| partLength = runtimeIdentifier.Length - partStart; | ||
| if (partLength > 0) | ||
| { | ||
| SetPart(); | ||
| } | ||
|
|
||
| string GetPart(RIDPart part) | ||
| { | ||
| return parts[(int)part]; | ||
| } | ||
|
|
||
| void SetPart() | ||
| { | ||
| if (partLength == 0) | ||
| { | ||
| throw new ArgumentException($"Unexpected delimiter at position {partStart} in \"{runtimeIdentifier}\""); | ||
| } | ||
|
|
||
| parts[(int)parseState] = runtimeIdentifier.Substring(partStart, partLength); | ||
| } | ||
|
|
||
| string version = GetPart(RIDPart.Version); | ||
|
|
||
| if (version == null) | ||
| { | ||
| omitVersionDelimiter = false; | ||
| } | ||
|
|
||
| return new RID() | ||
| { | ||
| BaseRID = GetPart(RIDPart.Base), | ||
| OmitVersionDelimiter = omitVersionDelimiter, | ||
| Version = version == null ? null : new RuntimeVersion(version), | ||
| Architecture = GetPart(RIDPart.Architecture), | ||
| Qualifier = GetPart(RIDPart.Qualifier) | ||
| }; | ||
| } | ||
|
|
||
| public bool HasVersion => Version != null; | ||
|
|
||
| public bool HasArchitecture => Architecture != null; | ||
|
|
||
| public bool HasQualifier => Qualifier != null; | ||
|
|
||
| public override bool Equals(object obj) | ||
| { | ||
| return Version != null; | ||
| return Equals(obj as RID); | ||
| } | ||
|
|
||
| public bool HasArchitecture() | ||
| public bool Equals(RID obj) | ||
| { | ||
| return Architecture != null; | ||
| return object.ReferenceEquals(obj, this) || | ||
| (obj is not null && | ||
| BaseRID == obj.BaseRID && | ||
| (Version == null || OmitVersionDelimiter == obj.OmitVersionDelimiter) && | ||
| Version == obj.Version && | ||
| Architecture == obj.Architecture && | ||
| Qualifier == obj.Qualifier); | ||
|
|
||
| } | ||
|
|
||
| public bool HasQualifier() | ||
| public override int GetHashCode() | ||
| { | ||
| return Qualifier != null; | ||
| #if NETFRAMEWORK | ||
| return BaseRID.GetHashCode(); | ||
| #else | ||
| HashCode hashCode = default; | ||
| hashCode.Add(BaseRID); | ||
| hashCode.Add(Version); | ||
| hashCode.Add(Architecture); | ||
| hashCode.Add(Qualifier); | ||
| return hashCode.ToHashCode(); | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's good we're appending the
OutputRIDat the end here. TheAdditionalRuntimeIdentifierswill be added in order, so we want them to be ordered from least to most specific.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That shouldn’t matter since the only way to establish a parent RID is through the parent parameter. New RIDs are added recursively following the rules in the runtime groups and parent. When written the graph is sorted.
In other words if you are imagining a case where order matters then you probably don’t need to specify that RID since it will be discovered recursively.