/// <summary> /// Determine if the arguments can be accepted. /// </summary> /// <param name="rawArgs">Arguments from commandline.</param> /// <param name="prefix">-</param> /// <param name="separator">:</param> /// <returns>True if success. False otherwise.</returns> public virtual BoolMessageItem <Args> AcceptArgs(string[] rawArgs, string prefix, string separator) { Settings.ArgsPrefix = prefix; Settings.ArgsSeparator = separator; // If there is an argument reciever, then reset the _args.Schema // using the arg attributes in the reciever. if (IsArgumentRecieverApplicable) { _args.Schema.Items = ArgsHelper.GetArgsFromReciever(Settings.ArgsReciever); } Args args = new Args(rawArgs, Options); // Are the args required? if (args.IsEmpty && !Settings.ArgsRequired) { return(new BoolMessageItem <Args>(args, true, "Arguments not required.")); } // Handle -help, -about, -pause. BoolMessageItem <Args> optionsResult = AppHelper.HandleOptions(this, args); if (!optionsResult.Success) { return(optionsResult); } // Validate/Parse args. BoolMessageItem <Args> result = Args.Accept(rawArgs, prefix, separator, 1, Options, OptionsExamples); // Successful ? Apply args to object reciever if (result.Success) { // Store the parsed args. _args = result.Item; if (IsArgumentRecieverApplicable) { Args.Accept(rawArgs, prefix, separator, Settings.ArgsReciever); } } // Errors ? Show them. if (!result.Success) { ArgsUsage.ShowError(result.Message); } return(result); }
/// <summary> /// Show how to parse the command line args. /// </summary> /// <returns></returns> public bool AcceptArguments() { // Show the arguments. Logger.Info(ArgsUsage.Build(_argsReciever)); // If args not supplied. simulate them. if (_args == null || _args.Length == 0) { _args = new string[] { "-env:Prod", "-date:${today}", "-dryrun:false", "MySettings", "8" } } ; return(Args.Accept(_args, "-", ":", _argsReciever)); }
/// <summary> /// Run the application. /// </summary> public override BoolMessageItem Execute() { //<doc:example> Args.InitServices((textargs) => ComLib.LexArgs.ParseList(textargs), (arg) => ComLib.Subs.Substitutor.Substitute(arg)); // Sample raw command line args. string[] rawArgs = new string[] { "-config:prod.xml", "-date:${t-1}", "-readonly:true", "myApplicationId" }; // Option 1. Statically parse using -, : as prefix/separator. Args args = Args.Parse(rawArgs, "-", ":").Item; Console.WriteLine("Config : {0}, BusinessDate : {1}, [0] : {2}", args.Named["config"], args.Named["date"], args.Positional[0]); // Option 2. Statically parse args and apply them on an object. StartupArgs reciever = new StartupArgs(); bool accepted = Args.Accept(rawArgs, "-", ":", reciever); Console.WriteLine(string.Format("Accepted config : {0}, date : {1}, readonly : {2}, settingsId: {3}", reciever.Config, reciever.BusinessDate, reciever.ReadonlyMode, reciever.DefaultSettingsId)); // Option 3: Instance based parsing with Fluent-like Schema population. Args args2 = new Args("-", ":").Schema.AddNamed <string>("config").Required.DefaultsTo("dev.xml").Describe("Configuration file") .AddNamed <bool>("readonly").Required.DefaultsTo(false).Describe("Run app in readonly mode") .AddNamed <DateTime>("date").Required.DefaultsTo(DateTime.Today).Interpret.Describe("Business date").Examples("${t-1}", "${today} | ${t-1}") .AddPositional <int>(0).Optional.Describe("Application Id").Args; args2.DoParse(rawArgs); // Check for -help, -version -info rawArgs = new string[] { "-help" }; Args args3 = new Args(rawArgs, "-", ":"); if (args3.IsHelp) { // Usage Option 1. Show usage of the arguments. Console.WriteLine(args2.GetUsage("My Sample Application")); // Usage Option 2. Display usage using reciever. // ( NOTE: -help is automatically interpreted to display args usage). ArgsUsage.ShowUsingReciever(Settings.ArgsReciever, Settings.ArgsPrefix, Settings.ArgsSeparator); } //</doc:example> return(BoolMessageItem.True); }
/// <summary> /// Run the application. /// </summary> public override BoolMessageItem Execute() { // Sample command line args. string[] argList = new string[] { "-config:prod.xml", "-date:${t-1}", "-readonly:true", "myApplicationId" }; // Option 1. Parse using -, : as prefix/separator. Args args = Args.Parse(argList, "-", ":").Item; Console.WriteLine("Config : {0}, BusinessDate : {1}, [0] : {2}", args.Named["config"], args.Named["date"], args.Positional[0]); // Option 2. Parse args and apply them on an object. StartupArgs reciever = new StartupArgs(); bool accepted = Args.Accept(argList, "-", ":", reciever); Console.WriteLine(string.Format("Accepted config : {0}, date : {1}, readonly : {2}, settingsId: {3}", reciever.Config, reciever.BusinessDate, reciever.ReadonlyMode, reciever.DefaultSettingsId)); // Display -help text. // ( NOTE: -help is automatically interpreted to display args usage). ArgsUsage.ShowUsingReciever(Settings.ArgsReciever); return(BoolMessageItem.True); }
/// <summary> /// <para> /// Handle possible "meta data" options of the application. /// 1. -help /// 2. -version /// 3. -pause /// </para> /// </summary> /// <param name="app"></param> /// <param name="args"></param> /// <returns></returns> public static BoolMessageItem <Args> HandleOptions(IApp app, Args args) { BoolMessageItem <Args> result = new BoolMessageItem <Args>(args, true, string.Empty); // Pause the execution of application to allow attaching of debugger. if (args.IsPause) { Console.WriteLine("Paused for debugging ...."); Console.ReadKey(); result = new BoolMessageItem <Args>(args, true, string.Empty); } else if (args.IsVersion || args.IsInfo) { AppHelper.ShowAppInfo(app); result = new BoolMessageItem <Args>(args, false, "Displaying description/version."); } else if (args.IsHelp) { var helpText = GetAppInfo(app) + Environment.NewLine + Environment.NewLine; // -help or ? if (args.Schema.IsEmpty) { helpText += "Argument definitions are not present."; } else { // 1. Get the examples var examplesText = app.OptionsExamples; // 2. Now get the options as text. helpText += ArgsUsage.BuildDescriptive(args.Schema.Items, examplesText, args.Prefix, args.Separator); } // 3. Print Console.WriteLine(helpText); result = new BoolMessageItem <Args>(args, false, "Displaying usage"); } return(result); }
/// <summary> /// Invokes the delegate given (if not <see langword="null" />) with protection against exceptions thrown by the /// invoked methods. /// </summary> /// <typeparam name="T">The type of the event args to pass.</typeparam> /// <param name="handler">The delegate to call.</param> /// <param name="eventName">The name of the event being raised.</param> /// <param name="sender">The object to pass as the sender.</param> /// <param name="usage">The way in which to use the factory to generate args.</param> /// <param name="eventArgFactory">A factory for generating event args.</param> /// <returns><see langword="true" /> if at least one delegate was successfully invoked, <see langword="false" /> otherwise.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown if an invalid value passed in the <paramref name="usage" /> /// argument. /// </exception> /// <exception cref="System.ArgumentNullException"><paramref name="eventName" /> is <see langword="null" />.</exception> /// <exception cref="System.ArgumentException"> /// <paramref name="eventName" /> is zero-length or contains only white space /// characters. /// </exception> /// <exception cref="System.ArgumentNullException"><paramref name="eventArgFactory" /> is <see langword="null" />.</exception> public static bool SafeInvoke <T>([CanBeNull] this Delegate handler, [NotNull] string eventName, [CanBeNull] object sender, ArgsUsage usage, EventArgsFactory <T> eventArgFactory) where T : EventArgs { eventName.Validate(nameof(eventName), StringIs.NotNullEmptyOrWhiteSpace); eventArgFactory.Validate(nameof(eventArgFactory), ObjectIs.NotNull); // An empty invocation list is null. if (ReferenceEquals(handler, null)) { return(false); } var delegates = handler.GetInvocationList(); // All non-null invocation lists are also non-empty, so no need to test here. object[] args = null; bool generateArgs; switch (usage) { case ArgsUsage.Reuse: args = new[] { sender, eventArgFactory() }; generateArgs = false; break; case ArgsUsage.UniqueInstance: generateArgs = true; break; default: throw new ArgumentOutOfRangeException(nameof(usage), usage, $@"'{nameof(usage)}' argument contains invalid value: {usage}."); } var raised = false; var checkForHandled = typeof(HandledEventArgs).IsAssignableFrom(typeof(T)); foreach (var callback in delegates) { try { if (generateArgs) { args = new[] { sender, eventArgFactory() }; } callback.DynamicInvoke(args); raised = true; if (checkForHandled && (((HandledEventArgs)args[1]).State == HandledEventState.HandledAndCeaseRaising)) { break; } } catch (ThreadAbortException) { // Ignore thread abort exceptions, but do stop processing any further. break; } catch (Exception ex) { if (typeof(UnhandledExceptionEventArgs).IsAssignableFrom(typeof(T))) { // If we already in the process of raising an exception just ignore anything further. continue; } // If an event handler has raised an exception report it, but carry on. ExceptionManager.OnUnhandledException(ex, $@"Error whilst '{eventName}' event was being handled by {GetDescription(callback)}."); } } return(raised); }
/// <summary> /// Show the command line options. /// </summary> public virtual void ShowOptions() { ArgsUsage.Show(Options, OptionsExamples); }