Skip to content

Commit

Permalink
Always log an error when static graph-based restore fails
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffkl committed Mar 10, 2023
1 parent 3ab7d14 commit 82d8671
Show file tree
Hide file tree
Showing 14 changed files with 607 additions and 530 deletions.
108 changes: 62 additions & 46 deletions src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -33,64 +34,79 @@ internal static class Program
/// <returns><code>0</code> if the application ran successfully with no errors, otherwise <code>1</code>.</returns>
public static async Task<int> 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<string, string> Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary<string, string> MSBuildGlobalProperties) arguments))
{
return 1;
}
NuGet.Common.Migrations.MigrationRunner.Run();

// Parse command-line arguments
if (!TryParseArguments(args, out (Dictionary<string, string> Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary<string, string> 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;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
11 changes: 10 additions & 1 deletion src/NuGet.Core/NuGet.Build.Tasks/ConsoleOutLogMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,5 +48,15 @@ public sealed class ConsoleOutLogMessage : ConsoleOutLogItem
public string Subcategory { get; set; }

public override string ToJson() => JsonConvert.SerializeObject(this, SerializerSettings);

/// <summary>
/// Represents the message importance. This is a copy of <see cref="MessageImportance" /> because in some code paths we need to log a message before MSBuild assemblies have been loaded.
/// </summary>
public enum MessageImportance
{
High,
Normal,
Low
}
}
}
Loading

0 comments on commit 82d8671

Please sign in to comment.