using System; using System.Collections.Generic; using Unosquare.Swan.Attributes; using System.Linq; namespace Unosquare.Swan.Components { /// /// 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 Unosquare.Swan; /// using Unosquare.Swan.Attributes; /// /// static void Main(string[] args) /// { /// // create an instance of the Options class /// var options = new Options(); /// /// // parse the supplied command-line arguments into the options object /// var res = Runtime.ArgumentParser.ParseArguments(args, 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 Unosquare.Swan; /// using Unosquare.Swan.Attributes; /// /// 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 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, 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; } System.Reflection.PropertyInfo[] properties = typeResolver.GetProperties(); if(properties == null) { throw new InvalidOperationException($"Type {typeof(T).Name} is not valid"); } Validator validator = new Validator(properties, args, options, this.Settings); if(validator.IsValid()) { return true; } this.ReportIssues(validator); return false; } private static void ReportUnknownVerb() { "No verb was specified".WriteLine(ConsoleColor.Red); "Valid verbs:".WriteLine(ConsoleColor.Cyan); Runtime.PropertyTypeCache.RetrieveAllProperties(true) .Select(x => Runtime.AttributeCache.RetrieveOne(x)) .Where(x => x != null) .ToList() .ForEach(x => x.ToString().WriteLine(ConsoleColor.Cyan)); } private void ReportIssues(Validator validator) { #if !NETSTANDARD1_3 if(this.Settings.WriteBanner) { Runtime.WriteWelcomeBanner(); } #endif IEnumerable options = validator.GetPropertiesOptions(); foreach(ArgumentOptionAttribute option in options) { String.Empty.WriteLine(); // 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}) "; $" {shortName}{comma}{longName}\t\t{defaultValue}{option.HelpText}".WriteLine(ConsoleColor.Cyan); } String.Empty.WriteLine(); " --help\t\tDisplay this help screen.".WriteLine(ConsoleColor.Cyan); if(validator.UnknownList.Any()) { $"Unknown arguments: {String.Join(", ", validator.UnknownList)}".WriteLine(ConsoleColor.Red); } if(validator.RequiredList.Any()) { $"Required arguments: {String.Join(", ", validator.RequiredList)}".WriteLine(ConsoleColor.Red); } } } }