Make desktop publishing "half-portable" by default

This commit is contained in:
Pavel Krymets 2016-04-08 08:51:51 -07:00 committed by Andrew Stanton-Nurse
parent 6184943910
commit 2d3a1fd177
22 changed files with 256 additions and 49 deletions

View file

@ -0,0 +1,17 @@
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-20113",
"Microsoft.AspNetCore.Hosting": "1.0.0-rc2-20113",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-20254"
},
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"../../../TestProjects/KestrelSample/src/*.cs"
],
"frameworks": {
"net451": { }
}
}

View file

@ -0,0 +1,21 @@
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-20113",
"Microsoft.AspNetCore.Hosting": "1.0.0-rc2-20113",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-20254"
},
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"../../../TestProjects/KestrelSample/src/*.cs"
],
"frameworks": {
"net451": { }
},
"runtimes": {
"win7-x64": {},
"osx.10.11-x64": {}
}
}

View file

@ -9,9 +9,8 @@
<ProjectGuid>c26a48bb-193f-450c-ab09-4d3324c78188</ProjectGuid>
<RootNamespace>dotnet-dependency-tool-invoker</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>

View file

@ -9,9 +9,8 @@
<ProjectGuid>da8e0e9e-a6d6-4583-864c-8f40465e3a48</ProjectGuid>
<RootNamespace>TestAppWithArgs</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>

View file

@ -9,9 +9,8 @@
<ProjectGuid>0138cb8f-4aa9-4029-a21e-c07c30f425ba</ProjectGuid>
<RootNamespace>TestAppWithContents</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>

View file

@ -248,7 +248,6 @@ namespace Microsoft.DotNet.Cli.Build
CleanOutputDir(Path.Combine(Dirs.Stage1, "sdk"));
FS.CopyRecursive(Dirs.Stage1, Dirs.Stage1Symbols);
RemovePdbsFromDir(Path.Combine(Dirs.Stage1, "sdk"));
return result;
}
@ -301,8 +300,6 @@ namespace Microsoft.DotNet.Cli.Build
CleanOutputDir(Path.Combine(Dirs.Stage2, "sdk"));
FS.CopyRecursive(Dirs.Stage2, Dirs.Stage2Symbols);
RemovePdbsFromDir(Path.Combine(Dirs.Stage2, "sdk"));
return c.Success();
}

View file

@ -245,7 +245,6 @@ namespace Microsoft.DotNet.Cli.Build
Rmdir(Path.Combine(Dirs.NuGetPackages, ".tools", packageProject.Name));
}
}
return c.Success();
}

View file

