Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Old-Style Arg Parsing #1301

Merged
merged 1 commit into from
Jul 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions src/app/FAKE/CommandlineParams.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,35 @@ open Fake

let printAllParams() = printfn "FAKE.exe [buildScript] [Target] Variable1=Value1 Variable2=Value2 ... "

(*
This is a set of flags that exist in code lower in the target processing that MUST be normalized to a certain form. This is necessary because
If any old styole variables are present in the FAKE invocation, Argu parsing will fail and we will not have parsed out those commands correctly
from the overall command line.

You can typically find usages of 'hasBuildParam' in this codebase to find places where these values are required.
*)
let specialFlags =
[
"-st", "single-target"
"--single-target", "single-target"
"-pd", "details"
"--print-details", "details"
] |> Map.ofList

let parseArgs cmdArgs =
let splitter = [| '=' |]
let split (arg:string) =
let pos = arg.IndexOfAny splitter
[| arg.Substring(0, pos); arg.Substring(pos + 1, arg.Length - pos - 1) |]
let (|KeyValue|Flag|TargetName|) ((i,arg) : int * string) =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same logic from the previous version, just captured into an AP to make it very clear what case is what.

if i = 0 then TargetName arg
else
match arg.IndexOf '=' with
| -1 -> Flag arg
| i -> KeyValue (arg.Substring(0, i), arg.Substring(i + 1, arg.Length - i - 1))

cmdArgs
|> Seq.skip 1
|> Seq.mapi (fun (i : int) (arg : string) ->
if arg.Contains "=" then
let s = split arg
if s.[0] = "logfile" then addXmlListener s.[1]
s.[0], s.[1]
else if i = 0 then "target", arg
else arg, "true")
|> Seq.mapi (fun i a -> match (i, a) with
| TargetName t -> "target", t
| Flag f when Map.containsKey f specialFlags -> Map.find f specialFlags, "true"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only new case, really, where we expand out new-style flags that had special handling in the code (See Program.fs where we yield ('single-target', true) for the new-style args as an example).

| Flag f -> f, "true"
| KeyValue (k,v) when k = "logfile" -> addXmlListener v; (k,v)
| KeyValue kvp -> kvp )
|> Seq.toList
11 changes: 6 additions & 5 deletions src/app/FAKE/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,16 @@ try
match Boot.ParseCommandLine(cmdArgs) with
| None ->
let buildScriptArg = if cmdArgs.Length > 1 && cmdArgs.[1].EndsWith ".fsx" then cmdArgs.[1] else Seq.head buildScripts
let fakeArgs = cmdArgs |> Array.filter (fun x -> x.StartsWith "-d:" = false)
let fsiArgs = cmdArgs |> Array.filter (fun x -> x.StartsWith "-d:") |> Array.toList
let args = CommandlineParams.parseArgs (fakeArgs |> Seq.filter ((<>) buildScriptArg) |> Seq.filter ((<>) "details"))
let fsiArgs, fakeArgs = cmdArgs |> Array.partition (fun x -> x.StartsWith "-d:")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that '-pd' and '--print-details' are being expanded, we can't go check back in cmdArgs for 'details', we have to check the inflated list of arguments. That's why I removed the details filter here. Then the lines below do the correct 'details' handling.

let args = CommandlineParams.parseArgs (fakeArgs |> Seq.filter ((<>) buildScriptArg))

traceStartBuild()
let printDetails = containsParam "details" cmdArgs
let printDetails = args |> List.exists (fst >> ((=) "details"))
let argsMinusDetails = args |> List.filter (fst >> ((=) "details"))
let fsiArgsList = fsiArgs |> Seq.toList
if printDetails then
printEnvironment cmdArgs args
if not (runBuildScript printDetails buildScriptArg fsiArgs args true) then Environment.ExitCode <- 1
if not (runBuildScript printDetails buildScriptArg fsiArgsList argsMinusDetails true) then Environment.ExitCode <- 1
else if printDetails then log "Ready."
| Some handler ->
handler.Interact()
Expand Down