Enhance CommandLine

- Allow CommandLineApplication to handle .rsp files.
- Allow CommandOption to handle MultilpeValue options that have "..." at the end of their template.
- Allow CommandOption to handle boolean values with explicit or null values.
This commit is contained in:
Eric Erhardt 2016-04-20 00:24:48 -05:00
parent 44483ddc98
commit 6fa3a8132e
3 changed files with 84 additions and 3 deletions

View file

@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -42,6 +43,7 @@ namespace Microsoft.DotNet.Cli.CommandLine
public Func<string> LongVersionGetter { get; set; }
public Func<string> ShortVersionGetter { get; set; }
public List<CommandLineApplication> Commands { get; private set; }
public bool HandleResponseFiles { get; set; }
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
@ -102,6 +104,11 @@ namespace Microsoft.DotNet.Cli.CommandLine
CommandOption option = null;
IEnumerator<CommandArgument> arguments = null;
if (HandleResponseFiles)
{
args = ExpandResponseFiles(args).ToArray();
}
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
@ -151,7 +158,7 @@ namespace Microsoft.DotNet.Cli.CommandLine
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue)
else if (option.OptionType == CommandOptionType.NoValue || option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
@ -196,7 +203,7 @@ namespace Microsoft.DotNet.Cli.CommandLine
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue)
else if (option.OptionType == CommandOptionType.NoValue || option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
@ -479,6 +486,50 @@ namespace Microsoft.DotNet.Cli.CommandLine
}
}
private IEnumerable<string> ExpandResponseFiles(IEnumerable<string> args)
{
foreach (var arg in args)
{
if (!arg.StartsWith("@", StringComparison.Ordinal))
{
yield return arg;
}
else
{
var fileName = arg.Substring(1);
var responseFileArguments = ParseResponseFile(fileName);
// ParseResponseFile can suppress expanding this response file by
// returning null. In that case, we'll treat the response
// file token as a regular argument.
if (responseFileArguments == null)
{
yield return arg;
}
else
{
foreach (var responseFileArgument in responseFileArguments)
yield return responseFileArgument.Trim();
}
}
}
}
private IEnumerable<string> ParseResponseFile(string fileName)
{
if (!HandleResponseFiles)
return null;
if (!File.Exists(fileName))
{
throw new InvalidOperationException($"Response file '{fileName}' doesn't exist.");
}
return File.ReadLines(fileName);
}
private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
{
private readonly IEnumerator<CommandArgument> _enumerator;

View file

@ -39,8 +39,12 @@ namespace Microsoft.DotNet.Cli.CommandLine
{
ValueName = part.Substring(1, part.Length - 2);
}
else
else if (optionType == CommandOptionType.MultipleValue && part.StartsWith("<") && part.EndsWith(">..."))
{
ValueName = part.Substring(1, part.Length - 5);
}
else
{
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
}
}
@ -58,6 +62,7 @@ namespace Microsoft.DotNet.Cli.CommandLine
public string ValueName { get; set; }
public string Description { get; set; }
public List<string> Values { get; private set; }
public bool? BoolValue { get; private set; }
public CommandOptionType OptionType { get; private set; }
public bool TryParse(string value)
@ -74,6 +79,30 @@ namespace Microsoft.DotNet.Cli.CommandLine
}
Values.Add(value);
break;
case CommandOptionType.BoolValue:
if (Values.Any())
{
return false;
}
if (value == null)
{
// add null to indicate that the option was present, but had no value
Values.Add(null);
BoolValue = true;
}
else
{
bool boolValue;
if (!bool.TryParse(value, out boolValue))
{
return false;
}
Values.Add(value);
BoolValue = boolValue;
}
break;
case CommandOptionType.NoValue:
if (value != null)
{

View file

@ -8,6 +8,7 @@ namespace Microsoft.DotNet.Cli.CommandLine
{
MultipleValue,
SingleValue,
BoolValue,
NoValue
}
}