-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adapt System.CommandLine (v2) in more places #72082
Merged
jkotas
merged 18 commits into
dotnet:main
from
am11:feature/deps/system.commandline_usage
Sep 23, 2022
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
a9a79d5
Switch ilc to use System.CommandLine
am11 c5e20e4
Switch cg2 to use System.CommandLine
am11 4e0cc48
Fix release build
am11 a275b13
Fix test build
am11 e235421
ilc: --insructionset, crossgen2: --instruction-set 🥲
am11 1aa261f
Fix a couple of defaults
am11 93b0586
Fix repro package arguments for cg2
am11 f896f93
Address CR feedback
am11 3a242d2
ilc: rename --instructionset to --instruction-set
am11 c626638
Merge dotnet/main into feature/deps/system.commandline_usage
am11 bf4bd51
Remove 'Microsoft (R)' from tools' banner
am11 1cab725
Merge dotnet/main into feature/deps/system.comman..
am11 75044e7
Merge conflict typo fix
am11 b409d0c
Merge dotnet/main into feature/deps/system.comman..
am11 6808013
Merge dotnet/main and resolve conflicts
am11 3cd9df4
Merge dotnet/main into feature/deps/system.comman..
am11 6b90827
Add -v alias for version (to match old behavior)
am11 ec4fc4d
Merge dotnet/main into feature/deps/system.comman..
am11 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
using System.CommandLine.Binding; | ||
using System.CommandLine.Parsing; | ||
using System.IO; | ||
using System.IO.Compression; | ||
using System.Runtime.InteropServices; | ||
|
||
using Internal.TypeSystem; | ||
|
||
namespace System.CommandLine | ||
{ | ||
internal sealed class CommandLineException : Exception | ||
{ | ||
public CommandLineException(string message) : base(message) { } | ||
} | ||
|
||
// | ||
// Helpers for command line processing | ||
// | ||
internal static class Helpers | ||
{ | ||
public const string DefaultSystemModule = "System.Private.CoreLib"; | ||
|
||
public static Dictionary<string, string> BuildPathDictionay(IReadOnlyList<Token> tokens, bool strict) | ||
{ | ||
Dictionary<string, string> dictionary = new(StringComparer.OrdinalIgnoreCase); | ||
|
||
foreach (Token token in tokens) | ||
{ | ||
AppendExpandedPaths(dictionary, token.Value, strict); | ||
} | ||
|
||
return dictionary; | ||
} | ||
|
||
public static TargetOS GetTargetOS(string token) | ||
{ | ||
if(string.IsNullOrEmpty(token)) | ||
{ | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
return TargetOS.Windows; | ||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | ||
return TargetOS.Linux; | ||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | ||
return TargetOS.OSX; | ||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) | ||
return TargetOS.FreeBSD; | ||
|
||
throw new NotImplementedException(); | ||
} | ||
|
||
if (token.Equals("windows", StringComparison.OrdinalIgnoreCase)) | ||
return TargetOS.Windows; | ||
else if (token.Equals("linux", StringComparison.OrdinalIgnoreCase)) | ||
return TargetOS.Linux; | ||
else if (token.Equals("osx", StringComparison.OrdinalIgnoreCase)) | ||
return TargetOS.OSX; | ||
|
||
throw new CommandLineException($"Target OS '{token}' is not supported"); | ||
} | ||
|
||
public static TargetArchitecture GetTargetArchitecture(string token) | ||
{ | ||
if(string.IsNullOrEmpty(token)) | ||
{ | ||
return RuntimeInformation.ProcessArchitecture switch | ||
{ | ||
Architecture.X86 => TargetArchitecture.X86, | ||
Architecture.X64 => TargetArchitecture.X64, | ||
Architecture.Arm => TargetArchitecture.ARM, | ||
Architecture.Arm64 => TargetArchitecture.ARM64, | ||
Architecture.LoongArch64 => TargetArchitecture.LoongArch64, | ||
_ => throw new NotImplementedException() | ||
}; | ||
} | ||
|
||
if (token.Equals("x86", StringComparison.OrdinalIgnoreCase)) | ||
return TargetArchitecture.X86; | ||
else if (token.Equals("x64", StringComparison.OrdinalIgnoreCase)) | ||
return TargetArchitecture.X64; | ||
else if (token.Equals("arm", StringComparison.OrdinalIgnoreCase)) | ||
return TargetArchitecture.ARM; | ||
else if (token.Equals("arm64", StringComparison.OrdinalIgnoreCase)) | ||
return TargetArchitecture.ARM64; | ||
else if (token.Equals("loongarch64", StringComparison.OrdinalIgnoreCase)) | ||
return TargetArchitecture.LoongArch64; | ||
|
||
throw new CommandLineException($"Target architecture '{token}' is not supported"); | ||
} | ||
|
||
public static void MakeReproPackage(string makeReproPath, string outputFilePath, string[] args, ParseResult res, IEnumerable<string> inputOptions) | ||
{ | ||
Directory.CreateDirectory(makeReproPath); | ||
|
||
List<string> details = new List<string>(); | ||
details.Add("Tool version"); | ||
try | ||
{ | ||
details.Add(Environment.GetCommandLineArgs()[0]); | ||
} | ||
catch { } | ||
try | ||
{ | ||
details.Add(System.Diagnostics.FileVersionInfo.GetVersionInfo(Environment.GetCommandLineArgs()[0]).ToString()); | ||
} | ||
catch { } | ||
|
||
details.Add("------------------------"); | ||
details.Add("Actual Command Line Args"); | ||
details.Add("------------------------"); | ||
details.AddRange(args); | ||
foreach (string arg in args) | ||
{ | ||
if (arg.StartsWith('@')) | ||
{ | ||
string rspFileName = arg.Substring(1); | ||
details.Add("------------------------"); | ||
details.Add(rspFileName); | ||
details.Add("------------------------"); | ||
try | ||
{ | ||
details.AddRange(File.ReadAllLines(rspFileName)); | ||
} | ||
catch { } | ||
} | ||
} | ||
|
||
HashCode hashCodeOfArgs = default; | ||
foreach (string s in details) | ||
hashCodeOfArgs.Add(s); | ||
|
||
string zipFileName = ((uint)hashCodeOfArgs.ToHashCode()).ToString(); | ||
|
||
if (outputFilePath != null) | ||
zipFileName = zipFileName + "_" + Path.GetFileName(outputFilePath); | ||
|
||
zipFileName = Path.Combine(makeReproPath, Path.ChangeExtension(zipFileName, ".zip")); | ||
|
||
Console.WriteLine($"Creating {zipFileName}"); | ||
using (var archive = ZipFile.Open(zipFileName, ZipArchiveMode.Create)) | ||
{ | ||
ZipArchiveEntry commandEntry = archive.CreateEntry("command.txt"); | ||
using (StreamWriter writer = new StreamWriter(commandEntry.Open())) | ||
{ | ||
foreach (string s in details) | ||
writer.WriteLine(s); | ||
} | ||
|
||
HashSet<string> inputOptionNames = new HashSet<string>(inputOptions); | ||
Dictionary<string, string> inputToReproPackageFileName = new(); | ||
|
||
List<string> rspFile = new List<string>(); | ||
foreach (var option in res.CommandResult.Command.Options) | ||
{ | ||
if (!res.HasOption(option) || option.Name == "make-repro-path") | ||
{ | ||
continue; | ||
} | ||
|
||
IValueDescriptor descriptor = option; | ||
object val = res.CommandResult.GetValueForOption(option); | ||
if (val is not null && !(descriptor.HasDefaultValue && descriptor.GetDefaultValue().Equals(val))) | ||
{ | ||
if (val is IEnumerable<string> values) | ||
{ | ||
if (inputOptionNames.Contains(option.Name)) | ||
{ | ||
Dictionary<string, string> dictionary = new(); | ||
foreach (string optInList in values) | ||
{ | ||
Helpers.AppendExpandedPaths(dictionary, optInList, false); | ||
} | ||
foreach (string inputFile in dictionary.Values) | ||
{ | ||
rspFile.Add($"--{option.Name}:{ConvertFromInputPathToReproPackagePath(inputFile)}"); | ||
} | ||
} | ||
else | ||
{ | ||
foreach (string optInList in values) | ||
{ | ||
rspFile.Add($"--{option.Name}:{optInList}"); | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
rspFile.Add($"--{option.Name}:{val}"); | ||
} | ||
} | ||
} | ||
|
||
foreach (var argument in res.CommandResult.Command.Arguments) | ||
{ | ||
object val = res.CommandResult.GetValueForArgument(argument); | ||
if (val is IEnumerable<string> values) | ||
{ | ||
foreach (string optInList in values) | ||
{ | ||
rspFile.Add($"{ConvertFromInputPathToReproPackagePath((string)optInList)}"); | ||
} | ||
} | ||
else | ||
{ | ||
rspFile.Add($"{ConvertFromInputPathToReproPackagePath((string)val)}"); | ||
} | ||
} | ||
|
||
ZipArchiveEntry rspEntry = archive.CreateEntry("repro.rsp"); | ||
using (StreamWriter writer = new StreamWriter(rspEntry.Open())) | ||
{ | ||
foreach (string s in rspFile) | ||
writer.WriteLine(s); | ||
} | ||
|
||
string ConvertFromInputPathToReproPackagePath(string inputPath) | ||
{ | ||
if (inputToReproPackageFileName.TryGetValue(inputPath, out string reproPackagePath)) | ||
{ | ||
return reproPackagePath; | ||
} | ||
|
||
try | ||
{ | ||
string inputFileDir = inputToReproPackageFileName.Count.ToString(); | ||
reproPackagePath = Path.Combine(inputFileDir, Path.GetFileName(inputPath)); | ||
archive.CreateEntryFromFile(inputPath, reproPackagePath); | ||
inputToReproPackageFileName.Add(inputPath, reproPackagePath); | ||
|
||
return reproPackagePath; | ||
} | ||
catch | ||
{ | ||
return inputPath; | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Helper to create a collection of paths unique in their simple names. | ||
private static void AppendExpandedPaths(Dictionary<string, string> dictionary, string pattern, bool strict) | ||
{ | ||
bool empty = true; | ||
string directoryName = Path.GetDirectoryName(pattern); | ||
string searchPattern = Path.GetFileName(pattern); | ||
|
||
if (directoryName == "") | ||
directoryName = "."; | ||
|
||
if (Directory.Exists(directoryName)) | ||
{ | ||
foreach (string fileName in Directory.EnumerateFiles(directoryName, searchPattern)) | ||
{ | ||
string fullFileName = Path.GetFullPath(fileName); | ||
|
||
string simpleName = Path.GetFileNameWithoutExtension(fileName); | ||
|
||
if (dictionary.ContainsKey(simpleName)) | ||
{ | ||
if (strict) | ||
{ | ||
throw new CommandLineException("Multiple input files matching same simple name " + | ||
fullFileName + " " + dictionary[simpleName]); | ||
} | ||
} | ||
else | ||
{ | ||
dictionary.Add(simpleName, fullFileName); | ||
} | ||
|
||
empty = false; | ||
} | ||
} | ||
|
||
if (empty) | ||
{ | ||
if (strict) | ||
{ | ||
throw new CommandLineException("No files matching " + pattern); | ||
} | ||
else | ||
{ | ||
Console.WriteLine("Warning: No files matching " + pattern); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is derived from
Common/CommandLine/CommandLineHelpers.cs
. The main difference is that it doesn't depend on anything fromCommon/CommandLine/*
and LINQ. TheMakeReproPackage
method in this file uses System.CommandLine'sParseResult
instead of Internal.CommandLine'sArgumentSyntax
.In a follow-up PR, I will delete
src/coreclr/tools/Common/CommandLine/*
after switching dotnet-pgo (its last consumer) to System.CommandLine. ILVerify will also be switched to use this helper during that work (without the need for<DefineConstants>ILVerify
,#if ILVERIFY
).