Merge pull request #2371 from dotnet/pakrym/low-fat

Make desktop publishing "half-portable" by default
This commit is contained in:
Pavel Krymets 2016-04-12 19:13:34 -07:00
commit 482f36d26b
35 changed files with 551 additions and 63 deletions

View file

@ -0,0 +1,11 @@
using System;
namespace DesktopAppWithNativeDep
{
public static class Program
{
public static void Main(string[] args)
{
}
}
}

View file

@ -0,0 +1,13 @@
{
"version": "1.0.0-*",
"dependencies": {
"PackageWithFakeNativeDep": "1.0.0-*",
"Microsoft.NETCore.Platforms": "1.0.0-rc2-24008"
},
"compilationOptions": {
"emitEntryPoint": true
},
"frameworks": {
"net451": { }
}
}

View file

@ -0,0 +1,18 @@
{
"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",
"Microsoft.NETCore.Platforms": "1.0.0-rc2-24008"
},
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"../src/*.cs"
],
"frameworks": {
"net451": { }
}
}

View file

@ -0,0 +1,19 @@
{
"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",
"Microsoft.NETCore.Platforms": "1.0.0-rc2-24008"
},
"compilationOptions": {
"platform": "anycpu32bitpreferred",
"emitEntryPoint": true
},
"compile": [
"../src/*.cs"
],
"frameworks": {
"net451": { }
}
}

View file

@ -0,0 +1,23 @@
{
"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",
"Microsoft.NETCore.Platforms": "1.0.0-rc2-24008"
},
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"../src/*.cs"
],
"frameworks": {
"net451": { }
},
"runtimes": {
"win7-x86": {},
"win7-x64": {},
"osx.10.11-x64": {}
}
}

View file

@ -0,0 +1,88 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Filter;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
namespace SampleApp
{
public class Startup
{
private static string Args { get; set; }
private static CancellationTokenSource ServerCancellationTokenSource { get; set; }
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IApplicationEnvironment env)
{
var ksi = app.ServerFeatures.Get<IKestrelServerInformation>();
ksi.NoDelay = true;
loggerFactory.AddConsole(LogLevel.Error);
app.UseKestrelConnectionLogging();
app.Run(async context =>
{
Console.WriteLine("{0} {1}{2}{3}",
context.Request.Method,
context.Request.PathBase,
context.Request.Path,
context.Request.QueryString);
Console.WriteLine($"Method: {context.Request.Method}");
Console.WriteLine($"PathBase: {context.Request.PathBase}");
Console.WriteLine($"Path: {context.Request.Path}");
Console.WriteLine($"QueryString: {context.Request.QueryString}");
var connectionFeature = context.Connection;
Console.WriteLine($"Peer: {connectionFeature.RemoteIpAddress?.ToString()} {connectionFeature.RemotePort}");
Console.WriteLine($"Sock: {connectionFeature.LocalIpAddress?.ToString()} {connectionFeature.LocalPort}");
var content = $"Hello world!{Environment.NewLine}Received '{Args}' from command line.";
context.Response.ContentLength = content.Length;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync(content);
});
}
public static int Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("KestrelHelloWorld <url to host>");
return 1;
}
var url = new Uri(args[0]);
Args = string.Join(" ", args);
var host = new WebHostBuilder()
.UseServer("Microsoft.AspNetCore.Server.Kestrel")
.UseUrls(url.ToString())
.UseStartup<Startup>()
.Build();
ServerCancellationTokenSource = new CancellationTokenSource();
// shutdown server after 20s.
var shutdownTask = Task.Run(async () =>
{
await Task.Delay(20000);
ServerCancellationTokenSource.Cancel();
});
host.Run(ServerCancellationTokenSource.Token);
shutdownTask.Wait();
return 0;
}
}
}

View file

@ -0,0 +1,10 @@
namespace PackageWithFakeNativeDep
{
public static class Lib
{
public static string GetMessage()
{
return "Hello, World";
}
}
}

View file

@ -0,0 +1,9 @@
{
"version": "1.0.0",
"packInclude": {
"runtimes/": "runtimes/"
},
"frameworks": {
"net45": {}
}
}

View file

@ -0,0 +1 @@
This is just a marker to ensure things are deployed right

View file

@ -0,0 +1 @@
This is just a marker to ensure things are deployed right

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

