Generate runtimeconfig.json and runtimeconfig.dev.json from MSBuild

Moves generating the runtimeconfig files to a separate MSBuild target which is only dependent on project.lock.json.

Also, moving up our NuGet dependency to 3.5.0-rc1-1653, since that brings in the LockFile.PackageFolders property, which is needed for runtimeconfig.dev.json.
This commit is contained in:
Eric Erhardt 2016-07-25 19:07:23 -05:00
parent 006ab56248
commit 6eabeb9be0
12 changed files with 204 additions and 28 deletions

View file

@ -20,7 +20,7 @@
"System.Runtime.Serialization.Primitives": "4.1.1",
"System.Xml.XmlSerializer": "4.0.11",
"WindowsAzure.Storage": "6.2.2-preview",
"NuGet.CommandLine.XPlat": "3.5.0-beta2-1484",
"NuGet.CommandLine.XPlat": "3.5.0-rc1-1653",
"Microsoft.Build.Framework": "0.1.0-preview-00024-160610",
"Microsoft.Build.Utilities.Core": "0.1.0-preview-00024-160610"
},

View file

@ -8,10 +8,10 @@
"Microsoft.DotNet.ProjectModel": {
"target": "project"
},
"NuGet.Versioning": "3.5.0-beta2-1484",
"NuGet.Packaging": "3.5.0-beta2-1484",
"NuGet.Frameworks": "3.5.0-beta2-1484",
"NuGet.ProjectModel": "3.5.0-beta2-1484"
"NuGet.Versioning": "3.5.0-rc1-1653",
"NuGet.Packaging": "3.5.0-rc1-1653",
"NuGet.Frameworks": "3.5.0-rc1-1653",
"NuGet.ProjectModel": "3.5.0-rc1-1653"
},
"frameworks": {
"net451": {

View file

@ -50,10 +50,10 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
_compilerOptions = _context.ProjectFile.GetCompilerOptions(_context.TargetFramework, configuration);
}
public void MakeCompilationOutputRunnable()
public void MakeCompilationOutputRunnable(bool skipRuntimeConfig = false)
{
CopyContentFiles();
ExportRuntimeAssets();
ExportRuntimeAssets(skipRuntimeConfig);
}
private void VerifyCoreClrPresenceInPackageGraph()
@ -73,7 +73,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
}
}
private void ExportRuntimeAssets()
private void ExportRuntimeAssets(bool skipRuntimeConfig)
{
if (_context.TargetFramework.IsDesktop())
{
@ -81,7 +81,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
}
else
{
MakeCompilationOutputRunnableForCoreCLR();
MakeCompilationOutputRunnableForCoreCLR(skipRuntimeConfig);
}
}
@ -93,9 +93,9 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
GenerateBindingRedirects(_exporter);
}
private void MakeCompilationOutputRunnableForCoreCLR()
private void MakeCompilationOutputRunnableForCoreCLR(bool skipRuntimeConfig)
{
WriteDepsFileAndCopyProjectDependencies(_exporter);
WriteDepsFileAndCopyProjectDependencies(_exporter, skipRuntimeConfig);
var isRunnable = _compilerOptions.EmitEntryPoint ?? _context.ProjectFile.OverrideIsRunnable;
@ -155,14 +155,14 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
}
}
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter)
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter, bool skipRuntimeConfig)
{
var exports = exporter.GetAllExports().ToList();
var exportsLookup = exports.ToDictionary(e => e.Library.Identity.Name);
var platformExclusionList = _context.GetPlatformExclusionList(exportsLookup);
var filteredExports = exports.FilterExports(platformExclusionList);
WriteConfigurationFiles(exports, filteredExports, exports, includeDevConfig: true);
WriteConfigurationFiles(exports, filteredExports, exports, includeDevConfig: true, skipRuntimeConfig: skipRuntimeConfig);
var projectExports = exporter.GetAllProjectTypeDependencies();
CopyAssemblies(projectExports);
@ -176,10 +176,11 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
IEnumerable<LibraryExport> allExports,
IEnumerable<LibraryExport> depsRuntimeExports,
IEnumerable<LibraryExport> depsCompilationExports,
bool includeDevConfig)
bool includeDevConfig,
bool skipRuntimeConfig = false)
{
WriteDeps(depsRuntimeExports, depsCompilationExports);
if (_context.ProjectFile.HasRuntimeOutput(_configuration))
if (_context.ProjectFile.HasRuntimeOutput(_configuration) && !skipRuntimeConfig)
{
WriteRuntimeConfig(allExports);
if (includeDevConfig)

View file

@ -0,0 +1,128 @@
// 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 System.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.DotNet.ProjectModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuGet.ProjectModel;
namespace Microsoft.DotNet.Cli.Tasks
{
/// <summary>
/// Generates the $(project).runtimeconfig.json and optionally $(project).runtimeconfig.dev.json files
/// for a project.
/// </summary>
public class GenerateRuntimeConfigurationFiles : Task
{
[Required]
public string RuntimeOutputPath { get; set; }
[Required]
public string OutputName { get; set; }
[Required]
public string LockFilePath { get; set; }
public string RawRuntimeOptions { get; set; }
public bool IncludeDevConfig { get; set; }
private LockFile LockFile { get; set; }
public override bool Execute()
{
LockFile = LockFileCache.Instance.GetLockFile(LockFilePath);
WriteRuntimeConfig();
if (IncludeDevConfig)
{
WriteDevRuntimeConfig();
}
return true;
}
private void WriteRuntimeConfig()
{
var json = new JObject();
var runtimeOptions = new JObject();
json.Add("runtimeOptions", runtimeOptions);
WriteFramework(runtimeOptions);
WriteRuntimeOptions(runtimeOptions);
var runtimeConfigJsonFile =
Path.Combine(RuntimeOutputPath, OutputName + FileNameSuffixes.RuntimeConfigJson);
using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile))))
{
writer.Formatting = Formatting.Indented;
json.WriteTo(writer);
}
}
private void WriteFramework(JObject runtimeOptions)
{
// TODO: get this from the lock file once https://github.com/NuGet/Home/issues/2695 is fixed.
var packageName = "Microsoft.NETCore.App";
var redistExport = LockFile.Libraries.FirstOrDefault(e => e.Name.Equals(packageName, StringComparison.OrdinalIgnoreCase));
if (redistExport != null)
{
var framework = new JObject(
new JProperty("name", redistExport.Name),
new JProperty("version", redistExport.Version.ToNormalizedString()));
runtimeOptions.Add("framework", framework);
}
}
private void WriteRuntimeOptions(JObject runtimeOptions)
{
if (string.IsNullOrEmpty(RawRuntimeOptions))
{
return;
}
var runtimeOptionsFromProject = JObject.Parse(RawRuntimeOptions);
foreach (var runtimeOption in runtimeOptionsFromProject)
{
runtimeOptions.Add(runtimeOption.Key, runtimeOption.Value);
}
}
private void WriteDevRuntimeConfig()
{
var json = new JObject();
var runtimeOptions = new JObject();
json.Add("runtimeOptions", runtimeOptions);
AddAdditionalProbingPaths(runtimeOptions);
var runtimeConfigDevJsonFile =
Path.Combine(RuntimeOutputPath, OutputName + FileNameSuffixes.RuntimeConfigDevJson);
using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigDevJsonFile))))
{
writer.Formatting = Formatting.Indented;
json.WriteTo(writer);
}
}
private void AddAdditionalProbingPaths(JObject runtimeOptions)
{
var additionalProbingPaths = new JArray();
foreach (var packageFolder in LockFile.PackageFolders)
{
additionalProbingPaths.Add(packageFolder.Path);
}
runtimeOptions.Add("additionalProbingPaths", additionalProbingPaths);
}
}
}

