using Swan.Reflection; using System; using System.Collections.Generic; using System.Linq; namespace Swan.Parsers { /// /// Provides methods to parse command line arguments. /// Based on CommandLine (Copyright 2005-2015 Giacomo Stelluti Scala and Contributors.). /// /// /// The following example shows how to parse CLI arguments into objects. /// /// class Example /// { /// using System; /// using Swan.Parsers; /// /// static void Main(string[] args) /// { /// // parse the supplied command-line arguments into the options object /// var res = Runtime.ArgumentParser.ParseArguments(args, out var options); /// } /// /// class Options /// { /// [ArgumentOption('v', "verbose", HelpText = "Set verbose mode.")] /// public bool Verbose { get; set; } /// /// [ArgumentOption('u', Required = true, HelpText = "Set user name.")] /// public string Username { get; set; } /// /// [ArgumentOption('n', "names", Separator = ',', /// Required = true, HelpText = "A list of files separated by a comma")] /// public string[] Files { get; set; } /// /// [ArgumentOption('p', "port", DefaultValue = 22, HelpText = "Set port.")] /// public int Port { get; set; } /// /// [ArgumentOption("color", DefaultValue = ConsoleColor.Red, /// HelpText = "Set a color.")] /// public ConsoleColor Color { get; set; } /// } /// } /// /// The following code describes how to parse CLI verbs. /// /// class Example2 /// { /// using Swan; /// using Swan.Parsers; /// /// static void Main(string[] args) /// { /// // create an instance of the VerbOptions class /// var options = new VerbOptions(); /// /// // parse the supplied command-line arguments into the options object /// var res = Runtime.ArgumentParser.ParseArguments(args, options); /// /// // if there were no errors parsing /// if (res) /// { /// if(options.Run != null) /// { /// // run verb was selected /// } /// /// if(options.Print != null) /// { /// // print verb was selected /// } /// } /// /// // flush all error messages /// Terminal.Flush(); /// } /// /// class VerbOptions /// { /// [VerbOption("run", HelpText = "Run verb.")] /// public RunVerbOption Run { get; set; } /// /// [VerbOption("print", HelpText = "Print verb.")] /// public PrintVerbOption Print { get; set; } /// } /// /// class RunVerbOption /// { /// [ArgumentOption('o', "outdir", HelpText = "Output directory", /// DefaultValue = "", Required = false)] /// public string OutDir { get; set; } /// } /// /// class PrintVerbOption /// { /// [ArgumentOption('t', "text", HelpText = "Text to print", /// DefaultValue = "", Required = false)] /// public string Text { get; set; } /// } /// } /// /// public partial class ArgumentParser { /// /// Initializes a new instance of the class. /// public ArgumentParser() : this(new ArgumentParserSettings()) { } /// /// Initializes a new instance of the class, /// configurable with using a delegate. /// /// The parse settings. public ArgumentParser(ArgumentParserSettings parseSettings) => this.Settings = parseSettings ?? throw new ArgumentNullException(nameof(parseSettings)); /// /// Gets the current. /// /// /// The current. /// public static ArgumentParser Current { get; } = new ArgumentParser(); /// /// Gets the instance that implements in use. /// /// /// The settings. /// public ArgumentParserSettings Settings { get; } /// /// Parses a string array of command line arguments constructing values in an instance of type . /// /// The type of the options. /// The arguments. /// The instance. /// /// true if was converted successfully; otherwise, false. /// /// /// The exception that is thrown when a null reference (Nothing in Visual Basic) /// is passed to a method that does not accept it as a valid argument. /// /// /// The exception that is thrown when a method call is invalid for the object's current state. /// public Boolean ParseArguments(IEnumerable args, out T instance) { instance = Activator.CreateInstance(); return this.ParseArguments(args, instance); } /// /// Parses a string array of command line arguments constructing values in an instance of type . /// /// The type of the options. /// The arguments. /// The instance. /// /// true if was converted successfully; otherwise, false. /// /// /// The exception that is thrown when a null reference (Nothing in Visual Basic) /// is passed to a method that does not accept it as a valid argument. /// /// /// The exception that is thrown when a method call is invalid for the object's current state. /// public Boolean ParseArguments(IEnumerable args, T instance) { if(args == null) { throw new ArgumentNullException(nameof(args)); } if(Equals(instance, default(T))) { throw new ArgumentNullException(nameof(instance)); } TypeResolver typeResolver = new TypeResolver(args.FirstOrDefault()); Object options = typeResolver.GetOptionsObject(instance); if(options == null) { ReportUnknownVerb(); return false; } if(typeResolver.Properties == null) { throw new InvalidOperationException($"Type {typeof(T).Name} is not valid"); } Validator validator = new Validator(typeResolver.Properties, args, options, this.Settings); if(validator.IsValid()) { return true; } this.ReportIssues(validator); return false; } private static void ReportUnknownVerb() { Terminal.WriteLine("No verb was specified", ConsoleColor.Red); Terminal.WriteLine("Valid verbs:", ConsoleColor.Cyan); PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(true).Select(x => AttributeCache.DefaultCache.Value.RetrieveOne(x)).Where(x => x != null).ToList().ForEach(x => Terminal.WriteLine(x.ToString(), ConsoleColor.Cyan)); } private void ReportIssues(Validator validator) { if(this.Settings.WriteBanner) { Terminal.WriteWelcomeBanner(); } IEnumerable options = validator.GetPropertiesOptions(); foreach(ArgumentOptionAttribute option in options) { Terminal.WriteLine(String.Empty); // TODO: If Enum list values String shortName = String.IsNullOrWhiteSpace(option.ShortName) ? String.Empty : $"-{option.ShortName}"; String longName = String.IsNullOrWhiteSpace(option.LongName) ? String.Empty : $"--{option.LongName}"; String comma = String.IsNullOrWhiteSpace(shortName) || String.IsNullOrWhiteSpace(longName) ? String.Empty : ", "; String defaultValue = option.DefaultValue == null ? String.Empty : $"(Default: {option.DefaultValue}) "; Terminal.WriteLine($" {shortName}{comma}{longName}\t\t{defaultValue}{option.HelpText}", ConsoleColor.Cyan); } Terminal.WriteLine(String.Empty); Terminal.WriteLine(" --help\t\tDisplay this help screen.", ConsoleColor.Cyan); if(validator.UnknownList.Any()) { Terminal.WriteLine($"Unknown arguments: {String.Join(", ", validator.UnknownList)}", ConsoleColor.Red); } if(validator.RequiredList.Any()) { Terminal.WriteLine($"Required arguments: {String.Join(", ", validator.RequiredList)}", ConsoleColor.Red); } } } }