@ -25,6 +25,15 @@ namespace Microsoft.DotNet.Cli.Build
public static readonly dynamic[] Projects = new[]
{
new
{
Name = "PackageWithFakeNativeDep",
IsTool = false,
Path = "TestAssets/TestPackages/PackageWithFakeNativeDep",
IsApplicable = new Func<bool>(() => true),
VersionSuffix = s_testPackageBuildVersionSuffix,
Clean = true
},
new
{
Name = "dotnet-dependency-context-test",

View file

@ -200,7 +200,6 @@ namespace Microsoft.DotNet.Cli.Build
.Execute();
}
var projectJson = Path.Combine(fullPath, "project.json");
var dotnetPackArgs = new List<string> {
projectJson,
@ -245,7 +244,6 @@ namespace Microsoft.DotNet.Cli.Build
Rmdir(Path.Combine(Dirs.NuGetPackages, ".tools", packageProject.Name));
}
}
return c.Success();
}

View file

@ -16,6 +16,7 @@ using Microsoft.Extensions.DependencyModel;
using NuGet.Frameworks;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Reflection.PortableExecutable;
namespace Microsoft.Dotnet.Cli.Compiler.Common
{
@ -147,16 +148,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,25 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
analyzerReferences.AddRange(libraryExport.AnalyzerReferences);
}
yield return LibraryExportBuilder.Create(library)
var builder = LibraryExportBuilder.Create(library);
if (_runtime != null && _runtimeFallbacks != null)
{
// For portable apps that are built with runtime trimming we replace RuntimeAssemblyGroups and NativeLibraryGroups
// with single default group that contains asset specific to runtime we are trimming for
// based on runtime fallback list
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 +142,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

@ -14,12 +14,18 @@ namespace Microsoft.DotNet.ProjectModel
{
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 +43,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 +53,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 +167,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
@ -32,7 +33,7 @@ namespace Microsoft.DotNet.ProjectModel
private string PackagesDirectory { get; set; }
private string ReferenceAssembliesPath { get; set; }
private bool IsDesignTime { get; set; }
private Func<string, Project> ProjectResolver { get; set; }
@ -118,7 +119,7 @@ namespace Microsoft.DotNet.ProjectModel
Settings = settings;
return this;
}
public ProjectContextBuilder AsDesignTime()
{
IsDesignTime = true;
@ -197,18 +198,53 @@ 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;
LibraryDescription platformLibrary = null;
if (lockFileLookup != null)
{
target = SelectTarget(LockFile);
target = SelectTarget(LockFile, isPortable);
if (target != null)
{
var nugetPackageResolver = new PackageDependencyProvider(PackagesDirectory, frameworkReferenceResolver);
var msbuildProjectResolver = new MSBuildDependencyProvider(Project, ProjectResolver);
ScanLibraries(target, lockFileLookup, libraries, msbuildProjectResolver, nugetPackageResolver, projectResolver);
if (platformDependency != null)
{
platformLibrary = libraries[new LibraryKey(platformDependency.Value.Name)];
}
}
}
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;
}
var referenceAssemblyDependencyResolver = new ReferenceAssemblyDependencyResolver(frameworkReferenceResolver);
bool requiresFrameworkAssemblies;
@ -272,8 +308,10 @@ namespace Microsoft.DotNet.ProjectModel
return new ProjectContext(
GlobalSettings,
mainProject,
platformLibrary,
TargetFramework,
target?.RuntimeIdentifier,
isPortable,
runtime,
PackagesDirectory,
libraryManager,
LockFile);
@ -454,15 +492,18 @@ namespace Microsoft.DotNet.ProjectModel
}
}
private LockFileTarget SelectTarget(LockFile lockFile)
private LockFileTarget SelectTarget(LockFile lockFile, bool isPortable)
{
foreach (var runtimeIdentifier in RuntimeIdentifiers)
if (!isPortable)
{
foreach (var scanTarget in lockFile.Targets)
foreach (var runtimeIdentifier in RuntimeIdentifiers)
{
if (Equals(scanTarget.TargetFramework, TargetFramework) && string.Equals(scanTarget.RuntimeIdentifier, runtimeIdentifier, StringComparison.Ordinal))
foreach (var scanTarget in lockFile.Targets)
{
return scanTarget;
if (Equals(scanTarget.TargetFramework, TargetFramework) && string.Equals(scanTarget.RuntimeIdentifier, runtimeIdentifier, StringComparison.Ordinal))
{
return scanTarget;
}
}
}
}

View file

@ -0,0 +1,34 @@
// 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.DotNet.ProjectModel.Graph;
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;
}
}
}

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