@ -147,16 +147,10 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
private void WriteFramework(JObject runtimeOptions, LibraryExporter exporter)
{
var redistPackage = _context.RootProject.Dependencies
.Where(r => r.Type.Equals(LibraryDependencyType.Platform))
.ToList();
if (redistPackage.Count > 0)
var redistPackage = _context.PlatformLibrary;
if (redistPackage != null)
{
if (redistPackage.Count > 1)
{
throw new InvalidOperationException("Multiple packages with type: \"platform\" were specified!");
}
var packageName = redistPackage.Single().Name;
var packageName = redistPackage.Identity.Name;
var redistExport = exporter.GetAllExports()
.FirstOrDefault(e => e.Library.Identity.Name.Equals(packageName));

View file

@ -20,6 +20,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
{
private readonly string _configuration;
private readonly string _runtime;
private readonly string[] _runtimeFallbacks;
private readonly ProjectDescription _rootProject;
private readonly string _buildBasePath;
private readonly string _solutionRootPath;
@ -28,6 +29,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
LibraryManager manager,
string configuration,
string runtime,
string[] runtimeFallbacks,
string buildBasePath,
string solutionRootPath)
{
@ -39,6 +41,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
LibraryManager = manager;
_configuration = configuration;
_runtime = runtime;
_runtimeFallbacks = runtimeFallbacks;
_buildBasePath = buildBasePath;
_solutionRootPath = solutionRootPath;
_rootProject = rootProject;
@ -96,7 +99,6 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
var analyzerReferences = new List<AnalyzerReference>();
var libraryExport = GetExport(library);
// We need to filter out source references from non-root libraries,
// so we rebuild the library export
foreach (var reference in libraryExport.CompilationAssemblies)
@ -114,12 +116,22 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
analyzerReferences.AddRange(libraryExport.AnalyzerReferences);
}
yield return LibraryExportBuilder.Create(library)
var builder = LibraryExportBuilder.Create(library);
if (_runtime != null && _runtimeFallbacks != null)
{
builder.WithRuntimeAssemblyGroups(TrimAssetGroups(libraryExport.RuntimeAssemblyGroups, _runtimeFallbacks));
builder.WithNativeLibraryGroups(TrimAssetGroups(libraryExport.NativeLibraryGroups, _runtimeFallbacks));
}
else
{
builder.WithRuntimeAssemblyGroups(libraryExport.RuntimeAssemblyGroups);
builder.WithNativeLibraryGroups(libraryExport.NativeLibraryGroups);
}
yield return builder
.WithCompilationAssemblies(compilationAssemblies)
.WithSourceReferences(sourceReferences)
.WithRuntimeAssemblyGroups(libraryExport.RuntimeAssemblyGroups)
.WithRuntimeAssets(libraryExport.RuntimeAssets)
.WithNativeLibraryGroups(libraryExport.NativeLibraryGroups)
.WithEmbedddedResources(libraryExport.EmbeddedResources)
.WithAnalyzerReference(analyzerReferences)
.WithResourceAssemblies(libraryExport.ResourceAssemblies)
@ -127,6 +139,27 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
}
}
private IEnumerable<LibraryAssetGroup> TrimAssetGroups(IEnumerable<LibraryAssetGroup> runtimeAssemblyGroups,
string[] runtimeFallbacks)
{
LibraryAssetGroup runtimeAssets;
foreach (var rid in runtimeFallbacks)
{
runtimeAssets = runtimeAssemblyGroups.GetRuntimeGroup(rid);
if (runtimeAssets != null)
{
yield return new LibraryAssetGroup(runtimeAssets.Assets);
yield break;
}
}
runtimeAssets = runtimeAssemblyGroups.GetDefaultGroup();
if (runtimeAssets != null)
{
yield return runtimeAssets;
}
}
/// <summary>
/// Create a LibraryExport from LibraryDescription.
///

View file

