Skip to content

Commit

Permalink
Revert functionality to have static graph-based restore write argumen…
Browse files Browse the repository at this point in the history
…ts to standard input (#5080)

* Revert "Properly handle alternate console stream encodings in StaticGraphRestoreArguments (#5010)"

This reverts commit 6512bed.

* Revert "Write static graph restore arguments to standard input instead of passing on the command-line (#4772)"

This reverts commit 19a4170.
  • Loading branch information
jeffkl committed Mar 9, 2023
1 parent f49ca00 commit 3ab7d14
Show file tree
Hide file tree
Showing 11 changed files with 572 additions and 711 deletions.
83 changes: 60 additions & 23 deletions src/NuGet.Core/NuGet.Build.Tasks.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// 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;
using System.Reflection;
using System.Threading.Tasks;

Expand All @@ -14,6 +16,16 @@ namespace NuGet.Build.Tasks.Console
/// </summary>
internal static class Program
{
/// <summary>
/// A <see cref="T:char[]" /> containing the equals sign '=' to be used to split key/value pairs that are separated by it.
/// </summary>
private static readonly char[] EqualSign = { '=' };

/// <summary>
/// A <see cref="T:char[]" /> containing the semicolon ';' to be used to split key/value pairs that are separated by it.
/// </summary>
private static readonly char[] Semicolon = { ';' };

/// <summary>
/// The main entry point to the console application.
/// </summary>
Expand All @@ -29,36 +41,34 @@ public static async Task<int> Main(string[] args)
}

NuGet.Common.Migrations.MigrationRunner.Run();
if (args.Length != 2)

// Parse command-line arguments
if (!TryParseArguments(args, out (Dictionary<string, string> Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary<string, string> MSBuildGlobalProperties) arguments))
{
return 1;
}

var msbuildFilePath = new FileInfo(args[0]);
var entryProjectPath = new FileInfo(args[1]);

// Enable MSBuild feature flags
MSBuildFeatureFlags.MSBuildExeFilePath = msbuildFilePath.FullName;
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
Assembly thisAssembly = Assembly.GetExecutingAssembly();
var thisAssembly = Assembly.GetExecutingAssembly();

AppDomain appDomain = AppDomain.CreateDomain(
thisAssembly.FullName,
securityInfo: null,
info: new AppDomainSetup
{
ApplicationBase = msbuildFilePath.DirectoryName,
ConfigurationFile = Path.Combine(msbuildFilePath.DirectoryName, "MSBuild.exe.config")
ApplicationBase = arguments.MSBuildExeFilePath.DirectoryName,
ConfigurationFile = Path.Combine(arguments.MSBuildExeFilePath.DirectoryName, "MSBuild.exe.config")
});

return appDomain
Expand All @@ -68,25 +78,19 @@ public static async Task<int> Main(string[] args)
}
#endif

// Parse command-line arguments
if (!TryGetArguments(out StaticGraphRestoreArguments arguments))
{
return 1;
}

// 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(entryProjectPath.FullName, arguments.GlobalProperties, arguments.Options) ? 0 : 1;
return dependencyGraphSpecGenerator.WriteDependencyGraphSpec(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1;
}
}

// Otherwise run restore!
using (var dependencyGraphSpecGenerator = new MSBuildStaticGraphRestore(debug: debug))
{
return await dependencyGraphSpecGenerator.RestoreAsync(entryProjectPath.FullName, arguments.GlobalProperties, arguments.Options) ? 0 : 1;
return await dependencyGraphSpecGenerator.RestoreAsync(arguments.EntryProjectFilePath, arguments.MSBuildGlobalProperties, arguments.Options) ? 0 : 1;
}
}

Expand All @@ -99,25 +103,58 @@ private static bool IsDebug()
return string.Equals(Environment.GetEnvironmentVariable("DEBUG_RESTORE_TASK"), bool.TrueString, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Parses a semicolon delimited list of equal sign separated key value pairs.
/// </summary>
/// <param name="value">The string containing a semicolon delimited list of key value pairs to parse.</param>
/// <returns>A <see cref="Dictionary{String,String}" /> containing the list of items as key value pairs.</returns>
private static Dictionary<string, string> ParseSemicolonDelimitedListOfKeyValuePairs(string value)
{
var properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

foreach (var pair in value
.Split(Semicolon, StringSplitOptions.RemoveEmptyEntries)
.Where(i => !string.IsNullOrWhiteSpace(i))
.Select(i => i.Split(EqualSign, 2))
.Where(i => i.Length == 2 && !string.IsNullOrWhiteSpace(i[0]) && !string.IsNullOrWhiteSpace(i[1])))
{
properties[pair[0].Trim()] = pair[1].Trim();
}

return properties;
}

/// <summary>
/// Parses command-line arguments.
/// </summary>
/// <param name="staticGraphRestoreArguments">Receives the arguments as a <see cref="StaticGraphRestoreArguments" />.</param>
/// <param name="args">A <see cref="T:string[]" /> containing the process command-line arguments.</param>
/// <param name="arguments">A <see cref="T:Tuple&lt;Dictionary&lt;string, string&gt;, FileInfo, string, Dictionary&lt;string, string&gt;&gt;" /> that receives the parsed command-line arguments.</param>
/// <returns><code>true</code> if the arguments were successfully parsed, otherwise <code>false</code>.</returns>
private static bool TryGetArguments(out StaticGraphRestoreArguments staticGraphRestoreArguments)
private static bool TryParseArguments(string[] args, out (Dictionary<string, string> Options, FileInfo MSBuildExeFilePath, string EntryProjectFilePath, Dictionary<string, string> MSBuildGlobalProperties) arguments)
{
staticGraphRestoreArguments = null;
if (args.Length != 4)
{
arguments = (null, null, null, null);

return false;
}

try
{
using Stream stream = System.Console.OpenStandardInput();
var options = ParseSemicolonDelimitedListOfKeyValuePairs(args[0]);
var msbuildExeFilePath = new FileInfo(args[1]);
var entryProjectFilePath = args[2];
var globalProperties = ParseSemicolonDelimitedListOfKeyValuePairs(args[3]);

staticGraphRestoreArguments = StaticGraphRestoreArguments.Read(stream, System.Console.InputEncoding);
arguments = (options, msbuildExeFilePath, entryProjectFilePath, globalProperties);

return staticGraphRestoreArguments != null;
// Command-line is correct if no exceptions were thrown and the MSBuild path exists and an entry project were specified
return msbuildExeFilePath.Exists && !string.IsNullOrWhiteSpace(entryProjectFilePath);
}
catch (Exception)
{
arguments = (null, null, null, null);

return false;
}
}
Expand Down
Loading

0 comments on commit 3ab7d14

Please sign in to comment.