blob: 2de96bee61153698e72fa7a417683f91b424a1ef (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
namespace SomhairlesDream.Cli
open System
open SomhairlesDream.Shared
[<CLIMutable>]
type RunOptions =
{ Ids: RunIds
OutputRoot: string
StageRoot: string
Python: string
Render: bool }
type Command =
| Run of RunOptions
| Verify of string
| Help
module Arguments =
let usage =
"usage: dotnet run --project src/SomhairlesDream.Cli -- run [options]\n"
+ " dotnet run --project src/SomhairlesDream.Cli -- verify <manifest.json>"
let private defaultPython () =
let configured = Environment.GetEnvironmentVariable("SOMHAIRLES_BPYTHON")
if String.IsNullOrWhiteSpace(configured) then "python3" else configured
let private defaults () =
{ Ids =
{ ProjectId = "heritage-001"
RunId = "run-001"
BaseId = "base-000"
TargetId = "target-003" }
OutputRoot = ".artifacts"
StageRoot = "stage"
Python = defaultPython ()
Render = false }
let private requiredValue (args: string array) (index: int) (optionName: string) =
if index + 1 >= args.Length || String.IsNullOrWhiteSpace(args[index + 1]) then
Error $"{optionName} requires a value"
else
Ok args[index + 1]
let private setValue optionName value (options: RunOptions) =
match optionName with
| "--project-id" -> Ok { options with Ids = { options.Ids with ProjectId = value } }
| "--run-id" -> Ok { options with Ids = { options.Ids with RunId = value } }
| "--base-id" -> Ok { options with Ids = { options.Ids with BaseId = value } }
| "--target-id" -> Ok { options with Ids = { options.Ids with TargetId = value } }
| "--output-root" -> Ok { options with OutputRoot = value }
| "--stage-root" -> Ok { options with StageRoot = value }
| "--python" -> Ok { options with Python = value }
| _ -> Error $"unknown option: {optionName}"
let private validateRunOptions (options: RunOptions) =
[| options.Ids.ProjectId; options.Ids.RunId; options.Ids.BaseId; options.Ids.TargetId |]
|> Array.tryFind (Ids.validateResourceId >> Result.isError)
|> function
| Some value -> Error $"invalid resource id: {value}"
| None -> Ok(Run options)
let private parseRun (args: string array) =
let rec loop (index: int) (options: RunOptions) =
if index >= args.Length then
validateRunOptions options
else
match args[index] with
| "--render" -> loop (index + 1) { options with Render = true }
| "--help" -> Ok Help
| optionName ->
match requiredValue args index optionName with
| Error message -> Error message
| Ok value ->
match setValue optionName value options with
| Error message -> Error message
| Ok updated -> loop (index + 2) updated
loop 0 (defaults ())
let parse (args: string array) =
match args with
| [||]
| [| "--help" |]
| [| "help" |] -> Ok Help
| [| "verify" |] -> Error "verify requires a manifest path"
| [| "verify"; path |] when not (String.IsNullOrWhiteSpace(path)) -> Ok(Verify path)
| [| "verify"; _ |] -> Error "verify requires a manifest path"
| values when values.Length > 2 && values[0] = "verify" -> Error "verify accepts exactly one manifest path"
| values when values.Length > 0 && values[0] = "run" -> parseRun (values |> Array.skip 1)
| _ -> Error usage
|