using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using McMaster.Extensions.CommandLineUtils;
namespace QuantConnect.Configuration
{
///
/// Command Line application parser
///
public static class ApplicationParser
{
///
/// This function will parse args based on options and will show application name, version, help
///
/// The application name to be shown
/// The application description to be shown
/// The application help text
/// The command line arguments
/// The applications command line available options
/// To show help when no command line arguments were provided
/// The user provided options. Key is option name
public static Dictionary Parse(string applicationName, string applicationDescription, string applicationHelpText,
string[] args, List options, bool noArgsShowHelp = false)
{
var application = new CommandLineApplication
{
Name = applicationName,
Description = applicationDescription,
ExtendedHelpText = applicationHelpText
};
application.HelpOption("-?|-h|--help");
// This is a helper/shortcut method to display version info - it is creating a regular Option, with some defaults.
// The default help text is "Show version Information"
application.VersionOption("-v|-V|--version",
() =>
$"Version {Assembly.GetEntryAssembly().GetCustomAttribute()?.InformationalVersion}");
var optionsObject = new Dictionary();
var listOfOptions = new List();
foreach (var option in options)
{
listOfOptions.Add(application.Option($"--{option.Name}", option.Description, option.Type));
}
application.OnExecute(() =>
{
foreach (var commandOption in listOfOptions.Where(option => option.HasValue()))
{
var optionKey = commandOption.Template.Replace("--", "");
var matchingOption = options.Find(o => o.Name == optionKey);
switch (matchingOption.Type)
{
// Booleans
case CommandOptionType.NoValue:
optionsObject[optionKey] = true;
break;
// Strings and numbers
case CommandOptionType.SingleValue:
optionsObject[optionKey] = commandOption.Value();
break;
// Parsing nested objects
case CommandOptionType.MultipleValue:
var keyValuePairs = commandOption.Value().Split(',');
var subDictionary = new Dictionary();
foreach (var keyValuePair in keyValuePairs)
{
var subKeys = keyValuePair.Split(':');
subDictionary[subKeys[0]] = subKeys.Length > 1 ? subKeys[1] : "";
}
optionsObject[optionKey] = subDictionary;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
return 0;
});
application.Execute(args);
if (noArgsShowHelp && args.Length == 0)
{
application.ShowHelp();
}
return optionsObject;
}
///
/// Prints a message advising the user to use the --help parameter for more information
///
public static void PrintMessageAndExit(int exitCode = 0, string message = "")
{
if (!string.IsNullOrEmpty(message))
{
Console.WriteLine("\n" + message);
}
Console.WriteLine("\nUse the '--help' parameter for more information");
Console.WriteLine("Press any key to quit");
Console.ReadLine();
Environment.Exit(exitCode);
}
///
/// Gets the parameter object from the given parameter (if it exists)
///
public static string GetParameterOrExit(IReadOnlyDictionary optionsObject, string parameter)
{
if (!optionsObject.ContainsKey(parameter))
{
PrintMessageAndExit(1, "ERROR: REQUIRED parameter --" + parameter + "= is missing");
}
return optionsObject[parameter].ToString();
}
///
/// Gets the parameter object from the given parameter. If it does not exists, it returns a default parameter object
///
public static string GetParameterOrDefault(IReadOnlyDictionary optionsObject, string parameter, string defaultValue)
{
object value;
if (!optionsObject.TryGetValue(parameter, out value))
{
Console.WriteLine($"'{parameter}' was not specified. Using default value: '{defaultValue}'");
return defaultValue;
}
return value.ToString();
}
}
}