diff --git a/src/Microsoft.DotNet.Build.Tasks.Packaging/src/GenerateRuntimeGraph.cs b/src/Microsoft.DotNet.Build.Tasks.Packaging/src/GenerateRuntimeGraph.cs
index 7948abe8db1..25946410251 100644
--- a/src/Microsoft.DotNet.Build.Tasks.Packaging/src/GenerateRuntimeGraph.cs
+++ b/src/Microsoft.DotNet.Build.Tasks.Packaging/src/GenerateRuntimeGraph.cs
@@ -4,12 +4,10 @@
using Microsoft.Build.Framework;
using Newtonsoft.Json;
using NuGet.RuntimeModel;
-using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
using System.Xml.Linq;
namespace Microsoft.DotNet.Build.Tasks.Packaging
@@ -54,6 +52,15 @@ public ITaskItem[] RuntimeGroups
set;
}
+ ///
+ /// Additional runtime identifiers to add to the graph.
+ ///
+ public string[] AdditionalRuntimeIdentifiers
+ {
+ get;
+ set;
+ }
+
///
/// Optional source Runtime.json to use as a starting point when merging additional RuntimeGroups
///
@@ -135,7 +142,11 @@ public override bool Execute()
runtimeGraph = new RuntimeGraph();
}
- foreach (var runtimeGroup in RuntimeGroups.NullAsEmpty().Select(i => new RuntimeGroup(i)))
+ List runtimeGroups = RuntimeGroups.NullAsEmpty().Select(i => new RuntimeGroup(i)).ToList();
+
+ AddRuntimeIdentifiers(runtimeGroups, AdditionalRuntimeIdentifiers.NullAsEmpty(), defaultParent: "linux");
+
+ foreach (var runtimeGroup in runtimeGroups)
{
runtimeGraph = SafeMerge(runtimeGraph, runtimeGroup);
}
@@ -273,307 +284,67 @@ private void ValidateImports(RuntimeGraph runtimeGraph, IDictionary runtimeGroups, IEnumerable runtimeIdentifiers, string defaultParent)
{
- private const string rootRID = "any";
- private const char VersionDelimiter = '.';
- private const char ArchitectureDelimiter = '-';
- private const char QualifierDelimiter = '-';
+ var runtimeGroupsByBaseRID = runtimeGroups.GroupBy(rg => rg.BaseRID).ToDictionary(g => g.Key, g => new List(g.AsEnumerable()));
- public RuntimeGroup(ITaskItem item)
+ foreach(var runtimeIdentifer in runtimeIdentifiers)
{
- BaseRID = item.ItemSpec;
- Parent = item.GetString(nameof(Parent));
- Versions = item.GetStrings(nameof(Versions));
- TreatVersionsAsCompatible = item.GetBoolean(nameof(TreatVersionsAsCompatible), true);
- OmitVersionDelimiter = item.GetBoolean(nameof(OmitVersionDelimiter));
- ApplyVersionsToParent = item.GetBoolean(nameof(ApplyVersionsToParent));
- Architectures = item.GetStrings(nameof(Architectures));
- AdditionalQualifiers = item.GetStrings(nameof(AdditionalQualifiers));
- OmitRIDs = new HashSet(item.GetStrings(nameof(OmitRIDs)));
- OmitRIDDefinitions = new HashSet(item.GetStrings(nameof(OmitRIDDefinitions)));
- OmitRIDReferences = new HashSet(item.GetStrings(nameof(OmitRIDReferences)));
- }
-
- public string BaseRID { get; }
- public string Parent { get; }
- public IEnumerable Versions { get; }
- public bool TreatVersionsAsCompatible { get; }
- public bool OmitVersionDelimiter { get; }
- public bool ApplyVersionsToParent { get; }
- public IEnumerable Architectures { get; }
- public IEnumerable AdditionalQualifiers { get; }
- public ICollection OmitRIDs { get; }
- public ICollection OmitRIDDefinitions { get; }
- public ICollection OmitRIDReferences { get; }
-
- private class RIDMapping
- {
- public RIDMapping(RID runtimeIdentifier)
- {
- RuntimeIdentifier = runtimeIdentifier;
- Imports = Enumerable.Empty();
- }
-
- public RIDMapping(RID runtimeIdentifier, IEnumerable imports)
- {
- RuntimeIdentifier = runtimeIdentifier;
- Imports = imports;
- }
-
- public RID RuntimeIdentifier { get; }
-
- public IEnumerable Imports { get; }
- }
-
- private class RID
- {
- public string BaseRID { get; set; }
- public string VersionDelimiter { get; set; }
- public string Version { get; set; }
- public string ArchitectureDelimiter { 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())
- {
- builder.Append(VersionDelimiter);
- builder.Append(Version);
- }
-
- if (HasArchitecture())
- {
- builder.Append(ArchitectureDelimiter);
- builder.Append(Architecture);
- }
-
- if (HasQualifier())
- {
- builder.Append(QualifierDelimiter);
- builder.Append(Qualifier);
- }
-
- return builder.ToString();
- }
-
- public bool HasVersion()
- {
- return Version != null;
- }
-
- public bool HasArchitecture()
- {
- return Architecture != null;
- }
-
- public bool HasQualifier()
- {
- return Qualifier != null;
- }
- }
-
- private RID CreateRuntime(string baseRid, string version = null, string architecture = null, string qualifier = null)
- {
- return new RID()
- {
- BaseRID = baseRid,
- VersionDelimiter = OmitVersionDelimiter ? String.Empty : VersionDelimiter.ToString(),
- Version = version,
- ArchitectureDelimiter = ArchitectureDelimiter.ToString(),
- Architecture = architecture,
- QualifierDelimiter = QualifierDelimiter.ToString(),
- Qualifier = qualifier
- };
- }
-
- private IEnumerable GetRIDMappings()
- {
- // base =>
- // Parent
- yield return Parent == null ?
- new RIDMapping(CreateRuntime(BaseRID)) :
- new RIDMapping(CreateRuntime(BaseRID), new[] { CreateRuntime(Parent) });
-
- foreach (var architecture in Architectures)
- {
- // base + arch =>
- // base,
- // parent + arch
- var imports = new List()
- {
- CreateRuntime(BaseRID)
- };
+ RuntimeGroup runtimeGroup = null;
+ RID rid = RID.Parse(runtimeIdentifer);
- if (!IsNullOrRoot(Parent))
- {
- imports.Add(CreateRuntime(Parent, architecture: architecture));
- }
-
- yield return new RIDMapping(CreateRuntime(BaseRID, architecture: architecture), imports);
- }
- string lastVersion = null;
- foreach (var version in Versions)
+ if (runtimeGroupsByBaseRID.TryGetValue(rid.BaseRID, out var candidateRuntimeGroups))
{
- // base + version =>
- // base + lastVersion,
- // parent + version (optionally)
- var imports = new List()
- {
- CreateRuntime(BaseRID, version: lastVersion)
- };
-
- if (ApplyVersionsToParent)
- {
- imports.Add(CreateRuntime(Parent, version: version));
- }
-
- yield return new RIDMapping(CreateRuntime(BaseRID, version: version), imports);
+ RuntimeVersion closestVersion = null;
- foreach (var architecture in Architectures)
+ foreach(var candidate in candidateRuntimeGroups)
{
- // base + version + architecture =>
- // base + version,
- // base + lastVersion + architecture,
- // parent + version + architecture (optionally)
- var archImports = new List()
- {
- CreateRuntime(BaseRID, version: version),
- CreateRuntime(BaseRID, version: lastVersion, architecture: architecture)
- };
-
- if (ApplyVersionsToParent)
+ if (rid.HasArchitecture && !candidate.Architectures.Contains(rid.Architecture))
{
- archImports.Add(CreateRuntime(Parent, version: version, architecture: architecture));
+ continue;
}
- yield return new RIDMapping(CreateRuntime(BaseRID, version: version, architecture: architecture), archImports);
- }
-
- if (TreatVersionsAsCompatible)
- {
- lastVersion = version;
- }
- }
-
- foreach (var qualifier in AdditionalQualifiers)
- {
- // base + qual =>
- // base,
- // parent + qual
- yield return new RIDMapping(CreateRuntime(BaseRID, qualifier: qualifier),
- new[]
- {
- CreateRuntime(BaseRID),
- IsNullOrRoot(Parent) ? CreateRuntime(qualifier) : CreateRuntime(Parent, qualifier:qualifier)
- });
-
- foreach (var architecture in Architectures)
- {
- // base + arch + qualifier =>
- // base + qualifier,
- // base + arch
- // parent + arch + qualifier
- var imports = new List()
+ if (!rid.HasVersion)
{
- CreateRuntime(BaseRID, qualifier: qualifier),
- CreateRuntime(BaseRID, architecture: architecture)
- };
-
- if (!IsNullOrRoot(Parent))
- {
- imports.Add(CreateRuntime(Parent, architecture: architecture, qualifier: qualifier));
+ runtimeGroup = candidate;
+ continue;
}
- yield return new RIDMapping(CreateRuntime(BaseRID, architecture: architecture, qualifier: qualifier), imports);
- }
-
- lastVersion = null;
- foreach (var version in Versions)
- {
- // base + version + qualifier =>
- // base + version,
- // base + lastVersion + qualifier
- // parent + version + qualifier (optionally)
- var imports = new List()
+ foreach(var version in candidate.Versions)
{
- CreateRuntime(BaseRID, version: version),
- CreateRuntime(BaseRID, version: lastVersion, qualifier: qualifier)
- };
-
- if (ApplyVersionsToParent)
- {
- imports.Add(CreateRuntime(Parent, version: version, qualifier: qualifier));
- }
-
- yield return new RIDMapping(CreateRuntime(BaseRID, version: version, qualifier: qualifier), imports);
-
- foreach (var architecture in Architectures)
- {
- // base + version + architecture + qualifier =>
- // base + version + qualifier,
- // base + version + architecture,
- // base + version,
- // base + lastVersion + architecture + qualifier,
- // parent + version + architecture + qualifier (optionally)
- var archImports = new List()
- {
- CreateRuntime(BaseRID, version: version, qualifier: qualifier),
- CreateRuntime(BaseRID, version: version, architecture: architecture),
- CreateRuntime(BaseRID, version: version),
- CreateRuntime(BaseRID, version: lastVersion, architecture: architecture, qualifier: qualifier)
- };
-
- if (ApplyVersionsToParent)
+ if (closestVersion == null ||
+ ((version <= rid.Version) &&
+ (version > closestVersion)))
{
- imports.Add(CreateRuntime(Parent, version: version, architecture: architecture, qualifier: qualifier));
+ closestVersion = version;
+ runtimeGroup = candidate;
}
-
- yield return new RIDMapping(CreateRuntime(BaseRID, version: version, architecture: architecture, qualifier: qualifier), archImports);
- }
-
- if (TreatVersionsAsCompatible)
- {
- lastVersion = version;
}
}
- }
- }
- private bool IsNullOrRoot(string rid)
- {
- return rid == null || rid == rootRID;
- }
+ if (runtimeGroup == null)
+ {
+ // couldn't find a close group, create a new one for just this arch/version
+ RuntimeGroup templateGroup = candidateRuntimeGroups.First();
+ runtimeGroup = RuntimeGroup.CreateFromTemplate(templateGroup);
+ // add to overall list
+ runtimeGroups.Add(runtimeGroup);
- public IEnumerable GetRuntimeDescriptions()
- {
- foreach (var mapping in GetRIDMappings())
- {
- var rid = mapping.RuntimeIdentifier.ToString();
-
- if (OmitRIDs.Contains(rid) || OmitRIDDefinitions.Contains(rid))
- {
- continue;
+ // add to our base-RID specific list from the dictionary so that further iterations see it.
+ candidateRuntimeGroups.Add(runtimeGroup);
}
+ }
+ else
+ {
+ runtimeGroup = new RuntimeGroup(rid.BaseRID, defaultParent);
+ runtimeGroups.Add(runtimeGroup);
- var imports = mapping.Imports
- .Select(i => i.ToString())
- .Where(i => !OmitRIDs.Contains(i) && !OmitRIDReferences.Contains(i))
- .ToArray();
-
- yield return new RuntimeDescription(rid, imports);
+ runtimeGroupsByBaseRID.Add(rid.BaseRID, new List() { runtimeGroup });
}
- }
- public RuntimeGraph GetRuntimeGraph()
- {
- return new RuntimeGraph(GetRuntimeDescriptions());
+ runtimeGroup.ApplyRid(rid);
}
}
diff --git a/src/Microsoft.DotNet.Build.Tasks.Packaging/src/Microsoft.DotNet.Build.Tasks.Packaging.csproj b/src/Microsoft.DotNet.Build.Tasks.Packaging/src/Microsoft.DotNet.Build.Tasks.Packaging.csproj
index 1148b8a5ac7..42d2e34cec2 100644
--- a/src/Microsoft.DotNet.Build.Tasks.Packaging/src/Microsoft.DotNet.Build.Tasks.Packaging.csproj
+++ b/src/Microsoft.DotNet.Build.Tasks.Packaging/src/Microsoft.DotNet.Build.Tasks.Packaging.csproj
@@ -48,6 +48,10 @@
$(BeforePack);AddRuntimeJson
+
+
+
+
-
+
<_candidatePackageFolder>%(_candidatPackageFolders.Identity)
@@ -50,17 +51,14 @@
$(_candidatePackageFolder)\%(Identity)\%(Version)
- $(_candidatePackageFolder)\$([System.String]::new("%(Identity)\%(Version)").ToLower())
+ $(_candidatePackageFolder)\$([System.String]::new("%(Identity)\%(Version)").ToLower())
-
-
+
+
diff --git a/src/Microsoft.DotNet.Build.Tasks.Packaging/tests/RidTests.cs b/src/Microsoft.DotNet.Build.Tasks.Packaging/tests/RidTests.cs
new file mode 100644
index 00000000000..762309bd79a
--- /dev/null
+++ b/src/Microsoft.DotNet.Build.Tasks.Packaging/tests/RidTests.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace Microsoft.DotNet.Build.Tasks.Packaging.Tests
+{
+ public class RidTests
+ {
+ public static IEnumerable