@ -9,17 +9,47 @@ using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution;
using NuGet.Frameworks;
using NuGet.RuntimeModel;
namespace Microsoft.DotNet.ProjectModel
{
class RuntimeGraphCollector
{
private const string RuntimeJsonFileName = "runtime.json";
public static RuntimeGraph Collect(IEnumerable<LibraryDescription> libraries)
{
var graph = RuntimeGraph.Empty;
foreach (var library in libraries)
{
if (library.Identity.Type == LibraryType.Package)
{
var runtimeJson = ((PackageDescription)library).PackageLibrary.Files.FirstOrDefault(f => f == RuntimeJsonFileName);
if (runtimeJson != null)
{
var runtimeJsonFullName = Path.Combine(library.Path, runtimeJson);
graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName));
}
}
}
return graph;
}
}
public class ProjectContext
{
private string[] _runtimeFallbacks;
public GlobalSettings GlobalSettings { get; }
public ProjectDescription RootProject { get; }
public NuGetFramework TargetFramework { get; }
public LibraryDescription PlatformLibrary { get; }
public bool IsPortable { get; }
public string RuntimeIdentifier { get; }
public Project ProjectFile => RootProject?.Project;
@ -37,7 +67,9 @@ namespace Microsoft.DotNet.ProjectModel
internal ProjectContext(
GlobalSettings globalSettings,
ProjectDescription rootProject,
LibraryDescription platformLibrary,
NuGetFramework targetFramework,
bool isPortable,
string runtimeIdentifier,
string packagesDirectory,
LibraryManager libraryManager,
@ -45,16 +77,29 @@ namespace Microsoft.DotNet.ProjectModel
{
GlobalSettings = globalSettings;
RootProject = rootProject;
PlatformLibrary = platformLibrary;
TargetFramework = targetFramework;
RuntimeIdentifier = runtimeIdentifier;
PackagesDirectory = packagesDirectory;
LibraryManager = libraryManager;
LockFile = lockfile;
IsPortable = isPortable;
}
public LibraryExporter CreateExporter(string configuration, string buildBasePath = null)
{
return new LibraryExporter(RootProject, LibraryManager, configuration, RuntimeIdentifier, buildBasePath, RootDirectory);
if (IsPortable && RuntimeIdentifier != null && _runtimeFallbacks == null)
{
var graph = RuntimeGraphCollector.Collect(LibraryManager.GetLibraries());
_runtimeFallbacks = graph.ExpandRuntime(RuntimeIdentifier).ToArray();
}
return new LibraryExporter(RootProject,
LibraryManager,
configuration,
RuntimeIdentifier,
_runtimeFallbacks,
buildBasePath,
RootDirectory);
}
/// <summary>
@ -146,15 +191,12 @@ namespace Microsoft.DotNet.ProjectModel
return this;
}
var standalone = !RootProject.Dependencies
.Any(d => d.Type.Equals(LibraryDependencyType.Platform));
var context = CreateBuilder(ProjectFile.ProjectFilePath, TargetFramework)
.WithRuntimeIdentifiers(standalone ? runtimeIdentifiers : Enumerable.Empty<string>())
.WithRuntimeIdentifiers(runtimeIdentifiers)
.WithLockFile(LockFile)
.Build();
if (standalone && context.RuntimeIdentifier == null)
if (!context.IsPortable && context.RuntimeIdentifier == null)
{
// We are standalone, but don't support this runtime
var rids = string.Join(", ", runtimeIdentifiers);

View file

@ -9,6 +9,7 @@ using System.Text;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
@ -197,10 +198,20 @@ namespace Microsoft.DotNet.ProjectModel
libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject);
}
LibraryRange? platformDependency = null;
if (mainProject != null)
{
platformDependency = mainProject.Dependencies
.Where(d => d.Type.Equals(LibraryDependencyType.Platform))
.Cast<LibraryRange?>()
.FirstOrDefault();
}
bool isPortable = platformDependency != null || TargetFramework.IsDesktop();
LockFileTarget target = null;
if (lockFileLookup != null)
{
target = SelectTarget(LockFile);
target = SelectTarget(LockFile, isPortable);
if (target != null)
{
var nugetPackageResolver = new PackageDependencyProvider(PackagesDirectory, frameworkReferenceResolver);
@ -209,6 +220,30 @@ namespace Microsoft.DotNet.ProjectModel
}
}
string runtime;
if (TargetFramework.IsDesktop())
{
var legacyRuntime = PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier();
if (RuntimeIdentifiers.Contains(legacyRuntime))
{
runtime = legacyRuntime;
}
else
{
runtime = RuntimeIdentifiers.FirstOrDefault();
}
}
else
{
runtime = target?.RuntimeIdentifier;
}
LibraryDescription platformLibrary = null;
if(platformDependency != null)
{
platformLibrary = libraries[new LibraryKey(platformDependency.Value.Name)];
}
var referenceAssemblyDependencyResolver = new ReferenceAssemblyDependencyResolver(frameworkReferenceResolver);
bool requiresFrameworkAssemblies;
@ -272,8 +307,10 @@ namespace Microsoft.DotNet.ProjectModel
return new ProjectContext(
GlobalSettings,
mainProject,
platformLibrary,
TargetFramework,
target?.RuntimeIdentifier,
isPortable,
runtime,
PackagesDirectory,
libraryManager,
LockFile);
@ -454,7 +491,9 @@ namespace Microsoft.DotNet.ProjectModel
}
}
private LockFileTarget SelectTarget(LockFile lockFile)
private LockFileTarget SelectTarget(LockFile lockFile, bool isPortable)
{
if (!isPortable)
{
foreach (var runtimeIdentifier in RuntimeIdentifiers)
{
@ -466,6 +505,7 @@ namespace Microsoft.DotNet.ProjectModel
}
}
}
}
foreach (var scanTarget in lockFile.Targets)
{

View file

@ -17,6 +17,7 @@
},
"Newtonsoft.Json": "7.0.1",
"NuGet.Packaging": "3.5.0-beta-1130",
"NuGet.RuntimeModel": "3.5.0-beta-1130",
"System.Reflection.Metadata": "1.3.0-rc2-24008"
},
"frameworks": {

View file

@ -161,7 +161,7 @@ namespace Microsoft.DotNet.Tools.Compiler
Debug.Assert(targets.Count == 1);
}
Debug.Assert(targets.All(t => string.IsNullOrEmpty(t.RuntimeIdentifier)));
//Debug.Assert(targets.All(t => string.IsNullOrEmpty(t.RuntimeIdentifier)));
var success = execute(targets, this);

View file

