mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-06 04:28:42 +00:00
Allow consuming *all* args as positionals, not just ones which look like --foo
(#255)
This commit is contained in:
@@ -148,11 +148,13 @@ module BasicNoPositionals =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_BasicNoPositionals.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_BasicNoPositionals.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_BasicNoPositionals.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_BasicNoPositionals.AwaitingKey args
|
||||
@@ -365,11 +367,13 @@ module Basic =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_Basic.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_Basic.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_Basic.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> arg_3.Add
|
||||
go ParseState_Basic.AwaitingKey args
|
||||
@@ -566,11 +570,13 @@ module BasicWithIntPositionals =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_BasicWithIntPositionals.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_BasicWithIntPositionals.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_BasicWithIntPositionals.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> System.Int32.Parse x) |> arg_3.Add
|
||||
go ParseState_BasicWithIntPositionals.AwaitingKey args
|
||||
@@ -945,11 +951,13 @@ module LoadsOfTypes =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_LoadsOfTypes.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_LoadsOfTypes.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_LoadsOfTypes.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> System.Int32.Parse x) |> arg_7.Add
|
||||
go ParseState_LoadsOfTypes.AwaitingKey args
|
||||
@@ -1371,11 +1379,13 @@ module LoadsOfTypesNoPositionals =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_LoadsOfTypesNoPositionals.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_LoadsOfTypesNoPositionals.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_LoadsOfTypesNoPositionals.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_LoadsOfTypesNoPositionals.AwaitingKey args
|
||||
@@ -1688,11 +1698,17 @@ module DatesAndTimesArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_DatesAndTimes.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_DatesAndTimes.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_DatesAndTimes.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_DatesAndTimes.AwaitingKey args
|
||||
@@ -1918,11 +1934,17 @@ module ParentRecordArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ParentRecord.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecord.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecord.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_ParentRecord.AwaitingKey args
|
||||
@@ -2124,11 +2146,17 @@ module ParentRecordChildPosArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ParentRecordChildPos.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecordChildPos.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecordChildPos.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> System.Uri x) |> arg_1.Add
|
||||
go ParseState_ParentRecordChildPos.AwaitingKey args
|
||||
@@ -2297,11 +2325,17 @@ module ParentRecordSelfPosArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ParentRecordSelfPos.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecordSelfPos.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ParentRecordSelfPos.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> System.Boolean.Parse x) |> arg_2.Add
|
||||
go ParseState_ParentRecordSelfPos.AwaitingKey args
|
||||
@@ -2428,11 +2462,17 @@ module ChoicePositionalsArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ChoicePositionals.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ChoicePositionals.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ChoicePositionals.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> Choice1Of2 |> arg_0.Add
|
||||
go ParseState_ChoicePositionals.AwaitingKey args
|
||||
@@ -2567,11 +2607,17 @@ module ContainsBoolEnvVarArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ContainsBoolEnvVar.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsBoolEnvVar.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsBoolEnvVar.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_ContainsBoolEnvVar.AwaitingKey args
|
||||
@@ -2747,11 +2793,17 @@ module WithFlagDuArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_WithFlagDu.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_WithFlagDu.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_WithFlagDu.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_WithFlagDu.AwaitingKey args
|
||||
@@ -2920,11 +2972,17 @@ module ContainsFlagEnvVarArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ContainsFlagEnvVar.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsFlagEnvVar.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsFlagEnvVar.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_ContainsFlagEnvVar.AwaitingKey args
|
||||
@@ -3126,11 +3184,17 @@ module ContainsFlagDefaultValueArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ContainsFlagDefaultValue.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsFlagDefaultValue.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ContainsFlagDefaultValue.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_ContainsFlagDefaultValue.AwaitingKey args
|
||||
@@ -3367,11 +3431,17 @@ module ManyLongFormsArgParse =
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_ManyLongForms.AwaitingKey args
|
||||
| Error None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Error (Some msg) ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ManyLongForms.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_ManyLongForms.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_ManyLongForms.AwaitingKey args
|
||||
@@ -3435,3 +3505,325 @@ module ManyLongFormsArgParse =
|
||||
|
||||
static member parse (args : string list) : ManyLongForms =
|
||||
ManyLongForms.parse' System.Environment.GetEnvironmentVariable args
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Methods to parse arguments for the type FlagsIntoPositionalArgs
|
||||
[<AutoOpen>]
|
||||
module FlagsIntoPositionalArgsArgParse =
|
||||
type private ParseState_FlagsIntoPositionalArgs =
|
||||
/// Ready to consume a key or positional arg
|
||||
| AwaitingKey
|
||||
/// Waiting to receive a value for the key we've already consumed
|
||||
| AwaitingValue of key : string
|
||||
|
||||
/// Extension methods for argument parsing
|
||||
type FlagsIntoPositionalArgs with
|
||||
|
||||
static member parse'
|
||||
(getEnvironmentVariable : string -> string)
|
||||
(args : string list)
|
||||
: FlagsIntoPositionalArgs
|
||||
=
|
||||
let ArgParser_errors = ResizeArray ()
|
||||
|
||||
let helpText () =
|
||||
[
|
||||
(sprintf "%s string%s%s" (sprintf "--%s" "a") "" "")
|
||||
(sprintf
|
||||
"%s string%s%s"
|
||||
(sprintf "--%s" "grab-everything")
|
||||
" (positional args) (can be repeated)"
|
||||
"")
|
||||
]
|
||||
|> String.concat "\n"
|
||||
|
||||
let arg_1 : string ResizeArray = ResizeArray ()
|
||||
let mutable arg_0 : string option = None
|
||||
|
||||
/// Processes the key-value pair, returning Error if no key was matched.
|
||||
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||
let processKeyValue (key : string) (value : string) : Result<unit, string option> =
|
||||
if System.String.Equals (key, sprintf "--%s" "a", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_0 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "a")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_0 <- value |> (fun x -> x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if
|
||||
System.String.Equals (
|
||||
key,
|
||||
sprintf "--%s" "grab-everything",
|
||||
System.StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
then
|
||||
value |> (fun x -> x) |> arg_1.Add
|
||||
() |> Ok
|
||||
else
|
||||
Error None
|
||||
|
||||
/// Returns false if we didn't set a value.
|
||||
let setFlagValue (key : string) : bool = false
|
||||
|
||||
let rec go (state : ParseState_FlagsIntoPositionalArgs) (args : string list) =
|
||||
match args with
|
||||
| [] ->
|
||||
match state with
|
||||
| ParseState_FlagsIntoPositionalArgs.AwaitingKey -> ()
|
||||
| ParseState_FlagsIntoPositionalArgs.AwaitingValue key ->
|
||||
if setFlagValue key then
|
||||
()
|
||||
else
|
||||
sprintf
|
||||
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
|
||||
key
|
||||
|> ArgParser_errors.Add
|
||||
| "--" :: rest -> arg_1.AddRange (rest |> Seq.map (fun x -> x))
|
||||
| arg :: args ->
|
||||
match state with
|
||||
| ParseState_FlagsIntoPositionalArgs.AwaitingKey ->
|
||||
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
|
||||
if arg = "--help" then
|
||||
helpText () |> failwithf "Help text requested.\n%s"
|
||||
else
|
||||
let equals = arg.IndexOf (char 61)
|
||||
|
||||
if equals < 0 then
|
||||
args |> go (ParseState_FlagsIntoPositionalArgs.AwaitingValue arg)
|
||||
else
|
||||
let key = arg.[0 .. equals - 1]
|
||||
let value = arg.[equals + 1 ..]
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
| Error x ->
|
||||
if true then
|
||||
arg |> (fun x -> x) |> arg_1.Add
|
||||
go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
else
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> arg_1.Add
|
||||
go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
| ParseState_FlagsIntoPositionalArgs.AwaitingValue key ->
|
||||
match processKeyValue key arg with
|
||||
| Ok () -> go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
| Error exc ->
|
||||
if setFlagValue key then
|
||||
go ParseState_FlagsIntoPositionalArgs.AwaitingKey (arg :: args)
|
||||
else
|
||||
match exc with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process supplied arg %s. Help text follows.\n%s"
|
||||
key
|
||||
(helpText ())
|
||||
| Some msg -> msg |> ArgParser_errors.Add
|
||||
|
||||
go ParseState_FlagsIntoPositionalArgs.AwaitingKey args
|
||||
let arg_1 = arg_1 |> Seq.toList
|
||||
|
||||
let arg_0 =
|
||||
match arg_0 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "a")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
if 0 = ArgParser_errors.Count then
|
||||
{
|
||||
A = arg_0
|
||||
GrabEverything = arg_1
|
||||
}
|
||||
else
|
||||
ArgParser_errors |> String.concat "\n" |> failwithf "Errors during parse!\n%s"
|
||||
|
||||
static member parse (args : string list) : FlagsIntoPositionalArgs =
|
||||
FlagsIntoPositionalArgs.parse' System.Environment.GetEnvironmentVariable args
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Methods to parse arguments for the type FlagsIntoPositionalArgs'
|
||||
[<AutoOpen>]
|
||||
module FlagsIntoPositionalArgs'ArgParse =
|
||||
type private ParseState_FlagsIntoPositionalArgs' =
|
||||
/// Ready to consume a key or positional arg
|
||||
| AwaitingKey
|
||||
/// Waiting to receive a value for the key we've already consumed
|
||||
| AwaitingValue of key : string
|
||||
|
||||
/// Extension methods for argument parsing
|
||||
type FlagsIntoPositionalArgs' with
|
||||
|
||||
static member parse'
|
||||
(getEnvironmentVariable : string -> string)
|
||||
(args : string list)
|
||||
: FlagsIntoPositionalArgs'
|
||||
=
|
||||
let ArgParser_errors = ResizeArray ()
|
||||
|
||||
let helpText () =
|
||||
[
|
||||
(sprintf "%s string%s%s" (sprintf "--%s" "a") "" "")
|
||||
(sprintf
|
||||
"%s string%s%s"
|
||||
(sprintf "--%s" "dont-grab-everything")
|
||||
" (positional args) (can be repeated)"
|
||||
"")
|
||||
]
|
||||
|> String.concat "\n"
|
||||
|
||||
let arg_1 : string ResizeArray = ResizeArray ()
|
||||
let mutable arg_0 : string option = None
|
||||
|
||||
/// Processes the key-value pair, returning Error if no key was matched.
|
||||
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||
let processKeyValue (key : string) (value : string) : Result<unit, string option> =
|
||||
if System.String.Equals (key, sprintf "--%s" "a", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_0 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "a")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_0 <- value |> (fun x -> x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if
|
||||
System.String.Equals (
|
||||
key,
|
||||
sprintf "--%s" "dont-grab-everything",
|
||||
System.StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
then
|
||||
value |> (fun x -> x) |> arg_1.Add
|
||||
() |> Ok
|
||||
else
|
||||
Error None
|
||||
|
||||
/// Returns false if we didn't set a value.
|
||||
let setFlagValue (key : string) : bool = false
|
||||
|
||||
let rec go (state : ParseState_FlagsIntoPositionalArgs') (args : string list) =
|
||||
match args with
|
||||
| [] ->
|
||||
match state with
|
||||
| ParseState_FlagsIntoPositionalArgs'.AwaitingKey -> ()
|
||||
| ParseState_FlagsIntoPositionalArgs'.AwaitingValue key ->
|
||||
if setFlagValue key then
|
||||
()
|
||||
else
|
||||
sprintf
|
||||
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
|
||||
key
|
||||
|> ArgParser_errors.Add
|
||||
| "--" :: rest -> arg_1.AddRange (rest |> Seq.map (fun x -> x))
|
||||
| arg :: args ->
|
||||
match state with
|
||||
| ParseState_FlagsIntoPositionalArgs'.AwaitingKey ->
|
||||
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
|
||||
if arg = "--help" then
|
||||
helpText () |> failwithf "Help text requested.\n%s"
|
||||
else
|
||||
let equals = arg.IndexOf (char 61)
|
||||
|
||||
if equals < 0 then
|
||||
args |> go (ParseState_FlagsIntoPositionalArgs'.AwaitingValue arg)
|
||||
else
|
||||
let key = arg.[0 .. equals - 1]
|
||||
let value = arg.[equals + 1 ..]
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
| Error x ->
|
||||
if false then
|
||||
arg |> (fun x -> x) |> arg_1.Add
|
||||
go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
else
|
||||
match x with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process argument %s as key %s and value %s"
|
||||
arg
|
||||
key
|
||||
value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> arg_1.Add
|
||||
go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
| ParseState_FlagsIntoPositionalArgs'.AwaitingValue key ->
|
||||
match processKeyValue key arg with
|
||||
| Ok () -> go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
| Error exc ->
|
||||
if setFlagValue key then
|
||||
go ParseState_FlagsIntoPositionalArgs'.AwaitingKey (arg :: args)
|
||||
else
|
||||
match exc with
|
||||
| None ->
|
||||
failwithf
|
||||
"Unable to process supplied arg %s. Help text follows.\n%s"
|
||||
key
|
||||
(helpText ())
|
||||
| Some msg -> msg |> ArgParser_errors.Add
|
||||
|
||||
go ParseState_FlagsIntoPositionalArgs'.AwaitingKey args
|
||||
let arg_1 = arg_1 |> Seq.toList
|
||||
|
||||
let arg_0 =
|
||||
match arg_0 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "a")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
if 0 = ArgParser_errors.Count then
|
||||
{
|
||||
A = arg_0
|
||||
DontGrabEverything = arg_1
|
||||
}
|
||||
else
|
||||
ArgParser_errors |> String.concat "\n" |> failwithf "Errors during parse!\n%s"
|
||||
|
||||
static member parse (args : string list) : FlagsIntoPositionalArgs' =
|
||||
FlagsIntoPositionalArgs'.parse' System.Environment.GetEnvironmentVariable args
|
||||
|
Reference in New Issue
Block a user