trim build dependencies from output
This commit is contained in:
parent
afa471cde3
commit
08c4aae6a9
11 changed files with 209 additions and 51 deletions
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0-rc2-*",
|
||||
"type": "platform"
|
||||
},
|
||||
"xunit.core": "2.1.0",
|
||||
"xunit": {
|
||||
"version": "2.1.0",
|
||||
"type": "build"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [ "portable-net451+win8" ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0-rc2-*",
|
||||
"type": "platform"
|
||||
},
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [ "portable-net451+win8" ]
|
||||
}
|
||||
},
|
||||
"runtimes": {
|
||||
"win7-x64": {},
|
||||
"win7-x86": {}
|
||||
}
|
||||
}
|
|
@ -109,8 +109,8 @@ namespace Microsoft.DotNet.Cli.Build
|
|||
|
||||
ExecSilent(_crossGenPath, crossgenArgs, env);
|
||||
|
||||
File.Delete(file);
|
||||
File.Move(tempPathName, file);
|
||||
File.Copy(tempPathName, file, overwrite: true);
|
||||
File.Delete(tempPathName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,14 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
private readonly CommonCompilerOptions _compilerOptions;
|
||||
|
||||
public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter, string configuration)
|
||||
: this(context, outputPaths, outputPaths.RuntimeOutputPath, outputPaths.IntermediateOutputDirectoryPath, exporter, configuration) { }
|
||||
|
||||
public Executable(ProjectContext context, OutputPaths outputPaths, string runtimeOutputPath, string intermediateOutputDirectoryPath, LibraryExporter exporter, string configuration)
|
||||
{
|
||||
_context = context;
|
||||
_outputPaths = outputPaths;
|
||||
_runtimeOutputPath = outputPaths.RuntimeOutputPath;
|
||||
_intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;
|
||||
_runtimeOutputPath = runtimeOutputPath;
|
||||
_intermediateOutputPath = intermediateOutputDirectoryPath;
|
||||
_exporter = exporter;
|
||||
_configuration = configuration;
|
||||
_compilerOptions = _context.ProjectFile.GetCompilerOptions(_context.TargetFramework, configuration);
|
||||
|
@ -135,12 +138,9 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
|
||||
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter)
|
||||
{
|
||||
WriteDeps(exporter);
|
||||
if (_context.ProjectFile.HasRuntimeOutput(_configuration))
|
||||
{
|
||||
WriteRuntimeConfig(exporter);
|
||||
WriteDevRuntimeConfig(exporter);
|
||||
}
|
||||
// When called this way we don't need to filter exports, so we pass the same list to both.
|
||||
var exports = exporter.GetAllExports().ToList();
|
||||
WriteConfigurationFiles(exports, exports, includeDevConfig: true);
|
||||
|
||||
var projectExports = exporter.GetDependencies(LibraryType.Project);
|
||||
CopyAssemblies(projectExports);
|
||||
|
@ -150,7 +150,20 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
CopyAssets(packageExports);
|
||||
}
|
||||
|
||||
private void WriteRuntimeConfig(LibraryExporter exporter)
|
||||
public void WriteConfigurationFiles(IEnumerable<LibraryExport> allExports, IEnumerable<LibraryExport> depsExports, bool includeDevConfig)
|
||||
{
|
||||
WriteDeps(depsExports);
|
||||
if (_context.ProjectFile.HasRuntimeOutput(_configuration))
|
||||
{
|
||||
WriteRuntimeConfig(allExports);
|
||||
if (includeDevConfig)
|
||||
{
|
||||
WriteDevRuntimeConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRuntimeConfig(IEnumerable<LibraryExport> allExports)
|
||||
{
|
||||
if (!_context.TargetFramework.IsDesktop())
|
||||
{
|
||||
|
@ -161,7 +174,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
var runtimeOptions = new JObject();
|
||||
json.Add("runtimeOptions", runtimeOptions);
|
||||
|
||||
WriteFramework(runtimeOptions, exporter);
|
||||
WriteFramework(runtimeOptions, allExports);
|
||||
WriteRuntimeOptions(runtimeOptions);
|
||||
|
||||
var runtimeConfigJsonFile =
|
||||
|
@ -175,15 +188,14 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
}
|
||||
}
|
||||
|
||||
private void WriteFramework(JObject runtimeOptions, LibraryExporter exporter)
|
||||
private void WriteFramework(JObject runtimeOptions, IEnumerable<LibraryExport> allExports)
|
||||
{
|
||||
var redistPackage = _context.PlatformLibrary;
|
||||
if (redistPackage != null)
|
||||
{
|
||||
var packageName = redistPackage.Identity.Name;
|
||||
|
||||
var redistExport = exporter.GetAllExports()
|
||||
.FirstOrDefault(e => e.Library.Identity.Name.Equals(packageName));
|
||||
var redistExport = allExports.FirstOrDefault(e => e.Library.Identity.Name.Equals(packageName));
|
||||
if (redistExport == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Platform package '{packageName}' was not present in the graph.");
|
||||
|
@ -212,7 +224,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
}
|
||||
}
|
||||
|
||||
private void WriteDevRuntimeConfig(LibraryExporter exporter)
|
||||
private void WriteDevRuntimeConfig()
|
||||
{
|
||||
if (_context.TargetFramework.IsDesktop())
|
||||
{
|
||||
|
@ -241,13 +253,12 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
|
|||
runtimeOptions.Add("additionalProbingPaths", additionalProbingPaths);
|
||||
}
|
||||
|
||||
public void WriteDeps(LibraryExporter exporter)
|
||||
public void WriteDeps(IEnumerable<LibraryExport> exports)
|
||||
{
|
||||
Directory.CreateDirectory(_runtimeOutputPath);
|
||||
|
||||
var includeCompile = _compilerOptions.PreserveCompilationContext == true;
|
||||
|
||||
var exports = exporter.GetAllExports().ToArray();
|
||||
var dependencyContext = new DependencyContextBuilder().Build(
|
||||
compilerOptions: includeCompile ? _compilerOptions : null,
|
||||
compilationExports: includeCompile ? exports : null,
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
.WithProjectResolver(ProjectResolver)
|
||||
.WithLockFileResolver(LockFileResolver)
|
||||
.WithProjectReaderSettings(ProjectReaderSettings);
|
||||
if(IsDesignTime)
|
||||
if (IsDesignTime)
|
||||
{
|
||||
builder.AsDesignTime();
|
||||
}
|
||||
|
@ -168,14 +168,14 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
var deduper = new HashSet<string>();
|
||||
foreach (var target in LockFile.Targets)
|
||||
{
|
||||
var id = $"{target.TargetFramework}/{target.RuntimeIdentifier}";
|
||||
var context = Clone()
|
||||
.WithTargetFramework(target.TargetFramework)
|
||||
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier }).Build();
|
||||
|
||||
var id = $"{context.TargetFramework}/{context.RuntimeIdentifier}";
|
||||
if (deduper.Add(id))
|
||||
{
|
||||
var builder = Clone()
|
||||
.WithTargetFramework(target.TargetFramework)
|
||||
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier });
|
||||
|
||||
yield return builder.Build();
|
||||
yield return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
|
||||
|
@ -9,13 +7,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
public static class ProjectModelPlatformExtensions
|
||||
{
|
||||
public static IEnumerable<LibraryExport> ExcludePlatformExports(this ProjectContext context, IEnumerable<LibraryExport> allExports)
|
||||
{
|
||||
var exclusionList = context.GetPlatformExclusionList(allExports);
|
||||
return allExports.Where(e => !exclusionList.Contains(e.Library.Identity.Name));
|
||||
}
|
||||
|
||||
public static HashSet<string> GetPlatformExclusionList(this ProjectContext context, IEnumerable<LibraryExport> allExports)
|
||||
public static HashSet<string> GetPlatformExclusionList(this ProjectContext context, IDictionary<string, LibraryExport> exports)
|
||||
{
|
||||
var exclusionList = new HashSet<string>();
|
||||
var redistPackage = context.PlatformLibrary;
|
||||
|
@ -23,9 +15,6 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
return exclusionList;
|
||||
}
|
||||
var exports = allExports
|
||||
.Where(e => e.Library.Identity.Type.Equals(LibraryType.Package))
|
||||
.ToDictionary(e => e.Library.Identity.Name);
|
||||
|
||||
var redistExport = exports[redistPackage.Identity.Name];
|
||||
|
||||
|
@ -34,7 +23,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
return exclusionList;
|
||||
}
|
||||
|
||||
private static void CollectDependencies(Dictionary<string, LibraryExport> exports, IEnumerable<LibraryRange> dependencies, HashSet<string> exclusionList)
|
||||
private static void CollectDependencies(IDictionary<string, LibraryExport> exports, IEnumerable<LibraryRange> dependencies, HashSet<string> exclusionList)
|
||||
{
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
|
@ -46,5 +35,34 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static HashSet<string> GetTypeBuildExclusionList(this ProjectContext context, IDictionary<string, LibraryExport> exports)
|
||||
{
|
||||
var acceptedExports = new HashSet<string>();
|
||||
|
||||
// Accept the root project, obviously :)
|
||||
acceptedExports.Add(context.RootProject.Identity.Name);
|
||||
|
||||
// Walk all dependencies, tagging exports. But don't walk through Build dependencies.
|
||||
CollectNonBuildDependencies(exports, context.RootProject.Dependencies, acceptedExports);
|
||||
|
||||
// Whatever is left in exports was brought in ONLY by a build dependency
|
||||
var exclusionList = new HashSet<string>(exports.Keys);
|
||||
exclusionList.ExceptWith(acceptedExports);
|
||||
return exclusionList;
|
||||
}
|
||||
|
||||
private static void CollectNonBuildDependencies(IDictionary<string, LibraryExport> exports, IEnumerable<LibraryRange> dependencies, HashSet<string> acceptedExports)
|
||||
{
|
||||
foreach (var dependency in dependencies)
|
||||
{
|
||||
var export = exports[dependency.Name];
|
||||
if (!dependency.Type.Equals(LibraryDependencyType.Build))
|
||||
{
|
||||
acceptedExports.Add(export.Library.Identity.Name);
|
||||
CollectNonBuildDependencies(exports, export.Library.Dependencies, acceptedExports);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,14 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
var buildOutputPaths = context.GetOutputPaths(configuration, buildBasePath);
|
||||
|
||||
var exports = exporter.GetAllExports();
|
||||
foreach (var export in context.ExcludePlatformExports(exports))
|
||||
|
||||
var exportsLookup = exports.ToDictionary(e => e.Library.Identity.Name);
|
||||
var platformExclusionList = context.GetPlatformExclusionList(exportsLookup);
|
||||
var buildExclusionList = context.GetTypeBuildExclusionList(exportsLookup);
|
||||
var allExclusionList = new HashSet<string>(platformExclusionList);
|
||||
allExclusionList.UnionWith(buildExclusionList);
|
||||
|
||||
foreach (var export in FilterExports(exports, allExclusionList))
|
||||
{
|
||||
Reporter.Verbose.WriteLine($"publish: Publishing {export.Library.Identity.ToString().Green().Bold()} ...");
|
||||
|
||||
|
@ -164,12 +171,9 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
|
||||
if (context.ProjectFile.HasRuntimeOutput(configuration) && !context.TargetFramework.IsDesktop())
|
||||
{
|
||||
PublishFiles(
|
||||
new[] {
|
||||
buildOutputPaths.RuntimeFiles.DepsJson,
|
||||
buildOutputPaths.RuntimeFiles.RuntimeConfigJson
|
||||
},
|
||||
outputPath);
|
||||
// Make executable in the new location
|
||||
var executable = new Executable(context, buildOutputPaths, outputPath, buildOutputPaths.IntermediateOutputDirectoryPath, exporter, configuration);
|
||||
executable.WriteConfigurationFiles(exports, FilterExports(exports, buildExclusionList), includeDevConfig: false);
|
||||
}
|
||||
|
||||
var contentFiles = new ContentFiles(context);
|
||||
|
@ -202,6 +206,11 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
return true;
|
||||
}
|
||||
|
||||
private static IEnumerable<LibraryExport> FilterExports(IEnumerable<LibraryExport> exports, HashSet<string> exclusionList)
|
||||
{
|
||||
return exports.Where(e => !exclusionList.Contains(e.Library.Identity.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters which export's RuntimeAssets should get copied to the output path.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Tests
|
||||
{
|
||||
public class ProjectContextBuilderTests
|
||||
public class ProjectContextBuilderTests : TestBase
|
||||
{
|
||||
private static readonly HashSet<string> KnownProperties = new HashSet<string>(StringComparer.Ordinal) {
|
||||
"Project",
|
||||
|
@ -48,7 +51,7 @@ namespace Microsoft.DotNet.ProjectModel.Tests
|
|||
var clonedBuilder = initialBuilder.Clone();
|
||||
|
||||
// Compare all the properties. This is a shallow clone, so they should all be exactly ReferenceEqual
|
||||
foreach(var prop in typeof(ProjectContextBuilder).GetTypeInfo().DeclaredProperties)
|
||||
foreach (var prop in typeof(ProjectContextBuilder).GetTypeInfo().DeclaredProperties)
|
||||
{
|
||||
KnownProperties.Remove(prop.Name).Should().BeTrue(because: $"{prop.Name} should be listed in the known properties to ensure it is properly tested.");
|
||||
|
||||
|
@ -65,5 +68,18 @@ namespace Microsoft.DotNet.ProjectModel.Tests
|
|||
|
||||
KnownProperties.Should().BeEmpty(because: "all properties should have been checked by the CloneTest");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildAllTargetsProperlyDeduplicatesTargets()
|
||||
{
|
||||
// Load all project contexts for the test project
|
||||
var contexts = new ProjectContextBuilder()
|
||||
.WithProjectDirectory(Path.Combine(TestAssetsManager.AssetsRoot, "TestProjectContextBuildAllDedupe"))
|
||||
.BuildAllTargets()
|
||||
.ToList();
|
||||
|
||||
// This is a portable app, so even though RIDs are specified, BuildAllTargets should only produce one output.
|
||||
Assert.Equal(1, contexts.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Microsoft.Extensions.Testing.Abstractions.UnitTests
|
|||
public void It_creates_a_pdb_reader_right_away()
|
||||
{
|
||||
var pdbReaderFactoryMock = new Mock<IPdbReaderFactory>();
|
||||
var sourceInformationProvider = new SourceInformationProvider(_pdbPath, null, pdbReaderFactoryMock.Object);
|
||||
var sourceInformationProvider = new SourceInformationProvider(_pdbPath, pdbReaderFactoryMock.Object);
|
||||
|
||||
pdbReaderFactoryMock.Verify(p => p.Create(_pdbPath), Times.Once);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace Microsoft.Extensions.Testing.Abstractions.UnitTests
|
|||
var pdbReaderFactoryMock = new Mock<IPdbReaderFactory>();
|
||||
pdbReaderFactoryMock.Setup(p => p.Create(_pdbPath)).Returns(pdbReaderMock.Object);
|
||||
|
||||
var sourceInformationProvider = new SourceInformationProvider(_pdbPath, null, pdbReaderFactoryMock.Object);
|
||||
var sourceInformationProvider = new SourceInformationProvider(_pdbPath, pdbReaderFactoryMock.Object);
|
||||
|
||||
var actualSourceInformation = sourceInformationProvider.GetSourceInformation(methodInfo);
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Testing.Abstractions.UnitTests
|
|||
pdbReaderFactoryMock.Setup(p => p.Create(_pdbPath)).Returns(pdbReaderMock.Object);
|
||||
|
||||
using (var sourceInformationProvider =
|
||||
new SourceInformationProvider(_pdbPath, null, pdbReaderFactoryMock.Object))
|
||||
new SourceInformationProvider(_pdbPath, pdbReaderFactoryMock.Object))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
51
test/dotnet-publish.Tests/PublishAppWithBuildDependency.cs
Normal file
51
test/dotnet-publish.Tests/PublishAppWithBuildDependency.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Publish.Tests
|
||||
{
|
||||
public class PublishAppWithBuildDependency : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void PublishExcludesBuildDependencies()
|
||||
{
|
||||
var testInstance = TestAssetsManager.CreateTestInstance("AppWithDirectDependencyAndTypeBuild")
|
||||
.WithLockFiles();
|
||||
|
||||
new RestoreCommand() { WorkingDirectory = testInstance.TestRoot }.Execute().Should().Pass();
|
||||
|
||||
var publishCommand = new PublishCommand(testInstance.TestRoot);
|
||||
var publishResult = publishCommand.Execute();
|
||||
publishResult.Should().Pass();
|
||||
|
||||
var publishDir = publishCommand.GetOutputDirectory(portable: true);
|
||||
|
||||
publishDir.Should().HaveFiles(new[]
|
||||
{
|
||||
// This one is directly referenced
|
||||
"xunit.core.dll"
|
||||
});
|
||||
|
||||
// But these are brought in only by the type:build dependency, and should not be published
|
||||
publishDir.Should().NotHaveFiles(new [] {
|
||||
"xunit.assert.dll"
|
||||
});
|
||||
|
||||
// Check the deps file
|
||||
var reader = new DependencyContextJsonReader();
|
||||
DependencyContext context;
|
||||
using (var file = File.OpenRead(Path.Combine(publishDir.FullName, "AppWithDirectDependencyAndTypeBuild.deps.json")))
|
||||
{
|
||||
context = reader.Read(file);
|
||||
}
|
||||
|
||||
context.RuntimeLibraries.Should().NotContain(l => string.Equals(l.Name, "xunit.assert"));
|
||||
context.CompileLibraries.Should().NotContain(l => string.Equals(l.Name, "xunit.assert"));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue