INFO
This documentation is for FAKE version 5.0 or later.
API-Reference CreateProcess
API-Reference Proc
API-Reference Process
You can either use a list of arguments:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
|
CreateProcess.fromRawCommand "./folder/mytool.exe" ["arg1"; "arg2"]
|> Proc.run // start with the above configuration
|> ignore // ignore exit code
// Or
[ "arg1"; "arg2"
"arg3" ]
|> CreateProcess.fromRawCommand "./folder/mytool.exe"
|> CreateProcess.withWorkingDirectory "./folder"
|> Proc.run
|> ignore
|
Or a properly escaped command line:
1:
2:
3:
|
CreateProcess.fromRawCommandLine "./folder/mytool.exe" "arg1 arg2 arg3"
|> Proc.run // start with the above configuration
|> ignore // ignore exit code
|
Or use some FAKE helpers:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
|
open Fake.Core
Arguments.Empty
|> Arguments.appendIf true "-Verbose"
|> Arguments.appendNotEmpty "-Channel" channelParamValue
|> Arguments.appendNotEmpty "-Version" versionParamValue
|> Arguments.appendOption "-Architecture" architectureParamValue
|> Arguments.appendNotEmpty "-InstallDir" (defaultArg param.CustomInstallDir defaultUserInstallDir)
|> Arguments.appendIf param.DebugSymbols "-DebugSymbols"
|> Arguments.appendIf param.DryRun "-DryRun"
|> Arguments.appendIf param.NoPath "-NoPath"
|
Or use helper libraries like BlackFox.CommandLine
:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
|
open BlackFox.CommandLine
CmdLine.empty
|> CmdLine.append "build"
|> CmdLine.appendIf noRestore "--no-restore"
|> CmdLine.appendPrefixIfSome "--framework" framework
|> CmdLine.appendPrefixf "--configuration" "%A" configuration
|> CmdLine.toString
|> CreateProcess.fromRawCommandLine "dotnet.exe"
|> Proc.run
|> ignore
|
The most obvious way is:
1:
2:
3:
4:
5:
6:
|
let result =
[ "arg1"; "arg2"; "arg3" ]
|> CreateProcess.fromRawCommand "./folder/mytool.exe"
|> Proc.run
if result.ExitCode <> 0 then failwith "Command failed"
|
To simplify your life you can "embed" the return code check into the CreateProcess
instance (which allows to pass the instance through your application and fail appropriately):
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
|
[ "arg1"; "arg2"; "arg3" ]
|> CreateProcess.fromRawCommand "./folder/mytool.exe"
|> CreateProcess.ensureExitCode // will make sure to throw on error
|> Proc.run
|> ignore
// The above is roughly equivalent to the following (which you can copy and edit to customize):
[ "arg1"; "arg2"; "arg3" ]
|> CreateProcess.fromRawCommand "./folder/mytool.exe"
|> CreateProcess.addOnExited (fun data exitCode ->
if exitCode <> 0 then
// TODO: throw your own exception here
failwithf "Process exit code '%d' <> 0. Command Line: %s" exitCode r.CommandLine
else
data)
|> Proc.run
|> ignore
|
The basic difference between "start" and "run" is:
- "start" starts the process and returns after the process is started. This usually means the process is still running.
- "run" waits for the started process to exit and returns the result.
The different ways to start or run a process are documented here.
Whatever processing option you choose in all cases you need to start process redirection:
1:
2:
3:
4:
|
let result =
CreateProcess.fromRawCommand "./folder/mytool.exe" ["arg1"; "arg2"]
|> CreateProcess.redirectOutput
|> Proc.run
|
This immediately changes the type of result
, now you can access the output:
1:
2:
3:
4:
5:
|
if result.ExitCode <> 0 then
printfn "%s" result.Result.Output
failwithf "FAKE Process exited with %d: %s" result.ExitCode result.Result.Error
let output = result.Result.Output
// Parse output?
|
But even better you can make the 'process-call' type safe for others, by parsing the output:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
|
type MySafeOutput = // ...
let parseOutput (r:ProcessResult<ProcessOutput>) : MySafeOutput =
// use r.Result.Output, r.ExitCode and create MySafeOutput
let startProcess () (*args*)=
CreateProcess.fromRawCommand "./folder/mytool.exe" ["arg1"; "arg2"]
|> CreateProcess.redirectOutput
|> CreateProcess.ensureExitCode // optional, if your parse function can handle output from failures as well
|> CreateProcess.map parseOutput
// Usage:
let myOutput : MySafeOutput =
startProcess()
|> Proc.run
|
Additionally sometimes you need/want asynchronous results to have intermediate results.
For example if you want that the user continuously "sees" the output as the process generates it:
1:
2:
3:
4:
5:
6:
7:
|
let output =
CreateProcess.fromRawCommand "./folder/mytool.exe" ["arg1"; "arg2"]
|> CreateProcess.redirectOutput
|> CreateProcess.withOutputEventsNotNull Trace.trace Trace.traceError
|> Proc.run
// "process" output
|
Redirect output from one process outgen.exe
to processIn.exe
:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
|
let input = StreamRef.Empty
let p1 =
CreateProcess.fromRawCommand "processIn.exe" []
|> CreateProcess.withStandardInput (CreatePipe input)
|> Proc.start
let p2 =
CreateProcess.fromRawCommand "outgen.exe" []
|> CreateProcess.withStandardOutput (UseStream(true, input.Value))
|> Proc.run
|
val ignore : value:'T -> unit
val defaultArg : arg:'T option -> defaultValue:'T -> 'T
val result : obj
val failwith : message:string -> 'T
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
val output : obj
type MySafeOutput
val parseOutput : r:'a -> MySafeOutput
val r : 'a
val startProcess : (unit -> 'b)
val myOutput : MySafeOutput
val input : obj
val p1 : obj
val p2 : obj