Skip to content

UnstoppableMango/CliWrap.FSharp

Repository files navigation

CliWrap.FSharp

Build Codecov GitHub Release NuGet Version NuGet Downloads

Idiomatic F# support for CliWrap.

Install

Usage

Bindings for normal CliWrap commands are available in the Cli module.

let main args = async {
  let! result =
    Cli.wrap "dotnet"
    |> Cli.args [ "build" ]
    |> Cli.workDir "~/src/CliWrap.FSharp"
    |> Cli.exec

  result.ExitCode
}

Cancellation token overloads are available in Cli.Tasks.

let main args = task {
  use cts = new CancellationTokenSource()
  let! result =
    Cli.wrap "dotnet"
    |> Cli.args [ "build" ]
    |> Cli.workDir "~/src/CliWrap.FSharp"
    |> Cli.Task.exec cts.Token

  result.ExitCode
}
let main args = task {
  use graceful = new CancellationTokenSource()
  use forceful = new CancellationTokenSource()
  let! result =
    Cli.wrap "dotnet"
    |> Cli.args [ "build" ]
    |> Cli.workDir "~/src/CliWrap.FSharp"
    |> Cli.Task.execf forceful.Token graceful.Token

  result.ExitCode
}

The core of the package is a simple computation expression that wraps CliWrap.Command. It attempts to mimic the builder pattern and .With* style methods.

let main args =
  let cmd = command "dotnet" {
    args = [ "build" ]
    workingDirectory = "~/src/CliWrap.FSharp"
  }

  cmd.ExecuteAsync()

The computation expression also supports executing the command with exec.

let main args = task {
  let! result = command "dotnet" {
    args = [ "build" ]
    workingDirectory = "~/src/CliWrap.FSharp"
    exec
  }

  result.ExitCode
}

Cancellation is also supported.

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.

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.

let main args = async {
  use cts = new CancellationTokenSource()
  let! result = command "dotnet" {
    args = [ "build" ]
    workingDirectory = "~/src/CliWrap.FSharp"
    async cts.Token
  }

  result.ExitCode
}

CliWrap's piping functionality is supported via the pipeline computation expression.

let main args =
  let cmd = pipeline {
    "an inline string source"
    Cli.wrap "echo"
  }

  cmd.ExecuteAsync()

Limited support for piping is available with |>>.

let main args =
  let cmd = Cli.wrap "yes" |>> Cli.wrap "echo"

  cmd.ExecuteAsync()

Inspirations

The idea to abuse F# computation expressions was inspired by Akkling.Hocon and FsHttp.

Obviously CliWrap was a big inspiration for this package.

Q/A

Idiomatic? This looks nothing like the F# I write!

If something looks off please open an issue! I've only recently been diving further into the F# ecosystem.

Why not paket?

If renovate ever supports it!