Skip to content

Commit

Permalink
Allow the project to provide the runtime identifier graph (#2882)
Browse files Browse the repository at this point in the history
  • Loading branch information
nkolev92 authored Jun 21, 2019
1 parent c537472 commit 04166a6
Show file tree
Hide file tree
Showing 21 changed files with 1,677 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ internal static TargetFrameworkInformation ToTargetFrameworkInformation(
// Update TFI with fallback properties
AssetTargetFallbackUtility.ApplyFramework(tfi, ptf, atf);


tfi.RuntimeIdentifierGraphPath = GetPropertyValueOrNull(targetFrameworkInfo.Properties, ProjectBuildProperties.RuntimeIdentifierGraphPath);

if (targetFrameworkInfo.PackageReferences != null)
{
tfi.Dependencies.AddRange(
Expand Down
10 changes: 10 additions & 0 deletions src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,16 @@ Copyright (c) .NET Foundation. All rights reserved.
ItemName="_RestoreGraphEntry" />
</GetRestoreFrameworkReferencesTask>

<!-- Write out the TargetFramework specific properties -->
<ItemGroup Condition=" '$(PackageReferenceCompatibleProjectStyle)' == 'true' AND '$(RuntimeIdentifierGraphPath)' != '' ">
<_RestoreGraphEntry Include="$([System.Guid]::NewGuid())">
<Type>TargetFrameworkProperties</Type>
<ProjectUniqueName>$(MSBuildProjectFullPath)</ProjectUniqueName>
<TargetFramework>$(TargetFramework)</TargetFramework>
<RuntimeIdentifierGraphPath>$(RuntimeIdentifierGraphPath)</RuntimeIdentifierGraphPath>
</_RestoreGraphEntry>
</ItemGroup>

<PropertyGroup>
<_CombinedFallbacks>$(PackageTargetFallback);$(AssetTargetFallback)</_CombinedFallbacks>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -15,6 +16,7 @@
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Packaging.Signing;
using NuGet.ProjectModel;
using NuGet.Repositories;
using NuGet.RuntimeModel;

Expand Down Expand Up @@ -116,11 +118,25 @@ public async Task<Tuple<bool, List<RestoreTargetGraph>, RuntimeGraph>> TryRestor

var runtimeGraphs = new List<RestoreTargetGraph>();
var runtimeTasks = new List<Task<RestoreTargetGraph[]>>();

var projectProvidedRuntimeIdentifierGraphs = new SortedList<string, RuntimeGraph>();
foreach (var graph in graphs)
{
// Get the runtime graph for this specific tfm graph
var runtimeGraph = GetRuntimeGraph(graph, localRepositories);
// PCL Projects with Supports have a runtime graph but no matching framework.
var runtimeGraphPath = _request.Project.TargetFrameworks.
FirstOrDefault(e => NuGetFramework.Comparer.Equals(e.FrameworkName, graph.Framework))?.RuntimeIdentifierGraphPath;

RuntimeGraph projectProviderRuntimeGraph = null;
if (runtimeGraphPath != null &&
!projectProvidedRuntimeIdentifierGraphs.TryGetValue(runtimeGraphPath, out projectProviderRuntimeGraph))
{

projectProviderRuntimeGraph = GetRuntimeGraph(runtimeGraphPath);
success &= projectProviderRuntimeGraph != null;
projectProvidedRuntimeIdentifierGraphs.Add(runtimeGraphPath, projectProviderRuntimeGraph);
}


var runtimeGraph = GetRuntimeGraph(graph, localRepositories, projectRuntimeGraph: projectProviderRuntimeGraph);
var runtimeIds = runtimesByFramework[graph.Framework];

// Merge all runtimes for the output
Expand Down Expand Up @@ -167,7 +183,44 @@ public async Task<Tuple<bool, List<RestoreTargetGraph>, RuntimeGraph>> TryRestor
return Tuple.Create(success, graphs, allRuntimes);
}

private async Task<DownloadDependencyResolutionResult> ResolveDownloadDependencies(RemoteWalkContext context, ConcurrentDictionary<LibraryRange, Task<Tuple<LibraryRange, RemoteMatch>>> downloadDependenciesCache, ProjectModel.TargetFrameworkInformation targetFrameworkInformation, CancellationToken token)
// Gets the runtime graph specified in the path.
// returns null if an error is hit. A valid runtime graph otherwise.
private RuntimeGraph GetRuntimeGraph(string runtimeGraphPath)
{
if (File.Exists(runtimeGraphPath))
{
try
{
using (var stream = File.OpenRead(runtimeGraphPath))
{
var runtimeGraph = JsonRuntimeFormat.ReadRuntimeGraph(stream);
return runtimeGraph;
}
}
catch (Exception e)
{
_logger.Log(
RestoreLogMessage.CreateError(
NuGetLogCode.NU1007,
string.Format(CultureInfo.CurrentCulture,
Strings.Error_ProjectRuntimeJsonIsUnreadable,
runtimeGraphPath,
e.Message)));
}
}
else
{
_logger.Log(
RestoreLogMessage.CreateError(
NuGetLogCode.NU1007,
string.Format(CultureInfo.CurrentCulture,
Strings.Error_ProjectRuntimeJsonNotFound,
runtimeGraphPath)));
}
return null;
}

private async Task<DownloadDependencyResolutionResult> ResolveDownloadDependencies(RemoteWalkContext context, ConcurrentDictionary<LibraryRange, Task<Tuple<LibraryRange, RemoteMatch>>> downloadDependenciesCache, TargetFrameworkInformation targetFrameworkInformation, CancellationToken token)
{
var packageDownloadTasks = targetFrameworkInformation.DownloadDependencies.Select(downloadDependency => ResolverUtility.FindPackageLibraryMatchCachedAsync(
downloadDependenciesCache, downloadDependency, context.RemoteLibraryProviders, context.LocalLibraryProviders, context.CacheContext, _logger, token));
Expand Down Expand Up @@ -401,10 +454,10 @@ private Task<RestoreTargetGraph[]> WalkRuntimeDependenciesAsync(LibraryRange pro
/// <summary>
/// Merge all runtime.json found in the flattened graph.
/// </summary>
private RuntimeGraph GetRuntimeGraph(RestoreTargetGraph graph, IReadOnlyList<NuGetv3LocalRepository> localRepositories)
private RuntimeGraph GetRuntimeGraph(RestoreTargetGraph graph, IReadOnlyList<NuGetv3LocalRepository> localRepositories, RuntimeGraph projectRuntimeGraph)
{
_logger.LogVerbose(Strings.Log_ScanningForRuntimeJson);
var runtimeGraph = RuntimeGraph.Empty;
var runtimeGraph = projectRuntimeGraph ?? RuntimeGraph.Empty;

// Find runtime.json files using the flattened graph which is unique per id.
// Using the flattened graph ensures that only accepted packages will be used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ public static PackageSpec GetPackageSpec(IEnumerable<IMSBuildItem> items)
// Add RIDs and Supports
result.RuntimeGraph = GetRuntimeGraph(specItem);

// Add Target Framework Specific Properties
AddTargetFrameworkSpecificProperties(result, items);

// Add PackageTargetFallback
AddPackageTargetFallbacks(result, items);

Expand Down Expand Up @@ -446,6 +449,16 @@ private static void AddPackageTargetFallbacks(PackageSpec spec, IEnumerable<IMSB
}
}

private static void AddTargetFrameworkSpecificProperties(PackageSpec spec, IEnumerable<IMSBuildItem> items)
{
foreach (var item in GetItemByType(items, "TargetFrameworkProperties"))
{
var frameworkString = item.GetProperty("TargetFramework");
var targetFrameworkInformation = spec.GetTargetFramework(NuGetFramework.Parse(frameworkString));
targetFrameworkInformation.RuntimeIdentifierGraphPath = item.GetProperty("RuntimeIdentifierGraphPath");
}
}

/// <summary>
/// Remove duplicates and excluded values a set of sources or fallback folders.
/// </summary>
Expand Down Expand Up @@ -744,18 +757,6 @@ private static PackageSpec GetBaseSpec(IMSBuildItem specItem)
return spec;
}

private static HashSet<NuGetFramework> GetFrameworks(IMSBuildItem item, PackageSpec spec)
{
var frameworks = GetFrameworks(item);

if (frameworks.Count == 0)
{
frameworks.UnionWith(spec.TargetFrameworks.Select(e => e.FrameworkName));
}

return frameworks;
}

private static HashSet<NuGetFramework> GetFrameworks(IMSBuildItem item)
{
return new HashSet<NuGetFramework>(
Expand Down
18 changes: 18 additions & 0 deletions src/NuGet.Core/NuGet.Commands/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/NuGet.Core/NuGet.Commands/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -884,4 +884,12 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r
<value>The package {0} {1} has a package type {2} that is incompatible with this project.</value>
<comment>0 - package id, 1 - version, 2 - package type</comment>
</data>
<data name="Error_ProjectRuntimeJsonNotFound" xml:space="preserve">
<value>The runtime.json specified in the project '{0}' could not be found.</value>
<comment>0 - runtime.json path, Please do not localize 'runtime.json'</comment>
</data>
<data name="Error_ProjectRuntimeJsonIsUnreadable" xml:space="preserve">
<value>The runtime.json specified in the project '{0}' could not be parsed. {1}</value>
<comment>0 - runtime.json path, 1 - Additional Message, Please do not localize 'runtime.json'.</comment>
</data>
</root>
5 changes: 5 additions & 0 deletions src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public enum NuGetLogCode
/// </summary>
NU1006 = 1006,

/// <summary>
/// Project provided runtime graph is invalid. Either does not exist or cannot be parsed.
/// </summary>
NU1007 = 1007,

/// <summary>
/// Unable to resolve package, generic message for unknown type constraints.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public static class NuGetConstants
public static readonly string NuGetHostName = "nuget.org";
public static readonly string NuGetSymbolHostName = "nuget.smbsrc.net";

public static readonly string V3FeedUrl = "https://api.nuget.org/v3/index.json";
public static readonly string V2FeedUrl = "https://www.nuget.org/api/v2/";
public const string V3FeedUrl = "https://api.nuget.org/v3/index.json";
public const string V2FeedUrl = "https://www.nuget.org/api/v2/";
public static readonly string V2LegacyOfficialPackageSourceUrl = "https://nuget.org/api/v2/";
public static readonly string V2LegacyFeedUrl = "https://go.microsoft.com/fwlink/?LinkID=230477";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ public static class ProjectBuildProperties
public const string PrivateAssets = nameof(PrivateAssets);
public const string ReferenceOutputAssembly = nameof(ReferenceOutputAssembly);
public const string Clear = nameof(Clear);
public const string RuntimeIdentifierGraphPath = nameof(RuntimeIdentifierGraphPath);
}
}
16 changes: 15 additions & 1 deletion src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,8 @@ private static bool BuildTargetFrameworkNode(PackageSpec packageSpec, KeyValuePa
Imports = importFrameworks,
Warn = GetWarnSetting(properties),
AssetTargetFallback = assetTargetFallback,
};
RuntimeIdentifierGraphPath = GetRuntimeIdentifierGraphPath(properties)
};

PopulateDependencies(
packageSpec.FilePath,
Expand Down Expand Up @@ -920,6 +921,19 @@ private static List<NuGetFramework> GetImports(JObject properties, PackageSpec p
return frameworks;
}

private static string GetRuntimeIdentifierGraphPath(JObject properties)
{
var runtimeIdentifierGraphPath = properties["runtimeIdentifierGraphPath"];

if (runtimeIdentifierGraphPath != null)
{
return runtimeIdentifierGraphPath.ToObject<string>();
}

return null;
}


private static bool GetWarnSetting(JObject properties)
{
var warn = false;
Expand Down
10 changes: 9 additions & 1 deletion src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ private static void SetFrameworks(IObjectWriter writer, IList<TargetFrameworkInf
SetValueIfTrue(writer, "warn", framework.Warn);
SetDownloadDependencies(writer, framework.DownloadDependencies);
SetFrameworkReferences(writer, framework.FrameworkReferences);

SetValueIfNotNull(writer, "runtimeIdentifierGraphPath", framework.RuntimeIdentifierGraphPath);
writer.WriteObjectEnd();
}

Expand Down Expand Up @@ -528,6 +528,14 @@ private static void SetValueIfTrue(IObjectWriter writer, string name, bool value
}
}

private static void SetValueIfNotNull(IObjectWriter writer, string name, string value)
{
if (!string.IsNullOrEmpty(value))
{
writer.WriteNameValue(name, value);
}
}

private static void SetValue(IObjectWriter writer, string name, string value)
{
if (value != null)
Expand Down
11 changes: 9 additions & 2 deletions src/NuGet.Core/NuGet.ProjectModel/TargetFrameworkInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public class TargetFrameworkInformation : IEquatable<TargetFrameworkInformation>
/// </summary>
public ISet<FrameworkDependency> FrameworkReferences { get; } = new HashSet<FrameworkDependency>();

/// <summary>
/// The project provided runtime.json
/// </summary>
public string RuntimeIdentifierGraphPath { get; set; }

public override string ToString()
{
return FrameworkName.GetShortFolderName();
Expand All @@ -58,7 +63,7 @@ public override int GetHashCode()
hashCode.AddSequence(Imports);
hashCode.AddSequence(DownloadDependencies);
hashCode.AddSequence(FrameworkReferences);

hashCode.AddObject(RuntimeIdentifierGraphPath);
return hashCode.CombinedHash;
}

Expand All @@ -84,7 +89,8 @@ public bool Equals(TargetFrameworkInformation other)
Imports.SequenceEqualWithNullCheck(other.Imports) &&
AssetTargetFallback == other.AssetTargetFallback &&
DownloadDependencies.OrderedEquals(other.DownloadDependencies, dep => dep) &&
FrameworkReferences.OrderedEquals(other.FrameworkReferences, fr => fr);
FrameworkReferences.OrderedEquals(other.FrameworkReferences, fr => fr) &&
string.Equals(RuntimeIdentifierGraphPath, other.RuntimeIdentifierGraphPath);
}

public TargetFrameworkInformation Clone()
Expand All @@ -97,6 +103,7 @@ public TargetFrameworkInformation Clone()
clonedObject.Warn = Warn;
clonedObject.DownloadDependencies.AddRange(DownloadDependencies.Select(item => item.Clone()));
clonedObject.FrameworkReferences.AddRange(FrameworkReferences);
clonedObject.RuntimeIdentifierGraphPath = RuntimeIdentifierGraphPath;
return clonedObject;
}
}
Expand Down
Loading

0 comments on commit 04166a6

Please sign in to comment.