Skip to content

Commit

Permalink
Add support for response files (#2320)
Browse files Browse the repository at this point in the history
* Add support for response files
I make workaround here for now, but essentially issues in CommadLine library.
Also place workardoud for stupid bug with quoted argumetns with space in them.

I notice issue with parsing and request for RSP on Discord where @kg and @radical discuss how to feed proper parameters in `benchmarks_ci.py`

* Address PR feedback
  • Loading branch information
kant2002 authored Jun 30, 2023
1 parent 58ee5c7 commit 977c05e
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 0 deletions.
117 changes: 117 additions & 0 deletions src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
Expand Down Expand Up @@ -75,6 +76,13 @@ public static (bool isSuccess, IConfig config, CommandLineOptions options) Parse
{
(bool isSuccess, IConfig config, CommandLineOptions options) result = default;

var (expandSuccess, expandedArgs) = ExpandResponseFile(args, logger);
if (!expandSuccess)
{
return (false, default, default);
}

args = expandedArgs;
using (var parser = CreateParser(logger))
{
parser
Expand All @@ -86,6 +94,115 @@ public static (bool isSuccess, IConfig config, CommandLineOptions options) Parse
return result;
}

private static (bool Success, string[] ExpandedTokens) ExpandResponseFile(string[] args, ILogger logger)
{
List<string> result = new ();
foreach (var arg in args)
{
if (arg.StartsWith("@"))
{
var fileName = arg.Substring(1);
try
{
if (File.Exists(fileName))
{
var lines = File.ReadAllLines(fileName);
foreach (var line in lines)
{
result.AddRange(ConsumeTokens(line));
}
}
else
{
logger.WriteLineError($"Response file {fileName} does not exists.");
return (false, Array.Empty<string>());
}
}
catch (Exception ex)
{
logger.WriteLineError($"Failed to parse RSP file: {fileName}, {ex.Message}");
return (false, Array.Empty<string>());
}
}
else
{
if (arg.Contains(' '))
{
// Workaround for CommandLine library issue with parsing these kind of args.
result.Add(" " + arg);
}
else
{
result.Add(arg);
}
}
}

return (true, result.ToArray());
}

private static IEnumerable<string> ConsumeTokens(string line)
{
bool insideQuotes = false;
var token = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
char currentChar = line[i];
if (currentChar == ' ' && !insideQuotes)
{
if (token.Length > 0)
{
yield return GetToken();
token = new StringBuilder();
}

continue;
}

if (currentChar == '"')
{
insideQuotes = !insideQuotes;
continue;
}

if (currentChar == '\\' && insideQuotes)
{
if (line[i + 1] == '"')
{
insideQuotes = false;
i++;
continue;
}

if (line[i + 1] == '\\')
{
token.Append('\\');
i++;
continue;
}
}

token.Append(currentChar);
}

if (token.Length > 0)
{
yield return GetToken();
}

string GetToken()
{
var result = token.ToString();
if (result.Contains(' '))
{
// Workaround for CommandLine library issue with parsing these kind of args.
return " " + result;
}

return result;
}
}

internal static bool TryUpdateArgs(string[] args, out string[]? updatedArgs, Action<CommandLineOptions> updater)
{
(bool isSuccess, CommandLineOptions options) result = default;
Expand Down
32 changes: 32 additions & 0 deletions tests/BenchmarkDotNet.Tests/ConfigParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,38 @@ public void UsersCanSpecifyWithoutOverheadEvalution()
}
}

[Fact]
public void UserCanSpecifyWasmArgs()
{
var parsedConfiguration = ConfigParser.Parse(new[] { "--runtimes", "wasm", "--wasmArgs", "--expose_wasm --module" }, new OutputLogger(Output));
Assert.True(parsedConfiguration.isSuccess);
var jobs = parsedConfiguration.config.GetJobs();
foreach (var job in parsedConfiguration.config.GetJobs())
{
var wasmRuntime = Assert.IsType<WasmRuntime>(job.Environment.Runtime);
Assert.Equal(" --expose_wasm --module", wasmRuntime.JavaScriptEngineArguments);
}
}

[Fact]
public void UserCanSpecifyWasmArgsViaResponseFile()
{
var tempResponseFile = Path.GetRandomFileName();
File.WriteAllLines(tempResponseFile, new[]
{
"--runtimes wasm",
"--wasmArgs \"--expose_wasm --module\""
});
var parsedConfiguration = ConfigParser.Parse(new[] { $"@{tempResponseFile}" }, new OutputLogger(Output));
Assert.True(parsedConfiguration.isSuccess);
var jobs = parsedConfiguration.config.GetJobs();
foreach (var job in parsedConfiguration.config.GetJobs())
{
var wasmRuntime = Assert.IsType<WasmRuntime>(job.Environment.Runtime);
Assert.Equal(" --expose_wasm --module", wasmRuntime.JavaScriptEngineArguments);
}
}

[Theory]
[InlineData("--filter abc", "--filter *")]
[InlineData("-f abc", "--filter *")]
Expand Down

0 comments on commit 977c05e

Please sign in to comment.