diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs b/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs index 92c303265851..3f41716858f9 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs @@ -27,6 +27,7 @@ internal class DependencyContextBuilder private IEnumerable _dependencyReferences; private Dictionary _referenceProjectInfos; private IEnumerable _excludeFromPublishPackageIds; + private IEnumerable _runtimePackAssets = Enumerable.Empty(); private CompilationOptions _compilationOptions; private string _referenceAssembliesPath; private Dictionary _filteredPackages; @@ -126,6 +127,12 @@ public DependencyContextBuilder WithExcludeFromPublishAssets(IEnumerable return this; } + public DependencyContextBuilder WithRuntimePackAssets(IEnumerable runtimePackAssets) + { + _runtimePackAssets = runtimePackAssets; + return this; + } + public DependencyContextBuilder WithCompilationOptions(CompilationOptions compilationOptions) { _compilationOptions = compilationOptions; @@ -177,6 +184,7 @@ public DependencyContext Build() }); } runtimeLibraries = runtimeLibraries + .Concat(GetRuntimePackLibraries(_runtimePackAssets)) .Concat(GetLibraries(runtimeExports, libraryLookup, dependencyLookup, runtime: true).Cast()) .Concat(GetDirectReferenceRuntimeLibraries()) .Concat(GetDependencyReferenceRuntimeLibraries()); @@ -314,6 +322,10 @@ private RuntimeLibrary GetProjectRuntimeLibrary( RuntimeAssetGroup[] runtimeAssemblyGroups = new[] { new RuntimeAssetGroup(string.Empty, projectInfo.OutputName) }; List dependencies = GetProjectDependencies(projectContext, dependencyLookup, includeCompilationLibraries); + foreach (var runtimePackGroup in _runtimePackAssets.GroupBy(asset => asset.PackageName + "/" + asset.PackageVersion)) + { + dependencies.Add(new Dependency("runtimepack." + runtimePackGroup.First().PackageName, runtimePackGroup.First().PackageVersion)); + } return CreateRuntimeLibrary( type: "project", @@ -345,6 +357,37 @@ private CompilationLibrary GetProjectCompilationLibrary( serviceable: false); } + private IEnumerable GetRuntimePackLibraries(IEnumerable runtimePackAssets) + { + return runtimePackAssets.GroupBy(asset => asset.PackageName + "/" + asset.PackageVersion).Select( + runtimePackAssetGroup => + { + // Prefix paths with "./" to workaround https://github.com/dotnet/core-setup/issues/4978 + List runtimeAssemblyGroups = new List() + { + new RuntimeAssetGroup(string.Empty, + runtimePackAssetGroup.Where(asset => asset.AssetType == AssetType.Runtime) + .Select(asset => CreateRuntimeFile("./" + asset.DestinationSubPath, asset.SourcePath))) + }; + List nativeLibraryGroups = new List() + { + new RuntimeAssetGroup(string.Empty, + runtimePackAssetGroup.Where(asset => asset.AssetType == AssetType.Native) + .Select(asset => CreateRuntimeFile($"./" + asset.DestinationSubPath, asset.SourcePath))) + }; + + return new RuntimeLibrary("runtimepack", + "runtimepack." + runtimePackAssetGroup.First().PackageName, + runtimePackAssetGroup.First().PackageVersion, + hash: string.Empty, + runtimeAssemblyGroups, + nativeLibraryGroups, + resourceAssemblies: Enumerable.Empty(), + dependencies: Enumerable.Empty(), + serviceable: false); + }); + } + private IEnumerable GetLibraries( IEnumerable exports, LockFileLookup libraryLookup, diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs index 5204b9abb2fe..851d1316e079 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs @@ -67,6 +67,8 @@ public class GenerateDepsFile : TaskBase [Required] public ITaskItem[] FilesToSkip { get; set; } + public ITaskItem[] RuntimePackAssets { get; set; } + public ITaskItem CompilerOptions { get; set; } public ITaskItem[] ExcludeFromPublishPackageReferences { get; set; } @@ -136,6 +138,9 @@ protected override void ExecuteCore() IEnumerable excludeFromPublishAssets = PackageReferenceConverter.GetPackageIds(ExcludeFromPublishPackageReferences); + IEnumerable runtimePackAssets = RuntimePackAssets == null ? Enumerable.Empty() : + RuntimePackAssets.Select(item => RuntimePackAssetInfo.FromItem(item)); + ProjectContext projectContext = lockFile.CreateProjectContext( NuGetUtils.ParseFrameworkName(TargetFramework), RuntimeIdentifier, @@ -150,6 +155,7 @@ protected override void ExecuteCore() .WithDependencyReferences(dependencyReferences) .WithReferenceProjectInfos(referenceProjects) .WithExcludeFromPublishAssets(excludeFromPublishAssets) + .WithRuntimePackAssets(runtimePackAssets) .WithCompilationOptions(compilationOptions) .WithReferenceAssembliesPath(FrameworkReferenceResolver.GetDefaultReferenceAssembliesPath()) .WithPackagesThatWhereFiltered(GetFilteredPackages()) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs index 5ccb25e04816..990c040c1343 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs @@ -44,15 +44,15 @@ public class ResolveFrameworkReferences : TaskBase [Output] public ITaskItem[] PackagesToDownload { get; set; } - [Output] - public ITaskItem[] PackagesToReference { get; set; } - [Output] public ITaskItem[] RuntimeFrameworks { get; set; } [Output] public ITaskItem[] TargetingPacks { get; set; } + [Output] + public ITaskItem[] RuntimePacks { get; set; } + // There should only be one AppHost item, but we use an item here so we can attach metadata to it // (ie the apphost pack name and version, and the relative path to the apphost inside of it so // we can resolve the full path later) @@ -70,9 +70,9 @@ protected override void ExecuteCore() .ToDictionary(kfr => kfr.Name); List packagesToDownload = new List(); - List packagesToReference = new List(); List runtimeFrameworks = new List(); List targetingPacks = new List(); + List runtimePacks = new List(); List unresolvedFrameworkReferences = new List(); string appHostPackPattern = null; @@ -149,10 +149,17 @@ protected override void ExecuteCore() string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimePackRuntimeIdentifier); TaskItem runtimePackItem = new TaskItem(runtimePackName); - runtimePackItem.SetMetadata(MetadataKeys.Version, knownFrameworkReference.LatestRuntimeFrameworkVersion); - runtimePackItem.SetMetadata(MetadataKeys.IsImplicitlyDefined, "true"); + runtimePackItem.SetMetadata(MetadataKeys.PackageName, runtimePackName); + runtimePackItem.SetMetadata(MetadataKeys.PackageVersion, knownFrameworkReference.LatestRuntimeFrameworkVersion); + runtimePackItem.SetMetadata("FrameworkReference", knownFrameworkReference.Name); + runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimePackRuntimeIdentifier); + + runtimePacks.Add(runtimePackItem); + + TaskItem packageToDownload = new TaskItem(runtimePackName); + packageToDownload.SetMetadata(MetadataKeys.Version, knownFrameworkReference.LatestRuntimeFrameworkVersion); - packagesToReference.Add(runtimePackItem); + packagesToDownload.Add(packageToDownload); } } } @@ -228,11 +235,6 @@ protected override void ExecuteCore() PackagesToDownload = packagesToDownload.ToArray(); } - if (packagesToReference.Any()) - { - PackagesToReference = packagesToReference.ToArray(); - } - if (runtimeFrameworks.Any()) { RuntimeFrameworks = runtimeFrameworks.ToArray(); @@ -243,6 +245,11 @@ protected override void ExecuteCore() TargetingPacks = targetingPacks.ToArray(); } + if (runtimePacks.Any()) + { + RuntimePacks = runtimePacks.ToArray(); + } + if (unresolvedFrameworkReferences.Any()) { UnresolvedFrameworkReferences = unresolvedFrameworkReferences.ToArray(); diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs new file mode 100644 index 000000000000..1f00423ac7c6 --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.NET.Build.Tasks +{ + public class ResolveRuntimePackAssets : TaskBase + { + public ITaskItem[] ResolvedRuntimePacks { get; set; } + + [Output] + public ITaskItem[] RuntimePackAssets { get; set; } + + protected override void ExecuteCore() + { + List runtimePackAssets = new List(); + + foreach (var runtimePack in ResolvedRuntimePacks) + { + string runtimePackRoot = runtimePack.GetMetadata(MetadataKeys.PackageDirectory); + string runtimeIdentifier = runtimePack.GetMetadata(MetadataKeys.RuntimeIdentifier); + + // These hard-coded paths are temporary until we have "real" runtime packs, which will likely have a flattened + // folder structure and a manifest indicating how the files should be used: https://github.com/dotnet/cli/issues/10442 + string runtimeAssetsPath = Path.Combine(runtimePackRoot, "runtimes", runtimeIdentifier, "lib", "netcoreapp3.0"); + string nativeAssetsPath = Path.Combine(runtimePackRoot, "runtimes", runtimeIdentifier, "native"); + + var runtimeAssets = Directory.Exists(runtimeAssetsPath) ? Directory.GetFiles(runtimeAssetsPath) : Array.Empty(); + var nativeAssets = Directory.Exists(nativeAssetsPath) ? Directory.GetFiles(nativeAssetsPath) : Array.Empty(); + + void AddAsset(string assetPath, string assetType) + { + if (assetPath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || + assetPath.EndsWith(".map", StringComparison.OrdinalIgnoreCase) || + assetPath.EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) + { + // Don't add assets for these files (shouldn't be necessary if/once we have a manifest in the runtime pack + // https://github.com/dotnet/cli/issues/10442 + return; + } + + var assetItem = new TaskItem(assetPath); + + assetItem.SetMetadata(MetadataKeys.CopyLocal, "true"); + assetItem.SetMetadata(MetadataKeys.DestinationSubPath, Path.GetFileName(assetPath)); + assetItem.SetMetadata(MetadataKeys.AssetType, assetType); + assetItem.SetMetadata(MetadataKeys.PackageName, runtimePack.GetMetadata(MetadataKeys.PackageName)); + assetItem.SetMetadata(MetadataKeys.PackageVersion, runtimePack.GetMetadata(MetadataKeys.PackageVersion)); + assetItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimeIdentifier); + + runtimePackAssets.Add(assetItem); + } + + foreach (var asset in runtimeAssets) + { + AddAsset(asset, "runtime"); + } + foreach (var asset in nativeAssets) + { + AddAsset(asset, "native"); + } + } + + RuntimePackAssets = runtimePackAssets.ToArray(); + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/RuntimePackAssetInfo.cs b/src/Tasks/Microsoft.NET.Build.Tasks/RuntimePackAssetInfo.cs new file mode 100644 index 000000000000..fbfd56b9ae3c --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks/RuntimePackAssetInfo.cs @@ -0,0 +1,50 @@ +// 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 Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks +{ + internal class RuntimePackAssetInfo + { + public string SourcePath { get; set; } + + public string DestinationSubPath { get; set; } + + public AssetType AssetType { get; set; } + + public string PackageName { get; set; } + + public string PackageVersion { get; set; } + + public string PackageRuntimeIdentifier { get; set; } + + public static RuntimePackAssetInfo FromItem(ITaskItem item) + { + var assetInfo = new RuntimePackAssetInfo(); + assetInfo.SourcePath = item.ItemSpec; + assetInfo.DestinationSubPath = item.GetMetadata(MetadataKeys.DestinationSubPath); + + string assetTypeString = item.GetMetadata(MetadataKeys.AssetType); + if (assetTypeString.Equals("runtime", StringComparison.OrdinalIgnoreCase)) + { + assetInfo.AssetType = AssetType.Runtime; + } + else if (assetTypeString.Equals("native", StringComparison.OrdinalIgnoreCase)) + { + assetInfo.AssetType = AssetType.Native; + } + else + { + throw new InvalidOperationException("Unexpected asset type: " + item.GetMetadata(MetadataKeys.AssetType)); + } + + assetInfo.PackageName = item.GetMetadata(MetadataKeys.PackageName); + assetInfo.PackageVersion = item.GetMetadata(MetadataKeys.PackageVersion); + assetInfo.PackageRuntimeIdentifier = item.GetMetadata(MetadataKeys.RuntimeIdentifier); + + return assetInfo; + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets index 95ba130e1128..bbeecbbbe09e 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets @@ -276,7 +276,8 @@ Copyright (c) .NET Foundation. All rights reserved. + _DefaultMicrosoftNETPlatformLibrary; + ResolveRuntimePackAssets"> + + <_ResolvedCopyLocalPublishAssets Include="@(RuntimePackAsset)"/> + + <_ResolvedCopyLocalPublishAssets Remove="@(_NativeRestoredAppHostNETCore)" /> @@ -599,7 +604,8 @@ Copyright (c) .NET Foundation. All rights reserved. _DefaultMicrosoftNETPlatformLibrary; _HandlePackageFileConflicts; _HandlePackageFileConflictsForPublish; - _ComputeReferenceAssemblies" + _ComputeReferenceAssemblies; + ResolveRuntimePackAssets" Condition="'$(GenerateDependencyFile)' == 'true' and '$(_UseBuildDependencyFile)' != 'true'"> @@ -618,6 +624,7 @@ Copyright (c) .NET Foundation. All rights reserved. ReferenceDependencyPaths="@(ReferenceDependencyPaths)" ReferenceSatellitePaths="@(ReferenceSatellitePaths)" ReferenceAssemblies="@(_ReferenceAssemblies)" + RuntimePackAssets="@(RuntimePackAsset)" IncludeMainProject="$(IncludeMainProjectInDepsFile)" RuntimeIdentifier="$(RuntimeIdentifier)" PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.TargetingPackResolution.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.TargetingPackResolution.targets index ecfa48367d07..de93ac740755 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.TargetingPackResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.TargetingPackResolution.targets @@ -58,9 +58,9 @@ Copyright (c) .NET Foundation. All rights reserved. DotNetAppHostExecutableNameWithoutExtension="$(_DotNetAppHostExecutableNameWithoutExtension)"> - + @@ -142,6 +142,32 @@ Copyright (c) .NET Foundation. All rights reserved. @(ResolvedAppHostPack->'%(Path)') + + + + + + + + + + + + + + + + + + + + +