Skip to content

Commit

Permalink
Merge pull request #66 from fsprojects/fix/separator-parsing
Browse files Browse the repository at this point in the history
Fix parsing issue in custom assignment separators
  • Loading branch information
eiriktsarpalis authored Dec 9, 2016
2 parents 8b6ad14 + 0cf8965 commit 96524e0
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 29 deletions.
17 changes: 5 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
language: csharp

matrix:
include:
- os: linux # Ubuntu 14.04
dist: trusty
sudo: required
mono: latest
dotnet: 1.0.0-preview2-003121
- os: osx # OSX 10.11
osx_image: xcode7.2
mono: latest
dotnet: 1.0.0-preview2-003121
sudo: required
dist: trusty # Ubuntu 14.04
mono: latest
dotnet: 1.0.0-preview2-003121

script:
- dotnet --info
- ./build.sh RunTests.NetCore
- ./build.sh RunTests.NetCore
19 changes: 7 additions & 12 deletions src/Argu/Parsers/Cli.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ type CliTokenReader(inputs : string[]) =
let mutable isPeekedValue = false
let mutable peekedValue = Unchecked.defaultof<CliParseToken>

static let assignmentRegex =
let escapedChars = new String(validSeparatorChars) |> Regex.Escape
new Regex(sprintf "^([%s]+)(.*)$" escapedChars, RegexOptions.Compiled)

member __.BeginCliSegment() =
segmentStartPos <- position

Expand Down Expand Up @@ -59,14 +55,13 @@ type CliTokenReader(inputs : string[]) =
let mutable case = Unchecked.defaultof<_>
if argInfo.CliParamIndex.Value.TryGetPrefix(token, &prefix, &case) then
if token = prefix then CliParam(token, prefix, case, NoAssignment) |> kont
elif case.IsCustomAssignment then
match case.AssignmentParser.Value token with
| NoAssignment -> tryExtractGroupedSwitches token
| assignment -> CliParam(token, prefix, case, assignment)
|> kont
else
let m = assignmentRegex.Match token.[prefix.Length ..]
if not m.Success then tryExtractGroupedSwitches token |> kont
else
let sep = m.Groups.[1].Value
let value = m.Groups.[2].Value
let assignment = Assignment(prefix, sep, value)
CliParam(token, prefix, case, assignment) |> kont
tryExtractGroupedSwitches token |> kont
else
tryExtractGroupedSwitches token |> kont

Expand Down Expand Up @@ -285,7 +280,7 @@ let rec private parseCommandLinePartial (state : CliParseState) (argInfo : Union
| OptionalParam _ -> aggregator.AppendResult caseInfo sw [|None|]
| _ -> error argInfo ErrorCode.CommandLine "argument '%s' cannot be grouped with other switches." sw

| CliParam(_, _, caseInfo, Assignment(name,sep,_)) when not (caseInfo.Arity = 1 && caseInfo.IsMatchingAssignmentSeparator sep) ->
| CliParam(_, _, caseInfo, Assignment(name,sep,_)) when caseInfo.Arity <> 1 ->
error argInfo ErrorCode.CommandLine "invalid CLI syntax '%s%s<param>'." name sep

| CliParam(token, name, caseInfo, assignment) ->
Expand Down
3 changes: 2 additions & 1 deletion src/Argu/PreCompute.fs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help
match customAssignmentSeparator with
| None -> arguExn "internal error: attempting to call assign parser on invalid parameter."
| Some sep ->
let regex = new Regex(sprintf @"^(.+)%s(.+)$" (Regex.Escape sep), RegexOptions.Compiled)
let pattern = sprintf @"^(.+)%s(.+)$" (Regex.Escape sep)
let regex = new Regex(pattern, RegexOptions.RightToLeft ||| RegexOptions.Compiled)
fun token ->
let m = regex.Match token
if m.Success then Assignment(m.Groups.[1].Value, sep, m.Groups.[2].Value)
Expand Down
4 changes: 0 additions & 4 deletions src/Argu/UnionArgInfo.fs
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,6 @@ with
member inline __.IsCommandLineArg = match __.CommandLineNames with [] -> __.IsMainCommand | _ -> true
member inline __.Type = __.ParameterInfo.Type
member inline __.IsCustomAssignment = Option.isSome __.CustomAssignmentSeparator
member inline __.IsMatchingAssignmentSeparator (separator : string) =
match __.CustomAssignmentSeparator with
| Some sep -> sep = separator
| None -> false


and ParameterInfo =
Expand Down
9 changes: 9 additions & 0 deletions tests/Argu.Tests/Argu.Tests.nuget.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(NuGetPackageRoot)' == ''">
<NuGetPackageRoot>$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
</PropertyGroup>
<ImportGroup>
<Import Project="$(NuGetPackageRoot)\Microsoft.DiaSymReader.Native\1.4.0-rc2\build\Microsoft.DiaSymReader.Native.props" Condition="Exists('$(NuGetPackageRoot)\Microsoft.DiaSymReader.Native\1.4.0-rc2\build\Microsoft.DiaSymReader.Native.props')" />
</ImportGroup>
</Project>
21 changes: 21 additions & 0 deletions tests/Argu.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ module ``Argu Tests`` =
| [<CustomAppSettings "Foo">] CustomAppConfig of string * int
| [<ColonAssignment>] Assignment of string
| [<EqualsAssignment>] Env of key:string * value:string
| [<EqualsAssignment>] Dir of path:string
| [<First>] First_Parameter of string
| [<Last>] Last_Parameter of string
| Optional of int option
Expand All @@ -103,6 +104,7 @@ module ``Argu Tests`` =
| Unique_Arg _ -> "a unique argument."
| Rest_Arg _ -> "an argument that consumes all remaining command line tokens."
| Data _ -> "pass raw data in base64 format."
| Dir _ -> "Project directory to place the config & database in."
| Log_Level _ -> "set the log level."
| Detach _ -> "detach daemon from console."
| Assignment _ -> "assign with colon operation."
Expand Down Expand Up @@ -287,6 +289,25 @@ module ``Argu Tests`` =
let result = parser.Parse(clp, ignoreMissing = true)
test <@ result.GetResult <@ Env @> = ("foo", "bar") @>

[<Fact>]
let ``Parse key-value equals assignment 2`` () =
let result = parser.Parse([|"--env"; "foo==bar"|], ignoreMissing = true)
test <@ result.GetResult <@ Env @> = ("foo", "=bar") @>

[<Fact>]
let ``Parse equals assignment`` () =
let result = parser.Parse([|"--dir=../../my-relative-path"|], ignoreMissing = true)
test <@ result.GetResult <@ Dir @> = "../../my-relative-path" @>

[<Fact>]
let ``Parse equals assignment 2`` () =
let result = parser.Parse([|"--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult <@ Dir @> = "=foo" @>

[<Fact>]
let ``Should fail on incorrect assignment 1`` () =
raises<ArguParseException> <@ parser.Parse([|"--dir:foo"|], ignoreMissing = true) @>


[<Fact>]
let ``Ignore Unrecognized parameters`` () =
Expand Down

0 comments on commit 96524e0

Please sign in to comment.