diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/Program.cs b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/Program.cs new file mode 100644 index 000000000..9e6dde0c3 --- /dev/null +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/Program.cs @@ -0,0 +1,13 @@ +using System; + +namespace Misc.DthTestProjects.SimpleConsoleApp +{ + public class Program + { + public int Main(string[] args) + { + Console.WriteLine("Hello, world."); + return 0; + } + } +} diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/project.json new file mode 100644 index 000000000..3621ef882 --- /dev/null +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyNetCoreApp/project.json @@ -0,0 +1,15 @@ +{ + "dependencies": {}, + "frameworks": { + "netcoreapp1.0": { + "imports": "dnxcore50", + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-23931" + }, + "Newtonsoft.Json": "8.0.3" + } + } + } +} \ No newline at end of file diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/.noautobuild b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/Validator.cs b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/Validator.cs index 4195d928d..b34b4c93b 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/Validator.cs +++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/Validator.cs @@ -44,6 +44,7 @@ namespace Microsoft.Extensions.DependencyModel var resolvedPaths = compilationLibrary.ResolveReferencePaths(); foreach (var resolvedPath in resolvedPaths) { + Console.WriteLine($"Compilation {compilationLibrary.Name}:{Path.GetFileName(resolvedPath)}"); if (!File.Exists(resolvedPath)) { Error($"Compilataion library resolved to non existent path {resolvedPath}"); @@ -55,8 +56,10 @@ namespace Microsoft.Extensions.DependencyModel foreach (var runtimeLibrary in context.RuntimeLibraries) { CheckMetadata(runtimeLibrary); - foreach (var assembly in runtimeLibrary.GetDefaultNativeAssets(context)) {} - foreach (var native in runtimeLibrary.GetDefaultAssemblyNames(context)) {} + foreach (var native in runtimeLibrary.GetDefaultNativeAssets(context)) {} + foreach (var assembly in runtimeLibrary.GetDefaultAssemblyNames(context)) { + Console.WriteLine($"Runtime {runtimeLibrary.Name}:{assembly.Name}"); + } } foreach (var native in context.GetDefaultNativeAssets()) {} diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json index 5501c0f42..c160bb47f 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json +++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json @@ -1,15 +1,19 @@ { "version": "1.0.0-*", "dependencies": { - "NETStandard.Library": "1.5.0-rc2-23931", "Microsoft.Extensions.DependencyModel": { "target": "project", "version": "1.0.0-*" } }, "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" + "netstandard1.5": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23931", + } + }, + "net451": { } } } diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/.noautobuild b/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/Program.cs b/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/Program.cs new file mode 100644 index 000000000..28b8f8435 --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/Program.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static void Main(string[] args) + { + Microsoft.Extensions.DependencyModel.DependencyContextValidator.Validate(true); + } + } +} diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/project.json new file mode 100644 index 000000000..c5331b23d --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppFullClr/project.json @@ -0,0 +1,14 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "DependencyContextValidator": "1.0.0-*" + }, + "frameworks": { + "net451": { + } + } +} diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/.noautobuild b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/Program.cs b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/Program.cs new file mode 100644 index 000000000..28b8f8435 --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/Program.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static void Main(string[] args) + { + Microsoft.Extensions.DependencyModel.DependencyContextValidator.Validate(true); + } + } +} diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/project.json new file mode 100644 index 000000000..f3fc18046 --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortable/project.json @@ -0,0 +1,19 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-23931" + }, + "DependencyContextValidator": "1.0.0-*" + }, + "frameworks": { + "netstandard1.5": { + "imports" : "dnxcore50" + } + } +} diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/.noautobuild b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/Program.cs b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/Program.cs new file mode 100644 index 000000000..28b8f8435 --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/Program.cs @@ -0,0 +1,16 @@ +// 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.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static void Main(string[] args) + { + Microsoft.Extensions.DependencyModel.DependencyContextValidator.Validate(true); + } + } +} diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/project.json new file mode 100644 index 000000000..2036c6d1a --- /dev/null +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppPortableDeps/project.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + }, + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-23931" + }, + "DependencyContextValidator": "1.0.0-*" + }, + "frameworks": { + "netstandard1.5": { + "imports" : "dnxcore50" + } + } +} diff --git a/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/.noautobuild b/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/Program.cs b/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/Program.cs new file mode 100644 index 000000000..fbe8e9b0e --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace PortableApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/project.json b/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/project.json new file mode 100644 index 000000000..54c2fde9b --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/PortableAppCompilationContext/project.json @@ -0,0 +1,21 @@ +{ + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": {}, + "frameworks": { + "netstandard1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ], + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-23931" + } + } + } + } +} diff --git a/packaging/windows/clisdk/bundle.wxs b/packaging/windows/clisdk/bundle.wxs index ffa1ca597..cfd89df67 100644 --- a/packaging/windows/clisdk/bundle.wxs +++ b/packaging/windows/clisdk/bundle.wxs @@ -4,6 +4,7 @@ xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> + + + + @@ -45,6 +62,23 @@ + + + diff --git a/packaging/windows/inc/crtvariables.wxi b/packaging/windows/inc/crtvariables.wxi new file mode 100644 index 000000000..12263d2bf --- /dev/null +++ b/packaging/windows/inc/crtvariables.wxi @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/windows/sharedframework/bundle.wxs b/packaging/windows/sharedframework/bundle.wxs index 8c5a9b845..85cb613ff 100644 --- a/packaging/windows/sharedframework/bundle.wxs +++ b/packaging/windows/sharedframework/bundle.wxs @@ -4,6 +4,7 @@ xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> + + + + @@ -38,6 +55,23 @@ + + + diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 79fccf0b3..5f9a577c4 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.Extensions.PlatformAbstractions; @@ -9,6 +10,8 @@ using static Microsoft.DotNet.Cli.Build.FS; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; using System.Text.RegularExpressions; using System.Reflection.PortableExecutable; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; namespace Microsoft.DotNet.Cli.Build { @@ -243,6 +246,9 @@ namespace Microsoft.DotNet.Cli.Build outputDir: Dirs.Stage1); CleanOutputDir(Path.Combine(Dirs.Stage1, "sdk")); + FS.CopyRecursive(Dirs.Stage1, Dirs.Stage1Symbols); + + RemovePdbsFromDir(Path.Combine(Dirs.Stage1, "sdk")); return result; } @@ -293,13 +299,23 @@ 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(); } private static void CleanOutputDir(string directory) { - FS.RmFilesInDirRecursive(directory, "vbc.exe"); + foreach (var file in FilesToClean) + { + FS.RmFilesInDirRecursive(directory, file); + } + } + + private static void RemovePdbsFromDir(string directory) + { FS.RmFilesInDirRecursive(directory, "*.pdb"); } @@ -352,6 +368,7 @@ namespace Microsoft.DotNet.Cli.Build // Rename the .deps file var destinationDeps = Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json"); File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps); + ChangeEntryPointLibraryName(destinationDeps, null); // Generate RID fallback graph string runtimeGraphGeneratorRuntime = null; @@ -445,7 +462,7 @@ namespace Microsoft.DotNet.Cli.Build "--output", outputDir, "--framework", - "netstandard1.5") + "netstandard1.5") .Execute() .EnsureSuccessful(); @@ -468,6 +485,7 @@ namespace Microsoft.DotNet.Cli.Build File.Delete(Path.Combine(binaryToCorehostifyOutDir, $"{binaryToCorehostify}.exe")); File.Copy(compilersDeps, Path.Combine(outputDir, binaryToCorehostify + ".deps.json")); File.Copy(compilersRuntimeConfig, Path.Combine(outputDir, binaryToCorehostify + ".runtimeconfig.json")); + ChangeEntryPointLibraryName(Path.Combine(outputDir, binaryToCorehostify + ".deps.json"), binaryToCorehostify); } catch (Exception ex) { @@ -577,6 +595,42 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + private static void ChangeEntryPointLibraryName(string depsFile, string newName) + { + JToken deps; + using (var file = File.OpenText(depsFile)) + using (JsonTextReader reader = new JsonTextReader(file)) + { + deps = JObject.ReadFrom(reader); + } + + var target = deps["targets"][deps["runtimeTarget"]["name"].Value()]; + var library = target.Children().First(); + var version = library.Name.Substring(library.Name.IndexOf('/') + 1); + if (newName == null) + { + library.Remove(); + } + else + { + library.Replace(new JProperty(newName + '/' + version, library.Value)); + } + library = deps["libraries"].Children().First(); + if (newName == null) + { + library.Remove(); + } + else + { + library.Replace(new JProperty(newName + '/' + version, library.Value)); + } + using (var file = File.CreateText(depsFile)) + using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented}) + { + deps.WriteTo(writer); + } + } + private static void DeleteMainPublishOutput(string path, string name) { File.Delete(Path.Combine(path, $"{name}{Constants.ExeSuffix}")); diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index 06214fc8c..aa5156be0 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Net.Http; using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.Extensions.PlatformAbstractions; @@ -14,11 +15,13 @@ namespace Microsoft.DotNet.Cli.Build { private const string ENGINE = "engine.exe"; + private const string WixVersion = "3.10.2"; + private static string WixRoot { get { - return Path.Combine(Dirs.Output, "WixTools"); + return Path.Combine(Dirs.Output, $"WixTools.{WixVersion}"); } } @@ -54,14 +57,24 @@ namespace Microsoft.DotNet.Cli.Build Directory.CreateDirectory(WixRoot); c.Info("Downloading WixTools.."); - // Download Wix version 3.10.2 - https://wix.codeplex.com/releases/view/619491 - Cmd("powershell", "-NoProfile", "-NoLogo", - $"Invoke-WebRequest -Uri https://wix.codeplex.com/downloads/get/1540241 -Method Get -OutFile {WixRoot}\\WixTools.zip") - .Execute() - .EnsureSuccessful(); + + DownloadFile($"https://dotnetcli.blob.core.windows.net/build/wix/wix.{WixVersion}.zip", Path.Combine(WixRoot, "WixTools.zip")); c.Info("Extracting WixTools.."); - ZipFile.ExtractToDirectory($"{WixRoot}\\WixTools.zip", WixRoot); + ZipFile.ExtractToDirectory(Path.Combine(WixRoot, "WixTools.zip"), WixRoot); + } + + private static void DownloadFile(string uri, string destinationPath) + { + using (var httpClient = new HttpClient()) + { + var getTask = httpClient.GetStreamAsync(uri); + + using (var outStream = File.OpenWrite(destinationPath)) + { + getTask.Result.CopyTo(outStream); + } + } } [Target] diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 40bc5e3bc..75ba0fb3d 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -175,6 +175,8 @@ namespace Microsoft.DotNet.Cli.Build CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); + CreateZipFromDirectory(Path.Combine(Dirs.Stage2Symbols, "sdk"), c.BuildContext.Get("SdkSymbolsCompressedFile")); + return c.Success(); } @@ -185,6 +187,8 @@ namespace Microsoft.DotNet.Cli.Build CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); + CreateTarBallFromDirectory(Path.Combine(Dirs.Stage2Symbols, "sdk"), c.BuildContext.Get("SdkSymbolsCompressedFile")); + return c.Success(); } diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index ac44561eb..778bda8b4 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -130,6 +130,7 @@ namespace Microsoft.DotNet.Cli.Build AddInstallerArtifactToContext(c, "dotnet-sharedframework", "SharedFramework", sharedFrameworkVersion); AddInstallerArtifactToContext(c, "dotnet-dev", "CombinedFrameworkSDKHost", cliVersion); AddInstallerArtifactToContext(c, "dotnet", "CombinedFrameworkHost", sharedFrameworkVersion); + AddInstallerArtifactToContext(c, "dotnet-sdk-debug", "SdkSymbols", cliVersion); return c.Success(); } @@ -205,8 +206,8 @@ namespace Microsoft.DotNet.Cli.Build { var dotnet = DotNetCli.Stage0; - dotnet.Restore("--verbosity", "verbose").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful(); - dotnet.Restore("--verbosity", "verbose", "--infer-runtimes").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful(); return c.Success(); } diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 10f4bb6a7..8ed4997a3 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -68,7 +68,8 @@ namespace Microsoft.DotNet.Cli.Build [Target( nameof(PublishTargets.PublishCombinedHostFrameworkArchiveToAzure), - nameof(PublishTargets.PublishCombinedHostFrameworkSdkArchiveToAzure))] + nameof(PublishTargets.PublishCombinedHostFrameworkSdkArchiveToAzure), + nameof(PublishTargets.PublishSDKSymbolsArchiveToAzure))] public static BuildTargetResult PublishArchivesToAzure(BuildTargetContext c) => c.Success(); [Target( @@ -176,6 +177,17 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + public static BuildTargetResult PublishSDKSymbolsArchiveToAzure(BuildTargetContext c) + { + var version = CliNuGetVersion; + var archiveFile = c.BuildContext.Get("SdkSymbolsCompressedFile"); + + AzurePublisherTool.PublishArchiveAndLatest(archiveFile, Channel, version); + + return c.Success(); + } + [Target] public static BuildTargetResult PublishCombinedHostFrameworkArchiveToAzure(BuildTargetContext c) { diff --git a/scripts/dotnet-cli-build/Utils/Dirs.cs b/scripts/dotnet-cli-build/Utils/Dirs.cs index 62ebe8f73..cec5db1cb 100644 --- a/scripts/dotnet-cli-build/Utils/Dirs.cs +++ b/scripts/dotnet-cli-build/Utils/Dirs.cs @@ -17,8 +17,10 @@ namespace Microsoft.DotNet.Cli.Build public static readonly string Packages = Path.Combine(Output, "packages"); public static readonly string Stage1 = Path.Combine(Output, "stage1"); public static readonly string Stage1Compilation = Path.Combine(Output, "stage1compilation"); + public static readonly string Stage1Symbols = Path.Combine(Output, "stage1symbols"); public static readonly string Stage2 = Path.Combine(Output, "stage2"); public static readonly string Stage2Compilation = Path.Combine(Output, "stage2compilation"); + public static readonly string Stage2Symbols = Path.Combine(Output, "stage2symbols"); public static readonly string Corehost = Path.Combine(Output, "corehost"); public static readonly string TestOutput = Path.Combine(Output, "tests"); public static readonly string TestArtifacts = Path.Combine(TestOutput, "artifacts"); diff --git a/scripts/dotnet-cli-build/Utils/FS.cs b/scripts/dotnet-cli-build/Utils/FS.cs index d425c7ce2..80cddcff2 100644 --- a/scripts/dotnet-cli-build/Utils/FS.cs +++ b/scripts/dotnet-cli-build/Utils/FS.cs @@ -111,7 +111,7 @@ namespace Microsoft.DotNet.Cli.Build if (string.Equals(Path.GetFileName(candidate), "bin") || string.Equals(Path.GetFileName(candidate), "obj")) { - Directory.Delete(candidate, recursive: true); + Utils.DeleteDirectory(candidate); } else { diff --git a/scripts/dotnet-cli-build/Utils/Utils.cs b/scripts/dotnet-cli-build/Utils/Utils.cs index bd7e5ad71..799bda56f 100644 --- a/scripts/dotnet-cli-build/Utils/Utils.cs +++ b/scripts/dotnet-cli-build/Utils/Utils.cs @@ -96,8 +96,24 @@ namespace Microsoft.DotNet.Cli.Build File.SetAttributes(file, FileAttributes.Normal); File.Delete(file); } - System.Threading.Thread.Sleep(1); - Directory.Delete(path, true); + var retry = 5; + while (retry >= 0) + { + try + { + Directory.Delete(path, true); + return; + } + catch (IOException ex) + { + if (retry == 0) + { + throw; + } + System.Threading.Thread.Sleep(200); + retry--; + } + } } } diff --git a/scripts/update-dependencies/BuildContextProperties.cs b/scripts/update-dependencies/BuildContextProperties.cs new file mode 100644 index 000000000..6cd488398 --- /dev/null +++ b/scripts/update-dependencies/BuildContextProperties.cs @@ -0,0 +1,30 @@ +// 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 Microsoft.DotNet.Cli.Build.Framework; + +namespace Microsoft.DotNet.Scripts +{ + public static class BuildContextProperties + { + public static List GetDependencyInfos(this BuildTargetContext c) + { + const string propertyName = "DependencyInfos"; + + List dependencyInfos; + object dependencyInfosObj; + if (c.BuildContext.Properties.TryGetValue(propertyName, out dependencyInfosObj)) + { + dependencyInfos = (List)dependencyInfosObj; + } + else + { + dependencyInfos = new List(); + c.BuildContext[propertyName] = dependencyInfos; + } + + return dependencyInfos; + } + } +} diff --git a/scripts/update-dependencies/Config.cs b/scripts/update-dependencies/Config.cs index c0e446ec3..7772bba52 100644 --- a/scripts/update-dependencies/Config.cs +++ b/scripts/update-dependencies/Config.cs @@ -23,6 +23,7 @@ namespace Microsoft.DotNet.Scripts /// GITHUB_UPSTREAM_OWNER - The owner of the GitHub base repo to create the PR to. (ex. "dotnet") /// GITHUB_PROJECT - The repo name under the ORIGIN and UPSTREAM owners. (ex. "cli") /// GITHUB_UPSTREAM_BRANCH - The branch in the GitHub base repo to create the PR to. (ex. "rel/1.0.0") + /// GITHUB_PULL_REQUEST_NOTIFICATIONS - A semi-colon ';' separated list of GitHub users to notify on the PR. /// public class Config { @@ -36,6 +37,7 @@ namespace Microsoft.DotNet.Scripts public string GitHubUpstreamOwner { get; set; } public string GitHubProject { get; set; } public string GitHubUpstreamBranch { get; set; } + public string[] GitHubPullRequestNotifications { get; set; } private static Config Read() { @@ -52,18 +54,20 @@ namespace Microsoft.DotNet.Scripts GitHubUpstreamOwner = GetEnvironmentVariable("GITHUB_UPSTREAM_OWNER", "dotnet"), GitHubProject = GetEnvironmentVariable("GITHUB_PROJECT", "cli"), GitHubUpstreamBranch = GetEnvironmentVariable("GITHUB_UPSTREAM_BRANCH", "rel/1.0.0"), + GitHubPullRequestNotifications = GetEnvironmentVariable("GITHUB_PULL_REQUEST_NOTIFICATIONS", "") + .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) }; } private static string GetEnvironmentVariable(string name, string defaultValue = null) { string value = Environment.GetEnvironmentVariable(name); - if (string.IsNullOrEmpty(value)) + if (value == null) { value = defaultValue; } - if (string.IsNullOrEmpty(value)) + if (value == null) { throw new BuildFailureException($"Can't find environment variable '{name}'."); } diff --git a/scripts/update-dependencies/DependencyInfo.cs b/scripts/update-dependencies/DependencyInfo.cs new file mode 100644 index 000000000..68cf4f45d --- /dev/null +++ b/scripts/update-dependencies/DependencyInfo.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.DotNet.Scripts +{ + public class DependencyInfo + { + public string Name { get; set; } + public string IdPattern { get; set; } + public string IdExclusionPattern { get; set; } + public string NewReleaseVersion { get; set; } + + public bool IsUpdated { get; set; } + } +} diff --git a/scripts/update-dependencies/PushPRTargets.cs b/scripts/update-dependencies/PushPRTargets.cs index 4d9ca44c1..2d989a79e 100644 --- a/scripts/update-dependencies/PushPRTargets.cs +++ b/scripts/update-dependencies/PushPRTargets.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Linq; using Microsoft.DotNet.Cli.Build.Framework; using Octokit; @@ -14,8 +15,6 @@ namespace Microsoft.DotNet.Scripts /// public static class PushPRTargets { - private const string PullRequestTitle = "Updating dependencies from last known good builds"; - private static readonly Config s_config = Config.Instance; [Target(nameof(CommitChanges), nameof(CreatePR))] @@ -28,14 +27,31 @@ namespace Microsoft.DotNet.Scripts [Target] public static BuildTargetResult CommitChanges(BuildTargetContext c) { - Cmd("git", "add", ".") - .Execute() - .EnsureSuccessful(); + CommandResult statusResult = Cmd("git", "status", "--porcelain") + .CaptureStdOut() + .Execute(); + statusResult.EnsureSuccessful(); + + bool hasModifiedFiles = !string.IsNullOrWhiteSpace(statusResult.StdOut); + bool hasUpdatedDependencies = c.GetDependencyInfos().Where(d => d.IsUpdated).Any(); + + if (hasModifiedFiles != hasUpdatedDependencies) + { + return c.Failed($"'git status' does not match DependencyInfo information. Git has modified files: {hasModifiedFiles}. DependencyInfo is updated: {hasUpdatedDependencies}."); + } + + if (!hasUpdatedDependencies) + { + c.Warn("Dependencies are currently up to date"); + return c.Success(); + } string userName = s_config.UserName; string email = s_config.Email; - Cmd("git", "commit", "-m", PullRequestTitle, "--author", $"{userName} <{email}>") + string commitMessage = GetCommitMessage(c); + + Cmd("git", "commit", "-a", "-m", commitMessage, "--author", $"{userName} <{email}>") .EnvironmentVariable("GIT_COMMITTER_NAME", userName) .EnvironmentVariable("GIT_COMMITTER_EMAIL", email) .Execute() @@ -79,12 +95,19 @@ namespace Microsoft.DotNet.Scripts public static BuildTargetResult CreatePR(BuildTargetContext c) { string remoteBranchName = c.GetRemoteBranchName(); + string commitMessage = c.GetCommitMessage(); NewPullRequest prInfo = new NewPullRequest( - PullRequestTitle, + commitMessage, s_config.GitHubOriginOwner + ":" + remoteBranchName, s_config.GitHubUpstreamBranch); + string[] prNotifications = s_config.GitHubPullRequestNotifications; + if (prNotifications.Length > 0) + { + prInfo.Body = $"/cc @{string.Join(" @", prNotifications)}"; + } + GitHubClient gitHub = new GitHubClient(new ProductHeaderValue("dotnetDependencyUpdater")); gitHub.Credentials = new Credentials(s_config.Password); @@ -104,5 +127,36 @@ namespace Microsoft.DotNet.Scripts { c.BuildContext["RemoteBranchName"] = value; } + + private static string GetCommitMessage(this BuildTargetContext c) + { + const string commitMessagePropertyName = "CommitMessage"; + + string message; + object messageObject; + if (c.BuildContext.Properties.TryGetValue(commitMessagePropertyName, out messageObject)) + { + message = (string)messageObject; + } + else + { + DependencyInfo[] updatedDependencies = c.GetDependencyInfos() + .Where(d => d.IsUpdated) + .ToArray(); + + string updatedDependencyNames = string.Join(", ", updatedDependencies.Select(d => d.Name)); + string updatedDependencyVersions = string.Join(", ", updatedDependencies.Select(d => d.NewReleaseVersion)); + + message = $"Updating {updatedDependencyNames} to {updatedDependencyVersions}"; + if (updatedDependencies.Count() > 1) + { + message += " respectively"; + } + + c.BuildContext[commitMessagePropertyName] = message; + } + + return message; + } } } diff --git a/scripts/update-dependencies/UpdateFilesTargets.cs b/scripts/update-dependencies/UpdateFilesTargets.cs index 31527ce59..cc4f75bc5 100644 --- a/scripts/update-dependencies/UpdateFilesTargets.cs +++ b/scripts/update-dependencies/UpdateFilesTargets.cs @@ -34,7 +34,7 @@ namespace Microsoft.DotNet.Scripts const string coreFxIdPattern = @"^(?i)((System\..*)|(NETStandard\.Library)|(Microsoft\.CSharp)|(Microsoft\.NETCore.*)|(Microsoft\.TargetingPack\.Private\.(CoreCLR|NETNative))|(Microsoft\.Win32\..*)|(Microsoft\.VisualBasic))$"; const string coreFxIdExclusionPattern = @"System.CommandLine"; - List dependencyInfos = c.GetDependencyInfo(); + List dependencyInfos = c.GetDependencyInfos(); dependencyInfos.Add(new DependencyInfo() { Name = "CoreFx", @@ -46,26 +46,7 @@ namespace Microsoft.DotNet.Scripts return c.Success(); } - private static List GetDependencyInfo(this BuildTargetContext c) - { - const string propertyName = "DependencyInfo"; - - List dependencyInfos; - object dependencyInfosObj; - if (c.BuildContext.Properties.TryGetValue(propertyName, out dependencyInfosObj)) - { - dependencyInfos = (List)dependencyInfosObj; - } - else - { - dependencyInfos = new List(); - c.BuildContext[propertyName] = dependencyInfos; - } - - return dependencyInfos; - } - - [Target(nameof(ReplaceProjectJson), nameof(ReplaceCrossGen))] + [Target(nameof(ReplaceProjectJson), nameof(ReplaceCrossGen), nameof(ReplaceCoreHostPackaging))] public static BuildTargetResult ReplaceVersions(BuildTargetContext c) => c.Success(); /// @@ -74,7 +55,7 @@ namespace Microsoft.DotNet.Scripts [Target] public static BuildTargetResult ReplaceProjectJson(BuildTargetContext c) { - List dependencyInfos = c.GetDependencyInfo(); + List dependencyInfos = c.GetDependencyInfos(); IEnumerable projectJsonFiles = Enumerable.Union( Directory.GetFiles(Dirs.RepoRoot, "project.json", SearchOption.AllDirectories), @@ -157,6 +138,9 @@ namespace Microsoft.DotNet.Scripts dependencyProperty.Value = newVersion; } + // mark the DependencyInfo as updated so we can tell which dependencies were updated + dependencyInfo.IsUpdated = true; + return true; } } @@ -194,40 +178,68 @@ namespace Microsoft.DotNet.Scripts .SelectMany(o => o.Children()); } - private class DependencyInfo - { - public string Name { get; set; } - public string IdPattern { get; set; } - public string IdExclusionPattern { get; set; } - public string NewReleaseVersion { get; set; } - } - /// /// Replaces version number that is hard-coded in the CrossGen script. /// [Target] public static BuildTargetResult ReplaceCrossGen(BuildTargetContext c) { - DependencyInfo coreFXInfo = c.GetDependencyInfo().Single(d => d.Name == "CoreFx"); - - string compileTargetsPath = Path.Combine(Dirs.RepoRoot, @"scripts\dotnet-cli-build\CompileTargets.cs"); - string compileTargetsContent = File.ReadAllText(compileTargetsPath); - - Regex regex = new Regex(@"CoreCLRVersion = ""(?\d.\d.\d)-(?.*)"";"); - compileTargetsContent = regex.Replace(compileTargetsContent, m => + ReplaceFileContents(@"scripts\dotnet-cli-build\CompileTargets.cs", compileTargetsContent => { - string replacedValue = m.Value; - Group releaseGroup = m.Groups["release"]; + DependencyInfo coreFXInfo = c.GetCoreFXDependency(); + Regex regex = new Regex(@"CoreCLRVersion = ""(?\d.\d.\d)-(?.*)"";"); - replacedValue = replacedValue.Remove(releaseGroup.Index - m.Index, releaseGroup.Length); - replacedValue = replacedValue.Insert(releaseGroup.Index - m.Index, coreFXInfo.NewReleaseVersion); - - return replacedValue; + return regex.ReplaceGroupValue(compileTargetsContent, "release", coreFXInfo.NewReleaseVersion); }); - File.WriteAllText(compileTargetsPath, compileTargetsContent, Encoding.UTF8); - return c.Success(); } + + /// + /// Replaces version number that is hard-coded in the corehost packaging dir.props file. + /// + [Target] + public static BuildTargetResult ReplaceCoreHostPackaging(BuildTargetContext c) + { + ReplaceFileContents(@"src\corehost\packaging\dir.props", contents => + { + DependencyInfo coreFXInfo = c.GetCoreFXDependency(); + Regex regex = new Regex(@"Microsoft\.NETCore\.Platforms\\(?\d\.\d\.\d)-(?.*)\\runtime\.json"); + + return regex.ReplaceGroupValue(contents, "release", coreFXInfo.NewReleaseVersion); + }); + + return c.Success(); + } + + private static DependencyInfo GetCoreFXDependency(this BuildTargetContext c) + { + return c.GetDependencyInfos().Single(d => d.Name == "CoreFx"); + } + + private static void ReplaceFileContents(string repoRelativePath, Func replacement) + { + string fullPath = Path.Combine(Dirs.RepoRoot, repoRelativePath); + string contents = File.ReadAllText(fullPath); + + contents = replacement(contents); + + File.WriteAllText(fullPath, contents, Encoding.UTF8); + } + + private static string ReplaceGroupValue(this Regex regex, string input, string groupName, string newValue) + { + return regex.Replace(input, m => + { + string replacedValue = m.Value; + Group group = m.Groups[groupName]; + int startIndex = group.Index - m.Index; + + replacedValue = replacedValue.Remove(startIndex, group.Length); + replacedValue = replacedValue.Insert(startIndex, newValue); + + return replacedValue; + }); + } } } diff --git a/scripts/update-dependencies/project.json b/scripts/update-dependencies/project.json index 1a2b48caf..63e87a442 100644 --- a/scripts/update-dependencies/project.json +++ b/scripts/update-dependencies/project.json @@ -9,7 +9,7 @@ "Microsoft.CSharp": "4.0.1-rc2-23931", "System.Runtime.Serialization.Primitives": "4.1.1-rc2-23931", "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", - "NuGet.Versioning": "3.5.0-beta-1123", + "NuGet.Versioning": "3.5.0-beta-1130", "Newtonsoft.Json": "7.0.1", "Octokit": "0.18.0", "Microsoft.Net.Http": "2.2.29" diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json index 6519d4aa7..07a1fd577 100644 --- a/src/Microsoft.DotNet.Cli.Utils/project.json +++ b/src/Microsoft.DotNet.Cli.Utils/project.json @@ -7,10 +7,10 @@ "dependencies": { "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-20100", - "NuGet.Versioning": "3.5.0-beta-1123", - "NuGet.Packaging": "3.5.0-beta-1123", - "NuGet.Frameworks": "3.5.0-beta-1123", - "NuGet.ProjectModel": "3.5.0-beta-1123" + "NuGet.Versioning": "3.5.0-beta-1130", + "NuGet.Packaging": "3.5.0-beta-1130", + "NuGet.Frameworks": "3.5.0-beta-1130", + "NuGet.ProjectModel": "3.5.0-beta-1130" }, "frameworks": { "net451": { diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index ce43b4b0b..8fc68ba34 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -424,7 +424,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation private IEnumerable PopulateAssets(TargetLibraryWithAssets library, IEnumerable section) { - foreach (var assemblyPath in section) + foreach (var assemblyPath in section.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.Path))) { yield return LibraryAsset.CreateFromRelativePath(library.Path, assemblyPath.Path); } diff --git a/src/Microsoft.DotNet.ProjectModel/Project.cs b/src/Microsoft.DotNet.ProjectModel/Project.cs index 2df027c5b..9e1c26437 100644 --- a/src/Microsoft.DotNet.ProjectModel/Project.cs +++ b/src/Microsoft.DotNet.ProjectModel/Project.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.DotNet.ProjectModel.Files; using Microsoft.DotNet.ProjectModel.Graph; using NuGet.Frameworks; @@ -91,7 +92,7 @@ namespace Microsoft.DotNet.ProjectModel public string RawRuntimeOptions { get; set; } public bool IsTestProject => !string.IsNullOrEmpty(TestRunner); - + public IEnumerable GetTargetFrameworks() { return _targetFrameworks.Values; diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index 7fe2e7622..b64c0dcef 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -145,11 +145,8 @@ namespace Microsoft.DotNet.ProjectModel { return this; } - - // Check if there are any runtime targets (i.e. are we portable) - var standalone = LockFile.Targets - .Where(t => t.TargetFramework.Equals(TargetFramework)) - .Any(t => !string.IsNullOrEmpty(t.RuntimeIdentifier)); + + var standalone = !ProjectFile.Dependencies.Any(d => d.Type.Equals(LibraryDependencyType.Platform)); var context = CreateBuilder(ProjectFile.ProjectFilePath, TargetFramework) .WithRuntimeIdentifiers(standalone ? runtimeIdentifiers : Enumerable.Empty()) diff --git a/src/Microsoft.DotNet.ProjectModel/project.json b/src/Microsoft.DotNet.ProjectModel/project.json index 8bcb9120e..125830412 100644 --- a/src/Microsoft.DotNet.ProjectModel/project.json +++ b/src/Microsoft.DotNet.ProjectModel/project.json @@ -6,7 +6,7 @@ "description": "Types to model a .NET Project", "dependencies": { "System.Reflection.Metadata": "1.3.0-rc2-23931", - "NuGet.Packaging": "3.5.0-beta-1123", + "NuGet.Packaging": "3.5.0-beta-1130", "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", "Microsoft.Extensions.JsonParser.Sources": { "type": "build", @@ -32,9 +32,6 @@ "System.IO": { "type": "build" } - }, - "dependencies": { - "System.Linq": "4.0.1-rc3-23727" } }, "netstandard1.5": { diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextExtensions.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextExtensions.cs index fd0e7ed39..59f73ea61 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextExtensions.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextExtensions.cs @@ -12,41 +12,101 @@ namespace Microsoft.Extensions.DependencyModel public static IEnumerable GetDefaultNativeAssets(this DependencyContext self) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } return self.RuntimeLibraries.SelectMany(library => library.GetDefaultNativeAssets(self)); } public static IEnumerable GetRuntimeNativeAssets(this DependencyContext self, string runtimeIdentifier) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } + if (runtimeIdentifier == null) + { + throw new ArgumentNullException(nameof(runtimeIdentifier)); + } return self.RuntimeLibraries.SelectMany(library => library.GetRuntimeNativeAssets(self, runtimeIdentifier)); } public static IEnumerable GetDefaultNativeAssets(this RuntimeLibrary self, DependencyContext context) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } return ResolveAssets(context, string.Empty, self.NativeLibraryGroups); } public static IEnumerable GetRuntimeNativeAssets(this RuntimeLibrary self, DependencyContext context, string runtimeIdentifier) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (runtimeIdentifier == null) + { + throw new ArgumentNullException(nameof(runtimeIdentifier)); + } return ResolveAssets(context, runtimeIdentifier, self.NativeLibraryGroups); } public static IEnumerable GetDefaultAssemblyNames(this DependencyContext self) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } return self.RuntimeLibraries.SelectMany(library => library.GetDefaultAssemblyNames(self)); } public static IEnumerable GetRuntimeAssemblyNames(this DependencyContext self, string runtimeIdentifier) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } + if (runtimeIdentifier == null) + { + throw new ArgumentNullException(nameof(runtimeIdentifier)); + } return self.RuntimeLibraries.SelectMany(library => library.GetRuntimeAssemblyNames(self, runtimeIdentifier)); } public static IEnumerable GetDefaultAssemblyNames(this RuntimeLibrary self, DependencyContext context) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } return ResolveAssets(context, string.Empty, self.RuntimeAssemblyGroups).Select(GetAssemblyName); } public static IEnumerable GetRuntimeAssemblyNames(this RuntimeLibrary self, DependencyContext context, string runtimeIdentifier) { + if (self == null) + { + throw new ArgumentNullException(nameof(self)); + } + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (runtimeIdentifier == null) + { + throw new ArgumentNullException(nameof(runtimeIdentifier)); + } return ResolveAssets(context, runtimeIdentifier, self.RuntimeAssemblyGroups).Select(GetAssemblyName); } diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index 13bee633d..57a0573a2 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -141,7 +141,8 @@ namespace Microsoft.Extensions.DependencyModel } return new CompilationOptions( - compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values() ?? Enumerable.Empty(), + compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values().ToArray() ?? Enumerable.Empty(), + // ToArray is here to prevent IEnumerable holding to json object graph compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value(), compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value(), compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value(), diff --git a/src/dotnet/commands/dotnet-projectmodel-server/Models/DependencyDescription.cs b/src/dotnet/commands/dotnet-projectmodel-server/Models/DependencyDescription.cs index 07aa58a64..32c3854e5 100644 --- a/src/dotnet/commands/dotnet-projectmodel-server/Models/DependencyDescription.cs +++ b/src/dotnet/commands/dotnet-projectmodel-server/Models/DependencyDescription.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Graph; +using NuGet.Versioning; namespace Microsoft.DotNet.ProjectModel.Server.Models { @@ -23,7 +24,7 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models public string Type { get; private set; } public bool Resolved { get; private set; } - + public IEnumerable Dependencies { get; private set; } public IEnumerable Errors { get; private set; } @@ -60,7 +61,7 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models { Name = library.Identity.Name, DisplayName = library.Identity.Name, - Version = library.Identity.Version?.ToNormalizedString(), + Version = (library.Identity.Version ?? new NuGetVersion("1.0.0")).ToNormalizedString(), Type = library.Identity.Type.Value, Resolved = library.Resolved, Path = library.Path, diff --git a/src/dotnet/commands/dotnet-publish/PublishCommand.cs b/src/dotnet/commands/dotnet-publish/PublishCommand.cs index abe835442..5c42f70e5 100644 --- a/src/dotnet/commands/dotnet-publish/PublishCommand.cs +++ b/src/dotnet/commands/dotnet-publish/PublishCommand.cs @@ -131,22 +131,26 @@ namespace Microsoft.DotNet.Tools.Publish var isPortable = string.IsNullOrEmpty(context.RuntimeIdentifier); // Collect all exports and organize them - var exports = exporter.GetAllExports() + var packageExports = exporter.GetAllExports() .Where(e => e.Library.Identity.Type.Equals(LibraryType.Package)) .ToDictionary(e => e.Library.Identity.Name); - var collectExclusionList = isPortable ? GetExclusionList(context, exports) : new HashSet(); + var collectExclusionList = isPortable ? GetExclusionList(context, packageExports) : new HashSet(); - foreach (var export in exporter.GetAllExports().Where(e => !collectExclusionList.Contains(e.Library.Identity.Name))) + var exports = exporter.GetAllExports(); + foreach (var export in exports.Where(e => !collectExclusionList.Contains(e.Library.Identity.Name))) { Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); PublishAssetGroups(export.RuntimeAssemblyGroups, outputPath, nativeSubdirectories: false, includeRuntimeGroups: isPortable); PublishAssetGroups(export.NativeLibraryGroups, outputPath, nativeSubdirectories, includeRuntimeGroups: isPortable); export.RuntimeAssets.StructuredCopyTo(outputPath, outputPaths.IntermediateOutputDirectoryPath); + } - if (options.PreserveCompilationContext.GetValueOrDefault()) + if (options.PreserveCompilationContext.GetValueOrDefault()) + { + foreach (var export in exports) { - PublishRefs(export, outputPath); + PublishRefs(export, outputPath, !collectExclusionList.Contains(export.Library.Identity.Name)); } } @@ -248,19 +252,19 @@ namespace Microsoft.DotNet.Tools.Publish } } - private static void PublishRefs(LibraryExport export, string outputPath) + private static void PublishRefs(LibraryExport export, string outputPath, bool deduplicate) { var refsPath = Path.Combine(outputPath, "refs"); if (!Directory.Exists(refsPath)) { Directory.CreateDirectory(refsPath); } - + // Do not copy compilation assembly if it's in runtime assemblies var runtimeAssemblies = new HashSet(export.RuntimeAssemblyGroups.GetDefaultAssets()); foreach (var compilationAssembly in export.CompilationAssemblies) { - if (!runtimeAssemblies.Contains(compilationAssembly)) + if (!deduplicate || !runtimeAssemblies.Contains(compilationAssembly)) { var destFileName = Path.Combine(refsPath, Path.GetFileName(compilationAssembly.ResolvedPath)); File.Copy(compilationAssembly.ResolvedPath, destFileName, overwrite: true); @@ -358,67 +362,16 @@ namespace Microsoft.DotNet.Tools.Publish private IEnumerable SelectContexts(string projectPath, NuGetFramework framework, string runtime) { - var allContexts = ProjectContext.CreateContextForEachTarget(projectPath).ToList(); - var frameworks = framework == null ? - allContexts.Select(c => c.TargetFramework).Distinct().ToArray() : - new[] { framework }; + var allContexts = framework == null ? + ProjectContext.CreateContextForEachFramework(projectPath) : + new[] { ProjectContext.Create(projectPath, framework) }; - if (string.IsNullOrEmpty(runtime)) - { - // For each framework, find the best matching RID item - var candidates = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); - return frameworks.Select(f => FindBestTarget(f, allContexts, candidates)); - } - else - { - return frameworks.SelectMany(f => allContexts.Where(c => - Equals(c.TargetFramework, f) && - string.Equals(c.RuntimeIdentifier, runtime, StringComparison.Ordinal))); - } + var runtimes = !string.IsNullOrEmpty(runtime) ? + new [] {runtime} : + PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); + return allContexts.Select(c => c.CreateRuntimeContext(runtimes)); } - - private ProjectContext FindBestTarget(NuGetFramework f, List allContexts, IEnumerable candidates) - { - foreach (var candidate in candidates) - { - var target = allContexts.FirstOrDefault(c => - Equals(c.TargetFramework, f) && - string.Equals(c.RuntimeIdentifier, candidate, StringComparison.Ordinal)); - if (target != null) - { - return target; - } - } - - // No RID-specific target found, use the RID-less target and publish portable - return allContexts.FirstOrDefault(c => - Equals(c.TargetFramework, f) && - string.IsNullOrEmpty(c.RuntimeIdentifier)); - } - - /// - /// Return the matching framework/runtime ProjectContext. - /// If 'framework' or 'runtimeIdentifier' is null or empty then it matches with any. - /// - private static IEnumerable GetMatchingProjectContexts(IEnumerable contexts, NuGetFramework framework, string runtimeIdentifier) - { - foreach (var context in contexts) - { - if (context.TargetFramework == null || string.IsNullOrEmpty(context.RuntimeIdentifier)) - { - continue; - } - - if (string.IsNullOrEmpty(runtimeIdentifier) || string.Equals(runtimeIdentifier, context.RuntimeIdentifier, StringComparison.OrdinalIgnoreCase)) - { - if (framework == null || framework.Equals(context.TargetFramework)) - { - yield return context; - } - } - } - } - + private static void CopyContents(ProjectContext context, string outputPath) { var contentFiles = context.ProjectFile.Files.GetContentFiles(); diff --git a/src/dotnet/project.json b/src/dotnet/project.json index b09efdd7b..3878fe1ba 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -17,10 +17,10 @@ ], "dependencies": { "NuGet.Commands": { - "version": "3.5.0-beta-1123", + "version": "3.5.0-beta-1130", "exclude": "compile" }, - "NuGet.CommandLine.XPlat": "3.5.0-beta-1123", + "NuGet.CommandLine.XPlat": "3.5.0-beta-1130", "Newtonsoft.Json": "7.0.1", "System.Text.Encoding.CodePages": "4.0.1-rc2-23931", "System.Diagnostics.FileVersionInfo": "4.0.0-rc2-23931", diff --git a/test/Installer/testmsi.ps1 b/test/Installer/testmsi.ps1 index d1b82f67b..f3d12cdbb 100644 --- a/test/Installer/testmsi.ps1 +++ b/test/Installer/testmsi.ps1 @@ -42,6 +42,7 @@ pushd "$Stage2Dir" try { .\dotnet restore ` + --infer-runtimes ` $testDir ` -f https://www.myget.org/F/dotnet-buildtools/api/v3/index.json | Out-Host diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json index bd59f0d4b..f2613b8aa 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json @@ -6,10 +6,10 @@ "dependencies": { "Microsoft.NETCore.App": "1.0.0-rc2-23931", "System.Runtime.Serialization.Primitives": "4.1.1-rc2-23931", - "NuGet.Versioning": "3.5.0-beta-1123", - "NuGet.Packaging": "3.5.0-beta-1123", - "NuGet.Frameworks": "3.5.0-beta-1123", - "NuGet.ProjectModel": "3.5.0-beta-1123", + "NuGet.Versioning": "3.5.0-beta-1130", + "NuGet.Packaging": "3.5.0-beta-1130", + "NuGet.Frameworks": "3.5.0-beta-1130", + "NuGet.ProjectModel": "3.5.0-beta-1130", "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs index 0d5f4a0a0..a72b7b18f 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs @@ -103,7 +103,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities string.Equals("on", val, StringComparison.OrdinalIgnoreCase)); } - protected void TestExecutable(string outputDir, + protected CommandResult TestExecutable(string outputDir, string executableName, string expectedOutput) { @@ -123,9 +123,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities var result = executableCommand.ExecuteWithCapturedOutput(string.Join(" ", args)); - result.Should().HaveStdOut(expectedOutput); + if (!string.IsNullOrEmpty(expectedOutput)) + { + result.Should().HaveStdOut(expectedOutput); + } result.Should().NotHaveStdErr(); result.Should().Pass(); + return result; } protected void TestOutputExecutable( diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs new file mode 100644 index 000000000..e051f178a --- /dev/null +++ b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Tools.Test.Utilities; +using FluentAssertions; +using Xunit; + +namespace Microsoft.Extensions.DependencyModel +{ + public class FunctionalTests : TestBase + { + private readonly string _testProjectsRoot; + + public FunctionalTests() + { + _testProjectsRoot = Path.Combine(AppContext.BaseDirectory, "TestAssets", "TestProjects"); + } + + [Theory] + [InlineData("TestApp", true)] + [InlineData("TestAppPortable", true)] + [InlineData("TestAppDeps", false)] + [InlineData("TestAppPortableDeps", false)] + public void RunTest(string appname, bool checkCompilation) + { + var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", appname); + var testProject = Path.Combine(testProjectPath, "project.json"); + + var runCommand = new RunCommand(testProject); + var result = runCommand.ExecuteWithCapturedOutput(); + result.Should().Pass(); + ValidateRuntimeLibrarites(result, appname); + if (checkCompilation) + { + ValidateCompilationLibraries(result, appname); + } + } + + [Theory] + [InlineData("TestApp", false, true)] + [InlineData("TestAppPortable", true, true)] + [InlineData("TestAppDeps", false, false)] + [InlineData("TestAppPortableDeps", true, false)] + public void PublishTest(string appname, bool portable, bool checkCompilation) + { + var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", appname); + var testProject = Path.Combine(testProjectPath, "project.json"); + + var publishCommand = new PublishCommand(testProject); + publishCommand.Execute().Should().Pass(); + + var exeName = portable ? publishCommand.GetPortableOutputName() : publishCommand.GetOutputExecutable(); + + var result = TestExecutable(publishCommand.GetOutputDirectory(portable).FullName, exeName, string.Empty); + ValidateRuntimeLibrarites(result, appname); + if (checkCompilation) + { + ValidateCompilationLibraries(result, appname); + } + } + + [WindowsOnlyFact] + public void RunTestFullClr() + { + var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestAppFullClr"); + var testProject = Path.Combine(testProjectPath, "project.json"); + + var runCommand = new RunCommand(testProject); + var result = runCommand.ExecuteWithCapturedOutput(); + result.Should().Pass(); + ValidateRuntimeLibraritesFullClr(result, "TestAppFullClr"); + ValidateCompilationLibrariesFullClr(result, "TestAppFullClr"); + } + + [WindowsOnlyFact] + public void PublishTestFullClr() + { + var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestAppFullClr"); + var testProject = Path.Combine(testProjectPath, "project.json"); + + var publishCommand = new PublishCommand(testProject); + publishCommand.Execute().Should().Pass(); + + var result = TestExecutable(publishCommand.GetOutputDirectory().FullName, publishCommand.GetOutputExecutable(), string.Empty); + ValidateRuntimeLibraritesFullClr(result, "TestAppFullClr"); + ValidateCompilationLibrariesFullClr(result, "TestAppFullClr"); + } + + private void ValidateRuntimeLibraritesFullClr(CommandResult result, string appname) + { + // entry assembly + result.Should().HaveStdOutContaining($"Runtime {appname}:{appname}"); + // project dependency + result.Should().HaveStdOutContaining("Runtime DependencyContextValidator:DependencyContextValidator"); + } + + private void ValidateCompilationLibrariesFullClr(CommandResult result, string appname) + { + // entry assembly + result.Should().HaveStdOutContaining($"Compilation {appname}:{appname}.exe"); + // project dependency + result.Should().HaveStdOutContaining("Compilation DependencyContextValidator:DependencyContextValidator.dll"); + // system assembly + result.Should().HaveStdOutContaining("Compilation mscorlib:mscorlib.dll"); + } + + + private void ValidateRuntimeLibrarites(CommandResult result, string appname) + { + // entry assembly + result.Should().HaveStdOutContaining($"Runtime {appname}:{appname}"); + // project dependency + result.Should().HaveStdOutContaining("Runtime DependencyContextValidator:DependencyContextValidator"); + // system assembly + result.Should().HaveStdOutContaining("Runtime System.Linq:System.Linq"); + } + + private void ValidateCompilationLibraries(CommandResult result, string appname) + { + // entry assembly + result.Should().HaveStdOutContaining($"Compilation {appname}:{appname}.dll"); + // project dependency + result.Should().HaveStdOutContaining("Compilation DependencyContextValidator:DependencyContextValidator.dll"); + // system assembly + result.Should().HaveStdOutContaining("Compilation System.Linq:System.Linq.dll"); + } + + } +} diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/project.json b/test/Microsoft.Extensions.DependencyModel.Tests/project.json index 82a324b4f..b1ca04ba3 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/project.json +++ b/test/Microsoft.Extensions.DependencyModel.Tests/project.json @@ -9,6 +9,9 @@ "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "Microsoft.DotNet.Cli.Utils": { + "target": "project" + }, "FluentAssertions": "4.0.0", "moq.netcore": "4.4.0-beta8", "xunit": "2.1.0", diff --git a/test/dotnet-compile.Tests/CompilerTests.cs b/test/dotnet-compile.Tests/CompilerTests.cs index 3151c0230..efbb5abf9 100644 --- a/test/dotnet-compile.Tests/CompilerTests.cs +++ b/test/dotnet-compile.Tests/CompilerTests.cs @@ -147,26 +147,6 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests result.StdOut.Should().Contain("MyNamespace.Util"); } - [Fact] - public void EmbeddedDependencyContextIsValidOnBuild() - { - var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestApp"); - var testProject = Path.Combine(testProjectPath, "project.json"); - - var runCommand = new RunCommand(testProject); - runCommand.Execute().Should().Pass(); - } - - [Fact] - public void DepsDependencyContextIsValidOnBuild() - { - var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestAppDeps"); - var testProject = Path.Combine(testProjectPath, "project.json"); - - var runCommand = new RunCommand(testProject); - runCommand.Execute().Should().Pass(); - } - [Fact] public void CanSetOutputAssemblyNameForLibraries() { diff --git a/test/dotnet-projectmodel-server.Tests/DthTests.cs b/test/dotnet-projectmodel-server.Tests/DthTests.cs index 92df20c70..4a36cd9f0 100644 --- a/test/dotnet-projectmodel-server.Tests/DthTests.cs +++ b/test/dotnet-projectmodel-server.Tests/DthTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -412,13 +413,47 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests } } } - + + [Fact] + public void AddMSBuildReferenceBeforeRestore() + { + var tam = new TestAssetsManager( + Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects")); + + // var appName = "EmptyNetCoreApp"; + var projectPath = tam.CreateTestInstance("ValidCase01").WithLockFiles().TestRoot; + projectPath = Path.Combine(projectPath, "src", "MainApp"); + + var projectFilePath = Path.Combine(projectPath, Project.FileName); + var projectJson = JsonConvert.DeserializeObject(File.ReadAllText(projectFilePath)); + + ((JObject)projectJson["frameworks"]["net46"]["dependencies"]) + .Add("ClassLibrary4", JToken.FromObject(new { target = "project" })); + + File.WriteAllText(projectFilePath, JsonConvert.SerializeObject(projectJson)); + + using (var server = new DthTestServer(_loggerFactory)) + using (var client = new DthTestClient(server, _loggerFactory)) + { + client.Initialize(projectPath); + var messages = client.DrainAllMessages(); + messages.AssertDoesNotContain(MessageTypes.Error); + // PrintAllMessages(new[] { messages.RetrieveSingleMessage(MessageTypes.Dependencies) }); + messages.RetrieveSingleMessage(MessageTypes.Dependencies) + .RetrieveDependency("ClassLibrary4") + .AssertProperty( + "Version", + v => !string.IsNullOrEmpty(v.ToString()), + v => $"Version string shouldn't be empty. Value [{v.ToString()}]"); + } + } + [Fact] public void MSBuildReferenceTest() { var testProject = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", - "MSBuildReferencesProjects", + "MSBuildReferencesProjects", "ValidCase01", "src", "MainApp"); @@ -428,12 +463,12 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests { client.Initialize(testProject); var messages = client.DrainAllMessages(); - + var classLibraries = new HashSet(new string[] { "ClassLibrary1", "ClassLibrary2", "ClassLibrary3" }); var dependencies = messages.RetrieveSingleMessage(MessageTypes.Dependencies); var testProjectRoot = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects", "ValidCase01"); foreach (var classLibrary in classLibraries) - { + { dependencies.RetrieveDependency(classLibrary) .AssertProperty("Type", LibraryType.MSBuildProject.ToString()) .AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, classLibrary, $"{classLibrary}.csproj"))) @@ -442,21 +477,21 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests .AssertProperty("Errors", array => array.Count == 0) .AssertProperty("Warnings", array => array.Count == 0); } - + var references = messages.RetrieveSingleMessage(MessageTypes.References) .RetrievePayloadAs(); - + var projectReferences = references.RetrievePropertyAs("ProjectReferences"); Assert.Equal(3, projectReferences.Count); for (int i = 0; i < 3; ++i) { var projectRef = projectReferences.RetrieveArraryElementAs(i); var name = projectRef["Name"].Value(); - + Assert.True(classLibraries.Contains(name)); projectRef.AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, name, $"{name}.csproj"))); } - + var fileReferences = references.RetrievePropertyAs("FileReferences") .Select(each => each.Value()) .ToArray(); @@ -467,9 +502,111 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests } } + [Fact] + public void RemovePackageDependencyFromProjectJson() + { + // Remove a package dependency from project.json and then request refreshing dependency before + // restore. + + var appName = "EmptyNetCoreApp"; + var projectPath = _testAssetsManager.CreateTestInstance(appName) + .WithLockFiles() + .TestRoot; + + using (var server = new DthTestServer(_loggerFactory)) + using (var client = new DthTestClient(server, _loggerFactory)) + { + client.Initialize(projectPath); + + client.DrainAllMessages() + .AssertDoesNotContain(MessageTypes.Error) + .RetrieveSingleMessage(MessageTypes.Dependencies) + .RetrieveDependency(appName) + .RetrievePropertyAs("Dependencies") + .AssertJArrayCount(2); + + var projectFilePath = Path.Combine(projectPath, Project.FileName); + var projectJson = JsonConvert.DeserializeObject(File.ReadAllText(projectFilePath)); + + // Remove newtonsoft.json dependency + var dependencies = projectJson["frameworks"]["netcoreapp1.0"]["dependencies"] as JObject; + dependencies.Remove("Newtonsoft.Json"); + + File.WriteAllText(projectFilePath, JsonConvert.SerializeObject(projectJson)); + + client.SendPayLoad(projectPath, MessageTypes.RefreshDependencies); + + var afterDependencies = client.DrainTillFirst(MessageTypes.Dependencies); + afterDependencies.RetrieveDependency(appName) + .RetrievePropertyAs("Dependencies") + .AssertJArrayCount(1) + .RetrieveArraryElementAs(0) + .AssertProperty("Name", "Microsoft.NETCore.App"); + afterDependencies.RetrieveDependency("Newtonsoft.Json"); + } + } + + [Fact] + public void RemoveMSBuildDependencyFromProjectJson() + { + // Remove a msbuild project dependency from project.json and then request refreshing dependency before + // restore. + + var tam = new TestAssetsManager( + Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects")); + + // var appName = "EmptyNetCoreApp"; + var projectPath = tam.CreateTestInstance("ValidCase01").WithLockFiles().TestRoot; + projectPath = Path.Combine(projectPath, "src", "MainApp"); + + using (var server = new DthTestServer(_loggerFactory)) + using (var client = new DthTestClient(server, _loggerFactory)) + { + client.Initialize(projectPath); + + client.DrainAllMessages() + .AssertDoesNotContain(MessageTypes.Error) + .RetrieveSingleMessage(MessageTypes.Dependencies) + .RetrieveDependency("MainApp") + .RetrievePropertyAs("Dependencies") + .AssertJArrayContains(dep => dep["Name"].Value() == "ClassLibrary1") + .AssertJArrayContains(dep => dep["Name"].Value() == "ClassLibrary2") + .AssertJArrayContains(dep => dep["Name"].Value() == "ClassLibrary3"); + + var projectFilePath = Path.Combine(projectPath, Project.FileName); + var projectJson = JsonConvert.DeserializeObject(File.ReadAllText(projectFilePath)); + + // Remove ClassLibrary2 and ClassLibrary3 dependency + var dependencies = projectJson["frameworks"]["net46"]["dependencies"] as JObject; + dependencies.Remove("ClassLibrary2"); + dependencies.Remove("ClassLibrary3"); + + File.WriteAllText(projectFilePath, JsonConvert.SerializeObject(projectJson)); + + client.SendPayLoad(projectPath, MessageTypes.RefreshDependencies); + + var afterDependencies = client.DrainTillFirst(MessageTypes.Dependencies); + afterDependencies.RetrieveDependency("MainApp") + .RetrievePropertyAs("Dependencies") + .AssertJArrayNotContains(dep => dep["Name"].Value() == "ClassLibrary2") + .AssertJArrayNotContains(dep => dep["Name"].Value() == "ClassLibrary3"); + + afterDependencies.RetrieveDependency("ClassLibrary2"); + afterDependencies.RetrieveDependency("ClassLibrary3"); + } + } + private static string NormalizePathString(string original) { return original.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar); } + + private static void PrintAllMessages(IEnumerable messages) + { + foreach (var message in messages) + { + Console.WriteLine($"{message.MessageType} => {message.Payload.ToString()}"); + } + } } } diff --git a/test/dotnet-projectmodel-server.Tests/Helpers/JArrayExtensions.cs b/test/dotnet-projectmodel-server.Tests/Helpers/JArrayExtensions.cs index f7cddb8bb..8dcd21861 100644 --- a/test/dotnet-projectmodel-server.Tests/Helpers/JArrayExtensions.cs +++ b/test/dotnet-projectmodel-server.Tests/Helpers/JArrayExtensions.cs @@ -70,6 +70,21 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests return array; } + public static JArray AssertJArrayNotContains(this JArray array, Func critiera) + { + foreach (var element in array) + { + var value = element.Value(); + + if (critiera(value)) + { + Assert.True(false, "JArray contains unexpected element."); + } + } + + return array; + } + public static T RetrieveArraryElementAs(this JArray json, int index) where T : JToken { diff --git a/test/dotnet-publish.Tests/PublishPortableTests.cs b/test/dotnet-publish.Tests/PublishPortableTests.cs index 8a551e6ca..9283b85dd 100644 --- a/test/dotnet-publish.Tests/PublishPortableTests.cs +++ b/test/dotnet-publish.Tests/PublishPortableTests.cs @@ -81,6 +81,24 @@ namespace Microsoft.DotNet.Tools.Publish.Tests publishDir.Should().NotHaveFile("PortableAppWithNative.runtimeconfig.dev.json"); } + [Fact] + public void RefsPublishTest() + { + TestInstance instance = TestAssetsManager.CreateTestInstance("PortableTests") + .WithLockFiles(); + + var publishCommand = new PublishCommand(Path.Combine(instance.TestRoot, "PortableAppCompilationContext")); + publishCommand.Execute().Should().Pass(); + + publishCommand.GetOutputDirectory(true).Should().HaveFile("PortableAppCompilationContext.dll"); + + var refsDirectory = new DirectoryInfo(Path.Combine(publishCommand.GetOutputDirectory(true).FullName, "refs")); + // Should have compilation time assemblies + refsDirectory.Should().HaveFile("System.IO.dll"); + // Libraries in which lib==ref should be deduped + refsDirectory.Should().NotHaveFile("PortableAppCompilationContext.dll"); + } + private DirectoryInfo Publish(TestInstance testInstance) { var publishCommand = new PublishCommand(Path.Combine(testInstance.TestRoot, "PortableAppWithNative")); diff --git a/tools/RuntimeGraphGenerator/project.json b/tools/RuntimeGraphGenerator/project.json index 78776f9a8..24ce6bd02 100644 --- a/tools/RuntimeGraphGenerator/project.json +++ b/tools/RuntimeGraphGenerator/project.json @@ -4,8 +4,8 @@ "emitEntryPoint": true }, "dependencies": { - "NuGet.RuntimeModel": "3.5.0-beta-1123", - "NuGet.Versioning": "3.5.0-beta-1123", + "NuGet.RuntimeModel": "3.5.0-beta-1130", + "NuGet.Versioning": "3.5.0-beta-1130", "System.CommandLine": "0.1.0-e160119-1", "System.Runtime.Serialization.Json": "4.0.2-rc2-23931", "Microsoft.DotNet.ProjectModel": "1.0.0-*",