@ -44,9 +44,9 @@ namespace Microsoft.DotNet.TestFramework
.Where(dir =>
{
dir = dir.ToLower();
return !dir.EndsWith($"{Path.DirectorySeparatorChar}bin")
return !dir.EndsWith($"{Path.DirectorySeparatorChar}bin")
&& !dir.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}")
&& !dir.EndsWith($"{Path.DirectorySeparatorChar}obj")
&& !dir.EndsWith($"{Path.DirectorySeparatorChar}obj")
&& !dir.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}");
});

View file

@ -108,10 +108,10 @@ namespace Microsoft.DotNet.Tools.Build
{
if (CLIChangedSinceLastCompilation(project))
{
Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because the CLI changed");
Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because the version or bitness of the CLI changed since the last build");
return true;
}
var compilerIO = GetCompileIO(project, dependencies);
// rebuild if empty inputs / outputs
@ -189,7 +189,7 @@ namespace Microsoft.DotNet.Tools.Build
return true;
}
private bool CLIChangedSinceLastCompilation(ProjectContext project)
{
var currentVersionFile = DotnetFiles.VersionFile;
@ -207,7 +207,9 @@ namespace Microsoft.DotNet.Tools.Build
return false;
}
var versionsAreEqual = string.Equals(File.ReadAllText(currentVersionFile), File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase);
var currentContent = ComputeCurrentVersionFileData();
var versionsAreEqual = string.Equals(currentContent, File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase);
return !versionsAreEqual;
}
@ -216,7 +218,7 @@ namespace Microsoft.DotNet.Tools.Build
{
if (File.Exists(DotnetFiles.VersionFile))
{
var projectVersionFile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue,_args.OutputValue);
var projectVersionFile = project.GetSDKVersionFile(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
var parentDirectory = Path.GetDirectoryName(projectVersionFile);
if (!Directory.Exists(parentDirectory))
@ -224,7 +226,9 @@ namespace Microsoft.DotNet.Tools.Build
Directory.CreateDirectory(parentDirectory);
}
File.Copy(DotnetFiles.VersionFile, projectVersionFile, true);
string content = ComputeCurrentVersionFileData();
File.WriteAllText(projectVersionFile, content);
}
else
{
@ -232,6 +236,14 @@ namespace Microsoft.DotNet.Tools.Build
}
}
private static string ComputeCurrentVersionFileData()
{
var content = File.ReadAllText(DotnetFiles.VersionFile);
content += Environment.NewLine;
content += PlatformServices.Default.Runtime.GetRuntimeIdentifier();
return content;
}
private void PrintSummary(bool success)
{
// todo: Ideally it's the builder's responsibility for adding the time elapsed. That way we avoid cross cutting display concerns between compile and build for printing time elapsed

View file

@ -5,11 +5,13 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.Extensions.DependencyModel;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Tools.Compiler
{
@ -77,6 +79,15 @@ namespace Microsoft.DotNet.Tools.Compiler
};
var compilationOptions = context.ResolveCompilationOptions(args.ConfigValue);
// Set default platform if it isn't already set and we're on desktop
if(compilationOptions.EmitEntryPoint == true && string.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop())
{
// See https://github.com/dotnet/cli/issues/2428 for more details.
compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ?
"x64" : "anycpu32bitpreferred";
}
var languageId = CompilerUtil.ResolveLanguageId(context);
var references = new List<string>();

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())
@ -152,7 +150,7 @@ namespace Microsoft.DotNet.Tools.Publish
PublishRefs(export, outputPath, !collectExclusionList.Contains(export.Library.Identity.Name));
}
}
var buildOutputPaths = context.GetOutputPaths(configuration, buildBasePath, null);
PublishBuildOutputFiles(buildOutputPaths, context, outputPath, Configuration);

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

