Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void ItBuildsDependencyContextsFromProjectLockFiles(
SingleProjectInfo mainProject = SingleProjectInfo.Create(
"/usr/Path",
mainProjectName,
".dll",
mainProjectVersion,
satelliteAssemblies ?? new ITaskItem[] { });

Expand Down
66 changes: 66 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ public class DependencyContextBuilder
private readonly VersionFolderPathResolver _versionFolderPathResolver;
private readonly SingleProjectInfo _mainProjectInfo;
private readonly ProjectContext _projectContext;
private IEnumerable<ReferenceInfo> _frameworkReferences;
private Dictionary<string, SingleProjectInfo> _referenceProjectInfos;
private IEnumerable<string> _privateAssetPackageIds;
private CompilationOptions _compilationOptions;
private string _referenceAssembliesPath;

public DependencyContextBuilder(SingleProjectInfo mainProjectInfo, ProjectContext projectContext)
{
Expand All @@ -33,6 +35,14 @@ public DependencyContextBuilder(SingleProjectInfo mainProjectInfo, ProjectContex
_versionFolderPathResolver = new VersionFolderPathResolver(path: null);
}

public DependencyContextBuilder WithFrameworkReferences(IEnumerable<ReferenceInfo> frameworkReferences)
{
// note: Framework libraries only export compile-time stuff
// since they assume the runtime library is present already
_frameworkReferences = frameworkReferences;
return this;
}

public DependencyContextBuilder WithReferenceProjectInfos(Dictionary<string, SingleProjectInfo> referenceProjectInfos)
{
_referenceProjectInfos = referenceProjectInfos;
Expand All @@ -51,6 +61,12 @@ public DependencyContextBuilder WithCompilationOptions(CompilationOptions compil
return this;
}

public DependencyContextBuilder WithReferenceAssembliesPath(string referenceAssembliesPath)
{
_referenceAssembliesPath = EnsureTrailingSlash(referenceAssembliesPath);
return this;
}

public DependencyContext Build()
{
bool includeCompilationLibraries = _compilationOptions != null;
Expand Down Expand Up @@ -88,6 +104,7 @@ public DependencyContext Build()
dependencyLookup);
compilationLibraries =
new[] { projectCompilationLibrary }
.Concat(GetFrameworkLibraries())
.Concat(GetLibraries(compilationExports, libraryLookup, dependencyLookup, runtime: false).Cast<CompilationLibrary>());
}
else
Expand Down Expand Up @@ -372,6 +389,34 @@ private IEnumerable<string> GetCompileTimeAssemblies(LockFileTargetLibrary targe
}
}

private IEnumerable<CompilationLibrary> GetFrameworkLibraries()
{
return _frameworkReferences
?.Select(r => new CompilationLibrary(
type: "referenceassembly",
name: r.Name,
version: r.Version,
hash: string.Empty,
assemblies: new[] { ResolveFrameworkReferencePath(r.FullPath) },
dependencies: Enumerable.Empty<Dependency>(),
serviceable: false))
??
Enumerable.Empty<CompilationLibrary>();
}

private string ResolveFrameworkReferencePath(string fullPath)
{
// If resolved path is under ReferenceAssembliesPath store it as a relative to it
// if not, save only assembly name and try to find it somehow later
if (!string.IsNullOrEmpty(_referenceAssembliesPath) &&
fullPath?.StartsWith(_referenceAssembliesPath) == true)
{
return fullPath.Substring(_referenceAssembliesPath.Length);
}

return Path.GetFileName(fullPath);
}

private static void EnsureProjectInfo(SingleProjectInfo referenceProjectInfo, string libraryName)
{
if (referenceProjectInfo == null)
Expand Down Expand Up @@ -400,5 +445,26 @@ private SingleProjectInfo GetProjectInfo(LockFileLibrary library)

return referenceProjectInfo;
}

private static string EnsureTrailingSlash(string path)
{
return EnsureTrailingCharacter(path, Path.DirectorySeparatorChar);
}

private static string EnsureTrailingCharacter(string path, char trailingCharacter)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}

// if the path is empty, we want to return the original string instead of a single trailing character.
if (path.Length == 0 || path[path.Length - 1] == trailingCharacter)
{
return path;
}

return path + trailingCharacter;
}
}
}
52 changes: 52 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/FrameworkReferenceResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 Microsoft.Build.Framework;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.DependencyModel.Resolution;

