Skip Menu |

This queue is for tickets about the Getopt-Long CPAN distribution.

Report information
The Basics
Id: 102276
Status: resolved
Priority: 0/
Queue: Getopt-Long

People
Owner: jv [...] cpan.org
Requestors: wsnyder [...] wsnyder.org
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in:
  • 2.43
  • 2.44
Fixed in: 2.45



Subject: More pass_through and <> woes
Hello, I have many programs and packages that use Getopt::Long, thanks for working on it. I have started getting user reports of these packages breaking due to the pass_through with <> change made in or around Getopt::Long version 2.43. For now, I have told users to revert to the old version, but obviously that is temporary until users can upgrade to a version of my scripts that "do the right thing". 1. The first problem is "Option spec <> cannot be used with pass_through." was an error. I see that this was just made a warning in 2.44, so thanks for that. 2. The second problem is even with the warning the behavior has changed so the old scripts still do not work with 2.44. The older version would pass the arguments to the <> callback function, while the newer version does not call the <> callback. For the example print "$ver ARGV in: ",join(' ',@ARGV),"\n"; if ($ver eq 'pb') { Getopt::Long::config ("pass_through"); if (! GetOptions ( "<>" => sub { print "$ver got <> callback: $_[0]\n"; }, )) { } print "$ver ARGV out: ",join(' ',@ARGV),"\n"; Here's an example difference (left is 2.38 right is 2.44 output): VERSION 2.38 | VERSION 2.44 ARGV in: -I yy | ARGV in: -I yy | Option spec <> cannot be used with pass_through. FIX IT! got <> callback: -I | got <> callback: yy | ARGV out: | | ARGV out: -I yy Could you please add a test to your suite to insure to match the old behavior after printing the warning? 3. The final problem is I don't see how pass_through and <> are mutually exclusive (I did read https://rt.cpan.org/Public/Bug/Display.html?id=92462 but unless I am misreading that could have been solved by documentation). It seems reasonable to want to get "all unknown" arguments and also have my parameter callback. Specifically consider this example print "$ver ARGV in: ",join(' ',@ARGV),"\n"; if ($ver eq 'pb') { Getopt::Long::config ("pass_through"); if (! GetOptions ( "boo" => sub { print "$ver got boo callback\n"; }, "<>" => sub { print "$ver got <> callback: $_[0]\n"; }, )) { } print "$ver ARGV out: ",join(' ',@ARGV),"\n"; Here's an example difference (left is 2.38 right is 2.44 output): ARGV in: --unr --boo -I xx | ARGV in: --unr --boo -I xx | Option spec <> cannot be used with pass_through. FIX IT! got <> callback: --unr | got boo callback | got boo callback got <> callback: -I | got <> callback: xx | ARGV out: | | ARGV out: --unr -I xx Note with both <> and pass_through the program could determine the ordering between the unknown parameters (e.g. --unr) and the recognized parameters (e.g. --boo). How do I maintain ordering between known and unknown arguments without both pass_through and <>? Obviously using only pass_through, or only <> will not work - the former looses ordering, the later will cause unknown option errors. I would like something that will work with at least 2.38 forward, ideally also working with 2.43. Thanks!
1. Ok. 2. Done. Please apply the following change (line 726): if ( !$passthrough && (defined ($cb = $linkage{'<>'})) ) { into if ( defined ($cb = $linkage{'<>'}) ) { 3. I see your point. Can you provide updated documentation on <> and pass_through so I can revert to the 2.42 behaviour?
Excellent thanks for the good support and quick reply too. Attached is a patch including your change, two tests, and docs.
Subject: getopt-pass-through.patch
diff --git a/lib/Getopt/Long.pm b/lib/Getopt/Long.pm index 8a99db9..4b9989e 100644 --- a/lib/Getopt/Long.pm +++ b/lib/Getopt/Long.pm @@ -373,11 +373,6 @@ sub GetOptionsFromArray(@) { next; } $linkage{'<>'} = shift (@optionlist); - if ( $passthrough ) { - # Too harsh... for now. - # $error .= "Option spec <> cannot be used with pass_through\n"; - warn("Option spec <> cannot be used with pass_through. FIX IT!\n"); - } next; } @@ -723,7 +718,7 @@ sub GetOptionsFromArray(@) { elsif ( $order == $PERMUTE ) { # Try non-options call-back. my $cb; - if ( !$passthrough && (defined ($cb = $linkage{'<>'})) ) { + if ( defined ($cb = $linkage{'<>'}) ) { print STDERR ("=> &L{$tryopt}(\"$tryopt\")\n") if $debug; my $eval_error = do { @@ -2451,22 +2446,22 @@ C<require> statement. =item pass_through (default: disabled) -Anything that is unknown, ambiguous or supplied with an invalid option -value is passed through in C<@ARGV> instead of being flagged as -errors. This makes it possible to write wrapper scripts that process -only part of the user supplied command line arguments, and pass the +With C<pass_through> anything that is unknown, ambiguous or supplied with +an invalid option will not be flagged as an error. Instead the unknown +option(s) will be passed to the catchall C<< <> >> if present, otherwise +through to C<@ARGV>. This makes it possible to write wrapper scripts that +process only part of the user supplied command line arguments, and pass the remaining options to some other program. -If C<require_order> is enabled, options processing will terminate at -the first unrecognized option, or non-option, whichever comes first. -However, if C<permute> is enabled instead, results can become confusing. +If C<require_order> is enabled, options processing will terminate at the +first unrecognized option, or non-option, whichever comes first and all +remaining arguments are passed to C<@ARGV> instead of the catchall +C<< <> >> if present. However, if C<permute> is enabled instead, results +can become confusing. Note that the options terminator (default C<-->), if present, will also be passed through in C<@ARGV>. -For obvious reasons, B<pass_through> cannot be used with the -non-option catchall C<< <> >>. - =item prefix The string that starts options. If a constant string is not diff --git a/t/gol-linkage.t b/t/gol-linkage.t index df975c8..d4b526b 100644 --- a/t/gol-linkage.t +++ b/t/gol-linkage.t @@ -11,7 +11,7 @@ BEGIN { use Getopt::Long; -print "1..33\n"; +print "1..37\n"; @ARGV = qw(-Foo -baR --foo bar); Getopt::Long::Configure ("no_ignore_case"); @@ -91,3 +91,31 @@ print (!(exists $lnk{bar}) ? "" : "not ", "ok 28\n"); package Overload::Test; use overload '""' => sub{ die "Bad mojo!" }; } + +{ + @ARGV = (qw[-thru -here -more 1]); + my $got = ""; + Getopt::Long::Configure("default"); + Getopt::Long::Configure("pass_through"); + print "not" unless GetOptions + ("here" => sub { $got .= " sub_here"; }, + "<>" => sub { $got .= " <>=".$_[0]; }, ); + $got .= " remain=".join(',',@ARGV); + print "ok 34\n"; + print +(($got eq " <>=-thru sub_here <>=-more <>=1 remain=") + ? "" : "not ", "ok 35\n"); +} + +{ + @ARGV = (qw[-thru -here -more -- 1]); + my $got = ""; + Getopt::Long::Configure("default"); + Getopt::Long::Configure("pass_through","require_order"); + print "not" unless GetOptions + ("here" => sub { $got .= " sub_here"; }, + "<>" => sub { $got .= " <>=".$_[0]; }, ); + $got .= " remain=".join(',',@ARGV); + print "ok 36\n"; + print +(($got eq " remain=-thru,-here,-more,--,1") + ? "" : "not ", "ok 37\n"); +}
On Sun Feb 22 10:21:16 2015, WSNYDER wrote: Show quoted text
> Excellent thanks for the good support and quick reply too. Attached is > a patch including your change, two tests, and docs.
Could this patch please be patched to a new version so I can close the downstream issues? Or, if there's anything I should change with the patch just let me know. Thanks!