View file

@ -0,0 +1,37 @@
// 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.Concurrent;
using NuGet.Common;
using NuGet.ProjectModel;
namespace Microsoft.DotNet.Cli.Tasks
{
internal class LockFileCache
{
public static LockFileCache Instance { get; } = new LockFileCache();
private ConcurrentDictionary<string, LockFile> _cache = new ConcurrentDictionary<string, LockFile>();
private LockFileCache()
{
}
public LockFile GetLockFile(string path)
{
LockFile result;
if (!_cache.TryGetValue(path, out result))
{
result = LoadLockFile(path);
_cache[path] = result;
}
return result;
}
private LockFile LoadLockFile(string path)
{
// TODO adapt task logger to Nuget Logger
return LockFileUtilities.GetLockFile(path, NullLogger.Instance);
}
}
}

View file

@ -63,7 +63,7 @@ namespace Microsoft.DotNet.Cli.Tasks
LibraryExporter libraryExporter = projectContext.CreateExporter(Configuration, buildBasePath);
Executable executable = new Executable(projectContext, outputPaths, libraryExporter, Configuration);
executable.MakeCompilationOutputRunnable();
executable.MakeCompilationOutputRunnable(skipRuntimeConfig: true);
}
return true;

View file

@ -9,8 +9,8 @@
"target": "project"
},
"Newtonsoft.Json": "9.0.1",
"NuGet.Packaging": "3.5.0-beta2-1484",
"NuGet.RuntimeModel": "3.5.0-beta2-1484",
"NuGet.Packaging": "3.5.0-rc1-1653",
"NuGet.RuntimeModel": "3.5.0-rc1-1653",
"System.Reflection.Metadata": "1.3.0"
},
"frameworks": {

View file

@ -39,7 +39,6 @@
<!-- Default settings for .NET Core build logic -->
<PropertyGroup>
<GenerateDependencyFile Condition=" '$(GenerateDependencyFile)' == '' ">true</GenerateDependencyFile>
<GenerateRuntimeConfigurationFiles Condition=" '$(GenerateRuntimeConfigurationFiles)' == '' ">true</GenerateRuntimeConfigurationFiles>
<!-- This will turn off the base 'ResolveNuGetPackages' target since it is UWP specific, and .NET Core needs it to be split up -->
<!--<ResolveNuGetPackages>false</ResolveNuGetPackages>-->

View file

@ -17,7 +17,12 @@
<_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)</_TargetFrameworkDirectories>
<_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>
</PropertyGroup>
<PropertyGroup>
<GenerateRuntimeConfigurationFiles Condition=" '$(GenerateRuntimeConfigurationFiles)' == '' and '$(OutputType)' == 'exe' ">true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
<UsingTask TaskName="GenerateRuntimeConfigurationFiles" AssemblyFile="$(MicrosoftDotNetCoreBuildTasksDirectory)Microsoft.DotNet.Core.Build.Tasks.dll" />
<UsingTask TaskName="MakeNetCoreRunnable" AssemblyFile="$(MicrosoftDotNetCoreBuildTasksDirectory)Microsoft.DotNet.Core.Build.Tasks.dll" />
<PropertyGroup>
@ -47,8 +52,15 @@
<Target Name="GenerateRuntimeConfigurationFiles"
Condition=" '$(GenerateRuntimeConfigurationFiles)' == 'true'">
<!-- TODO: Split up MakeNetCoreRunnable and implement this target-->
<!-- Putting this here to show the structure that we should use in production -->
<!--
TODO: Get RawRuntimeOptions from where it lives in the MSBuild world
-->
<GenerateRuntimeConfigurationFiles LockFilePath="$(MSBuildProjectDirectory)/project.lock.json"
RuntimeOutputPath="$(TargetDir)"
OutputName="$(AssemblyName)"
RawRuntimeOptions=""
IncludeDevConfig="true" />
</Target>
<!--