namespace Microsoft.NET.Build.Tasks
{
internal static class FrameworkReferenceResolver
{
public static string GetDefaultReferenceAssembliesPath()
{
// Allow setting the reference assemblies path via an environment variable
var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve();

if (!string.IsNullOrEmpty(referenceAssembliesPath))
{
return referenceAssembliesPath;
}

if (RuntimeEnvironment.OperatingSystemPlatform != Platform.Windows)
{
// There is no reference assemblies path outside of windows
// The environment variable can be used to specify one
return null;
}

// References assemblies are in %ProgramFiles(x86)% on
// 64 bit machines
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles(x86)");

if (string.IsNullOrEmpty(programFiles))
{
// On 32 bit machines they are in %ProgramFiles%
programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
}

if (string.IsNullOrEmpty(programFiles))
{
// Reference assemblies aren't installed
return null;
}

return Path.Combine(
programFiles,
"Reference Assemblies", "Microsoft", "Framework");
}
}
}
22 changes: 18 additions & 4 deletions src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ public class GenerateDepsFile : TaskBase
[Required]
public string AssemblyName { get; set; }

[Required]
public string AssemblyExtension { get; set; }

[Required]
public string AssemblyVersion { get; set; }

[Required]
public ITaskItem[] AssemblySatelliteAssemblies { get; set; }

[Required]
public ITaskItem[] ProjectReferencePaths { get; set; }
public ITaskItem[] ReferencePaths { get; set; }

[Required]
public ITaskItem[] ProjectReferenceSatellitePaths { get; set; }
Expand All @@ -57,9 +60,18 @@ protected override void ExecuteCore()
LockFile lockFile = new LockFileCache(BuildEngine4).GetLockFile(AssetsFilePath);
CompilationOptions compilationOptions = CompilationOptionsConverter.ConvertFrom(CompilerOptions);

SingleProjectInfo mainProject = SingleProjectInfo.Create(ProjectPath, AssemblyName, AssemblyVersion, AssemblySatelliteAssemblies);
Dictionary<string, SingleProjectInfo> referenceProjects = SingleProjectInfo.CreateFromProjectReferences(
ProjectReferencePaths,
SingleProjectInfo mainProject = SingleProjectInfo.Create(
ProjectPath,
AssemblyName,
AssemblyExtension,
AssemblyVersion,
AssemblySatelliteAssemblies);

IEnumerable<ReferenceInfo> frameworkReferences =
ReferenceInfo.CreateFrameworkReferenceInfos(ReferencePaths);

Dictionary<string, SingleProjectInfo> referenceProjects = SingleProjectInfo.CreateProjectReferenceInfos(
ReferencePaths,
ProjectReferenceSatellitePaths);

IEnumerable<string> privateAssets = PackageReferenceConverter.GetPackageIds(PrivateAssetsPackageReferences);
Expand All @@ -70,9 +82,11 @@ protected override void ExecuteCore()
PlatformLibraryName);

DependencyContext dependencyContext = new DependencyContextBuilder(mainProject, projectContext)
.WithFrameworkReferences(frameworkReferences)
.WithReferenceProjectInfos(referenceProjects)
.WithPrivateAssets(privateAssets)
.WithCompilationOptions(compilationOptions)
.WithReferenceAssembliesPath(FrameworkReferenceResolver.GetDefaultReferenceAssembliesPath())
.Build();

var writer = new DependencyContextWriter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="LockFileLookup.cs" />
<Compile Include="FrameworkReferenceResolver.cs" />
<Compile Include="ReportUserErrorException.cs" />
<Compile Include="ReferenceInfo.cs" />
<Compile Include="TaskBase.cs" />
<Compile Include="PackageReferenceConverter.cs" />
<Compile Include="NugetContentAssetPreprocessor.cs" />
Expand Down
42 changes: 42 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/ReferenceInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 System.IO;
using System.Linq;
using Microsoft.Build.Framework;

namespace Microsoft.NET.Build.Tasks
{
public class ReferenceInfo
{
public string Name { get; }
public string Version { get; }
public string FullPath { get; }

private ReferenceInfo(string name, string version, string fullPath)
{
Name = name;
Version = version;
FullPath = fullPath;
}

public static IEnumerable<ReferenceInfo> CreateFrameworkReferenceInfos(IEnumerable<ITaskItem> referencePaths)
{
IEnumerable<ITaskItem> frameworkReferencePaths = referencePaths
.Where(r => r.GetBooleanMetadata("FrameworkFile") == true);

List<ReferenceInfo> frameworkReferences = new List<ReferenceInfo>();
foreach (ITaskItem frameworkReferencePath in frameworkReferencePaths)
{
string fullPath = frameworkReferencePath.ItemSpec;
string name = Path.GetFileNameWithoutExtension(fullPath);
string version = frameworkReferencePath.GetMetadata("Version");

frameworkReferences.Add(new ReferenceInfo(name, version, fullPath));
}

return frameworkReferences;
}
}
}
15 changes: 10 additions & 5 deletions src/Tasks/Microsoft.NET.Build.Tasks/SingleProjectInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Build.Framework;

Expand Down Expand Up @@ -30,7 +31,7 @@ private SingleProjectInfo(string projectPath, string name, string version, strin
_resourceAssemblies = resourceAssemblies;
}

