Skip to content

Commit 96524e0

Browse files
Merge pull request #66 from fsprojects/fix/separator-parsing
Fix parsing issue in custom assignment separators
2 parents 8b6ad14 + 0cf8965 commit 96524e0

File tree

6 files changed

+44
-29
lines changed

6 files changed

+44
-29
lines changed

.travis.yml

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
language: csharp
22

3-
matrix:
4-
include:
5-
- os: linux # Ubuntu 14.04
6-
dist: trusty
7-
sudo: required
8-
mono: latest
9-
dotnet: 1.0.0-preview2-003121
10-
- os: osx # OSX 10.11
11-
osx_image: xcode7.2
12-
mono: latest
13-
dotnet: 1.0.0-preview2-003121
3+
sudo: required
4+
dist: trusty # Ubuntu 14.04
5+
mono: latest
6+
dotnet: 1.0.0-preview2-003121
147

158
script:
169
- dotnet --info
17-
- ./build.sh RunTests.NetCore
10+
- ./build.sh RunTests.NetCore

src/Argu/Parsers/Cli.fs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ type CliTokenReader(inputs : string[]) =
1717
let mutable isPeekedValue = false
1818
let mutable peekedValue = Unchecked.defaultof<CliParseToken>
1919

20-
static let assignmentRegex =
21-
let escapedChars = new String(validSeparatorChars) |> Regex.Escape
22-
new Regex(sprintf "^([%s]+)(.*)$" escapedChars, RegexOptions.Compiled)
23-
2420
member __.BeginCliSegment() =
2521
segmentStartPos <- position
2622

@@ -59,14 +55,13 @@ type CliTokenReader(inputs : string[]) =
5955
let mutable case = Unchecked.defaultof<_>
6056
if argInfo.CliParamIndex.Value.TryGetPrefix(token, &prefix, &case) then
6157
if token = prefix then CliParam(token, prefix, case, NoAssignment) |> kont
58+
elif case.IsCustomAssignment then
59+
match case.AssignmentParser.Value token with
60+
| NoAssignment -> tryExtractGroupedSwitches token
61+
| assignment -> CliParam(token, prefix, case, assignment)
62+
|> kont
6263
else
63-
let m = assignmentRegex.Match token.[prefix.Length ..]
64-
if not m.Success then tryExtractGroupedSwitches token |> kont
65-
else
66-
let sep = m.Groups.[1].Value
67-
let value = m.Groups.[2].Value
68-
let assignment = Assignment(prefix, sep, value)
69-
CliParam(token, prefix, case, assignment) |> kont
64+
tryExtractGroupedSwitches token |> kont
7065
else
7166
tryExtractGroupedSwitches token |> kont
7267

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

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

291286
| CliParam(token, name, caseInfo, assignment) ->

src/Argu/PreCompute.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help
400400
match customAssignmentSeparator with
401401
| None -> arguExn "internal error: attempting to call assign parser on invalid parameter."
402402
| Some sep ->
403-
let regex = new Regex(sprintf @"^(.+)%s(.+)$" (Regex.Escape sep), RegexOptions.Compiled)
403+
let pattern = sprintf @"^(.+)%s(.+)$" (Regex.Escape sep)
404+
let regex = new Regex(pattern, RegexOptions.RightToLeft ||| RegexOptions.Compiled)
404405
fun token ->
405406
let m = regex.Match token
406407
if m.Success then Assignment(m.Groups.[1].Value, sep, m.Groups.[2].Value)

src/Argu/UnionArgInfo.fs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,6 @@ with
126126
member inline __.IsCommandLineArg = match __.CommandLineNames with [] -> __.IsMainCommand | _ -> true
127127
member inline __.Type = __.ParameterInfo.Type
128128
member inline __.IsCustomAssignment = Option.isSome __.CustomAssignmentSeparator
129-
member inline __.IsMatchingAssignmentSeparator (separator : string) =
130-
match __.CustomAssignmentSeparator with
131-
| Some sep -> sep = separator
132-
| None -> false
133129

134130

135131
and ParameterInfo =
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8" standalone="no"?>
2+
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup Condition="'$(NuGetPackageRoot)' == ''">
4+
<NuGetPackageRoot>$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
5+
</PropertyGroup>
6+
<ImportGroup>
7+
<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')" />
8+
</ImportGroup>
9+
</Project>

tests/Argu.Tests/Tests.fs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ module ``Argu Tests`` =
7979
| [<CustomAppSettings "Foo">] CustomAppConfig of string * int
8080
| [<ColonAssignment>] Assignment of string
8181
| [<EqualsAssignment>] Env of key:string * value:string
82+
| [<EqualsAssignment>] Dir of path:string
8283
| [<First>] First_Parameter of string
8384
| [<Last>] Last_Parameter of string
8485
| Optional of int option
@@ -103,6 +104,7 @@ module ``Argu Tests`` =
103104
| Unique_Arg _ -> "a unique argument."
104105
| Rest_Arg _ -> "an argument that consumes all remaining command line tokens."
105106
| Data _ -> "pass raw data in base64 format."
107+
| Dir _ -> "Project directory to place the config & database in."
106108
| Log_Level _ -> "set the log level."
107109
| Detach _ -> "detach daemon from console."
108110
| Assignment _ -> "assign with colon operation."
@@ -287,6 +289,25 @@ module ``Argu Tests`` =
287289
let result = parser.Parse(clp, ignoreMissing = true)
288290
test <@ result.GetResult <@ Env @> = ("foo", "bar") @>
289291

292+
[<Fact>]
293+
let ``Parse key-value equals assignment 2`` () =
294+
let result = parser.Parse([|"--env"; "foo==bar"|], ignoreMissing = true)
295+
test <@ result.GetResult <@ Env @> = ("foo", "=bar") @>
296+
297+
[<Fact>]
298+
let ``Parse equals assignment`` () =
299+
let result = parser.Parse([|"--dir=../../my-relative-path"|], ignoreMissing = true)
300+
test <@ result.GetResult <@ Dir @> = "../../my-relative-path" @>
301+
302+
[<Fact>]
303+
let ``Parse equals assignment 2`` () =
304+
let result = parser.Parse([|"--dir==foo"|], ignoreMissing = true)
305+
test <@ result.GetResult <@ Dir @> = "=foo" @>
306+
307+
[<Fact>]
308+
let ``Should fail on incorrect assignment 1`` () =
309+
raises<ArguParseException> <@ parser.Parse([|"--dir:foo"|], ignoreMissing = true) @>
310+
290311

291312
[<Fact>]
292313
let ``Ignore Unrecognized parameters`` () =

0 commit comments

Comments
 (0)