Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.ProcessA ProcessCommand describes a native process; it does not start one. cmd builds it from an
interpolated template and tokenizes that template safely: each interpolation hole becomes exactly one native
argument:
Process.run executes a single command and returns its result:
Show page setup
// Setup for the checked examples on this page.
open System
open Axial.Process
open Axial.Process.DSL
/// Fails the docs test when an example's result differs from the value shown.
let shouldEqual expected actual =
if actual <> expected then failwithf "Expected %A but got %A" expected actualcmd $"printf hello" |> Process.run |> _.StdOut |> shouldEqual "hello"
cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultStdOut: stringshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process; open Axial.Process.DSL (packages: Axial.Process)To check another repository, cwd runs Git there. env "GIT_OPTIONAL_LOCKS" "0" skips optional locks and index
refreshes for a status check, and timeout bounds the wait. None of the settings start a process; each returns
another ProcessCommand:
let status (repository: string) : ProcessCommand =
cmd $"git status --short"
|> cwd repository
|> env "GIT_OPTIONAL_LOCKS" "0"
|> timeout (TimeSpan.FromSeconds 15.0)
status: string -> ProcessCommandrepository: stringstringAn abbreviation for the CLI type . Basic Types
Axial.Process.ProcessCommandOne immutable command; configure it before connecting stages.
cmd: FormattableString -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
cwd: string -> ProcessCommand -> ProcessCommandenv: string -> string -> ProcessCommand -> ProcessCommandtimeout: TimeSpan -> ProcessCommand -> ProcessCommandSystem.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
Requires & types
Requires: open Axial.Process; open Axial.Process.DSL; open System (packages: Axial.Process)val status: string -> ProcessCommandThese functions take a ProcessCommand, so set them before joining the stage into a ProcessSpec. When a reusable
function has already returned a complete topology, Process.mapFinalCommand
lets a caller adjust settings on its final command without rebuilding the pipeline. It preserves that command's
executable and arguments; use it for caller-specific settings such as a deadline, not to change what program runs.
Qualified helpers such as Process.arg, Process.secretArg,
Process.removeEnvironment,
Process.encoding, and
Process.successCodes also take a ProcessCommand.
Connect native process stages
A shell can run this pipeline as one Bash program:
let countLinesInShell =
bash $"printf 'error one\\nerror two\\n' | wc -l"
countLinesInShell: ProcessCommandbash: FormattableString -> ProcessCommandBuilds a Bash program with interpolation values passed as positional arguments.
Requires & types
Requires: open Axial.Process.DSL (packages: Axial.Process)val countLinesInShell: ProcessCommandThe => operator builds the same topology from two command descriptions: the left command's stdout becomes the
right command's stdin. Each stage remains a separate value in the ProcessSpec; no shell parses the pipeline.
That means each command can have its own working directory, environment, timeout, and success-code policy, and
Process.plan can show the connected stages before execution. Use bash when shell syntax itself is what you need;
use => when you want Axial to compose and manage native process stages.
let countLines : ProcessSpec =
cmd $"printf 'error one\\nerror two\\n'"
=> cmd $"wc -l"
countLines: ProcessSpecAxial.Process.ProcessSpecAn immutable process topology, configured without starting any processes.
cmd: FormattableString -> ProcessCommand(=>): ^source -> ^destination -> ^resultRequires & types
Requires: open Axial.Process; open Axial.Process.DSL (packages: Axial.Process)val countLines: ProcessSpecBoth forms count the same two lines:
let shellCount = countLinesInShell |> Process.run |> _.StdOut.Trim()
let composedCount = countLines |> Process.run |> _.StdOut.Trim()
shouldEqual "2" shellCount
shouldEqual shellCount composedCount
shellCount: stringcountLinesInShell: ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultTrim: unit -> stringRemoves all leading and trailing white-space characters from the current object. The string that remains after all white-space characters are removed from the start and end of the current string. If no characters can be trimmed from the current instance, the method returns the current instance unchanged.
StdOut: stringcomposedCount: stringcountLines: ProcessSpecshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process (packages: Axial.Process)val shellCount: stringval composedCount: stringParentheses let a downstream stage carry its own settings before it is connected:
open Axial.Process.DSL
let shout (value: string) : ProcessSpec =
cmd $"printf %%s {value}"
=> (cmd $"tr '[:lower:]' '[:upper:]'"
|> timeout (TimeSpan.FromSeconds 5.0))
AxialProcessAxial.Process.DSLshout: string -> ProcessSpecvalue: stringstringAn abbreviation for the CLI type . Basic Types
Axial.Process.ProcessSpecAn immutable process topology, configured without starting any processes.
cmd: FormattableString -> ProcessCommand(=>): ^source -> ^destination -> ^result(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
timeout: TimeSpan -> ProcessCommand -> ProcessCommandSystem.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
Requires & types
Requires: open Axial.Process; open Axial.Process.DSL; open System (packages: Axial.Process)val shout: string -> ProcessSpecThe interpolated value is one argument, even with spaces or shell characters in it:
shout "hello; world" |> Process.run |> _.StdOut |> shouldEqual "HELLO; WORLD"
shout: string -> ProcessSpec(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultStdOut: stringshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process (packages: Axial.Process)The same configured pipeline can use qualified functions throughout:
let shoutWithFunctions (value: string) : ProcessSpec =
Process.command $"printf %%s {value}"
|> Process.pipe (Process.command $"tr '[:lower:]' '[:upper:]'"
|> Process.timeout (TimeSpan.FromSeconds 5.))
shoutWithFunctions: string -> ProcessSpecvalue: stringstringAn abbreviation for the CLI type . Basic Types
Axial.Process.ProcessSpecAn immutable process topology, configured without starting any processes.
Axial.Process.Processcommand: FormattableString -> ProcessCommandCreates a safely tokenized one-command process specification from an interpolated command template. Each interpolation hole is one native argument. Example: Process.command $"git show {revision}" |> Process.toFlow
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
pipe: ^a -> ^b -> ProcessSpectimeout: TimeSpan -> ProcessCommand -> ProcessCommandBounds one stage from successful native launch to direct exit; use overallTimeout to include drainage.
System.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
Requires & types
Requires: open Axial.Process; open System (packages: Axial.Process)val shoutWithFunctions: string -> ProcessSpecshoutWithFunctions "hello; world" |> Process.run |> _.StdOut |> shouldEqual "HELLO; WORLD"
shoutWithFunctions: string -> ProcessSpec(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultStdOut: stringshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process (packages: Axial.Process)Interpolation keeps each value in one argument
Values from your program belong in interpolation holes. cmd and Process.command pass each whole value as one
native argument, so spaces and characters such as ;, |, and $ stay literal — neither runs a shell. The
shout example above passes "hello; world" to printf unchanged before piping it into tr.
Use secret when plans and diagnostics must show *** instead of the real
argument. Use cmdText for fixed command text: Axial tokenizes it into an
executable and arguments without invoking a shell, so operators such as | and ; stay ordinary arguments.
For shell syntax, see scripts and shell syntax.
Use Process.commandArgs when arguments already exist as separate
values. It skips command-line parsing and produces the same immutable command.
Process.plan returns a redacted, serializable description without executing anything. Process.render returns a redacted, shell-like diagnostic string for humans; it is not a shell command generator.
Settings shared by a whole pipeline belong on the topology rather than repeated per command. Explicit command
settings override them, and defaults reach stages connected later. Process.plan shows the resolved settings
and where each came from.
let defaults =
StageDefaults.empty
|> StageDefaults.environment "CI" "true"
|> StageDefaults.timeout (TimeSpan.FromSeconds 15.)
let sharedPipeline : ProcessSpec =
cmd $"printf ready"
|> stageDefaults defaults
|> pipeTo (cmd $"cat" |> withoutTimeout)
defaults: StageDefaultsAxial.Process.StageDefaultsModuleempty: StageDefaults(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
environment: string -> string -> StageDefaults -> StageDefaultstimeout: TimeSpan -> StageDefaults -> StageDefaultsSystem.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
sharedPipeline: ProcessSpecAxial.Process.ProcessSpecAn immutable process topology, configured without starting any processes.
cmd: FormattableString -> ProcessCommandstageDefaults: StageDefaults -> ^a -> ProcessSpecpipeTo: ^a -> ^b -> ProcessSpecwithoutTimeout: ProcessCommand -> ProcessCommandRequires & types
Requires: open Axial.Process; open Axial.Process.DSL; open System (packages: Axial.Process)val defaults: StageDefaultsval sharedPipeline: ProcessSpecsharedPipeline |> Process.run |> _.StdOut |> shouldEqual "ready"
sharedPipeline: ProcessSpec(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultStdOut: stringshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process (packages: Axial.Process)mapFinalCommand is useful when the pipeline is reusable but a caller owns the policy for its final stage. For
example, add a deadline after the topology has been assembled:
let countLinesWithDeadline =
countLines
|> Process.mapFinalCommand (Process.timeout (TimeSpan.FromSeconds 5.0))
countLinesWithDeadline: ProcessSpeccountLines: ProcessSpec(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.ProcessmapFinalCommand: (ProcessCommand -> ProcessCommand) -> ProcessSpec -> ProcessSpecChanges settings on the unique final command; executable and arguments must remain unchanged.
timeout: TimeSpan -> ProcessCommand -> ProcessCommandBounds one stage from successful native launch to direct exit; use overallTimeout to include drainage.
System.TimeSpanRepresents a time interval.
FromSeconds: float -> TimeSpanReturns a that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. A number of seconds, accurate to the nearest millisecond. An object that represents . is less than or greater than . -or- is . -or- is . is equal to .
Requires & types
Requires: open Axial.Process; open System (packages: Axial.Process)val countLinesWithDeadline: ProcessSpeccountLinesWithDeadline |> Process.run |> _.StdOut.Trim() |> shouldEqual "2"
countLinesWithDeadline: ProcessSpec(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultTrim: unit -> stringRemoves all leading and trailing white-space characters from the current object. The string that remains after all white-space characters are removed from the start and end of the current string. If no characters can be trimmed from the current instance, the method returns the current instance unchanged.
StdOut: stringshouldEqual: 'a -> 'a -> unitRequires & types
Requires: open Axial.Process (packages: Axial.Process)This transforms the unique final command's settings. It rejects changing its executable or arguments, and cannot apply to a topology with multiple final commands. Prefer configuring a stage before connecting it when the setting is intrinsic to that stage. A stdout route and a pipe are mutually exclusive: configure the downstream command's route, or tee to a readable external channel.
For checked examples of stdin, file routes, tee, fan-in, parallel capture, and recovery, see DSL recipes.
Build from fixed text or argument lists
cmdText parses fixed text without invoking a shell, so shell operators become ordinary arguments. pipe builds
a pipeline from a list of interpolated templates when the stages are assembled dynamically.
cmdText "printf fixed" |> Process.run |> _.StdOut |> shouldEqual "fixed"
pipe [ $"printf 'one\ntwo\n'"; $"wc -l" ]
|> Process.run |> _.StdOut.Trim() |> shouldEqual "2"
Process.commandArgs "printf" ["%s"; "space and ; characters"]
|> Process.run |> _.StdOut |> shouldEqual "space and ; characters"
cmdText: string -> ProcessCommand(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.Processrun: ^source -> ^resultRuns with live services and returns the value; raises ProcessRunException on failure.
_arg1: ProcessResultStdOut: stringshouldEqual: 'a -> 'a -> unitpipe: 'a seq -> ProcessSpecTrim: unit -> stringRemoves all leading and trailing white-space characters from the current object. The string that remains after all white-space characters are removed from the start and end of the current string. If no characters can be trimmed from the current instance, the method returns the current instance unchanged.
commandArgs: string -> string list -> ProcessCommandCreates a one-command process specification from an executable and already-separated arguments. Example: Process.commandArgs "git" [ "status"; "--short" ] |> Process.toFlow
Requires & types
Requires: open Axial.Process; open Axial.Process.DSL (packages: Axial.Process)
