Skip to content
  • René Scharfe's avatar
    parse-options: make CMDMODE errors more precise · 0025dde7
    René Scharfe authored and Junio C Hamano's avatar Junio C Hamano committed
    
    
    Only a single PARSE_OPT_CMDMODE option can be specified for the same
    variable at the same time.  This is enforced by get_value(), but the
    error messages are imprecise in three ways:
    
    1. If a non-PARSE_OPT_CMDMODE option changes the value variable of a
    PARSE_OPT_CMDMODE option then an ominously vague message is shown:
    
       $ t/helper/test-tool parse-options --set23 --mode1
       error: option `mode1' : incompatible with something else
    
    Worse: If the order of options is reversed then no error is reported at
    all:
    
       $ t/helper/test-tool parse-options --mode1 --set23
       boolean: 0
       integer: 23
       magnitude: 0
       timestamp: 0
       string: (not set)
       abbrev: 7
       verbose: -1
       quiet: 0
       dry run: no
       file: (not set)
    
    Fortunately this can currently only happen in the test helper; actual
    Git commands don't share the same variable for the value of options with
    and without the flag PARSE_OPT_CMDMODE.
    
    2. If there are multiple options with the same value (synonyms), then
    the one that is defined first is shown rather than the one actually
    given on the command line, which is confusing:
    
       $ git am --resolved --quit
       error: option `quit' is incompatible with --continue
    
    3. Arguments of PARSE_OPT_CMDMODE options are not handled by the
    parse-option machinery.  This is left to the callback function.  We
    currently only have a single affected option, --show-current-patch of
    git am.  Errors for it can show an argument that was not actually given
    on the command line:
    
       $ git am --show-current-patch --show-current-patch=diff
       error: options '--show-current-patch=diff' and '--show-current-patch=raw' cannot be used together
    
    The options --show-current-patch and --show-current-patch=raw are
    synonyms, but the error accuses the user of input they did not actually
    made.  Or it can awkwardly print a NULL pointer:
    
       $ git am --show-current-patch=diff --show-current-patch
       error: options '--show-current-patch=(null)' and '--show-current-patch=diff' cannot be used together
    
    The reasons for these shortcomings is that the current code checks
    incompatibility only when encountering a PARSE_OPT_CMDMODE option at the
    command line, and that it searches the previous incompatible option by
    value.
    
    Fix the first two points by checking all PARSE_OPT_CMDMODE variables
    after parsing each option and by storing all relevant details if their
    value changed.  Do that whether or not the changing options has the flag
    PARSE_OPT_CMDMODE set.  Report an incompatibility only if two options
    change the variable to different values and at least one of them is a
    PARSE_OPT_CMDMODE option.  This changes the output of the first three
    examples above to:
    
       $ t/helper/test-tool parse-options --set23 --mode1
       error: --mode1 is incompatible with --set23
       $ t/helper/test-tool parse-options --mode1 --set23
       error: --set23 is incompatible with --mode1
       $ git am --resolved --quit
       error: --quit is incompatible with --resolved
    
    Store the argument of PARSE_OPT_CMDMODE options of type OPTION_CALLBACK
    as well to allow taking over the responsibility for compatibility
    checking from the callback function.  The next patch will use this
    capability to fix the messages for git am --show-current-patch.
    
    Use a linked list for storing the PARSE_OPT_CMDMODE variables.  This
    somewhat outdated data structure is simple and suffices, as the number
    of elements per command is currently only zero or one.  We do support
    multiple different command modes variables per command, but I don't
    expect that we'd ever use a significant number of them.  Once we do we
    can switch to a hashmap.
    
    Since we no longer need to search the conflicting option, the all_opts
    parameter of get_value() is no longer used.  Remove it.
    
    Extend the tests to check for both conflicting option names, but don't
    insist on a particular order.
    
    Signed-off-by: default avatarRené Scharfe <l.s.r@web.de>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    0025dde7