public static SingleProjectInfo Create(string projectPath, string name, string version, ITaskItem[] satelliteAssemblies)
public static SingleProjectInfo Create(string projectPath, string name, string fileExtension, string version, ITaskItem[] satelliteAssemblies)
{
List<ResourceAssemblyInfo> resourceAssemblies = new List<ResourceAssemblyInfo>();

Expand All @@ -42,15 +43,19 @@ public static SingleProjectInfo Create(string projectPath, string name, string v
resourceAssemblies.Add(new ResourceAssemblyInfo(culture, relativePath));
}

return new SingleProjectInfo(projectPath, name, version, $"{name}.dll", resourceAssemblies);
string outputName = name + fileExtension;
return new SingleProjectInfo(projectPath, name, version, outputName, resourceAssemblies);
}

public static Dictionary<string, SingleProjectInfo> CreateFromProjectReferences(
ITaskItem[] projectReferencePaths,
ITaskItem[] projectReferenceSatellitePaths)
public static Dictionary<string, SingleProjectInfo> CreateProjectReferenceInfos(
IEnumerable<ITaskItem> referencePaths,
IEnumerable<ITaskItem> projectReferenceSatellitePaths)
{
Dictionary<string, SingleProjectInfo> projectReferences = new Dictionary<string, SingleProjectInfo>();

IEnumerable<ITaskItem> projectReferencePaths = referencePaths
.Where(r => string.Equals(r.GetMetadata("ReferenceSourceTarget"), "ProjectReference", StringComparison.OrdinalIgnoreCase));

foreach (ITaskItem projectReferencePath in projectReferencePaths)
{
string sourceProjectFile = projectReferencePath.GetMetadata("MSBuildSourceProjectFile");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,9 +437,10 @@ Copyright (c) .NET Foundation. All rights reserved.
DepsFilePath="$(PublishDepsFilePath)"
TargetFramework="$(TargetFrameworkMoniker)"
AssemblyName="$(AssemblyName)"
AssemblyExtension="$(TargetExt)"
AssemblyVersion="$(Version)"
AssemblySatelliteAssemblies="@(IntermediateSatelliteAssembliesWithTargetPath)"
ProjectReferencePaths="@(ReferencePath->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"
ReferencePaths="@(ReferencePath)"
ProjectReferenceSatellitePaths="@(ReferenceSatellitePaths)"
RuntimeIdentifier="$(RuntimeIdentifier)"
PlatformLibraryName="$(MicrosoftNETPlatformLibrary)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ Copyright (c) .NET Foundation. All rights reserved.
DepsFilePath="$(ProjectDepsFilePath)"
TargetFramework="$(TargetFrameworkMoniker)"
AssemblyName="$(AssemblyName)"
AssemblyExtension="$(TargetExt)"
AssemblyVersion="$(Version)"
AssemblySatelliteAssemblies="@(IntermediateSatelliteAssembliesWithTargetPath)"
ProjectReferencePaths="@(ReferencePath->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"
ReferencePaths="@(ReferencePath)"
ProjectReferenceSatellitePaths="@(ReferenceSatellitePaths)"
RuntimeIdentifier="$(RuntimeIdentifier)"
PlatformLibraryName="$(MicrosoftNETPlatformLibrary)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public void It_publishes_the_project_with_a_refs_folder_and_correct_deps_file()
dependencyContext.CompilationOptions.EmitEntryPoint.Should().Be(true);
dependencyContext.CompilationOptions.DebugType.Should().Be("portable");

dependencyContext.CompileLibraries.Count.Should().Be(targetFramework == "net46" ? 51 : 116);
dependencyContext.CompileLibraries.Count.Should().Be(targetFramework == "net46" ? 53 : 116);

// Ensure P2P references are specified correctly
var testLibrary = dependencyContext
Expand All @@ -90,6 +90,22 @@ public void It_publishes_the_project_with_a_refs_folder_and_correct_deps_file()

testLibrary.Assemblies.Count.Should().Be(1);
testLibrary.Assemblies[0].Should().Be("TestLibrary.dll");

// Ensure framework references are specified correctly
if (targetFramework == "net46")
{
var mscorlibLibrary = dependencyContext
.CompileLibraries
.FirstOrDefault(l => string.Equals(l.Name, "mscorlib", StringComparison.OrdinalIgnoreCase));
mscorlibLibrary.Assemblies.Count.Should().Be(1);
mscorlibLibrary.Assemblies[0].Should().Be(".NETFramework/v4.6/mscorlib.dll");

var systemCoreLibrary = dependencyContext
.CompileLibraries
.FirstOrDefault(l => string.Equals(l.Name, "system.core", StringComparison.OrdinalIgnoreCase));
systemCoreLibrary.Assemblies.Count.Should().Be(1);
systemCoreLibrary.Assemblies[0].Should().Be(".NETFramework/v4.6/System.Core.dll");
}
}
}
}
Expand Down