@@ -39,6 +39,8 @@ let main argv =
39
39
}
40
40
```
41
41
42
+ 💥WARNING: You must declare ` inputs ` before ` setHandler ` or else the type checking will not work properly and you will get a build error!💥
43
+
42
44
``` batch
43
45
> unzip.exe "c:\test\stuff.zip"
44
46
Result: Unzipping stuff.zip to c:\test
@@ -131,6 +133,8 @@ let main argv =
131
133
rootCommand argv {
132
134
description "File System Manager"
133
135
setHandler id
136
+ // if using async task sub commands, setHandler to `Task.FromResult`
137
+ // setHandler Task.FromResult
134
138
addCommand listCmd
135
139
addCommand deleteCmd
136
140
}
@@ -199,44 +203,108 @@ let main argv =
199
203
|> Async.RunSynchronously
200
204
```
201
205
202
-
203
- ### Async App with a Partially Applied Dependency
206
+ ### Example using Microsoft.Extensions.Hosting
204
207
205
208
``` F#
209
+ open System
210
+ open System.IO
206
211
open FSharp.SystemCommandLine
207
- open System.CommandLine.Builder
208
- open System.Threading.Tasks
209
-
210
- type WordService() =
211
- member _.Join(separator: string, words: string array) =
212
- task {
213
- do! Task.Delay(1000)
214
- return System.String.Join(separator, words)
215
- }
212
+ open Microsoft.Extensions.Hosting
213
+ open Microsoft.Extensions.Logging
214
+ open Microsoft.Extensions.Configuration
215
+ open Microsoft.Extensions.DependencyInjection
216
+ open Serilog
217
+
218
+ let buildHost (argv: string[]) =
219
+ Host.CreateDefaultBuilder(argv)
220
+ .ConfigureHostConfiguration(fun configHost ->
221
+ configHost.SetBasePath(Directory.GetCurrentDirectory()) |> ignore
222
+ configHost.AddJsonFile("appsettings.json", optional = false) |> ignore
223
+ )
224
+ .ConfigureLogging(fun logging ->
225
+ logging.AddConsole() |> ignore
226
+ logging.AddSerilog() |> ignore
227
+ )
228
+ .ConfigureServices(fun services ->
229
+ // Serilog configuration
230
+ let logger =
231
+ LoggerConfiguration()
232
+ .WriteTo.File(path = "logs/log.txt")
233
+ .CreateLogger()
234
+
235
+ services.AddLogging(fun builder ->
236
+ builder
237
+ .SetMinimumLevel(LogLevel.Information)
238
+ .AddSerilog(logger, dispose = true) |> ignore
239
+ ) |> ignore
240
+ )
241
+ .Build()
216
242
217
- let app (svc: WordService ) (words : string array, separator: string ) =
243
+ let exportHandler (logger: ILogger ) (connStr : string, outputDir: DirectoryInfo, startDate: DateTime, endDate: DateTime ) =
218
244
task {
219
- let! result = svc.Join(separator, words )
220
- result |> printfn "Result: %s"
245
+ logger.LogInformation($"Querying from {startDate.ToShortDateString()} to {endDate.ToShortDateString()}" )
246
+ // Do export stuff...
221
247
}
222
-
223
- [<EntryPoint>]
224
- let main argv =
225
- let words = Input.Option<string array>(["--word"; "-w"], Array.empty, "A list of words to be appended")
226
- let separator = Input.Option<string>(["--separator"; "-s"], ", ", "A character that will separate the joined words.")
227
248
228
- // Initialize app dependencies
229
- let svc = WordService()
249
+ [<EntryPoint>]
250
+ let main argv =
251
+ let host = buildHost argv
252
+ let logger = host.Services.GetService<ILogger<_>>()
253
+ let cfg = host.Services.GetService<IConfiguration>()
254
+
255
+ let connStr = Input.Option<string>(
256
+ aliases = ["-c"; "--connection-string"],
257
+ defaultValue = cfg["ConnectionStrings:DB"],
258
+ description = "Database connection string")
259
+
260
+ let outputDir = Input.Option<DirectoryInfo>(
261
+ aliases = ["-o";"--output-directory"],
262
+ defaultValue = DirectoryInfo(cfg["DefaultOutputDirectory"]),
263
+ description = "Output directory folder.")
264
+
265
+ let startDate = Input.Option<DateTime>(
266
+ name = "--start-date",
267
+ defaultValue = DateTime.Today.AddDays(-7),
268
+ description = "Start date (defaults to 1 week ago from today)")
269
+
270
+ let endDate = Input.Option<DateTime>(
271
+ name = "--end-date",
272
+ defaultValue = DateTime.Today,
273
+ description = "End date (defaults to today)")
230
274
231
275
rootCommand argv {
232
- description "Appends words together"
233
- inputs (words, separator)
234
- usePipeline (fun builder ->
235
- CommandLineBuilder() // Pipeline is initialized with .UseDefaults() by default,
236
- .UseTypoCorrections(3) // but you can override it here if needed.
237
- )
238
- setHandler (app svc) // Partially apply app dependencies
276
+ description "Data Export"
277
+ inputs (connStr, outputDir, startDate, endDate)
278
+ setHandler (exportHandler logger)
239
279
}
240
280
|> Async.AwaitTask
241
281
|> Async.RunSynchronously
242
282
```
283
+
284
+ ### Creating a Root Command Parser
285
+
286
+ If you want to manually invoke your root command, use the ` rootCommandParser ` CE (because the ` rootCommand ` CE is auto-executing).
287
+
288
+ ``` F#
289
+ open FSharp.SystemCommandLine
290
+ open System.CommandLine.Parsing
291
+
292
+ let app (words: string array, separator: string option) =
293
+ let separator = separator |> Option.defaultValue ", "
294
+ System.String.Join(separator, words) |> printfn "Result: %s"
295
+ 0
296
+
297
+ [<EntryPoint>]
298
+ let main argv =
299
+ let words = Input.Option(["--word"; "-w"], Array.empty, "A list of words to be appended")
300
+ let separator = Input.OptionMaybe(["--separator"; "-s"], "A character that will separate the joined words.")
301
+
302
+ let parser =
303
+ rootCommandParser {
304
+ description "Appends words together"
305
+ inputs (words, separator)
306
+ setHandler app
307
+ }
308
+
309
+ parser.Parse(argv).Invoke()
310
+ ```
0 commit comments