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

Repeated options #559

Closed
bootstraponline opened this issue Nov 30, 2018 · 3 comments
Closed

Repeated options #559

bootstraponline opened this issue Nov 30, 2018 · 3 comments
Labels
status: invalid 😶 An issue that we don't feel is valid theme: parser An issue or change related to the parser

Comments

@bootstraponline
Copy link

If this is the same request as #454 then the issue can be closed.

I am trying to match the gcloud tool which supports repeating arguments. For example:

  --device model=Nexus6
  --device model=Nexus6

results in two devices. I have the following pico cli code:

@Option(
        names = ["--device"], split = ",", description = ["""A list of DIMENSION=VALUE pairs which specify a target
        |device to test against. This flag may be repeated to specify multiple devices. The four device dimensions are:
        | model, version, locale, and orientation. If any dimensions are omitted, they will use a default value. Omitting
        |  all of the preceding dimension-related flags will run tests against a single device using defaults for all four
        |   device dimensions."""]
    )
    fun deviceMap(map: Map<String, String>?) {
        if (map.isNullOrEmpty()) return
        val androidDevice = Device(
            model = map.getOrDefault("model", defaultAndroidModel),
            version = map.getOrDefault("version", defaultAndroidVersion),
            locale = map.getOrDefault("locale", defaultLocale),
            orientation = map.getOrDefault("orientation", defaultOrientation)
        )

        if (device == null) device = mutableListOf()
        device?.add(androidDevice)
    }

    var device: MutableList<Device>? = null

When I test the code, only one device is kept:

    @Test
    fun cli_device_repeat() {
        val cli = AndroidRunCommand()
        CommandLine(cli).parse(
            "--device=model=shamu,version=22,locale=zh_CN,orientation=default " +
                "--device=model=shamu,version=22,locale=zh_CN,orientation=default")

        val yaml = """
        gcloud:
          app: $appApk
          test: $testApk
      """
        val androidArgs = AndroidArgs.load(yaml, cli)
        val expectedDevice = Device("shamu", "22", "zh_CN", "default")
        val actualDevices = androidArgs.devices
        assertThat(actualDevices.size).isEqualTo(2)
        assertThat(actualDevices[0]).isEqualTo(expectedDevice)
        assertThat(actualDevices[1]).isEqualTo(expectedDevice)
    }

Is there no support for repeating commands in picocli?

@remkop
Copy link
Owner

remkop commented Dec 1, 2018

I have been able to reproduce the problem. I believe it is a bug in the test. The test passes a single argument string to the parser:

"--device=model=shamu,version=22,locale=zh_CN,orientation=default " +
        "--device=model=shamu,version=22,locale=zh_CN,orientation=default"

If you switch on parser tracing with system property -Dpicocli.trace=DEBUG you can see what is happening:

# this is one argument
[picocli DEBUG] Processing argument '--device=model=shamu,version=22,locale=zh_CN,orientation=default --device=model=shamu,version=22,locale=zh_CN,orientation=default'. Remainder=[]

# separating option name from the value
[picocli DEBUG] Separated '--device' option from 'model=shamu,version=22,locale=zh_CN,orientation=default --device=model=shamu,version=22,locale=zh_CN,orientation=default' option parameter

# find the method bound to the option
[picocli DEBUG] Found option named '--device': method (...)deviceMap(java.util.Map<String, String>), arity=1

# splitting the value with regex and putting key-value pairs in the map
[picocli INFO] Putting [model : shamu] in LinkedHashMap (...) for option --device
[picocli INFO] Putting [version : 22] in LinkedHashMap(...) for option --device
[picocli INFO] Putting [locale : zh_CN] in LinkedHashMap(...) for option --device

# oops!
# orientation is mapped to "default --device=model=shamu"
[picocli INFO] Putting [orientation : default --device=model=shamu] in LinkedHashMap(...) for option --device
[picocli INFO] Putting [version : 22] in LinkedHashMap(...) for option --device
[picocli INFO] Putting [locale : zh_CN] in LinkedHashMap(...) for option --device

# orientation is overwritten with value "default"
[picocli INFO] Putting [orientation : default] in LinkedHashMap(...) for option --device

The test is easily fixed by passing two arguments "arg1", "arg2 instead of one "arg1" + arg2":

"--device=model=shamu,version=22,locale=zh_CN,orientation=default ",
        "--device=model=shamu,version=22,locale=zh_CN,orientation=default"

This will result in two Device objects in the list.

@bootstraponline
Copy link
Author

Ah, that makes sense. Thank you for taking the time to debug and explain the issue!

@remkop
Copy link
Owner

remkop commented Dec 1, 2018

You're welcome! Good luck with the flank project!

@remkop remkop changed the title Repeat commands Repeated options Dec 1, 2018
@remkop remkop added the status: invalid 😶 An issue that we don't feel is valid label Dec 1, 2018
@remkop remkop added the theme: parser An issue or change related to the parser label Apr 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid 😶 An issue that we don't feel is valid theme: parser An issue or change related to the parser
Projects
None yet
Development

No branches or pull requests

2 participants