Merge pull request #1012 from dotnet/davidfowl/auto-facade

Auto reference facades in the common cases
This commit is contained in:
Piotr Puszkiewicz 2016-01-25 10:43:21 -08:00
commit 044b9473e9
7 changed files with 117 additions and 25 deletions

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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));
}
}
}

View file

@ -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",