Skip to content

Commit

Permalink
Merge pull request #72 from CaptnCodr/empty-file-output
Browse files Browse the repository at this point in the history
Empty file output will not write to file
  • Loading branch information
CaptnCodr authored May 31, 2024
2 parents d8fb46c + ce408bf commit 5d5fa46
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 39 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ Add environment variables for the executing program:
cli {
Exec "git"
EnvironmentVariables [("GIT_AUTHOR_NAME", "Jon Doe"); ("GIT_AUTHOR_EMAIL", "[email protected]")]
Output ""
}
|> Command.execute
```
Hint: `Output ""` will be ignored. This is for conditional cases, e.g.: `Output (if true then logFilePath else "")`.

Add credentials to program:
```fsharp
Expand All @@ -127,8 +129,8 @@ cli {
For Windows applications it's possible to set their visibility. There are four possible values: `Hidden`, `Maximized`, `Minimized` and `Normal`. The default is `Hidden`.
```fsharp
cli {
Exec @"C:\Windows\regedit.exe"
WindowStyle Normal
Exec @"C:\Windows\regedit.exe"
WindowStyle Normal
}
|> Command.execute
```
Expand Down
2 changes: 1 addition & 1 deletion src/Fli.Tests/ExecContext/ExecCommandConfigureUnixTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open System.Text
let ``Check FileName in ProcessStartInfo Exec program`` () =
cli { Exec "bash" }
|> Command.buildProcess
|> (fun p -> p.FileName)
|> _.FileName
|> should equal "bash"

[<Test>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open System.Text
let ``Check FileName in ProcessStartInfo Exec program`` () =
cli { Exec "cmd.exe" }
|> Command.buildProcess
|> (fun p -> p.FileName)
|> _.FileName
|> should equal "cmd.exe"

[<Test>]
Expand Down
18 changes: 17 additions & 1 deletion src/Fli.Tests/ExecContext/ExecConfigTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ let ``Check Output config for executing program`` () =
|> _.config.Output
|> should equal (Some(File @"C:\Users\test.txt"))

[<Test>]
let ``Empty string in Output ends up as None`` () =
cli {
Exec "cmd.exe"
Output ""
}
|> _.config.Output |> should be (ofCase <@ None @>)

[<Test>]
let ``Nullable file path in Output ends up as None`` () =
cli {
Exec "cmd.exe"
Output (File(null))
}
|> _.config.Output |> should be (ofCase <@ None @>)

[<Test>]
let ``Check working directory config for executing program`` () =
cli {
Expand All @@ -55,7 +71,7 @@ let ``Check working directory config for executing program`` () =
|> should equal (Some @"C:\Users")

[<Test>]
let ``Check windowstyle config for executing program`` () =
let ``Check WindowStyle config for executing program`` () =
cli {
Exec "cmd.exe"
WindowStyle Normal }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open System.Text
let ``Check FileName in ProcessStartInfo with CMD Shell`` () =
cli { Shell BASH }
|> Command.buildProcess
|> (fun p -> p.FileName)
|> _.FileName
|> should equal "bash"

[<Test>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open System.Text
let ``Check FileName in ProcessStartInfo with CMD Shell`` () =
cli { Shell CMD }
|> Command.buildProcess
|> (fun p -> p.FileName)
|> _.FileName
|> should equal "cmd.exe"

[<Test>]
Expand Down
16 changes: 16 additions & 0 deletions src/Fli.Tests/ShellContext/ShellConfigTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ let ``Check Output config for CMD`` () =
|> _.config.Output
|> should equal (Some(File @"C:\Users\test.txt"))

[<Test>]
let ``Empty string in Output ends up as None`` () =
cli {
Shell CMD
Output ""
}
|> _.config.Output |> should be (ofCase <@ None @>)

[<Test>]
let ``Nullable file path in Output ends up as None`` () =
cli {
Shell CMD
Output (File(null))
}
|> _.config.Output |> should be (ofCase <@ None @>)

[<Test>]
let ``Check WorkingDirectory config`` () =
cli {
Expand Down
16 changes: 13 additions & 3 deletions src/Fli/CE.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module CE =

type ICommandContext<'a> with

member this.Yield(_) = this
member this.Yield _ = this

type StartingContext =
{ config: Config option }
Expand Down Expand Up @@ -36,6 +36,11 @@ module CE =
[<CustomOperation("Input")>]
member _.Input(context: ICommandContext<ShellContext>, input) = Cli.input input context.Context

/// Extra `Output` that is being executed immediately after getting output from execution.
[<CustomOperation("Output")>]
member _.Output(context: ICommandContext<ShellContext>, output: Outputs) =
Cli.output output context.Context

/// Extra `Output` that is being executed immediately after getting output from execution.
[<CustomOperation("Output")>]
member _.Output(context: ICommandContext<ShellContext>, filePath: string) =
Expand Down Expand Up @@ -93,7 +98,7 @@ module CE =
[<CustomOperation("Arguments")>]
member _.Arguments(context: ICommandContext<ExecContext>, arguments) =
let matchArguments arguments =
match box (arguments) with
match box arguments with
| :? string as s -> s
| :? seq<string> as s -> s |> Seq.map string |> String.concat " "
| _ -> failwith "Cannot convert arguments to a string!"
Expand All @@ -104,6 +109,11 @@ module CE =
[<CustomOperation("Input")>]
member _.Input(context: ICommandContext<ExecContext>, input) = Program.input input context.Context

/// Extra `Output` that is being executed immediately after getting output from execution.
[<CustomOperation("Output")>]
member _.Output(context: ICommandContext<ExecContext>, output: Outputs) =
Program.output output context.Context

/// Extra `Output` that is being executed immediately after getting output from execution.
[<CustomOperation("Output")>]
member _.Output(context: ICommandContext<ExecContext>, filePath: string) =
Expand Down Expand Up @@ -143,7 +153,7 @@ module CE =
/// Hint: `Domain` and `Password` are available for Windows systems only.
[<CustomOperation("Credentials")>]
member _.Credentials(context: ICommandContext<ExecContext>, credentials) =
let (domain, user, pw) = credentials in Program.credentials (Credentials(domain, user, pw)) context.Context
let domain, user, pw = credentials in Program.credentials (Credentials(domain, user, pw)) context.Context

/// One tupled `EnvironmentVariable`.
[<CustomOperation("EnvironmentVariable")>]
Expand Down
40 changes: 16 additions & 24 deletions src/Fli/Command.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ module Command =
open System.Threading

let private getAvailablePwshExe () =
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
"pwsh.exe"
else
"pwsh"
match RuntimeInformation.IsOSPlatform(OSPlatform.Windows) with
| true -> "pwsh.exe"
| false -> "pwsh"

let private shellToProcess (shell: Shells) (input: string option) =
match shell with
Expand All @@ -30,30 +29,24 @@ module Command =
| ZSH -> "zsh", "-c"
| CUSTOM(shell, flag) -> shell, flag

let private toOption =
function
| null
| "" -> None
| _ as s -> Some s

let private createProcess executable argumentString openDefault =
ProcessStartInfo(
FileName = executable,
Arguments = argumentString,
CreateNoWindow = true,
UseShellExecute = openDefault,
RedirectStandardInput = not (openDefault),
RedirectStandardOutput = not (openDefault),
RedirectStandardError = not (openDefault)
RedirectStandardInput = not openDefault,
RedirectStandardOutput = not openDefault,
RedirectStandardError = not openDefault
)

let private trim (s: string) = s.TrimEnd([| '\r'; '\n' |])

let returnOr (sb: StringBuilder) (output: string) =
match (sb.ToString(), output) with
| (t, _) when t.Length > 0 -> t
| (_, o) when o.Length > 0 -> o
| (_, _) -> ""
| t, _ when t.Length > 0 -> t
| _, o when o.Length > 0 -> o
| _, _ -> ""

#if NET
let private startProcessAsync
Expand Down Expand Up @@ -133,7 +126,7 @@ module Command =

let private checkVerb (verb: string option) (executable: string) =
match verb with
| Some(v) ->
| Some v ->
let verbs = ProcessStartInfo(executable).Verbs

if not (verbs |> Array.contains v) then
Expand All @@ -144,7 +137,7 @@ module Command =

let private addEnvironmentVariables (variables: (string * string) list option) (psi: ProcessStartInfo) =
if psi.UseShellExecute |> not then
((variables |> Option.defaultValue [] |> List.iter (psi.Environment.Add)), psi)
((variables |> Option.defaultValue [] |> List.iter psi.Environment.Add), psi)
|> snd
else
psi
Expand All @@ -163,7 +156,7 @@ module Command =

let private writeInput (input: string option) (encoding: Encoding option) (p: Process) =
match input with
| Some(inputText) ->
| Some inputText ->
try
use sw = p.StandardInput
sw.WriteLine(inputText, encoding)
Expand All @@ -176,7 +169,7 @@ module Command =
let private writeInputAsync (input: string option) (p: Process) =
async {
match input with
| Some(inputText) ->
| Some inputText ->
try
use sw = p.StandardInput
do! inputText |> sw.WriteLineAsync |> Async.AwaitTask
Expand All @@ -195,7 +188,6 @@ module Command =
| Outputs.File(file) -> File.WriteAllText(file, output)
| Outputs.StringBuilder(stringBuilder) -> output |> stringBuilder.Append |> ignore
| Outputs.Custom(func) -> func.Invoke(output)

| None -> ()

let private setupCancellationToken (cancelAfter: int option) =
Expand Down Expand Up @@ -228,7 +220,7 @@ module Command =

type Command =
static member internal buildProcess(context: ShellContext) =
let (proc, flag) = (context.config.Shell, context.config.Input) ||> shellToProcess
let proc, flag = (context.config.Shell, context.config.Input) ||> shellToProcess
let command = context |> quoteBashCommand

(createProcess proc $"""{flag} {command}""" false)
Expand All @@ -242,7 +234,7 @@ module Command =
checkVerb context.config.Verb context.config.Program

let arguments = (context.config.Arguments |> Option.defaultValue "")

let openDefault =
context.config.Arguments.IsNone
&& context.config.EnvironmentVariables.IsNone
Expand All @@ -260,7 +252,7 @@ module Command =

/// Stringifies shell + opening flag and given command.
static member toString(context: ShellContext) =
let (proc, flag) = (context.config.Shell, context.config.Input) ||> shellToProcess
let proc, flag = (context.config.Shell, context.config.Input) ||> shellToProcess
let command = context |> quoteBashCommand
$"""{proc} {flag} {command}"""

Expand Down
17 changes: 13 additions & 4 deletions src/Fli/Dsl.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Fli

open Domain
open Helpers

module Cli =

Expand All @@ -18,8 +19,12 @@ module Cli =
config.Input = Some input }

let output (output: Outputs) (context: ShellContext) =
{ context with
config.Output = Some output }
let outputsOption =
match output with
| File path -> path |> toOptionWithDefault output
| _ -> Some output

{ context with config.Output = outputsOption }

let workingDirectory (workingDirectory: string) (context: ShellContext) =
{ context with
Expand Down Expand Up @@ -62,8 +67,12 @@ module Program =
config.Input = Some input }

let output (output: Outputs) (context: ExecContext) =
{ context with
config.Output = Some output }
let outputsOption =
match output with
| File path -> path |> toOptionWithDefault output
| _ -> Some output

{ context with config.Output = outputsOption }

let workingDirectory (workingDirectory: string) (context: ExecContext) =
{ context with
Expand Down
2 changes: 1 addition & 1 deletion src/Fli/Fli.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
<Compile Include="AssemblyInfo.fs" />
<Compile Include="Domain.fs" />
<Compile Include="Output.fs" />
<Compile Include="Helpers.fs" />
<Compile Include="Dsl.fs" />
<Compile Include="CE.fs" />
<Compile Include="Extensions.fs" />
<Compile Include="Helpers.fs" />
<Compile Include="Command.fs" />
<None Include="paket.references" />
<None Include="paket.template" />
Expand Down
12 changes: 12 additions & 0 deletions src/Fli/Helpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ module Helpers =
secureString
finally
gcHandle.Free()

let toOption =
function
| null
| "" -> None
| s -> Some s

let toOptionWithDefault defaultValue value =
match value with
| null
| "" -> None
| _ -> Some defaultValue

0 comments on commit 5d5fa46

Please sign in to comment.