@ -7,6 +7,7 @@ using Microsoft.Extensions.PlatformAbstractions;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Microsoft.DotNet.Tools.Test.Utilities
{
@ -42,6 +43,12 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_buidBasePathDirectory = buildBasePath;
}
public override Task<CommandResult> ExecuteAsync(string args = "")
{
args = $"publish {BuildArgs()} {args}";
return base.ExecuteAsync(args);
}
public override CommandResult Execute(string args = "")
{
args = $"publish {BuildArgs()} {args}";

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,129 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.PlatformAbstractions;
using Xunit;
namespace Microsoft.DotNet.Tools.Publish.Tests
{
public class PublishDesktopTests : TestBase
{
[WindowsOnlyTheory]
[InlineData(null, null)]
[InlineData("win7-x64", "the-win-x64-version.txt")]
[InlineData("win7-x86", "the-win-x86-version.txt")]
public async Task DesktopApp_WithDependencyOnNativePackage_ProducesExpectedOutput(string runtime, string expectedOutputName)
{
if(string.IsNullOrEmpty(expectedOutputName))
{
expectedOutputName = $"the-win-{RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant()}-version.txt";
}
var testInstance = TestAssetsManager.CreateTestInstance(Path.Combine("..", "DesktopTestProjects", "DesktopAppWithNativeDep"))
.WithLockFiles();
var publishCommand = new PublishCommand(testInstance.TestRoot, runtime: runtime);
var result = await publishCommand.ExecuteAsync();
result.Should().Pass();
// Test the output
var outputDir = publishCommand.GetOutputDirectory(portable: false);
outputDir.Should().HaveFile(expectedOutputName);
outputDir.Should().HaveFile(publishCommand.GetOutputExecutable());
}
[WindowsOnlyTheory]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20201", null, "libuv.dll", false)]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20202", "win7-x64", "libuv.dll", false)]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20203", "win7-x86", "libuv.dll", false)]
[InlineData("KestrelDesktopForce32", "http://localhost:20204", "win7-x86", "libuv.dll", true)]
[InlineData("KestrelDesktop", "http://localhost:20205", null, "libuv.dll", false)]
[InlineData("KestrelDesktop", "http://localhost:20206", "win7-x64", "libuv.dll", false)]
[InlineData("KestrelDesktop", "http://localhost:20207", "win7-x86", "libuv.dll", false)]
public async Task DesktopApp_WithKestrel_WorksWhenPublished(string project, string url, string runtime, string libuvName, bool forceRunnable)
{
var runnable = forceRunnable || string.IsNullOrEmpty(runtime) || (PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier().Contains(runtime));
var testInstance = GetTestInstance()
.WithLockFiles();
var publishCommand = new PublishCommand(Path.Combine(testInstance.TestRoot, project), runtime: runtime);
var result = await publishCommand.ExecuteAsync();
result.Should().Pass();
// Test the output
var outputDir = publishCommand.GetOutputDirectory(portable: false);
outputDir.Should().HaveFile(libuvName);
outputDir.Should().HaveFile(publishCommand.GetOutputExecutable());
Task exec = null;
if (runnable)
{
var outputExePath = Path.Combine(outputDir.FullName, publishCommand.GetOutputExecutable());
var command = new TestCommand(outputExePath);
try
{
exec = command.ExecuteAsync(url);
NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {project} @ {url}");
NetworkHelper.TestGetRequest(url, url);
}
finally
{
command.KillTree();
}
if (exec != null)
{
await exec;
}
}
}
[WindowsOnlyTheory]
[InlineData("KestrelDesktop", "http://localhost:20301")]
[InlineData("KestrelDesktopWithRuntimes", "http://localhost:20302")]
public async Task DesktopApp_WithKestrel_WorksWhenRun(string project, string url)
{
// Disabled due to https://github.com/dotnet/cli/issues/2428
if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
{
return;
}
var testInstance = GetTestInstance()
.WithLockFiles()
.WithBuildArtifacts();
Task exec = null;
var command = new RunCommand(Path.Combine(testInstance.TestRoot, project));
try
{
exec = command.ExecuteAsync(url);
NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {project} @ {url}");
NetworkHelper.TestGetRequest(url, url);
}
finally
{
command.KillTree();
}
if (exec != null)
{
await exec;
}
}
private static TestInstance GetTestInstance([CallerMemberName] string callingMethod = "")
{
return TestAssetsManager.CreateTestInstance(Path.Combine("..", "DesktopTestProjects", "DesktopKestrelSample"), callingMethod);
}
}
}

View file

@ -10,21 +10,19 @@
"Microsoft.DotNet.Tools.Tests.Utilities": {
"target": "project"
},
"Microsoft.DotNet.Cli.Utils": {
"target": "project"
},
"xunit": "2.1.0",
"xunit.netcore.extensions": "1.0.0-prerelease-00206",
"dotnet-test-xunit": "1.0.0-dev-140469-38"
"dotnet-test-xunit": "1.0.0-dev-140469-38",
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0-rc2-24008"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"netstandardapp1.5",
"dnxcore50",
"portable-net45+win8"
]
}
"netcoreapp1.0": {
"imports": [
"netstandardapp1.5",
"dnxcore50",
"portable-net45+win8"
]
}
},
"testRunner": "xunit"
}