View file

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.Tools.Test;
using Microsoft.Extensions.Testing.Abstractions;
using NuGet.Protocol.Core.v3;
namespace Microsoft.DotNet.Cli.Tools.Test
{

View file

@ -34,10 +34,10 @@
},
"dependencies": {
"NuGet.Commands": {
"version": "3.5.0-beta2-1484",
"version": "3.5.0-rc1-1653",
"exclude": "compile"
},
"NuGet.CommandLine.XPlat": "3.5.0-beta2-1484",
"NuGet.CommandLine.XPlat": "3.5.0-rc1-1653",
"Newtonsoft.Json": "9.0.1",
"System.Text.Encoding.CodePages": "4.0.1",
"System.Diagnostics.FileVersionInfo": "4.0.0",

View file

@ -20,10 +20,10 @@
},
"System.Diagnostics.TraceSource": "4.0.0",
"System.Runtime.Serialization.Primitives": "4.1.1",
"NuGet.Versioning": "3.5.0-beta2-1484",
"NuGet.Packaging": "3.5.0-beta2-1484",
"NuGet.Frameworks": "3.5.0-beta2-1484",
"NuGet.ProjectModel": "3.5.0-beta2-1484",
"NuGet.Versioning": "3.5.0-rc1-1653",
"NuGet.Packaging": "3.5.0-rc1-1653",
"NuGet.Frameworks": "3.5.0-rc1-1653",
"NuGet.ProjectModel": "3.5.0-rc1-1653",
"Microsoft.DotNet.ProjectModel": {
"target": "project"
},