Skip to content

Commit 4a906e7

Browse files
authored
improve F# bindings usage (#9)
* improve F# bindings usage * Quick README's * Quick README's * ensure readme gets packaged
1 parent 60cc61a commit 4a906e7

File tree

6 files changed

+423
-87
lines changed

6 files changed

+423
-87
lines changed

examples/ScratchPad.Fs/Program.fs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,48 @@
1-
open Proc.Fs
1+
open System
2+
open Proc.Fs
23

3-
let uname = shell {
4+
let _ = shell {
45
exec "dotnet" "--version"
5-
exec "uname"
6+
exec "uname"
67
}
78

89
let dotnetVersion = exec {
910
binary "dotnet"
1011
args "--help"
12+
filter_output (fun l -> l.Line.Contains "clean")
1113
filter (fun l -> l.Line.Contains "clean")
1214
}
1315

16+
exec {
17+
binary "dotnet"
18+
args "--help"
19+
env Map[("key", "value")]
20+
workingDirectory "."
21+
send_control_c false
22+
timeout (TimeSpan.FromSeconds(10))
23+
thread_wrap false
24+
validExitCode (fun i -> i <> 0)
25+
run
26+
}
27+
28+
let helpStatus = exec {
29+
binary "dotnet"
30+
args "--help"
31+
exit_code
32+
}
33+
34+
let helpOutput = exec {
35+
binary "dotnet"
36+
args "--help"
37+
output
38+
}
39+
1440
printfn "Found lines %i" dotnetVersion.Length
1541

16-
let dotnetRestoreHelp = exec {
42+
exec {
1743
binary "dotnet"
18-
invoke_args ["restore"; "--help"]
44+
run_args ["restore"; "--help"]
1945
}
46+
47+
exec { run "dotnet" " "}
48+
let statusCode = exec { exit_code_of "dotnet" " "}

src/Proc.Fs/Bindings.fs

Lines changed: 124 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,57 +4,6 @@ open System
44
open ProcNet
55
open ProcNet.Std
66

7-
let execWithTimeout binary args timeout =
8-
let opts =
9-
ExecArguments(binary, args |> List.map (sprintf "\"%s\"") |> List.toArray)
10-
let options = args |> String.concat " "
11-
printfn ":: Running command: %s %s" binary options
12-
let r = Proc.Exec(opts, timeout)
13-
14-
match r.HasValue with
15-
| true -> r.Value
16-
| false -> failwithf "invocation of `%s` timed out" binary
17-
18-
///executes
19-
let exec2 (binary: string) (args: string list): int =
20-
execWithTimeout binary args (TimeSpan.FromMinutes 10)
21-
22-
let private redirected (binary: string) (args: string list) : ProcessCaptureResult =
23-
Proc.Start(binary, args |> Array.ofList)
24-
25-
type RunningStatus = {
26-
LastExitCode: int
27-
GrepOutput: Std.LineOut list option
28-
}
29-
type ShellBuilder() =
30-
31-
member t.Yield _ = None
32-
33-
[<CustomOperation("exec")>]
34-
member inline this.ExecuteWithArguments(status, binary, [<ParamArray>] args: string array) =
35-
let exitCode = exec2 binary (args |> List.ofArray)
36-
match status with
37-
| None ->
38-
Some { LastExitCode = exitCode; GrepOutput = None }
39-
| Some s ->
40-
Some { s with LastExitCode = exitCode }
41-
42-
[<CustomOperation("grep")>]
43-
member this.Grep(status, searchForRe, binary, [<ParamArray>] args: string array) =
44-
let r = Proc.Start(binary, args)
45-
let o =
46-
r.ConsoleOut
47-
|> Seq.filter (_.Line.Contains(searchForRe))
48-
|> List.ofSeq
49-
50-
match status with
51-
| None ->
52-
Some { LastExitCode = 0; GrepOutput = Some o }
53-
| Some s ->
54-
Some { LastExitCode = 0; GrepOutput = Some o }
55-
56-
let shell = ShellBuilder()
57-
587
type ExecOptions = {
598
Binary: string
609
Arguments: string list option
@@ -71,39 +20,86 @@ type ExecOptions = {
7120
SendControlCFirst: bool option
7221
WaitForStreamReadersTimeout: TimeSpan option
7322
}
74-
75-
type ExecBuilder() =
76-
77-
let startArgs (opts: ExecOptions) =
78-
let startArguments = StartArguments(opts.Binary, opts.Arguments |> Option.defaultValue [])
79-
opts.LineOutFilter |> Option.iter(fun f -> startArguments.LineOutFilter <- f)
80-
opts.Environment |> Option.iter(fun e -> startArguments.Environment <- e)
81-
opts.WorkingDirectory |> Option.iter(fun d -> startArguments.WorkingDirectory <- d)
82-
opts.NoWrapInThread |> Option.iter(fun b -> startArguments.NoWrapInThread <- b)
83-
opts.SendControlCFirst |> Option.iter(fun b -> startArguments.SendControlCFirst <- b)
84-
opts.WaitForStreamReadersTimeout |> Option.iter(fun t -> startArguments.WaitForStreamReadersTimeout <- t)
85-
startArguments
86-
87-
let execArgs (opts: ExecOptions) =
88-
let execArguments = ExecArguments(opts.Binary, opts.Arguments |> Option.defaultValue [])
89-
opts.Environment |> Option.iter(fun e -> execArguments.Environment <- e)
90-
opts.WorkingDirectory |> Option.iter(fun d -> execArguments.WorkingDirectory <- d)
91-
opts.ValidExitCodeClassifier |> Option.iter(fun f -> execArguments.ValidExitCodeClassifier <- f)
92-
execArguments
93-
94-
member t.Yield _ =
23+
with
24+
static member Empty =
9525
{
9626
Binary = ""; Arguments = None; Find = None;
9727
LineOutFilter = None; WorkingDirectory = None; Environment = None
9828
Timeout = None
9929
ValidExitCodeClassifier = None;
10030
NoWrapInThread = None; SendControlCFirst = None; WaitForStreamReadersTimeout = None;
10131
}
32+
33+
let private startArgs (opts: ExecOptions) =
34+
let startArguments = StartArguments(opts.Binary, opts.Arguments |> Option.defaultValue [])
35+
opts.LineOutFilter |> Option.iter(fun f -> startArguments.LineOutFilter <- f)
36+
opts.Environment |> Option.iter(fun e -> startArguments.Environment <- e)
37+
opts.WorkingDirectory |> Option.iter(fun d -> startArguments.WorkingDirectory <- d)
38+
opts.NoWrapInThread |> Option.iter(fun b -> startArguments.NoWrapInThread <- b)
39+
opts.SendControlCFirst |> Option.iter(fun b -> startArguments.SendControlCFirst <- b)
40+
opts.WaitForStreamReadersTimeout |> Option.iter(fun t -> startArguments.WaitForStreamReadersTimeout <- t)
41+
startArguments
42+
43+
let private execArgs (opts: ExecOptions) =
44+
let execArguments = ExecArguments(opts.Binary, opts.Arguments |> Option.defaultValue [])
45+
opts.Environment |> Option.iter(fun e -> execArguments.Environment <- e)
46+
opts.WorkingDirectory |> Option.iter(fun d -> execArguments.WorkingDirectory <- d)
47+
opts.ValidExitCodeClassifier |> Option.iter(fun f -> execArguments.ValidExitCodeClassifier <- f)
48+
execArguments
49+
50+
51+
type ShellBuilder() =
52+
53+
member t.Yield _ = ExecOptions.Empty
54+
55+
[<CustomOperation("workingDirectory")>]
56+
member inline this.WorkingDirectory(opts, workingDirectory: string) =
57+
{ opts with WorkingDirectory = Some workingDirectory }
58+
59+
[<CustomOperation("env")>]
60+
member inline this.EnvironmentVariables(opts, env: Map<string, string>) =
61+
{ opts with Environment = Some env }
62+
63+
[<CustomOperation("timeout")>]
64+
member inline this.Timeout(opts, timeout) =
65+
{ opts with Timeout = Some timeout }
66+
67+
[<CustomOperation("stream_reader_wait_timeout")>]
68+
member inline this.WaitForStreamReadersTimeout(opts, timeout) =
69+
{ opts with WaitForStreamReadersTimeout = Some timeout }
70+
71+
[<CustomOperation("send_control_c")>]
72+
member inline this.SendControlCFirst(opts, sendControlCFirst) =
73+
{ opts with SendControlCFirst = Some sendControlCFirst }
74+
75+
[<CustomOperation("thread_wrap")>]
76+
member inline this.NoWrapInThread(opts, threadWrap) =
77+
{ opts with NoWrapInThread = Some (not threadWrap) }
78+
79+
[<CustomOperation("exec")>]
80+
member this.ExecuteWithArguments(opts, binary, [<ParamArray>] args: string array) =
81+
let opts = { opts with Binary = binary; Arguments = Some (args |> List.ofArray) }
82+
let execArgs = execArgs opts
83+
Proc.Exec(execArgs) |> ignore
84+
opts
85+
86+
[<CustomOperation("exec")>]
87+
member this.ExecuteWithArguments(opts, binary, args: string list) =
88+
let opts = { opts with Binary = binary; Arguments = Some args }
89+
let execArgs = execArgs opts
90+
Proc.Exec(execArgs) |> ignore
91+
opts
92+
93+
let shell = ShellBuilder()
94+
95+
type ExecBuilder() =
96+
97+
member t.Yield _ = ExecOptions.Empty
10298

10399
[<CustomOperation("binary")>]
104-
member inline this.Binary(opts, binary) =
100+
member this.Binary(opts, binary) =
105101
{ opts with Binary = binary }
106-
102+
107103
[<CustomOperation("args")>]
108104
member inline this.Arguments(opts, [<ParamArray>] args: string array) =
109105
{ opts with Arguments = Some (args |> List.ofArray) }
@@ -136,7 +132,7 @@ type ExecBuilder() =
136132
member inline this.NoWrapInThread(opts, threadWrap) =
137133
{ opts with NoWrapInThread = Some (not threadWrap) }
138134

139-
[<CustomOperation("filterOutput")>]
135+
[<CustomOperation("filter_output")>]
140136
member inline this.FilterOutput(opts, find: LineOut -> bool) =
141137
{ opts with LineOutFilter = Some find }
142138

@@ -161,22 +157,68 @@ type ExecBuilder() =
161157
|> Seq.filter find
162158
|> List.ofSeq
163159

164-
[<CustomOperation("invoke_args")>]
160+
[<CustomOperation("output")>]
161+
member this.Output(opts) =
162+
let startArguments = startArgs opts
163+
Proc.Start(startArguments)
164+
165+
[<CustomOperation("run_args")>]
165166
member this.InvokeArgs(opts, [<ParamArray>] args: string array) =
166167
let opts = { opts with Arguments = Some (args |> List.ofArray) }
167168
let execArgs = execArgs opts
168-
Proc.Exec(execArgs)
169+
Proc.Exec(execArgs) |> ignore
169170

170-
[<CustomOperation("invoke_args")>]
171+
[<CustomOperation("run_args")>]
171172
member this.InvokeArgs(opts, args: string list) =
172173
let opts = { opts with Arguments = Some args}
173174
let execArgs = execArgs opts
174-
Proc.Exec(execArgs)
175+
Proc.Exec(execArgs) |> ignore
176+
177+
[<CustomOperation("run")>]
178+
member this.Execute(opts) =
179+
let execArgs = execArgs opts
180+
Proc.Exec(execArgs) |> ignore
175181

176-
[<CustomOperation("invoke")>]
177-
member this.Invoke(opts) =
182+
[<CustomOperation("run")>]
183+
member this.Execute(opts, binary, args: string list) =
184+
let opts = { opts with Binary = binary; Arguments = Some args}
178185
let execArgs = execArgs opts
179-
Proc.Exec(execArgs)
186+
Proc.Exec(execArgs) |> ignore
187+
188+
[<CustomOperation("run")>]
189+
member this.Execute(opts, binary, [<ParamArray>] args: string array) =
190+
let opts = { opts with Binary = binary; Arguments = Some (args |> List.ofArray)}
191+
let execArgs = execArgs opts
192+
Proc.Exec(execArgs) |> ignore
193+
194+
[<CustomOperation("exit_code_of")>]
195+
member this.ReturnStatus(opts, binary, args: string list) =
196+
let opts = { opts with Binary = binary; Arguments = Some args}
197+
let execArgs = execArgs opts
198+
Proc.Exec(execArgs).GetValueOrDefault 1
199+
200+
[<CustomOperation("exit_code_of")>]
201+
member this.ReturnStatus(opts, binary, [<ParamArray>] args: string array) =
202+
let opts = { opts with Binary = binary; Arguments = Some (args |> List.ofArray)}
203+
let execArgs = execArgs opts
204+
Proc.Exec(execArgs).GetValueOrDefault 1
205+
206+
[<CustomOperation("exit_code")>]
207+
member this.ReturnStatus(opts) =
208+
let execArgs = execArgs opts
209+
Proc.Exec(execArgs).GetValueOrDefault 1
210+
211+
[<CustomOperation("output_of")>]
212+
member this.ReturnOutput(opts, binary, [<ParamArray>] args: string array) =
213+
let opts = { opts with Binary = binary; Arguments = Some (args |> List.ofArray)}
214+
let execArgs = startArgs opts
215+
Proc.Start(execArgs)
216+
217+
[<CustomOperation("output_of")>]
218+
member this.ReturnOutput(opts) =
219+
let startArgs = startArgs opts
220+
Proc.Start(startArgs)
221+
180222

181223
let exec = ExecBuilder()
182224

src/Proc.Fs/Proc.Fs.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
<GenerateDocumentationFile>true</GenerateDocumentationFile>
2525
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
2626
<LangVersion>Latest</LangVersion>
27+
<PackageReadmeFile>README.md</PackageReadmeFile>
2728
</PropertyGroup>
2829

2930
<ItemGroup>
3031
<Compile Include="Bindings.fs" />
3132
</ItemGroup>
3233

3334
<ItemGroup>
35+
<Content Include="README.md" Pack="true" PackagePath="README.md" CopyToOutputDirectory="PreserveNewest"/>
3436
<Content Include="..\..\nuget-icon.png" CopyToOutputDirectory="PreserveNewest">
3537
<Link>nuget-icon.png</Link>
3638
<Pack>True</Pack>

0 commit comments

Comments
 (0)