From 82d8671379874cabaf9177eec24a026c7c375b83 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Fri, 10 Mar 2023 10:10:23 -0800 Subject: [PATCH] Always log an error when static graph-based restore fails https://github.com/NuGet/Home/issues/12372 --- .../NuGet.Build.Tasks.Console/Program.cs | 108 ++++--- .../NuGet.Build.Tasks/ConsoleOutLogItem.cs | 2 +- .../NuGet.Build.Tasks/ConsoleOutLogMessage.cs | 11 +- .../GenerateRestoreGraphFileTask.cs | 234 +------------- .../NuGet.Build.Tasks/GlobalSuppressions.cs | 2 +- .../NuGet.Build.Tasks/RestoreTaskEx.cs | 264 +--------------- .../StaticGraphRestoreTaskBase.cs | 297 ++++++++++++++++++ .../NuGet.Build.Tasks/Strings.Designer.cs | 28 ++ src/NuGet.Core/NuGet.Build.Tasks/Strings.resx | 16 +- .../NuGet.Build.Tasks/TaskLoggingQueue.cs | 2 +- .../NuGet.Build.Tasks.Console.Test.sln | 165 ++++++++++ .../GenerateRestoreGraphFileTaskTests.cs | 4 +- .../RestoreTaskExTests.cs | 2 +- .../TaskLoggingQueueTests.cs | 2 +- 14 files changed, 607 insertions(+), 530 deletions(-) create mode 100644 src/NuGet.Core/NuGet.Build.Tasks/StaticGraphRestoreTaskBase.cs create mode 100644 test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.sln diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs b/src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs index 64a1735d21e..17b153317cf 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -33,64 +34,79 @@ internal static class Program /// 0 if the application ran successfully with no errors, otherwise 1. public static async Task Main(string[] args) { - var debug = IsDebug(); - - if (debug) + try { - Debugger.Launch(); - } + var debug = IsDebug(); - NuGet.Common.Migrations.MigrationRunner.Run(); + if (debug) + { + Debugger.Launch(); + } - // Parse command-line arguments - if (!TryParseArguments(args, out (Dictionary Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary MSBuildGlobalProperties) arguments)) - { - return 1; - } + NuGet.Common.Migrations.MigrationRunner.Run(); + + // Parse command-line arguments + if (!TryParseArguments(args, out (Dictionary Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary MSBuildGlobalProperties) arguments)) + { + return 1; + } - // Enable MSBuild feature flags - MSBuildFeatureFlags.MSBuildExeFilePath = arguments.MSBuildExeFilePath.FullName; - MSBuildFeatureFlags.EnableCacheFileEnumerations = true; - MSBuildFeatureFlags.LoadAllFilesAsReadonly = true; - MSBuildFeatureFlags.SkipEagerWildcardEvaluations = true; + // Enable MSBuild feature flags + MSBuildFeatureFlags.MSBuildExeFilePath = arguments.MSBuildExeFilePath.FullName; + MSBuildFeatureFlags.EnableCacheFileEnumerations = true; + MSBuildFeatureFlags.LoadAllFilesAsReadonly = true; + MSBuildFeatureFlags.SkipEagerWildcardEvaluations = true; #if NETFRAMEWORK - if (AppDomain.CurrentDomain.IsDefaultAppDomain()) - { - // MSBuild.exe.config has binding redirects that change from time to time and its very hard to make sure that NuGet.Build.Tasks.Console.exe.config is correct. - // It also can be different per instance of Visual Studio so when running unit tests it always needs to match that instance of MSBuild - // The code below runs this EXE in an AppDomain as if its MSBuild.exe so the assembly search location is next to MSBuild.exe and all binding redirects are used - // allowing this process to evaluate MSBuild projects as if it is MSBuild.exe - var thisAssembly = Assembly.GetExecutingAssembly(); - - AppDomain appDomain = AppDomain.CreateDomain( - thisAssembly.FullName, - securityInfo: null, - info: new AppDomainSetup - { - ApplicationBase = arguments.MSBuildExeFilePath.DirectoryName, - ConfigurationFile = Path.Combine(arguments.MSBuildExeFilePath.DirectoryName, "MSBuild.exe.config") - }); - - return appDomain - .ExecuteAssembly( - thisAssembly.Location, - args); - } + if (AppDomain.CurrentDomain.IsDefaultAppDomain()) + { + // MSBuild.exe.config has binding redirects that change from time to time and its very hard to make sure that NuGet.Build.Tasks.Console.exe.config is correct. + // It also can be different per instance of Visual Studio so when running unit tests it always needs to match that instance of MSBuild + // The code below runs this EXE in an AppDomain as if its MSBuild.exe so the assembly search location is next to MSBuild.exe and all binding redirects are used + // allowing this process to evaluate MSBuild projects as if it is MSBuild.exe + var thisAssembly = Assembly.GetExecutingAssembly(); + + AppDomain appDomain = AppDomain.CreateDomain( + thisAssembly.FullName, + securityInfo: null, + info: new AppDomainSetup + { + ApplicationBase = arguments.MSBuildExeFilePath.DirectoryName, + ConfigurationFile = Path.Combine(arguments.MSBuildExeFilePath.DirectoryName, "MSBuild.exe.config") + }); + + return appDomain + .ExecuteAssembly( + thisAssembly.Location, + args); + } #endif - // Check whether the ask is to generate the restore graph file. - if (MSBuildStaticGraphRestore.IsOptionTrue("GenerateRestoreGraphFile", arguments.Options)) - { + // Check whether the ask is to generate the restore graph file. + if (MSBuildStaticGraphRestore.IsOptionTrue("GenerateRestoreGraphFile", arguments.Options)) + { + using (var dependencyGraphSpecGenerator = new MSBuildStaticGraphRestore(debug: debug)) + { + return dependencyGraphSpecGenerator.WriteDependencyGraphSpec(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1; + } + } + + // Otherwise run restore! using (var dependencyGraphSpecGenerator = new MSBuildStaticGraphRestore(debug: debug)) { - return dependencyGraphSpecGenerator.WriteDependencyGraphSpec(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1; + return await dependencyGraphSpecGenerator.RestoreAsync(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1; } } - - // Otherwise run restore! - using (var dependencyGraphSpecGenerator = new MSBuildStaticGraphRestore(debug: debug)) + catch (Exception e) { - return await dependencyGraphSpecGenerator.RestoreAsync(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1; + var consoleOutLogMessage = new ConsoleOutLogMessage + { + Message = string.Format(CultureInfo.CurrentCulture, Strings.Error_StaticGraphUnhandledException, e.ToString()), + MessageType = ConsoleOutLogMessageType.Error, + }; + + System.Console.Out.WriteLine(consoleOutLogMessage.ToJson()); + + return -1; } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogItem.cs b/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogItem.cs index 926df5458fe..02ab5f3972d 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogItem.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogItem.cs @@ -41,7 +41,7 @@ public static implicit operator ConsoleOutLogItem(BuildMessageEventArgs buildMes { return new ConsoleOutLogMessage { - Importance = buildMessageEventArgs.Importance, + Importance = (ConsoleOutLogMessage.MessageImportance)buildMessageEventArgs.Importance, Message = buildMessageEventArgs.Message, MessageType = ConsoleOutLogMessageType.Message, }; diff --git a/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogMessage.cs b/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogMessage.cs index e13cc7531aa..0909b9626bd 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogMessage.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogMessage.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.Build.Framework; using Newtonsoft.Json; namespace NuGet.Build.Tasks @@ -49,5 +48,15 @@ public sealed class ConsoleOutLogMessage : ConsoleOutLogItem public string Subcategory { get; set; } public override string ToJson() => JsonConvert.SerializeObject(this, SerializerSettings); + + /// + /// Represents the message importance. This is a copy of because in some code paths we need to log a message before MSBuild assemblies have been loaded. + /// + public enum MessageImportance + { + High, + Normal, + Low + } } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks/GenerateRestoreGraphFileTask.cs b/src/NuGet.Core/NuGet.Build.Tasks/GenerateRestoreGraphFileTask.cs index 851d172d171..08267a2cd76 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/GenerateRestoreGraphFileTask.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/GenerateRestoreGraphFileTask.cs @@ -1,253 +1,33 @@ // 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.Collections.Generic; -using System.Diagnostics; using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using NuGet.Packaging; namespace NuGet.Build.Tasks { /// /// Represents an MSBuild task that performs a command-line based restore. /// - public sealed class GenerateRestoreGraphFileTask : Microsoft.Build.Utilities.Task, ICancelableTask, IDisposable + public sealed class GenerateRestoreGraphFileTask : StaticGraphRestoreTaskBase { - internal readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - /// - /// Gets the full path to this assembly. - /// - private static readonly Lazy ThisAssemblyLazy = new Lazy(() => new FileInfo(typeof(GenerateRestoreGraphFileTask).Assembly.Location)); - - /// - /// Gets a value indicating whether or not contains a value. - /// - private bool IsSolutionPathDefined => !string.IsNullOrWhiteSpace(SolutionPath) && !string.Equals(SolutionPath, "*Undefined*", StringComparison.OrdinalIgnoreCase); - - /// - /// Gets or sets the full path to the directory containing MSBuild. - /// - [Required] - public string MSBuildBinPath { get; set; } - - /// - /// Gets or sets the full path to the current project file. - /// - [Required] - public string ProjectFullPath { get; set; } - - /// - /// Get or sets a value indicating whether or not the restore should restore all projects or just the entry project. - /// - public bool Recursive { get; set; } - - /// - /// Gets or sets the full path to the solution file (if any) that is being built. - /// - public string SolutionPath { get; set; } - - /// - /// The path to the file to start the additional process with. - /// - public string ProcessFileName { get; set; } - - /// - /// MSBuildStartupDirectory - Used to calculate relative paths - /// - public string MSBuildStartupDirectory { get; set; } - /// /// RestoreGraphOutputPath - The location to write the output to. /// [Required] public string RestoreGraphOutputPath { get; set; } - /// - public void Cancel() => _cancellationTokenSource.Cancel(); - - /// - public void Dispose() - { - _cancellationTokenSource.Dispose(); - } + protected override string DebugEnvironmentVariableName => "DEBUG_GENERATE_RESTORE_GRAPH"; - /// - public override bool Execute() + protected override Dictionary GetOptions() { - try - { -#if DEBUG - var debugTask = Environment.GetEnvironmentVariable("DEBUG_GENERATE_RESTORE_GRAPH"); - if (!string.IsNullOrEmpty(debugTask) && debugTask.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase)) - { - Debugger.Launch(); - } -#endif - using (var semaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1)) - using (var loggingQueue = new TaskLoggingQueue(Log)) - using (var process = new Process()) - { - process.EnableRaisingEvents = true; - process.StartInfo = new ProcessStartInfo - { - Arguments = $"\"{string.Join("\" \"", GetCommandLineArguments())}\"", - CreateNoWindow = true, - FileName = GetProcessFileName(ProcessFileName), - RedirectStandardOutput = true, - UseShellExecute = false, - WorkingDirectory = Environment.CurrentDirectory, - }; - - // Place the output in the queue which handles logging messages coming through on StdOut - process.OutputDataReceived += (sender, args) => loggingQueue.Enqueue(args?.Data); - - process.Exited += (sender, args) => semaphore.Release(); - - try - { - Log.LogMessage(MessageImportance.Low, "\"{0}\" {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); - - process.BeginOutputReadLine(); - - semaphore.Wait(_cancellationTokenSource.Token); - - if (!process.HasExited) - { - try - { - process.Kill(); - } - catch (InvalidOperationException) - { - // The process may have exited, in this case ignore the exception - } - } - } - catch (Exception e) when ( - e is OperationCanceledException - || (e is AggregateException aggregateException && aggregateException.InnerException is OperationCanceledException)) - { - } - } - } - catch (Exception e) - { - Log.LogErrorFromException(e); - } - - return !Log.HasLoggedErrors; - } - - /// - /// Gets the command-line arguments to use when launching the process that executes the restore. - /// - /// An containing the command-line arguments that need to separated by spaces and surrounded by quotes. - internal IEnumerable GetCommandLineArguments() - { -#if IS_CORECLR - // The full path to the executable for dotnet core - yield return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.dll")); -#endif - - var options = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - ["GenerateRestoreGraphFile"] = true.ToString(CultureInfo.CurrentCulture), - [nameof(Recursive)] = Recursive.ToString(CultureInfo.CurrentCulture), - [nameof(RestoreGraphOutputPath)] = RestoreGraphOutputPath, - }; - // Semicolon delimited list of options - yield return string.Join(";", options.Select(i => $"{i.Key}={i.Value}")); - - // Full path to MSBuild.exe or MSBuild.dll -#if IS_CORECLR - yield return Path.Combine(MSBuildBinPath, "MSBuild.dll"); -#else - yield return Path.Combine(MSBuildBinPath, "MSBuild.exe"); - -#endif - // Full path to the entry project. If its a solution file, it will be the full path to solution, otherwise SolutionPath is either empty - // or is the value "*Undefined*" and ProjectFullPath is set instead. - yield return IsSolutionPathDefined - ? SolutionPath - : ProjectFullPath; - - // Semicolon delimited list of MSBuild global properties - var globalProperties = GetGlobalProperties().Select(i => $"{i.Key}={i.Value}").Concat(new string[] { $"OriginalMSBuildStartupDirectory={MSBuildStartupDirectory}" }); - - yield return string.Join(";", globalProperties); - } - - /// - /// Gets the file name of the process. - /// - /// The full path to the file for the process. - internal string GetProcessFileName(string processFileName) - { - if (!string.IsNullOrEmpty(processFileName)) - { - return Path.GetFullPath(processFileName); - } -#if IS_CORECLR - // In .NET Core, the path to dotnet is the file to run - return Path.GetFullPath(Path.Combine(MSBuildBinPath, "..", "..", "dotnet")); -#else - return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.exe")); -#endif - } - - internal Dictionary GetGlobalProperties() - { -#if IS_CORECLR - // MSBuild 16.5 and above has a method to get the global properties, older versions do not - Dictionary msBuildGlobalProperties = BuildEngine is IBuildEngine6 buildEngine6 - ? buildEngine6.GetGlobalProperties().ToDictionary(i => i.Key, i => i.Value, StringComparer.OrdinalIgnoreCase) - : new Dictionary(StringComparer.OrdinalIgnoreCase); -#else - var msBuildGlobalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // MSBuild 16.5 added a new interface, IBuildEngine6, which has a GetGlobalProperties() method. However, we compile against - // Microsoft.Build.Framework version 4.0 when targeting .NET Framework, so reflection is required since type checking - // can't be done at compile time - var buildEngine6Type = typeof(IBuildEngine).Assembly.GetType("Microsoft.Build.Framework.IBuildEngine6"); - - if (buildEngine6Type != null) - { - var getGlobalPropertiesMethod = buildEngine6Type.GetMethod("GetGlobalProperties", BindingFlags.Instance | BindingFlags.Public); - - if (getGlobalPropertiesMethod != null) - { - try - { - if (getGlobalPropertiesMethod.Invoke(BuildEngine, null) is IReadOnlyDictionary globalProperties) - { - msBuildGlobalProperties.AddRange(globalProperties); - } - } - catch (Exception) - { - // Ignored - } - } - } -#endif - msBuildGlobalProperties["ExcludeRestorePackageImports"] = "true"; + Dictionary options = base.GetOptions(); - if (IsSolutionPathDefined) - { - msBuildGlobalProperties["SolutionPath"] = SolutionPath; - } + options["GenerateRestoreGraphFile"] = true.ToString(CultureInfo.CurrentCulture); + options[nameof(RestoreGraphOutputPath)] = RestoreGraphOutputPath; - return msBuildGlobalProperties; + return options; } } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks/GlobalSuppressions.cs b/src/NuGet.Core/NuGet.Build.Tasks/GlobalSuppressions.cs index 6dd9306d47a..43a2b0c5b08 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/GlobalSuppressions.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/GlobalSuppressions.cs @@ -69,5 +69,5 @@ [assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild tasks expect arrays.", Scope = "member", Target = "~P:NuGet.Build.Tasks.CheckForDuplicateNuGetItemsTask.Items")] [assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild tasks expect arrays.", Scope = "member", Target = "~P:NuGet.Build.Tasks.CheckForDuplicateNuGetItemsTask.DeduplicatedItems")] [assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild tasks expect arrays.", Scope = "member", Target = "~P:NuGet.Build.Tasks.RestoreTask.EmbedInBinlog")] -[assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild tasks expect arrays.", Scope = "member", Target = "~P:NuGet.Build.Tasks.RestoreTaskEx.EmbedInBinlog")] +[assembly: SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild tasks expect arrays.", Scope = "member", Target = "~P:NuGet.Build.Tasks.StaticGraphRestoreTaskBase.EmbedInBinlog")] [assembly: SuppressMessage("Usage", "CA2208:Instantiate argument exceptions correctly", Justification = "Argument comes from another method.", Scope = "member", Target = "~M:NuGet.Build.Tasks.TaskLoggingQueue.ConsoleOutLogItemConverter.Create(System.Type)~NuGet.Build.Tasks.ConsoleOutLogItem")] diff --git a/src/NuGet.Core/NuGet.Build.Tasks/RestoreTaskEx.cs b/src/NuGet.Core/NuGet.Build.Tasks/RestoreTaskEx.cs index c1c4536c433..0cd8d73ab75 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/RestoreTaskEx.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/RestoreTaskEx.cs @@ -3,30 +3,17 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; #if !IS_CORECLR using System.Reflection; #endif -using System.Threading; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; namespace NuGet.Build.Tasks { /// /// Represents an MSBuild task that performs a command-line based restore. /// - public sealed class RestoreTaskEx : Microsoft.Build.Utilities.Task, ICancelableTask, IDisposable + public sealed class RestoreTaskEx : StaticGraphRestoreTaskBase { - internal readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - /// - /// Gets the full path to this assembly. - /// - private static readonly Lazy ThisAssemblyLazy = new Lazy(() => new FileInfo(typeof(RestoreTaskEx).Assembly.Location)); - /// /// Gets or sets a value indicating whether or not assets should be deleted for projects that don't support PackageReference. /// @@ -65,252 +52,33 @@ public sealed class RestoreTaskEx : Microsoft.Build.Utilities.Task, ICancelableT /// public bool Interactive { get; set; } - /// - /// Gets a value indicating whether or not contains a value. - /// - public bool IsSolutionPathDefined => !string.IsNullOrWhiteSpace(SolutionPath) && !string.Equals(SolutionPath, "*Undefined*", StringComparison.OrdinalIgnoreCase); - - /// - /// Gets or sets the full path to the directory containing MSBuild. - /// - [Required] - public string MSBuildBinPath { get; set; } - /// /// Gets or sets a value indicating whether or not to avoid using cached packages. /// public bool NoCache { get; set; } - /// - /// Gets or sets the full path to the current project file. - /// - [Required] - public string ProjectFullPath { get; set; } - - /// - /// Get or sets a value indicating whether or not the restore should restore all projects or just the entry project. - /// - public bool Recursive { get; set; } - /// /// Gets or sets a value indicating whether or not to restore projects using packages.config. /// public bool RestorePackagesConfig { get; set; } - /// - /// Gets or sets the full path to the solution file (if any) that is being built. - /// - public string SolutionPath { get; set; } + protected override string DebugEnvironmentVariableName => "DEBUG_RESTORE_TASK_EX"; - /// - /// The path to the file to start the additional process with. - /// - public string ProcessFileName { get; set; } - - /// - /// MSBuildStartupDirectory - Used to calculate relative paths - /// - public string MSBuildStartupDirectory { get; set; } - - [Output] - public ITaskItem[] EmbedInBinlog { get; set; } - - /// - public void Cancel() => _cancellationTokenSource.Cancel(); - - /// - public void Dispose() + protected override Dictionary GetOptions() { - _cancellationTokenSource.Dispose(); - } - - /// - public override bool Execute() - { - try - { -#if DEBUG - var debugRestoreTask = Environment.GetEnvironmentVariable("DEBUG_RESTORE_TASK_EX"); - if (!string.IsNullOrEmpty(debugRestoreTask) && debugRestoreTask.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase)) - { - Debugger.Launch(); - } -#endif - using (var semaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1)) - using (var loggingQueue = new TaskLoggingQueue(Log)) - using (var process = new Process()) - { - process.EnableRaisingEvents = true; - process.StartInfo = new ProcessStartInfo - { - Arguments = $"\"{string.Join("\" \"", GetCommandLineArguments())}\"", - CreateNoWindow = true, - FileName = GetProcessFileName(ProcessFileName), - RedirectStandardOutput = true, - UseShellExecute = false, - WorkingDirectory = Environment.CurrentDirectory, - }; - - // Place the output in the queue which handles logging messages coming through on StdOut - process.OutputDataReceived += (sender, args) => loggingQueue.Enqueue(args?.Data); - - process.Exited += (sender, args) => semaphore.Release(); - - try - { - Log.LogMessage(MessageImportance.Low, "\"{0}\" {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Start(); - - process.BeginOutputReadLine(); - - semaphore.Wait(_cancellationTokenSource.Token); - - if (!process.HasExited) - { - try - { - process.Kill(); - } - catch (InvalidOperationException) - { - // The process may have exited, in this case ignore the exception - } - } - - EmbedInBinlog = loggingQueue.FilesToEmbedInBinlog.Select(i => new TaskItem(i)).ToArray(); - } - catch (Exception e) when ( - e is OperationCanceledException - || (e is AggregateException aggregateException && aggregateException.InnerException is OperationCanceledException)) - { - } - } - } - catch (Exception e) - { - Log.LogErrorFromException(e); - } - - return !Log.HasLoggedErrors; - } - - /// - /// Gets the command-line arguments to use when launching the process that executes the restore. - /// - /// An containing the command-line arguments that need to separated by spaces and surrounded by quotes. - internal IEnumerable GetCommandLineArguments() - { -#if IS_CORECLR - // The full path to the executable for dotnet core - yield return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.dll")); -#endif - - var options = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - [nameof(CleanupAssetsForUnsupportedProjects)] = CleanupAssetsForUnsupportedProjects, - [nameof(DisableParallel)] = DisableParallel, - [nameof(Force)] = Force, - [nameof(ForceEvaluate)] = ForceEvaluate, - [nameof(HideWarningsAndErrors)] = HideWarningsAndErrors, - [nameof(IgnoreFailedSources)] = IgnoreFailedSources, - [nameof(Interactive)] = Interactive, - [nameof(NoCache)] = NoCache, - [nameof(Recursive)] = Recursive, - [nameof(RestorePackagesConfig)] = RestorePackagesConfig, - }; - - // Semicolon delimited list of options - yield return string.Join(";", options.Where(i => i.Value).Select(i => $"{i.Key}={i.Value}")); - - // Full path to MSBuild.exe or MSBuild.dll -#if IS_CORECLR - yield return Path.Combine(MSBuildBinPath, "MSBuild.dll"); -#else - yield return Path.Combine(MSBuildBinPath, "MSBuild.exe"); - -#endif - // Full path to the entry project. If its a solution file, it will be the full path to solution, otherwise SolutionPath is either empty - // or is the value "*Undefined*" and ProjectFullPath is set instead. - yield return IsSolutionPathDefined - ? SolutionPath - : ProjectFullPath; - - // Semicolon delimited list of MSBuild global properties - yield return string.Join(";", GetGlobalProperties().Select(i => $"{i.Key}={i.Value}")); - } - - /// - /// Gets the file name of the process. - /// - /// The full path to the file for the process. - internal string GetProcessFileName(string processFileName) - { - if (!string.IsNullOrEmpty(processFileName)) - { - return Path.GetFullPath(processFileName); - } -#if IS_CORECLR - // In .NET Core, the path to dotnet is the file to run - return Path.GetFullPath(Path.Combine(MSBuildBinPath, "..", "..", "dotnet")); -#else - return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.exe")); -#endif - } - - /// - /// Enumerates a list of global properties for the current MSBuild instance. - /// - /// An of objects containing global properties. - internal IEnumerable> GetGlobalProperties() - { - IReadOnlyDictionary globalProperties = null; - -#if IS_CORECLR - // MSBuild 16.5 and above has a method to get the global properties, older versions do not - if (BuildEngine is IBuildEngine6 buildEngine6) - { - globalProperties = buildEngine6.GetGlobalProperties(); - } -#else - // MSBuild 16.5 added a new interface, IBuildEngine6, which has a GetGlobalProperties() method. However, we compile against - // Microsoft.Build.Framework version 4.0 when targeting .NET Framework, so reflection is required since type checking - // can't be done at compile time - Type buildEngine6Type = typeof(IBuildEngine).Assembly.GetType("Microsoft.Build.Framework.IBuildEngine6"); - - if (buildEngine6Type != null) - { - MethodInfo getGlobalPropertiesMethod = buildEngine6Type.GetMethod("GetGlobalProperties", BindingFlags.Instance | BindingFlags.Public); - - if (getGlobalPropertiesMethod != null) - { - try - { - globalProperties = getGlobalPropertiesMethod.Invoke(BuildEngine, parameters: null) as IReadOnlyDictionary; - } - catch (Exception) - { - // Ignored - } - } - } -#endif - if (globalProperties != null) - { - foreach (KeyValuePair item in globalProperties) - { - yield return item; - } - } - - yield return new KeyValuePair("ExcludeRestorePackageImports", bool.TrueString); - - yield return new KeyValuePair("OriginalMSBuildStartupDirectory", MSBuildStartupDirectory); - - if (IsSolutionPathDefined) - { - yield return new KeyValuePair("SolutionPath", SolutionPath); - } + Dictionary options = base.GetOptions(); + + options[nameof(CleanupAssetsForUnsupportedProjects)] = CleanupAssetsForUnsupportedProjects.ToString(); + options[nameof(DisableParallel)] = DisableParallel.ToString(); + options[nameof(Force)] = Force.ToString(); + options[nameof(ForceEvaluate)] = ForceEvaluate.ToString(); + options[nameof(HideWarningsAndErrors)] = HideWarningsAndErrors.ToString(); + options[nameof(IgnoreFailedSources)] = IgnoreFailedSources.ToString(); + options[nameof(Interactive)] = Interactive.ToString(); + options[nameof(NoCache)] = NoCache.ToString(); + options[nameof(RestorePackagesConfig)] = RestorePackagesConfig.ToString(); + + return options; } } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks/StaticGraphRestoreTaskBase.cs b/src/NuGet.Core/NuGet.Build.Tasks/StaticGraphRestoreTaskBase.cs new file mode 100644 index 00000000000..08f2acb8227 --- /dev/null +++ b/src/NuGet.Core/NuGet.Build.Tasks/StaticGraphRestoreTaskBase.cs @@ -0,0 +1,297 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +#if !IS_CORECLR +using System.Reflection; +#endif +using System.Threading; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace NuGet.Build.Tasks +{ + /// + /// Represents a base class for tasks that use the out-of-proc NuGet.Build.Tasks.Console to perform restore operations with MSBuild's static graph. + /// + public abstract class StaticGraphRestoreTaskBase : Microsoft.Build.Utilities.Task, ICancelableTask, IDisposable + { + internal readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + protected StaticGraphRestoreTaskBase() + : base(Strings.ResourceManager) + { + } + + /// + /// Gets the full path to this assembly. + /// + protected static readonly Lazy ThisAssemblyLazy = new Lazy(() => new FileInfo(typeof(RestoreTaskEx).Assembly.Location)); + + [Output] + public ITaskItem[] EmbedInBinlog { get; set; } + + /// + /// Gets a value indicating whether or not contains a value. + /// + public bool IsSolutionPathDefined => !string.IsNullOrWhiteSpace(SolutionPath) && !string.Equals(SolutionPath, "*Undefined*", StringComparison.OrdinalIgnoreCase); + + /// + /// Gets or sets the full path to the directory containing MSBuild. + /// + [Required] + public string MSBuildBinPath { get; set; } + + /// + /// MSBuildStartupDirectory - Used to calculate relative paths + /// + public string MSBuildStartupDirectory { get; set; } + + /// + /// The path to the file to start the additional process with. + /// + public string ProcessFileName { get; set; } + + /// + /// Gets or sets the full path to the current project file. + /// + [Required] + public string ProjectFullPath { get; set; } + + /// + /// Get or sets a value indicating whether or not the restore should restore all projects or just the entry project. + /// + public bool Recursive { get; set; } + + /// + /// Gets or sets the full path to the solution file (if any) that is being built. + /// + public string SolutionPath { get; set; } + + protected abstract string DebugEnvironmentVariableName { get; } + + /// + public void Cancel() => _cancellationTokenSource.Cancel(); + + /// + public void Dispose() + { + Dispose(disposing: true); + + GC.SuppressFinalize(this); + } + + public override bool Execute() + { + try + { +#if DEBUG + if (string.Equals(Environment.GetEnvironmentVariable(DebugEnvironmentVariableName), bool.TrueString, StringComparison.OrdinalIgnoreCase)) + { + Debugger.Launch(); + } +#endif + MSBuildLogger logger = new MSBuildLogger(Log); + + using (var semaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1)) + using (var loggingQueue = new TaskLoggingQueue(Log)) + using (var process = new Process()) + { + process.EnableRaisingEvents = true; + process.StartInfo = new ProcessStartInfo + { + Arguments = $"\"{string.Join("\" \"", GetCommandLineArguments())}\"", + CreateNoWindow = true, + FileName = GetProcessFileName(ProcessFileName), + RedirectStandardInput = true, + RedirectStandardOutput = true, + UseShellExecute = false, + WorkingDirectory = Environment.CurrentDirectory, + }; + + // Place the output in the queue which handles logging messages coming through on StdOut + process.OutputDataReceived += (sender, args) => loggingQueue.Enqueue(args?.Data); + + process.Exited += (sender, args) => semaphore.Release(); + + try + { + Log.LogMessageFromResources(MessageImportance.Low, nameof(Strings.Log_RunningStaticGraphRestoreCommand), process.StartInfo.FileName, process.StartInfo.Arguments); + + process.Start(); + + process.BeginOutputReadLine(); + + semaphore.Wait(_cancellationTokenSource.Token); + + if (!process.HasExited) + { + try + { + process.Kill(); + } + catch (InvalidOperationException) + { + // The process may have exited, in this case ignore the exception + } + } + + if (_cancellationTokenSource.IsCancellationRequested) + { + return true; + } + + if (process.ExitCode > 0 && !Log.HasLoggedErrors) + { + // All non-zero exit codes should have logged an error, if not its unexpected so log an error asking the user to file an issue + Log.LogErrorFromResources(nameof(Strings.Error_StaticGraphNonZeroExitCode), process.ExitCode); + } + + EmbedInBinlog = loggingQueue.FilesToEmbedInBinlog.Select(i => new TaskItem(i)).ToArray(); + } + catch (Exception e) when ( + e is OperationCanceledException + || (e is AggregateException aggregateException && aggregateException.InnerException is OperationCanceledException)) + { + // Build was canceled + return true; + } + } + } + catch (Exception e) + { + Log.LogErrorFromException(e); + } + + return !Log.HasLoggedErrors; + } + + /// + /// Gets the command-line arguments to use when launching the process that executes the restore. + /// + internal IEnumerable GetCommandLineArguments() + { +#if IS_CORECLR + // The full path to the executable for dotnet core + yield return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.dll")); +#endif + + var options = GetOptions(); + + // Semicolon delimited list of options + yield return string.Join(";", options.Select(i => $"{i.Key}={i.Value}")); + + // Full path to MSBuild.exe or MSBuild.dll +#if IS_CORECLR + yield return Path.Combine(MSBuildBinPath, "MSBuild.dll"); +#else + yield return Path.Combine(MSBuildBinPath, "MSBuild.exe"); + +#endif + // Full path to the entry project. If its a solution file, it will be the full path to solution, otherwise SolutionPath is either empty + // or is the value "*Undefined*" and ProjectFullPath is set instead. + yield return IsSolutionPathDefined + ? SolutionPath + : ProjectFullPath; + + // Semicolon delimited list of MSBuild global properties + var globalProperties = GetGlobalProperties().Select(i => $"{i.Key}={i.Value}"); + + yield return string.Join(";", globalProperties); + } + + /// + /// Enumerates a list of global properties for the current MSBuild instance. + /// + /// A containing global properties. + internal virtual Dictionary GetGlobalProperties() + { + IReadOnlyDictionary globalProperties = null; + +#if IS_CORECLR + // MSBuild 16.5 and above has a method to get the global properties, older versions do not + if (BuildEngine is IBuildEngine6 buildEngine6) + { + globalProperties = buildEngine6.GetGlobalProperties(); + } +#else + // MSBuild 16.5 added a new interface, IBuildEngine6, which has a GetGlobalProperties() method. However, we compile against + // Microsoft.Build.Framework version 4.0 when targeting .NET Framework, so reflection is required since type checking + // can't be done at compile time + Type buildEngine6Type = typeof(IBuildEngine).Assembly.GetType("Microsoft.Build.Framework.IBuildEngine6"); + + if (buildEngine6Type != null) + { + MethodInfo getGlobalPropertiesMethod = buildEngine6Type.GetMethod("GetGlobalProperties", BindingFlags.Instance | BindingFlags.Public); + + if (getGlobalPropertiesMethod != null) + { + try + { + globalProperties = getGlobalPropertiesMethod.Invoke(BuildEngine, parameters: null) as IReadOnlyDictionary; + } + catch (Exception) + { + // Ignored + } + } + } +#endif + Dictionary newGlobalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (globalProperties != null) + { + foreach (KeyValuePair item in globalProperties) + { + newGlobalProperties[item.Key] = item.Value; + } + } + + newGlobalProperties["ExcludeRestorePackageImports"] = bool.TrueString; + newGlobalProperties["OriginalMSBuildStartupDirectory"] = MSBuildStartupDirectory; + + if (IsSolutionPathDefined) + { + newGlobalProperties["SolutionPath"] = SolutionPath; + } + + return newGlobalProperties; + } + + /// + /// Gets the file name of the process. + /// + /// An optional process filename to use as an override. + /// The full path to the file for the process. + internal string GetProcessFileName(string processFileName) + { + if (!string.IsNullOrEmpty(processFileName)) + { + return Path.GetFullPath(processFileName); + } +#if IS_CORECLR + // In .NET Core, the path to dotnet is the file to run + return Path.GetFullPath(Path.Combine(MSBuildBinPath, "..", "..", "dotnet")); +#else + return Path.Combine(ThisAssemblyLazy.Value.DirectoryName, Path.ChangeExtension(ThisAssemblyLazy.Value.Name, ".Console.exe")); +#endif + } + + protected virtual void Dispose(bool disposing) + { + _cancellationTokenSource.Dispose(); + } + + protected virtual Dictionary GetOptions() + { + return new Dictionary(StringComparer.OrdinalIgnoreCase) + { + [nameof(Recursive)] = Recursive.ToString() + }; + } + } +} diff --git a/src/NuGet.Core/NuGet.Build.Tasks/Strings.Designer.cs b/src/NuGet.Core/NuGet.Build.Tasks/Strings.Designer.cs index 74721c4d7bd..57a26eac0b7 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/Strings.Designer.cs @@ -132,6 +132,25 @@ public static string Error_PackagesConfigParseError { } } + /// + /// Looks up a localized string similar to Static graph-based restore failed with exit code '{0}' but did not log an error. Please file an issue at https://github.com/NuGet/Home.. + /// + public static string Error_StaticGraphNonZeroExitCode { + get { + return ResourceManager.GetString("Error_StaticGraphNonZeroExitCode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Static graph-based restore encountered an unhandled exception. Please file an issue at https://github.com/NuGet/Home. The exception was: + ///{0}. + /// + public static string Error_StaticGraphUnhandledException { + get { + return ResourceManager.GetString("Error_StaticGraphUnhandledException", resourceCulture); + } + } + /// /// Looks up a localized string similar to ProjectReference '{0}' was resolved using '{1}' instead of the project target framework '{2}'. This project may not be fully compatible with your project.. /// @@ -168,6 +187,15 @@ public static string Log_ProjectsInSolutionNotKnowntoMSBuild { } } + /// + /// Looks up a localized string similar to Running command: '{0}' {1}. + /// + public static string Log_RunningStaticGraphRestoreCommand { + get { + return ResourceManager.GetString("Log_RunningStaticGraphRestoreCommand", resourceCulture); + } + } + /// /// Looks up a localized string similar to Project '{0}' targets '{2}'. It cannot be referenced by a project that targets '{1}'.. /// diff --git a/src/NuGet.Core/NuGet.Build.Tasks/Strings.resx b/src/NuGet.Core/NuGet.Build.Tasks/Strings.resx index 1ba201c6fa1..9205e527ec9 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/Strings.resx +++ b/src/NuGet.Core/NuGet.Build.Tasks/Strings.resx @@ -186,4 +186,18 @@ Duplicate '{0}' items found. Remove the duplicate items or use the Update functionality to ensure a consistent restore behavior. The duplicate '{0}' items are: {1}. - \ No newline at end of file + + Static graph-based restore failed with exit code '{0}' but did not log an error. Please file an issue at https://github.com/NuGet/Home. + 0 - the exit code of the process + + + Static graph-based restore encountered an unhandled exception. Please file an issue at https://github.com/NuGet/Home. The exception was: +{0} + 0 - The exception as a string. + + + Running command: '{0}' {1} + 0 - the path to the EXE being launched +1 - The command-line arguments + + diff --git a/src/NuGet.Core/NuGet.Build.Tasks/TaskLoggingQueue.cs b/src/NuGet.Core/NuGet.Build.Tasks/TaskLoggingQueue.cs index df9cab80e37..d595473de6a 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/TaskLoggingQueue.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks/TaskLoggingQueue.cs @@ -116,7 +116,7 @@ protected override void Process(string message) return; case ConsoleOutLogMessageType.Message: - _log.LogMessageFromText(consoleOutLogMessage.Message, consoleOutLogMessage.Importance); + _log.LogMessageFromText(consoleOutLogMessage.Message, (MessageImportance)consoleOutLogMessage.Importance); return; } } diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.sln b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.sln new file mode 100644 index 00000000000..e27e2daf4dc --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Console.Test/NuGet.Build.Tasks.Console.Test.sln @@ -0,0 +1,165 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Tasks.Console.Test", "NuGet.Build.Tasks.Console.Test.csproj", "{83869ABF-8141-41C6-927E-CBA9023B719C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.CommandLine", "..\..\..\src\NuGet.Clients\NuGet.CommandLine\NuGet.CommandLine.csproj", "{64297ACA-B28F-4A7B-847E-424FF4259432}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Indexing", "..\..\..\src\NuGet.Clients\NuGet.Indexing\NuGet.Indexing.csproj", "{960377DC-BB8C-4B46-84E9-B69502337842}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.PackageManagement.VisualStudio", "..\..\..\src\NuGet.Clients\NuGet.PackageManagement.VisualStudio\NuGet.PackageManagement.VisualStudio.csproj", "{741C58BE-B44A-4D83-9D8D-A65FCED2D787}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.VisualStudio.Common", "..\..\..\src\NuGet.Clients\NuGet.VisualStudio.Common\NuGet.VisualStudio.Common.csproj", "{DDC6D4FC-5AF5-4022-BFD0-7D14641EF84D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.VisualStudio.Internal.Contracts", "..\..\..\src\NuGet.Clients\NuGet.VisualStudio.Internal.Contracts\NuGet.VisualStudio.Internal.Contracts.csproj", "{C093C977-C76E-421A-B8E3-2B310B476985}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.VisualStudio", "..\..\..\src\NuGet.Clients\NuGet.VisualStudio\NuGet.VisualStudio.csproj", "{1E5D101D-0EEE-4112-BE1D-11D6981D807A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Tasks.Console", "..\..\..\src\NuGet.Core\NuGet.Build.Tasks.Console\NuGet.Build.Tasks.Console.csproj", "{91395822-2CBC-4085-AD3D-EAC361D0E2E1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Tasks", "..\..\..\src\NuGet.Core\NuGet.Build.Tasks\NuGet.Build.Tasks.csproj", "{B0D7A1F3-A6AE-46B8-B451-A6002DCCEF37}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Commands", "..\..\..\src\NuGet.Core\NuGet.Commands\NuGet.Commands.csproj", "{2344E327-5E73-4CD0-99DD-5FB7A1F74931}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Common", "..\..\..\src\NuGet.Core\NuGet.Common\NuGet.Common.csproj", "{FAD59990-AB0E-49F4-8324-6AFAB4ACC02C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Configuration", "..\..\..\src\NuGet.Core\NuGet.Configuration\NuGet.Configuration.csproj", "{8E154147-BDF1-427F-B67E-A9AA4BA7571E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Credentials", "..\..\..\src\NuGet.Core\NuGet.Credentials\NuGet.Credentials.csproj", "{DFAAB8F2-5F3A-49D2-9953-7F1F8C302F13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.DependencyResolver.Core", "..\..\..\src\NuGet.Core\NuGet.DependencyResolver.Core\NuGet.DependencyResolver.Core.csproj", "{BF3E47F5-5B64-4EB3-9FF1-4B3656566CD3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Frameworks", "..\..\..\src\NuGet.Core\NuGet.Frameworks\NuGet.Frameworks.csproj", "{F208AC8D-1997-47A9-9E2E-4371ED987855}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.LibraryModel", "..\..\..\src\NuGet.Core\NuGet.LibraryModel\NuGet.LibraryModel.csproj", "{61AE8CF8-13A2-4B3A-A1F2-8397A62E40B7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.PackageManagement", "..\..\..\src\NuGet.Core\NuGet.PackageManagement\NuGet.PackageManagement.csproj", "{4D840A4A-281A-40A1-A982-2D1E707E82DF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Packaging", "..\..\..\src\NuGet.Core\NuGet.Packaging\NuGet.Packaging.csproj", "{3E1F2AD0-62C1-48D6-8E03-D1DAFC13B4EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.ProjectModel", "..\..\..\src\NuGet.Core\NuGet.ProjectModel\NuGet.ProjectModel.csproj", "{BA91A423-C75B-4B32-A722-1F4429D9FBD4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Protocol", "..\..\..\src\NuGet.Core\NuGet.Protocol\NuGet.Protocol.csproj", "{B0BB224E-4C98-4804-AF95-7507F3FA98DD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Resolver", "..\..\..\src\NuGet.Core\NuGet.Resolver\NuGet.Resolver.csproj", "{CB0382A2-0F69-4D9A-831B-A4158991A52F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Versioning", "..\..\..\src\NuGet.Core\NuGet.Versioning\NuGet.Versioning.csproj", "{697BCD44-63BB-4014-AD3D-BFA752974362}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Build.Tasks.Test", "..\NuGet.Build.Tasks.Test\NuGet.Build.Tasks.Test.csproj", "{2071560F-EB85-476B-80BD-7091BEBDF27C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Configuration.Test", "..\NuGet.Configuration.Test\NuGet.Configuration.Test.csproj", "{6A8B25D5-2D80-4585-A0E6-970462EBC8D9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Utility", "..\..\TestUtilities\Test.Utility\Test.Utility.csproj", "{2DEA4B93-992C-4C27-B509-2A4A24B7D127}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {83869ABF-8141-41C6-927E-CBA9023B719C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83869ABF-8141-41C6-927E-CBA9023B719C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83869ABF-8141-41C6-927E-CBA9023B719C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83869ABF-8141-41C6-927E-CBA9023B719C}.Release|Any CPU.Build.0 = Release|Any CPU + {64297ACA-B28F-4A7B-847E-424FF4259432}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64297ACA-B28F-4A7B-847E-424FF4259432}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64297ACA-B28F-4A7B-847E-424FF4259432}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64297ACA-B28F-4A7B-847E-424FF4259432}.Release|Any CPU.Build.0 = Release|Any CPU + {960377DC-BB8C-4B46-84E9-B69502337842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {960377DC-BB8C-4B46-84E9-B69502337842}.Debug|Any CPU.Build.0 = Debug|Any CPU + {960377DC-BB8C-4B46-84E9-B69502337842}.Release|Any CPU.ActiveCfg = Release|Any CPU + {960377DC-BB8C-4B46-84E9-B69502337842}.Release|Any CPU.Build.0 = Release|Any CPU + {741C58BE-B44A-4D83-9D8D-A65FCED2D787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {741C58BE-B44A-4D83-9D8D-A65FCED2D787}.Debug|Any CPU.Build.0 = Debug|Any CPU + {741C58BE-B44A-4D83-9D8D-A65FCED2D787}.Release|Any CPU.ActiveCfg = Release|Any CPU + {741C58BE-B44A-4D83-9D8D-A65FCED2D787}.Release|Any CPU.Build.0 = Release|Any CPU + {DDC6D4FC-5AF5-4022-BFD0-7D14641EF84D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDC6D4FC-5AF5-4022-BFD0-7D14641EF84D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDC6D4FC-5AF5-4022-BFD0-7D14641EF84D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDC6D4FC-5AF5-4022-BFD0-7D14641EF84D}.Release|Any CPU.Build.0 = Release|Any CPU + {C093C977-C76E-421A-B8E3-2B310B476985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C093C977-C76E-421A-B8E3-2B310B476985}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C093C977-C76E-421A-B8E3-2B310B476985}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C093C977-C76E-421A-B8E3-2B310B476985}.Release|Any CPU.Build.0 = Release|Any CPU + {1E5D101D-0EEE-4112-BE1D-11D6981D807A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E5D101D-0EEE-4112-BE1D-11D6981D807A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E5D101D-0EEE-4112-BE1D-11D6981D807A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E5D101D-0EEE-4112-BE1D-11D6981D807A}.Release|Any CPU.Build.0 = Release|Any CPU + {91395822-2CBC-4085-AD3D-EAC361D0E2E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91395822-2CBC-4085-AD3D-EAC361D0E2E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91395822-2CBC-4085-AD3D-EAC361D0E2E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91395822-2CBC-4085-AD3D-EAC361D0E2E1}.Release|Any CPU.Build.0 = Release|Any CPU + {B0D7A1F3-A6AE-46B8-B451-A6002DCCEF37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0D7A1F3-A6AE-46B8-B451-A6002DCCEF37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0D7A1F3-A6AE-46B8-B451-A6002DCCEF37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0D7A1F3-A6AE-46B8-B451-A6002DCCEF37}.Release|Any CPU.Build.0 = Release|Any CPU + {2344E327-5E73-4CD0-99DD-5FB7A1F74931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2344E327-5E73-4CD0-99DD-5FB7A1F74931}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2344E327-5E73-4CD0-99DD-5FB7A1F74931}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2344E327-5E73-4CD0-99DD-5FB7A1F74931}.Release|Any CPU.Build.0 = Release|Any CPU + {FAD59990-AB0E-49F4-8324-6AFAB4ACC02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAD59990-AB0E-49F4-8324-6AFAB4ACC02C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAD59990-AB0E-49F4-8324-6AFAB4ACC02C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAD59990-AB0E-49F4-8324-6AFAB4ACC02C}.Release|Any CPU.Build.0 = Release|Any CPU + {8E154147-BDF1-427F-B67E-A9AA4BA7571E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E154147-BDF1-427F-B67E-A9AA4BA7571E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E154147-BDF1-427F-B67E-A9AA4BA7571E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E154147-BDF1-427F-B67E-A9AA4BA7571E}.Release|Any CPU.Build.0 = Release|Any CPU + {DFAAB8F2-5F3A-49D2-9953-7F1F8C302F13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFAAB8F2-5F3A-49D2-9953-7F1F8C302F13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFAAB8F2-5F3A-49D2-9953-7F1F8C302F13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFAAB8F2-5F3A-49D2-9953-7F1F8C302F13}.Release|Any CPU.Build.0 = Release|Any CPU + {BF3E47F5-5B64-4EB3-9FF1-4B3656566CD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF3E47F5-5B64-4EB3-9FF1-4B3656566CD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF3E47F5-5B64-4EB3-9FF1-4B3656566CD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF3E47F5-5B64-4EB3-9FF1-4B3656566CD3}.Release|Any CPU.Build.0 = Release|Any CPU + {F208AC8D-1997-47A9-9E2E-4371ED987855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F208AC8D-1997-47A9-9E2E-4371ED987855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F208AC8D-1997-47A9-9E2E-4371ED987855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F208AC8D-1997-47A9-9E2E-4371ED987855}.Release|Any CPU.Build.0 = Release|Any CPU + {61AE8CF8-13A2-4B3A-A1F2-8397A62E40B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61AE8CF8-13A2-4B3A-A1F2-8397A62E40B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61AE8CF8-13A2-4B3A-A1F2-8397A62E40B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61AE8CF8-13A2-4B3A-A1F2-8397A62E40B7}.Release|Any CPU.Build.0 = Release|Any CPU + {4D840A4A-281A-40A1-A982-2D1E707E82DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D840A4A-281A-40A1-A982-2D1E707E82DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D840A4A-281A-40A1-A982-2D1E707E82DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D840A4A-281A-40A1-A982-2D1E707E82DF}.Release|Any CPU.Build.0 = Release|Any CPU + {3E1F2AD0-62C1-48D6-8E03-D1DAFC13B4EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E1F2AD0-62C1-48D6-8E03-D1DAFC13B4EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E1F2AD0-62C1-48D6-8E03-D1DAFC13B4EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E1F2AD0-62C1-48D6-8E03-D1DAFC13B4EF}.Release|Any CPU.Build.0 = Release|Any CPU + {BA91A423-C75B-4B32-A722-1F4429D9FBD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA91A423-C75B-4B32-A722-1F4429D9FBD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA91A423-C75B-4B32-A722-1F4429D9FBD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA91A423-C75B-4B32-A722-1F4429D9FBD4}.Release|Any CPU.Build.0 = Release|Any CPU + {B0BB224E-4C98-4804-AF95-7507F3FA98DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0BB224E-4C98-4804-AF95-7507F3FA98DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0BB224E-4C98-4804-AF95-7507F3FA98DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0BB224E-4C98-4804-AF95-7507F3FA98DD}.Release|Any CPU.Build.0 = Release|Any CPU + {CB0382A2-0F69-4D9A-831B-A4158991A52F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB0382A2-0F69-4D9A-831B-A4158991A52F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB0382A2-0F69-4D9A-831B-A4158991A52F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB0382A2-0F69-4D9A-831B-A4158991A52F}.Release|Any CPU.Build.0 = Release|Any CPU + {697BCD44-63BB-4014-AD3D-BFA752974362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {697BCD44-63BB-4014-AD3D-BFA752974362}.Debug|Any CPU.Build.0 = Debug|Any CPU + {697BCD44-63BB-4014-AD3D-BFA752974362}.Release|Any CPU.ActiveCfg = Release|Any CPU + {697BCD44-63BB-4014-AD3D-BFA752974362}.Release|Any CPU.Build.0 = Release|Any CPU + {2071560F-EB85-476B-80BD-7091BEBDF27C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2071560F-EB85-476B-80BD-7091BEBDF27C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2071560F-EB85-476B-80BD-7091BEBDF27C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2071560F-EB85-476B-80BD-7091BEBDF27C}.Release|Any CPU.Build.0 = Release|Any CPU + {6A8B25D5-2D80-4585-A0E6-970462EBC8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A8B25D5-2D80-4585-A0E6-970462EBC8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A8B25D5-2D80-4585-A0E6-970462EBC8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A8B25D5-2D80-4585-A0E6-970462EBC8D9}.Release|Any CPU.Build.0 = Release|Any CPU + {2DEA4B93-992C-4C27-B509-2A4A24B7D127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DEA4B93-992C-4C27-B509-2A4A24B7D127}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DEA4B93-992C-4C27-B509-2A4A24B7D127}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DEA4B93-992C-4C27-B509-2A4A24B7D127}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {99D74849-423C-4BC5-A2B2-FD5F3523BD23} + EndGlobalSection +EndGlobal diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/GenerateRestoreGraphFileTaskTests.cs b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/GenerateRestoreGraphFileTaskTests.cs index 449e4357042..4e1e6bc3baa 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/GenerateRestoreGraphFileTaskTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/GenerateRestoreGraphFileTaskTests.cs @@ -54,14 +54,14 @@ public void GetCommandLineArguments_WhenOptionsSpecified_CorrectValuesReturned() #if IS_CORECLR Path.ChangeExtension(typeof(RestoreTaskEx).Assembly.Location, ".Console.dll"), #endif - $"GenerateRestoreGraphFile=True;Recursive=True;RestoreGraphOutputPath={restoreGraphOutputPath}", + $"Recursive=True;GenerateRestoreGraphFile=True;RestoreGraphOutputPath={restoreGraphOutputPath}", #if IS_CORECLR Path.Combine(msbuildBinPath, "MSBuild.dll"), #else Path.Combine(msbuildBinPath, "MSBuild.exe"), #endif projectPath, - $"Property1=Value1;Property2= Value2 ;ExcludeRestorePackageImports=true;OriginalMSBuildStartupDirectory={testDirectory}"); + $"Property1=Value1;Property2= Value2 ;ExcludeRestorePackageImports=True;OriginalMSBuildStartupDirectory={testDirectory}"); } } } diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/RestoreTaskExTests.cs b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/RestoreTaskExTests.cs index ec7d7ac1ee5..245e483a510 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/RestoreTaskExTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/RestoreTaskExTests.cs @@ -62,7 +62,7 @@ public void GetCommandLineArguments_WhenOptionsSpecified_CorrectValuesReturned() #if IS_CORECLR Path.ChangeExtension(typeof(RestoreTaskEx).Assembly.Location, ".Console.dll"), #endif - "CleanupAssetsForUnsupportedProjects=True;DisableParallel=True;Force=True;ForceEvaluate=True;HideWarningsAndErrors=True;IgnoreFailedSources=True;Interactive=True;NoCache=True;Recursive=True;RestorePackagesConfig=True", + "Recursive=True;CleanupAssetsForUnsupportedProjects=True;DisableParallel=True;Force=True;ForceEvaluate=True;HideWarningsAndErrors=True;IgnoreFailedSources=True;Interactive=True;NoCache=True;RestorePackagesConfig=True", #if IS_CORECLR Path.Combine(msbuildBinPath, "MSBuild.dll"), #else diff --git a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/TaskLoggingQueueTests.cs b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/TaskLoggingQueueTests.cs index eb62134e199..ae125bbe8a7 100644 --- a/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/TaskLoggingQueueTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Build.Tasks.Test/TaskLoggingQueueTests.cs @@ -52,7 +52,7 @@ public void TaskLoggingQueue_Process_LogsMessages(string messageType, string mes if (messageImportance.HasValue) { - expected.Importance = messageImportance.Value; + expected.Importance = (ConsoleOutLogMessage.MessageImportance)messageImportance.Value; } var buildEngine = new TestBuildEngine();