@ -128,21 +128,19 @@ namespace Microsoft.DotNet.Tools.Publish
// Use a library exporter to collect publish assets
var exporter = context.CreateExporter(configuration, buildBasePath);
var isPortable = string.IsNullOrEmpty(context.RuntimeIdentifier);
// Collect all exports and organize them
var packageExports = exporter.GetAllExports()
.Where(e => e.Library.Identity.Type.Equals(LibraryType.Package))
.ToDictionary(e => e.Library.Identity.Name);
var collectExclusionList = isPortable ? GetExclusionList(context, packageExports) : new HashSet<string>();
var collectExclusionList = context.IsPortable ? GetExclusionList(context, packageExports) : new HashSet<string>();
var exports = exporter.GetAllExports();
foreach (var export in exports.Where(e => !collectExclusionList.Contains(e.Library.Identity.Name)))
{
Reporter.Verbose.WriteLine($"publish: Publishing {export.Library.Identity.ToString().Green().Bold()} ...");
PublishAssetGroups(export.RuntimeAssemblyGroups, outputPath, nativeSubdirectories: false, includeRuntimeGroups: isPortable);
PublishAssetGroups(export.NativeLibraryGroups, outputPath, nativeSubdirectories, includeRuntimeGroups: isPortable);
PublishAssetGroups(export.RuntimeAssemblyGroups, outputPath, nativeSubdirectories: false, includeRuntimeGroups: context.IsPortable);
PublishAssetGroups(export.NativeLibraryGroups, outputPath, nativeSubdirectories, includeRuntimeGroups: context.IsPortable);
}
if (options.PreserveCompilationContext.GetValueOrDefault())

View file

@ -9,7 +9,7 @@
<ProjectGuid>0B31C336-149D-471A-B7B1-27B0F1E80F83</ProjectGuid>
<RootNamespace>Microsoft.DotNet.Cli.Msi.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>

View file

@ -328,7 +328,7 @@ namespace Microsoft.DotNet.ProjectModel.Tests
}
var libraryManager = new LibraryManager(new[] { description }, new DiagnosticMessage[] { }, "");
var allExports = new LibraryExporter(rootProjectDescription, libraryManager, "config", "runtime", "basepath", "solutionroot").GetAllExports();
var allExports = new LibraryExporter(rootProjectDescription, libraryManager, "config", "runtime", null, "basepath", "solutionroot").GetAllExports();
var export = allExports.Single();
return export;
}

View file

@ -16,4 +16,15 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
}
}
}
public class WindowsOnlyTheoryAttribute : TheoryAttribute
{
public WindowsOnlyTheoryAttribute()
{
if (PlatformServices.Default.Runtime.OperatingSystemPlatform != Platform.Windows)
{
this.Skip = "This test requires windows to run";
}
}
}
}

View file

@ -0,0 +1,52 @@
using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tools.Publish.Tests
{
public class PublishDesktopTests : TestBase
{
[WindowsOnlyTheory]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20201", null)]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20201", "win7-x64")]
[InlineData("KestrelDesktop", "http://localhost:20203", null)]
[InlineData("KestrelDesktop", "http://localhost:20204", "win7-x64")]
public async Task DesktopApp_WithKestrel_WorksWhenPublishedWithRID(string project, string url, string runtime)
{
var testInstance = GetTestInstance(project)
.WithLockFiles()
.WithBuildArtifacts();
var publishCommand = new PublishCommand(testInstance.TestRoot, runtime);
var result = await publishCommand.ExecuteAsync();
result.Should().Pass();
// Test the output
var outputDir = publishCommand.GetOutputDirectory(portable: false);
outputDir.Should().HaveFile("libuv.dll");
outputDir.Should().HaveFile(publishCommand.GetOutputExecutable());
var command = new TestCommand(Path.Combine(outputDir.FullName, publishCommand.GetOutputExecutable()));
try
{
command.Execute(url);
NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {project} @ {url}");
NetworkHelper.TestGetRequest(url, url);
}
finally
{
command.KillTree();
}
}
private static TestInstance GetTestInstance(string name)
{
return TestAssetsManager.CreateTestInstance(Path.Combine("..", "DesktopTestProjects", "DesktopKestrelSample", name));
}
}
}

View file

@ -10,8 +10,13 @@
"Microsoft.DotNet.Tools.Tests.Utilities": {
"target": "project"
},
"Microsoft.DotNet.Cli.Utils": {
"target": "project"
"frameworks": {
"netstandardapp1.5": {
"imports": [
"dnxcore50",
"portable-net45+win8"
]
}
},
"xunit": "2.1.0",
"xunit.netcore.extensions": "1.0.0-prerelease-00206",