Add MSBuildProjectDescription

This commit is contained in:
Mihai Codoban 2016-03-23 15:26:36 -07:00
parent 06ff80392e
commit ca2707292e
12 changed files with 276 additions and 77 deletions

View file

@ -140,11 +140,12 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
return LibraryExportBuilder.Create(library).Build();
}
if (Equals(LibraryType.Package, library.Identity.Type))
var libraryType = library.Identity.Type;
if (Equals(LibraryType.Package, libraryType) || Equals(LibraryType.MSBuildProject, libraryType))
{
return ExportPackage((PackageDescription)library);
return ExportPackage((TargetLibraryWithAssets)library);
}
else if (Equals(LibraryType.Project, library.Identity.Type))
else if (Equals(LibraryType.Project, libraryType))
{
return ExportProject((ProjectDescription)library);
}
@ -154,22 +155,22 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
}
}
private LibraryExport ExportPackage(PackageDescription package)
private LibraryExport ExportPackage(TargetLibraryWithAssets library)
{
var builder = LibraryExportBuilder.Create(package);
builder.AddNativeLibraryGroup(new LibraryAssetGroup(PopulateAssets(package, package.NativeLibraries)));
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(PopulateAssets(package, package.RuntimeAssemblies)));
builder.WithCompilationAssemblies(PopulateAssets(package, package.CompileTimeAssemblies));
builder.WithSourceReferences(GetSharedSources(package));
builder.WithAnalyzerReference(GetAnalyzerReferences(package));
var builder = LibraryExportBuilder.Create(library);
builder.AddNativeLibraryGroup(new LibraryAssetGroup(PopulateAssets(library, library.NativeLibraries)));
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(PopulateAssets(library, library.RuntimeAssemblies)));
builder.WithCompilationAssemblies(PopulateAssets(library, library.CompileTimeAssemblies));
builder.WithSourceReferences(GetSharedSources(library));
builder.WithAnalyzerReference(GetAnalyzerReferences(library));
if (package.ContentFiles.Any())
if (library.ContentFiles.Any())
{
var parameters = PPFileParameters.CreateForProject(_rootProject.Project);
Action<Stream, Stream> transform = (input, output) => PPFilePreprocessor.Preprocess(input, output, parameters);
var sourceCodeLanguage = _rootProject.Project.GetSourceCodeLanguage();
var languageGroups = package.ContentFiles.GroupBy(file => file.CodeLanguage);
var languageGroups = library.ContentFiles.GroupBy(file => file.CodeLanguage);
var selectedGroup = languageGroups.FirstOrDefault(g => g.Key == sourceCodeLanguage) ??
languageGroups.FirstOrDefault(g => g.Key == null);
if (selectedGroup != null)
@ -184,14 +185,14 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
var fileTransform = contentFile.PPOutputPath != null ? transform : null;
var fullPath = Path.Combine(package.Path, contentFile.Path);
var fullPath = Path.Combine(library.Path, contentFile.Path);
if (contentFile.BuildAction == BuildAction.Compile)
{
builder.AddSourceReference(LibraryAsset.CreateFromRelativePath(package.Path, contentFile.Path, fileTransform));
builder.AddSourceReference(LibraryAsset.CreateFromRelativePath(library.Path, contentFile.Path, fileTransform));
}
else if (contentFile.BuildAction == BuildAction.EmbeddedResource)
{
builder.AddEmbedddedResource(LibraryAsset.CreateFromRelativePath(package.Path, contentFile.Path, fileTransform));
builder.AddEmbedddedResource(LibraryAsset.CreateFromRelativePath(library.Path, contentFile.Path, fileTransform));
}
if (contentFile.CopyToOutput)
{
@ -200,9 +201,9 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
}
}
}
if (package.RuntimeTargets.Any())
if (library.RuntimeTargets.Any())
{
foreach (var targetGroup in package.RuntimeTargets.GroupBy(t => t.Runtime))
foreach (var targetGroup in library.RuntimeTargets.GroupBy(t => t.Runtime))
{
var runtime = new List<LibraryAsset>();
var native = new List<LibraryAsset>();
@ -211,11 +212,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
{
if (string.Equals(lockFileRuntimeTarget.AssetType, "native", StringComparison.OrdinalIgnoreCase))
{
native.Add(LibraryAsset.CreateFromRelativePath(package.Path, lockFileRuntimeTarget.Path));
native.Add(LibraryAsset.CreateFromRelativePath(library.Path, lockFileRuntimeTarget.Path));
}
else if (string.Equals(lockFileRuntimeTarget.AssetType, "runtime", StringComparison.OrdinalIgnoreCase))
{
runtime.Add(LibraryAsset.CreateFromRelativePath(package.Path, lockFileRuntimeTarget.Path));
runtime.Add(LibraryAsset.CreateFromRelativePath(library.Path, lockFileRuntimeTarget.Path));
}
}
@ -339,22 +340,14 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
return builder.Build();
}
private IEnumerable<LibraryAsset> GetSharedSources(PackageDescription package)
private IEnumerable<LibraryAsset> GetSharedSources(TargetLibraryWithAssets library)
{
return package
.Library
.Files
.Where(path => path.StartsWith("shared" + Path.DirectorySeparatorChar))
.Select(path => LibraryAsset.CreateFromRelativePath(package.Path, path));
return library.GetSharedSources().Select(path => LibraryAsset.CreateFromRelativePath(library.Path, path));
}
private IEnumerable<AnalyzerReference> GetAnalyzerReferences(PackageDescription package)
private IEnumerable<AnalyzerReference> GetAnalyzerReferences(TargetLibraryWithAssets package)
{
var analyzers = package
.Library
.Files
.Where(path => path.StartsWith("analyzers" + Path.DirectorySeparatorChar) &&
path.EndsWith(".dll"));
var analyzers = package.GetAnalyzerReferences();
var analyzerRefs = new List<AnalyzerReference>();
// See https://docs.nuget.org/create/analyzers-conventions for the analyzer
@ -416,12 +409,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
return analyzerRefs;
}
private IEnumerable<LibraryAsset> PopulateAssets(PackageDescription package, IEnumerable<LockFileItem> section)
private IEnumerable<LibraryAsset> PopulateAssets(TargetLibraryWithAssets library, IEnumerable<LockFileItem> section)
{
foreach (var assemblyPath in section)
{
yield return LibraryAsset.CreateFromRelativePath(package.Path, assemblyPath.Path);
yield return LibraryAsset.CreateFromRelativePath(library.Path, assemblyPath.Path);
}
}

View file

@ -115,7 +115,7 @@ namespace Microsoft.Extensions.DependencyModel
{
var type = export.Library.Identity.Type;
var serviceable = (export.Library as PackageDescription)?.Library.IsServiceable ?? false;
var serviceable = (export.Library as PackageDescription)?.PackageLibrary.IsServiceable ?? false;
var libraryDependencies = new HashSet<Dependency>();
foreach (var libraryDependency in export.Library.Dependencies)

View file

@ -11,11 +11,13 @@ namespace Microsoft.DotNet.ProjectModel.Graph
public static readonly LibraryType Package = new LibraryType(nameof(Package));
public static readonly LibraryType Project = new LibraryType(nameof(Project));
public static readonly LibraryType ReferenceAssembly = new LibraryType(nameof(ReferenceAssembly));
public static readonly LibraryType MSBuildProject = new LibraryType(nameof(MSBuildProject));
// Default value
public static readonly LibraryType Unspecified = new LibraryType();
public string Value { get; }
private LibraryType(string value)
{

View file

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Resolution;
namespace Microsoft.DotNet.ProjectModel.Graph
{
@ -17,7 +18,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
{
_lockFile = lockFile;
var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(IsMSBuildProjectLibrary);
var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(MSBuildDependencyProvider.IsMSBuildProjectLibrary);
_msbuildTargetLibraries = msbuildProjectLibraries.ToDictionary(GetProjectLibraryKey, l => GetTargetsForLibrary(_lockFile, l));
}
@ -64,11 +65,6 @@ namespace Microsoft.DotNet.ProjectModel.Graph
var export = exportDict[exportKey];
var librariesToPatch = _msbuildTargetLibraries[exportKey];
if (export.TargetFramework == null)
{
throw new LockFilePatchingException($"Export library {export.Name} could not be resolved during nuget restore");
}
foreach (var libraryToPatch in librariesToPatch)
{
Patch(libraryToPatch, export);
@ -88,13 +84,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
libraryToPatch.RuntimeAssemblies = export.RuntimeAssemblies;
}
private static bool IsMSBuildProjectLibrary(LockFileProjectLibrary projectLibrary)
{
var hasMSbuildProjectValue = !string.IsNullOrEmpty(projectLibrary.MSBuildProject);
var doesNotHavePathValue = string.IsNullOrEmpty(projectLibrary.Path);
return doesNotHavePathValue && hasMSbuildProjectValue;
}
private static IList<LockFileTargetLibrary> GetTargetsForLibrary(LockFile lockFile, LockFileProjectLibrary library)
{

View file

@ -61,6 +61,10 @@ namespace Microsoft.DotNet.ProjectModel.Graph
return lockFile;
}
catch (LockFilePatchingException exception)
{
throw;
}
catch
{
// Ran into parsing errors, mark it as unlocked and out-of-date

View file

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Graph;
namespace Microsoft.DotNet.ProjectModel
{
/// <summary>
/// Represents an MSBuild project.
/// It has been invisibly built by MSBuild, so it behaves like a package: can provide all assets up front
/// </summary>
public class MSBuildProjectDescription : TargetLibraryWithAssets
{
public MSBuildProjectDescription(
string path,
LockFileProjectLibrary projectLibrary,
LockFileTargetLibrary lockFileLibrary,
Project projectFile,
IEnumerable<LibraryRange> dependencies,
bool compatible,
bool resolved)
: base(
new LibraryIdentity(projectLibrary.Name, projectLibrary.Version, LibraryType.MSBuildProject),
string.Empty, //msbuild projects don't have hashes
path,
lockFileLibrary,
dependencies,
resolved: resolved,
compatible: compatible,
framework: null)
{
ProjectFile = projectFile;
ProjectLibrary = projectLibrary;
}
public LockFileProjectLibrary ProjectLibrary { get; }
public Project ProjectFile { get; }
public override IEnumerable<string> GetSharedSources()
{
return Enumerable.Empty<string>();
}
public override IEnumerable<string> GetAnalyzerReferences()
{
return Enumerable.Empty<string>();
}
}
}

View file

@ -1,15 +1,16 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution;
using System;
namespace Microsoft.DotNet.ProjectModel
{
public class PackageDescription : LibraryDescription
public class PackageDescription : TargetLibraryWithAssets
{
public PackageDescription(
string path,
@ -22,34 +23,39 @@ namespace Microsoft.DotNet.ProjectModel
new LibraryIdentity(package.Name, package.Version, LibraryType.Package),
"sha512-" + package.Sha512,
path,
dependencies: dependencies,
framework: null,
lockFileLibrary,
dependencies,
resolved: resolved,
compatible: compatible)
compatible: compatible,
framework: null)
{
Library = package;
Target = lockFileLibrary;
PackageLibrary = package;
}
private LockFileTargetLibrary Target { get; }
public LockFilePackageLibrary PackageLibrary { get; }
public LockFilePackageLibrary Library { get; }
public override IEnumerable<LockFileItem> RuntimeAssemblies => FilterPlaceholders(base.RuntimeAssemblies);
public IEnumerable<LockFileItem> RuntimeAssemblies => FilterPlaceholders(Target.RuntimeAssemblies);
public override IEnumerable<LockFileItem> CompileTimeAssemblies => FilterPlaceholders(base.CompileTimeAssemblies);
public IEnumerable<LockFileItem> CompileTimeAssemblies => FilterPlaceholders(Target.CompileTimeAssemblies);
public IEnumerable<LockFileItem> ResourceAssemblies => Target.ResourceAssemblies;
public IEnumerable<LockFileItem> NativeLibraries => Target.NativeLibraries;
public IEnumerable<LockFileContentFile> ContentFiles => Target.ContentFiles;
public IEnumerable<LockFileRuntimeTarget> RuntimeTargets => Target.RuntimeTargets;
private IEnumerable<LockFileItem> FilterPlaceholders(IList<LockFileItem> items)
private static IEnumerable<LockFileItem> FilterPlaceholders(IEnumerable<LockFileItem> items)
{
return items.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a));
}
public override IEnumerable<string> GetSharedSources()
{
return PackageLibrary
.Files
.Where(path => path.StartsWith("shared" + System.IO.Path.DirectorySeparatorChar));
}
public override IEnumerable<string> GetAnalyzerReferences()
{
return PackageLibrary
.Files
.Where(path => path.StartsWith("analyzers" + System.IO.Path.DirectorySeparatorChar) &&
path.EndsWith(".dll"));
}
}
}

View file

@ -192,8 +192,9 @@ namespace Microsoft.DotNet.ProjectModel
target = SelectTarget(LockFile);
if (target != null)
{
var packageResolver = new PackageDependencyProvider(PackagesDirectory, frameworkReferenceResolver);
ScanLibraries(target, lockFileLookup, libraries, packageResolver, projectResolver);
var nugetPackageResolver = new PackageDependencyProvider(PackagesDirectory, frameworkReferenceResolver);
var msbuildProjectResolver = new MSBuildDependencyProvider(ProjectResolver);
ScanLibraries(target, lockFileLookup, libraries, msbuildProjectResolver, nugetPackageResolver, projectResolver);
}
}
@ -342,7 +343,7 @@ namespace Microsoft.DotNet.ProjectModel
}
}
private void ScanLibraries(LockFileTarget target, LockFileLookup lockFileLookup, Dictionary<LibraryKey, LibraryDescription> libraries, PackageDependencyProvider packageResolver, ProjectDependencyProvider projectDependencyProvider)
private void ScanLibraries(LockFileTarget target, LockFileLookup lockFileLookup, Dictionary<LibraryKey, LibraryDescription> libraries, MSBuildDependencyProvider msbuildResolver, PackageDependencyProvider packageResolver, ProjectDependencyProvider projectResolver)
{
foreach (var library in target.Libraries)
{
@ -355,11 +356,18 @@ namespace Microsoft.DotNet.ProjectModel
if (projectLibrary != null)
{
var path = Path.GetFullPath(Path.Combine(ProjectDirectory, projectLibrary.Path));
description = projectDependencyProvider.GetDescription(library.Name, path, library, ProjectResolver);
if (MSBuildDependencyProvider.IsMSBuildProjectLibrary(projectLibrary))
{
description = msbuildResolver.GetDescription(TargetFramework, projectLibrary, library);
type = LibraryType.MSBuildProject;
}
else
{
var path = Path.GetFullPath(Path.Combine(ProjectDirectory, projectLibrary.Path));
description = projectResolver.GetDescription(library.Name, path, library, ProjectResolver);
type = LibraryType.Project;
}
}
type = LibraryType.Project;
}
else
{

View file

@ -0,0 +1,88 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Graph;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Resolution
{
public class MSBuildDependencyProvider
{
private readonly Func<string, Project> _projectResolver;
public MSBuildDependencyProvider(Func<string, Project> projectResolver)
{
_projectResolver = projectResolver;
}
public MSBuildProjectDescription GetDescription(NuGetFramework targetFramework, LockFileProjectLibrary projectLibrary, LockFileTargetLibrary targetLibrary)
{
var compatible = targetLibrary.FrameworkAssemblies.Any() ||
targetLibrary.CompileTimeAssemblies.Any() ||
targetLibrary.RuntimeAssemblies.Any();
var dependencies = new List<LibraryRange>(targetLibrary.Dependencies.Count + targetLibrary.FrameworkAssemblies.Count);
PopulateDependencies(dependencies, targetLibrary, targetFramework);
var path = Path.GetDirectoryName(Path.GetFullPath(projectLibrary.MSBuildProject));
var exists = Directory.Exists(path);
var projectFile = projectLibrary.Path == null ? null : _projectResolver(projectLibrary.Path);
var msbuildPackageDescription = new MSBuildProjectDescription(
path,
projectLibrary,
targetLibrary,
projectFile,
dependencies,
compatible,
resolved: compatible && exists);
return msbuildPackageDescription;
}
private void PopulateDependencies(
List<LibraryRange> dependencies,
LockFileTargetLibrary targetLibrary,
NuGetFramework targetFramework)
{
foreach (var dependency in targetLibrary.Dependencies)
{
dependencies.Add(new LibraryRange(
dependency.Id,
dependency.VersionRange,
LibraryType.Unspecified,
LibraryDependencyType.Default));
}
if (!targetFramework.IsPackageBased)
{
// Only add framework assemblies for non-package based frameworks.
foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies)
{
dependencies.Add(new LibraryRange(
frameworkAssembly,
LibraryType.ReferenceAssembly,
LibraryDependencyType.Default));
}
}
}
public static bool IsMSBuildProjectLibrary(LockFileProjectLibrary projectLibrary)
{
var msbuildProjectPath = projectLibrary.MSBuildProject;
if (msbuildProjectPath == null)
{
return false;
}
var extension = Path.GetExtension(msbuildProjectPath);
return !string.Equals(extension, ".xproj", StringComparison.OrdinalIgnoreCase);
}
}
}

View file

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Microsoft.DotNet.ProjectModel.Graph;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
{
public abstract class TargetLibraryWithAssets : LibraryDescription
{
public TargetLibraryWithAssets(
LibraryIdentity libraryIdentity,
string sha512,
string path,
LockFileTargetLibrary lockFileLibrary,
IEnumerable<LibraryRange> dependencies,
bool compatible,
bool resolved,
NuGetFramework framework = null)
: base(
libraryIdentity,
sha512,
path,
dependencies: dependencies,
framework: null,
resolved: resolved,
compatible: compatible)
{
TargetLibrary = lockFileLibrary;
}
private LockFileTargetLibrary TargetLibrary { get; }
public virtual IEnumerable<LockFileItem> RuntimeAssemblies => TargetLibrary.RuntimeAssemblies;
public virtual IEnumerable<LockFileItem> CompileTimeAssemblies => TargetLibrary.CompileTimeAssemblies;
public virtual IEnumerable<LockFileItem> ResourceAssemblies => TargetLibrary.ResourceAssemblies;
public virtual IEnumerable<LockFileItem> NativeLibraries => TargetLibrary.NativeLibraries;
public virtual IEnumerable<LockFileContentFile> ContentFiles => TargetLibrary.ContentFiles;
public virtual IEnumerable<LockFileRuntimeTarget> RuntimeTargets => TargetLibrary.RuntimeTargets;
public abstract IEnumerable<string> GetSharedSources();
public abstract IEnumerable<string> GetAnalyzerReferences();
}
}

View file

@ -603,6 +603,11 @@ namespace Microsoft.DotNet.Tools.Build
}
compilerIO.Inputs.Add(project.LockFile.LockFilePath);
if (project.LockFile.ExportFile != null)
{
compilerIO.Inputs.Add(project.LockFile.ExportFile.ExportFilePath);
}
}
private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)

View file

@ -21,7 +21,7 @@ namespace Microsoft.DotNet.ProjectModel
{
if (export.Library.Identity.Type == LibraryType.Package)
{
var runtimeJson = ((PackageDescription) export.Library).Library.Files.FirstOrDefault(f => f == RuntimeJsonFileName);
var runtimeJson = ((PackageDescription) export.Library).PackageLibrary.Files.FirstOrDefault(f => f == RuntimeJsonFileName);
if (runtimeJson != null)
{
var runtimeJsonFullName = Path.Combine(export.Library.Path, runtimeJson);