From 09d1112e6a8f062f9f5b39cf127073bd21759a62 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Sat, 13 Jan 2024 18:07:40 -0600 Subject: [PATCH 1/2] Include renovate.json in solution --- CliWrap.FSharp.sln | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CliWrap.FSharp.sln b/CliWrap.FSharp.sln index a396a7f..286879c 100644 --- a/CliWrap.FSharp.sln +++ b/CliWrap.FSharp.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 @@ -25,6 +25,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{FE346152-5716-4224-9B25-C6B3815C70CA}" ProjectSection(SolutionItems) = preProject .github\workflows\main.yml = .github\workflows\main.yml + .github\renovate.json = .github\renovate.json EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{BC50591F-A365-4A92-9FDC-4CD2D75EE6A4}" From e63ec45563e0bc7d317d52538d141739787d95a1 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Sat, 13 Jan 2024 18:37:39 -0600 Subject: [PATCH 2/2] Execution with a single builder --- README.md | 60 ++++++++++++++++++++++-- src/CliWrap.FSharp/CliWrap.FSharp.fsproj | 1 - src/CliWrap.FSharp/CommandBuilder.fs | 35 ++++++++++++++ src/CliWrap.FSharp/ExecBuilder.fs | 41 ---------------- 4 files changed, 90 insertions(+), 47 deletions(-) delete mode 100644 src/CliWrap.FSharp/ExecBuilder.fs diff --git a/README.md b/README.md index 564555e..5c6f680 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CliWrap.FSharp -Idiomatic F# support for CliWrap +Idiomatic F# support for CliWrap. ## Usage @@ -17,11 +17,59 @@ let main args = cmd.ExecuteAsync() ``` +The computation expression also supports executing the command with `exec`. + +```fsharp +let main args = task { + let! result = command "dotnet" { + args = [ "build" ] + workingDirectory = "~/src/CliWrap.FSharp" + exec + } + + result.ExitCode +} +``` + +Cancellation is also supported. + +```fsharp +let main args = task { + use cts = new CancellationTokenSource() + let! result = command "dotnet" { + args = [ "build" ] + workingDirectory = "~/src/CliWrap.FSharp" + exec cts.Token + } + + result.ExitCode +} +``` + +CliWrap's buffered execution is supported with `buffered`. + +```fsharp +let main args = task { + use cts = new CancellationTokenSource() + let! result = command "dotnet" { + args = [ "build" ] + workingDirectory = "~/src/CliWrap.FSharp" + buffered Encoding.UTF8 cts.Token + } + + result.ExitCode +} +``` + +Asynchrony with F#'s `Async<'T>` is supported with `async`. + ```fsharp let main args = async { - let! result = exec "dotnet" { + use cts = new CancellationTokenSource() + let! result = command "dotnet" { args = [ "build" ] workingDirectory = "~/src/CliWrap.FSharp" + async cts.Token } result.ExitCode @@ -38,10 +86,12 @@ let main args = cmd.ExecuteAsync() ``` -## Idiomatic? This looks nothing like normal F# code! +## Q/A + +### Idiomatic? This looks nothing like the F# I write! -I've only recently been diving further into the F# ecosystem, if something looks off please open an issue! +If something looks off please open an issue! I've only recently been diving further into the F# ecosystem. -## Why not paket? +### Why not paket? If renovate ever [supports it](https://github.com/renovatebot/renovate/issues/11211)! diff --git a/src/CliWrap.FSharp/CliWrap.FSharp.fsproj b/src/CliWrap.FSharp/CliWrap.FSharp.fsproj index 058ae27..564fe55 100644 --- a/src/CliWrap.FSharp/CliWrap.FSharp.fsproj +++ b/src/CliWrap.FSharp/CliWrap.FSharp.fsproj @@ -12,7 +12,6 @@ - diff --git a/src/CliWrap.FSharp/CommandBuilder.fs b/src/CliWrap.FSharp/CommandBuilder.fs index 4363cee..8b10887 100644 --- a/src/CliWrap.FSharp/CommandBuilder.fs +++ b/src/CliWrap.FSharp/CommandBuilder.fs @@ -2,7 +2,9 @@ module UnMango.CliWrap.FSharp.CommandBuilder open System.ComponentModel +open System.Text open CliWrap +open CliWrap.Buffered type CommandBuilder(target: string) = [] @@ -11,6 +13,12 @@ type CommandBuilder(target: string) = [] member _.Run(command: Command) = command + [] + member _.Run<'T>(command: CommandTask<'T>) = command + + [] + member _.Run<'T>(task: Async<'T>) = task + [] member _.Env(command: Command, env) = Cli.env env command @@ -47,4 +55,31 @@ type CommandBuilder(target: string) = [] member _.Validation(command: Command, validation) = Cli.validation validation command + [] + member _.Exec(command: Command) = command.ExecuteAsync() + + [] + member _.Exec(command: Command, cancellationToken) = command.ExecuteAsync(cancellationToken) + + [] + member _.Buffered(command: Command) = command.ExecuteBufferedAsync() + + [] + member _.Buffered(command: Command, encoding: Encoding) = command.ExecuteBufferedAsync(encoding) + + [] + member _.Buffered(command: Command, encoding, cancellationToken) = + command.ExecuteBufferedAsync(encoding, cancellationToken) + + [] + member _.Async<'T>(task: CommandTask<'T>) = + task |> CommandTask.op_Implicit |> Async.AwaitTask + + [] + member this.Async(command: Command) = this.Async(command.ExecuteAsync()) + + [] + member this.Async(command: Command, cancellationToken) = + this.Async(command.ExecuteAsync(cancellationToken)) + let command target = CommandBuilder(target) diff --git a/src/CliWrap.FSharp/ExecBuilder.fs b/src/CliWrap.FSharp/ExecBuilder.fs deleted file mode 100644 index 52a2ca6..0000000 --- a/src/CliWrap.FSharp/ExecBuilder.fs +++ /dev/null @@ -1,41 +0,0 @@ -[] -module UnMango.CliWrap.FSharp.ExecBuilder - -open System -open System.ComponentModel -open System.Threading -open CliWrap - -type State = - { Command: Command - Cts: CancellationTokenSource } - - interface IDisposable with - member this.Dispose() = this.Cts.Dispose() - -module State = - let initial name = - { Command = Command(name) - Cts = new CancellationTokenSource() } - -type ExecBuilder(name: string) = - [] - member _.Yield(_: unit) = State.initial name - - [] - member _.Run(state: State) = - state.Command.ExecuteAsync(state.Cts.Token) - |> CommandTask.op_Implicit - |> Async.AwaitTask - - [] - member _.Args(state: State, args: string) = - { state with - Command = state.Command.WithArguments(args) } - - [] - member _.Args(state: State, args: string seq) = - { state with - Command = state.Command.WithArguments(args) } - -let exec name = ExecBuilder(name)