Merge pull request #1012 from dotnet/davidfowl/auto-facade
Auto reference facades in the common cases
This commit is contained in:
commit
044b9473e9
7 changed files with 117 additions and 25 deletions
|
@ -212,11 +212,6 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
|
|||
{
|
||||
foreach (var assemblyPath in section)
|
||||
{
|
||||
if (IsPlaceholderFile(assemblyPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
assets.Add(new LibraryAsset(
|
||||
Path.GetFileNameWithoutExtension(assemblyPath),
|
||||
assemblyPath,
|
||||
|
@ -224,11 +219,6 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
|
|||
}
|
||||
}
|
||||
|
||||
private static bool IsPlaceholderFile(string path)
|
||||
{
|
||||
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static bool LibraryIsOfType(LibraryType type, LibraryDescription library)
|
||||
{
|
||||
return type.Equals(LibraryType.Unspecified) || // No type filter was requested
|
||||
|
|
|
@ -7,13 +7,15 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
{
|
||||
public struct LibraryDependencyType
|
||||
{
|
||||
private readonly LibraryDependencyTypeFlag _flags;
|
||||
|
||||
public static LibraryDependencyType Default = LibraryDependencyType.Parse("default");
|
||||
|
||||
public static LibraryDependencyType Build = LibraryDependencyType.Parse("build");
|
||||
|
||||
public LibraryDependencyTypeFlag Flags { get; private set; }
|
||||
|
||||
private LibraryDependencyType(LibraryDependencyTypeFlag flags)
|
||||
{
|
||||
_flags = flags;
|
||||
Flags = flags;
|
||||
}
|
||||
|
||||
public static LibraryDependencyType Parse(string keyword)
|
||||
|
@ -41,7 +43,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
|
||||
public bool HasFlag(LibraryDependencyTypeFlag flag)
|
||||
{
|
||||
return (_flags & flag) != 0;
|
||||
return (Flags & flag) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Identity} = {Path}";
|
||||
return $"{Identity} ({Identity.Type}) = {Path}";
|
||||
}
|
||||
|
||||
// For diagnostics, we don't want to duplicate requested dependencies so we
|
||||
|
|
|
@ -154,6 +154,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
RootDirectory = GlobalSettings?.DirectoryPath ?? RootDirectory;
|
||||
PackagesDirectory = PackagesDirectory ?? PackageDependencyProvider.ResolvePackagesPath(RootDirectory, GlobalSettings);
|
||||
ReferenceAssembliesPath = ReferenceAssembliesPath ?? FrameworkReferenceResolver.GetDefaultReferenceAssembliesPath();
|
||||
var frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath);
|
||||
|
||||
LockFileLookup lockFileLookup = null;
|
||||
|
||||
|
@ -185,12 +186,11 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
target = SelectTarget(LockFile);
|
||||
if (target != null)
|
||||
{
|
||||
var packageResolver = new PackageDependencyProvider(PackagesDirectory);
|
||||
var packageResolver = new PackageDependencyProvider(PackagesDirectory, frameworkReferenceResolver);
|
||||
ScanLibraries(target, lockFileLookup, libraries, packageResolver, projectResolver);
|
||||
}
|
||||
}
|
||||
|
||||
var frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath);
|
||||
var referenceAssemblyDependencyResolver = new ReferenceAssemblyDependencyResolver(frameworkReferenceResolver);
|
||||
bool requiresFrameworkAssemblies;
|
||||
|
||||
|
@ -269,8 +269,10 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
requiresFrameworkAssemblies = false;
|
||||
|
||||
foreach (var library in libraries.Values.ToList())
|
||||
foreach (var pair in libraries.ToList())
|
||||
{
|
||||
var library = pair.Value;
|
||||
|
||||
if (Equals(library.Identity.Type, LibraryType.Package) &&
|
||||
!Directory.Exists(library.Path))
|
||||
{
|
||||
|
@ -278,6 +280,27 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
library.Resolved = false;
|
||||
}
|
||||
|
||||
// The System.* packages provide placeholders on any non netstandard platform
|
||||
// To make them work seamlessly on those platforms, we fill the gap with a reference
|
||||
// assembly (if available)
|
||||
var package = library as PackageDescription;
|
||||
if (package != null && package.Resolved && !package.Target.CompileTimeAssemblies.Any())
|
||||
{
|
||||
var replacement = referenceAssemblyDependencyResolver.GetDescription(new LibraryRange(library.Identity.Name, LibraryType.ReferenceAssembly), TargetFramework);
|
||||
if (replacement?.Resolved == true)
|
||||
{
|
||||
requiresFrameworkAssemblies = true;
|
||||
|
||||
// Remove the original package reference
|
||||
libraries.Remove(pair.Key);
|
||||
|
||||
// Add the reference to the refernce assembly.
|
||||
libraries[new LibraryKey(replacement.Identity.Name)] = replacement;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
library.Framework = library.Framework ?? TargetFramework;
|
||||
foreach (var dependency in library.Dependencies)
|
||||
{
|
||||
|
@ -335,7 +358,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
if (packageEntry != null)
|
||||
{
|
||||
description = packageResolver.GetDescription(packageEntry, library);
|
||||
description = packageResolver.GetDescription(TargetFramework, packageEntry, library);
|
||||
}
|
||||
|
||||
type = LibraryType.Package;
|
||||
|
|
|
@ -5,7 +5,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using NuGet.Frameworks;
|
||||
using NuGet.Packaging;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Resolution
|
||||
|
@ -13,13 +16,15 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
public class PackageDependencyProvider
|
||||
{
|
||||
private readonly VersionFolderPathResolver _packagePathResolver;
|
||||
private readonly FrameworkReferenceResolver _frameworkReferenceResolver;
|
||||
|
||||
public PackageDependencyProvider(string packagesPath)
|
||||
public PackageDependencyProvider(string packagesPath, FrameworkReferenceResolver frameworkReferenceResolver)
|
||||
{
|
||||
_packagePathResolver = new VersionFolderPathResolver(packagesPath);
|
||||
_frameworkReferenceResolver = frameworkReferenceResolver;
|
||||
}
|
||||
|
||||
public PackageDescription GetDescription(LockFilePackageLibrary package, LockFileTargetLibrary targetLibrary)
|
||||
public PackageDescription GetDescription(NuGetFramework targetFramework, LockFilePackageLibrary package, LockFileTargetLibrary targetLibrary)
|
||||
{
|
||||
// If a NuGet dependency is supposed to provide assemblies but there is no assembly compatible with
|
||||
// current target framework, we should mark this dependency as unresolved
|
||||
|
@ -37,6 +42,14 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
|
||||
var path = _packagePathResolver.GetInstallPath(package.Name, package.Version);
|
||||
|
||||
// Remove place holders
|
||||
targetLibrary.CompileTimeAssemblies = targetLibrary.CompileTimeAssemblies.Where(item => !IsPlaceholderFile(item.Path)).ToList();
|
||||
targetLibrary.RuntimeAssemblies = targetLibrary.RuntimeAssemblies.Where(item => !IsPlaceholderFile(item.Path)).ToList();
|
||||
|
||||
// If the package's compile time assemblies is for a portable profile then, read the assembly metadata
|
||||
// and turn System.* references into reference assembly dependencies
|
||||
PopulateLegacyPortableDependencies(targetFramework, dependencies, path, targetLibrary);
|
||||
|
||||
var packageDescription = new PackageDescription(
|
||||
path,
|
||||
package,
|
||||
|
@ -47,6 +60,64 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
return packageDescription;
|
||||
}
|
||||
|
||||
private void PopulateLegacyPortableDependencies(NuGetFramework targetFramework, List<LibraryRange> dependencies, string packagePath, LockFileTargetLibrary targetLibrary)
|
||||
{
|
||||
var seen = new HashSet<string>();
|
||||
|
||||
foreach (var assembly in targetLibrary.CompileTimeAssemblies)
|
||||
{
|
||||
// (ref/lib)/{tfm}/{assembly}
|
||||
var pathParts = assembly.Path.Split('/');
|
||||
|
||||
if (pathParts.Length != 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var assemblyTargetFramework = NuGetFramework.Parse(pathParts[1]);
|
||||
|
||||
if (!assemblyTargetFramework.IsPCL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var assemblyPath = Path.Combine(packagePath, assembly.Path);
|
||||
|
||||
foreach (var dependency in GetDependencies(assemblyPath))
|
||||
{
|
||||
if (seen.Add(dependency))
|
||||
{
|
||||
string path;
|
||||
Version version;
|
||||
|
||||
// If there exists a reference assembly on the requested framework with the same name then turn this into a
|
||||
// framework assembly dependency
|
||||
if (_frameworkReferenceResolver.TryGetAssembly(dependency, targetFramework, out path, out version))
|
||||
{
|
||||
dependencies.Add(new LibraryRange(dependency,
|
||||
LibraryType.ReferenceAssembly,
|
||||
LibraryDependencyType.Build));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetDependencies(string path)
|
||||
{
|
||||
using (var peReader = new PEReader(File.OpenRead(path)))
|
||||
{
|
||||
var metadataReader = peReader.GetMetadataReader();
|
||||
|
||||
foreach (var assemblyReferenceHandle in metadataReader.AssemblyReferences)
|
||||
{
|
||||
var assemblyReference = metadataReader.GetAssemblyReference(assemblyReferenceHandle);
|
||||
|
||||
yield return metadataReader.GetString(assemblyReference.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateDependencies(List<LibraryRange> dependencies, LockFileTargetLibrary targetLibrary)
|
||||
{
|
||||
foreach (var dependency in targetLibrary.Dependencies)
|
||||
|
@ -67,6 +138,11 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
}
|
||||
}
|
||||
|
||||
public static bool IsPlaceholderFile(string path)
|
||||
{
|
||||
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static string ResolvePackagesPath(string rootDirectory, GlobalSettings settings)
|
||||
{
|
||||
// Order
|
||||
|
|
|
@ -48,17 +48,17 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
|
||||
if (targetFramework != null && targetFramework.IsDesktop())
|
||||
{
|
||||
targetFrameworkDependencies.Add(new LibraryRange("mscorlib", LibraryType.ReferenceAssembly));
|
||||
targetFrameworkDependencies.Add(new LibraryRange("mscorlib", LibraryType.ReferenceAssembly, LibraryDependencyType.Build));
|
||||
|
||||
targetFrameworkDependencies.Add(new LibraryRange("System", LibraryType.ReferenceAssembly));
|
||||
targetFrameworkDependencies.Add(new LibraryRange("System", LibraryType.ReferenceAssembly, LibraryDependencyType.Build));
|
||||
|
||||
if (targetFramework.Version >= new Version(3, 5))
|
||||
{
|
||||
targetFrameworkDependencies.Add(new LibraryRange("System.Core", LibraryType.ReferenceAssembly));
|
||||
targetFrameworkDependencies.Add(new LibraryRange("System.Core", LibraryType.ReferenceAssembly, LibraryDependencyType.Build));
|
||||
|
||||
if (targetFramework.Version >= new Version(4, 0))
|
||||
{
|
||||
targetFrameworkDependencies.Add(new LibraryRange("Microsoft.CSharp", LibraryType.ReferenceAssembly));
|
||||
targetFrameworkDependencies.Add(new LibraryRange("Microsoft.CSharp", LibraryType.ReferenceAssembly, LibraryDependencyType.Build));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"description": "Types to model a .NET Project",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23704",
|
||||
"System.Reflection.Metadata": "1.2.0-rc2-23608",
|
||||
"System.Runtime.Loader": "4.0.0-rc2-23704",
|
||||
"System.Dynamic.Runtime": "4.0.11-rc2-23704",
|
||||
"System.Security.Cryptography.Algorithms": "4.0.0-rc2-23704",
|
||||
|
|
Loading…
Reference in a new issue