2015-11-16 11:21:57 -08:00
|
|
|
// 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.
|
2015-10-13 14:31:29 -07:00
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
2015-11-27 16:19:54 -08:00
|
|
|
using Microsoft.DotNet.ProjectModel.Graph;
|
|
|
|
using Microsoft.DotNet.ProjectModel.Resolution;
|
|
|
|
using Microsoft.DotNet.ProjectModel.Utilities;
|
2015-10-13 14:31:29 -07:00
|
|
|
using NuGet.Frameworks;
|
|
|
|
|
2015-11-27 16:19:54 -08:00
|
|
|
namespace Microsoft.DotNet.ProjectModel.Compilation
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
public class LibraryExporter
|
|
|
|
{
|
|
|
|
private readonly string _configuration;
|
|
|
|
private readonly ProjectDescription _rootProject;
|
|
|
|
|
|
|
|
public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, string configuration)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(configuration))
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(configuration));
|
|
|
|
}
|
|
|
|
|
|
|
|
LibraryManager = manager;
|
|
|
|
_configuration = configuration;
|
|
|
|
_rootProject = rootProject;
|
|
|
|
}
|
|
|
|
|
|
|
|
public LibraryManager LibraryManager { get; }
|
|
|
|
|
2015-11-01 16:21:10 -08:00
|
|
|
/// <summary>
|
|
|
|
/// Gets all the exports specified by this project, including the root project itself
|
|
|
|
/// </summary>
|
2015-10-13 14:31:29 -07:00
|
|
|
public IEnumerable<LibraryExport> GetAllExports()
|
|
|
|
{
|
|
|
|
return ExportLibraries(_ => true);
|
|
|
|
}
|
|
|
|
|
2015-11-01 16:21:10 -08:00
|
|
|
/// <summary>
|
|
|
|
/// Gets all exports required by the project, NOT including the project itself
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
public IEnumerable<LibraryExport> GetDependencies()
|
|
|
|
{
|
|
|
|
return GetDependencies(LibraryType.Unspecified);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets all exports required by the project, of the specified <see cref="LibraryType"/>, NOT including the project itself
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
public IEnumerable<LibraryExport> GetDependencies(LibraryType type)
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
// Export all but the main project
|
2015-11-01 16:21:10 -08:00
|
|
|
return ExportLibraries(library =>
|
|
|
|
library != _rootProject &&
|
|
|
|
LibraryIsOfType(type, library));
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves a list of <see cref="LibraryExport"/> objects representing the assets
|
|
|
|
/// required from other libraries to compile this project.
|
|
|
|
/// </summary>
|
|
|
|
private IEnumerable<LibraryExport> ExportLibraries(Func<LibraryDescription, bool> condition)
|
|
|
|
{
|
|
|
|
var seenMetadataReferences = new HashSet<string>();
|
|
|
|
|
|
|
|
// Iterate over libraries in the library manager
|
|
|
|
foreach (var library in LibraryManager.GetLibraries())
|
|
|
|
{
|
2015-10-16 22:50:44 -07:00
|
|
|
if (!condition(library))
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
var compilationAssemblies = new List<LibraryAsset>();
|
2015-10-13 14:31:29 -07:00
|
|
|
var sourceReferences = new List<string>();
|
|
|
|
|
|
|
|
var libraryExport = GetExport(library);
|
|
|
|
|
|
|
|
if (libraryExport != null)
|
|
|
|
{
|
|
|
|
// We need to filter out source references from non-root libraries,
|
|
|
|
// so we rebuild the library export
|
|
|
|
foreach (var reference in libraryExport.CompilationAssemblies)
|
|
|
|
{
|
2015-10-21 15:21:14 -07:00
|
|
|
if (seenMetadataReferences.Add(reference.Name))
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
compilationAssemblies.Add(reference);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-16 22:50:44 -07:00
|
|
|
if (library.Parents.Contains(_rootProject))
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
// Only process source references for direct dependencies
|
|
|
|
foreach (var sourceReference in libraryExport.SourceReferences)
|
|
|
|
{
|
|
|
|
sourceReferences.Add(sourceReference);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
yield return new LibraryExport(library, compilationAssemblies, sourceReferences, libraryExport.RuntimeAssemblies, libraryExport.NativeLibraries);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private LibraryExport GetExport(LibraryDescription library)
|
|
|
|
{
|
|
|
|
// Don't even try to export unresolved libraries
|
|
|
|
if (!library.Resolved)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Equals(LibraryType.Package, library.Identity.Type))
|
|
|
|
{
|
|
|
|
return ExportPackage((PackageDescription)library);
|
|
|
|
}
|
|
|
|
else if (Equals(LibraryType.Project, library.Identity.Type))
|
|
|
|
{
|
|
|
|
return ExportProject((ProjectDescription)library);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ExportFrameworkLibrary(library);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private LibraryExport ExportPackage(PackageDescription package)
|
|
|
|
{
|
2015-10-21 15:21:14 -07:00
|
|
|
var nativeLibraries = new List<LibraryAsset>();
|
2015-10-13 14:31:29 -07:00
|
|
|
PopulateAssets(package, package.Target.NativeLibraries, nativeLibraries);
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
var runtimeAssemblies = new List<LibraryAsset>();
|
2015-10-13 14:31:29 -07:00
|
|
|
PopulateAssets(package, package.Target.RuntimeAssemblies, runtimeAssemblies);
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
var compileAssemblies = new List<LibraryAsset>();
|
2015-10-13 14:31:29 -07:00
|
|
|
PopulateAssets(package, package.Target.CompileTimeAssemblies, compileAssemblies);
|
|
|
|
|
|
|
|
var sourceReferences = new List<string>();
|
|
|
|
foreach (var sharedSource in GetSharedSources(package))
|
|
|
|
{
|
|
|
|
sourceReferences.Add(sharedSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new LibraryExport(package, compileAssemblies, sourceReferences, runtimeAssemblies, nativeLibraries);
|
|
|
|
}
|
|
|
|
|
|
|
|
private LibraryExport ExportProject(ProjectDescription project)
|
|
|
|
{
|
2015-10-21 15:21:14 -07:00
|
|
|
var compileAssemblies = new List<LibraryAsset>();
|
2015-10-13 14:31:29 -07:00
|
|
|
var sourceReferences = new List<string>();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath))
|
|
|
|
{
|
|
|
|
// Project specifies a pre-compiled binary. We're done!
|
|
|
|
var assemblyPath = ResolvePath(project.Project, _configuration, project.TargetFrameworkInfo.AssemblyPath);
|
2015-10-21 15:21:14 -07:00
|
|
|
compileAssemblies.Add(new LibraryAsset(
|
|
|
|
project.Project.Name,
|
|
|
|
assemblyPath,
|
|
|
|
Path.Combine(project.Project.ProjectDirectory, assemblyPath)));
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
|
2015-10-16 22:50:44 -07:00
|
|
|
// Add shared sources
|
|
|
|
foreach (var sharedFile in project.Project.Files.SharedFiles)
|
|
|
|
{
|
|
|
|
sourceReferences.Add(sharedFile);
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// No support for ref or native in projects, so runtimeAssemblies is just the same as compileAssemblies and nativeLibraries are empty
|
2015-10-21 15:21:14 -07:00
|
|
|
return new LibraryExport(project, compileAssemblies, sourceReferences, compileAssemblies, Enumerable.Empty<LibraryAsset>());
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
2015-11-01 16:21:10 -08:00
|
|
|
|
2015-10-13 14:31:29 -07:00
|
|
|
private static string ResolvePath(Project project, string configuration, string path)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = PathUtility.GetPathWithDirectorySeparator(path);
|
|
|
|
|
|
|
|
path = path.Replace("{configuration}", configuration);
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
return path;
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private LibraryExport ExportFrameworkLibrary(LibraryDescription library)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(library.Path))
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We assume the path is to an assembly. Framework libraries only export compile-time stuff
|
|
|
|
// since they assume the runtime library is present already
|
|
|
|
return new LibraryExport(
|
|
|
|
library,
|
2015-10-21 15:21:14 -07:00
|
|
|
new[] { new LibraryAsset(library.Identity.Name, library.Path, library.Path) },
|
2015-10-13 14:31:29 -07:00
|
|
|
Enumerable.Empty<string>(),
|
2015-10-21 15:21:14 -07:00
|
|
|
Enumerable.Empty<LibraryAsset>(),
|
|
|
|
Enumerable.Empty<LibraryAsset>());
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<string> GetSharedSources(PackageDescription package)
|
|
|
|
{
|
|
|
|
return package
|
|
|
|
.Library
|
|
|
|
.Files
|
|
|
|
.Where(path => path.StartsWith("shared" + Path.DirectorySeparatorChar))
|
|
|
|
.Select(path => Path.Combine(package.Path, path));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
private void PopulateAssets(PackageDescription package, IEnumerable<LockFileItem> section, IList<LibraryAsset> assets)
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
foreach (var assemblyPath in section)
|
|
|
|
{
|
2015-11-12 03:50:38 -08:00
|
|
|
if (IsPlaceholderFile(assemblyPath))
|
2015-10-13 14:31:29 -07:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-21 15:21:14 -07:00
|
|
|
assets.Add(new LibraryAsset(
|
|
|
|
Path.GetFileNameWithoutExtension(assemblyPath),
|
|
|
|
assemblyPath,
|
|
|
|
Path.Combine(package.Path, assemblyPath)));
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
|
|
|
}
|
2015-11-01 16:21:10 -08:00
|
|
|
|
2015-11-12 03:50:38 -08:00
|
|
|
private static bool IsPlaceholderFile(string path)
|
|
|
|
{
|
|
|
|
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
|
|
|
|
}
|
|
|
|
|
2015-11-01 16:21:10 -08:00
|
|
|
private static bool LibraryIsOfType(LibraryType type, LibraryDescription library)
|
|
|
|
{
|
|
|
|
return type.Equals(LibraryType.Unspecified) || // No type filter was requested
|
|
|
|
library.Identity.Type.Equals(type); // OR, library type matches requested type
|
|
|
|
}
|
2015-10-13 14:31:29 -07:00
|
|
|
}
|
2015-10-21 15:21:14 -07:00
|
|
|
}
|