mirror of
https://github.com/git/git
synced 2024-10-02 14:45:21 +00:00
Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.
Signed-off-by: Pierre Habouzit <madcoder@debian.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
fe61935007
commit
21d4783538
|
@ -23,6 +23,13 @@ distinguish between them.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
--parseopt::
|
||||||
|
Use `git-rev-parse` in option parsing mode (see PARSEOPT section below).
|
||||||
|
|
||||||
|
--keep-dash-dash::
|
||||||
|
Only meaningful in `--parseopt` mode. Tells the option parser to echo
|
||||||
|
out the first `--` met instead of skipping it.
|
||||||
|
|
||||||
--revs-only::
|
--revs-only::
|
||||||
Do not output flags and parameters not meant for
|
Do not output flags and parameters not meant for
|
||||||
`git-rev-list` command.
|
`git-rev-list` command.
|
||||||
|
@ -288,10 +295,75 @@ Here are a handful examples:
|
||||||
C^@ I J F
|
C^@ I J F
|
||||||
F^! D G H D F
|
F^! D G H D F
|
||||||
|
|
||||||
|
PARSEOPT
|
||||||
|
--------
|
||||||
|
|
||||||
|
In `--parseopt` mode, `git-rev-parse` helps massaging options to bring to shell
|
||||||
|
scripts the same facilities C builtins have. It works as an option normalizer
|
||||||
|
(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
|
||||||
|
|
||||||
|
It takes on the standard input the specification of the options to parse and
|
||||||
|
understand, and echoes on the standard output a line suitable for `sh(1)` `eval`
|
||||||
|
to replace the arguments with normalized ones. In case of error, it outputs
|
||||||
|
usage on the standard error stream, and exits with code 129.
|
||||||
|
|
||||||
|
Input Format
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
`git-rev-parse --parseopt` input format is fully text based. It has two parts,
|
||||||
|
separated by a line that contains only `--`. The lines before the separator
|
||||||
|
(should be more than one) are used for the usage.
|
||||||
|
The lines after the separator describe the options.
|
||||||
|
|
||||||
|
Each line of options has this format:
|
||||||
|
|
||||||
|
------------
|
||||||
|
<opt_spec><arg_spec>? SP+ help LF
|
||||||
|
------------
|
||||||
|
|
||||||
|
`<opt_spec>`::
|
||||||
|
its format is the short option character, then the long option name
|
||||||
|
separated by a comma. Both parts are not required, though at least one
|
||||||
|
is necessary. `h,help`, `dry-run` and `f` are all three correct
|
||||||
|
`<opt_spec>`.
|
||||||
|
|
||||||
|
`<arg_spec>`::
|
||||||
|
an `<arg_spec>` tells the option parser if the option has an argument
|
||||||
|
(`=`), an optional one (`?` though its use is discouraged) or none
|
||||||
|
(no `<arg_spec>` in that case).
|
||||||
|
|
||||||
|
The remainder of the line, after stripping the spaces, is used
|
||||||
|
as the help associated to the option.
|
||||||
|
|
||||||
|
Blank lines are ignored, and lines that don't match this specification are used
|
||||||
|
as option group headers (start the line with a space to create such
|
||||||
|
lines on purpose).
|
||||||
|
|
||||||
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
------------
|
||||||
|
OPTS_SPEC="\
|
||||||
|
some-command [options] <args>...
|
||||||
|
|
||||||
|
some-command does foo and bar!
|
||||||
|
--
|
||||||
|
h,help show the help
|
||||||
|
|
||||||
|
foo some nifty option --foo
|
||||||
|
bar= some cool option --bar with an argument
|
||||||
|
|
||||||
|
An option group Header
|
||||||
|
C? option C with an optional argument"
|
||||||
|
|
||||||
|
eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org> and
|
Written by Linus Torvalds <torvalds@osdl.org> .
|
||||||
Junio C Hamano <junkio@cox.net>
|
Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
|
||||||
#define DO_REVS 1
|
#define DO_REVS 1
|
||||||
#define DO_NOREV 2
|
#define DO_NOREV 2
|
||||||
|
@ -209,6 +210,128 @@ static int try_difference(const char *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parseopt_dump(const struct option *o, const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct strbuf *parsed = o->value;
|
||||||
|
if (unset)
|
||||||
|
strbuf_addf(parsed, " --no-%s", o->long_name);
|
||||||
|
else if (o->short_name)
|
||||||
|
strbuf_addf(parsed, " -%c", o->short_name);
|
||||||
|
else
|
||||||
|
strbuf_addf(parsed, " --%s", o->long_name);
|
||||||
|
if (arg) {
|
||||||
|
strbuf_addch(parsed, ' ');
|
||||||
|
sq_quote_buf(parsed, arg);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *skipspaces(const char *s)
|
||||||
|
{
|
||||||
|
while (isspace(*s))
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
static int keep_dashdash = 0;
|
||||||
|
static char const * const parseopt_usage[] = {
|
||||||
|
"git-rev-parse --parseopt [options] -- [<args>...]",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static struct option parseopt_opts[] = {
|
||||||
|
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
|
||||||
|
"keep the `--` passed as an arg"),
|
||||||
|
OPT_END(),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct strbuf sb, parsed;
|
||||||
|
const char **usage = NULL;
|
||||||
|
struct option *opts = NULL;
|
||||||
|
int onb = 0, osz = 0, unb = 0, usz = 0;
|
||||||
|
|
||||||
|
strbuf_init(&parsed, 0);
|
||||||
|
strbuf_addstr(&parsed, "set --");
|
||||||
|
argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
|
||||||
|
PARSE_OPT_KEEP_DASHDASH);
|
||||||
|
if (argc < 1 || strcmp(argv[0], "--"))
|
||||||
|
usage_with_options(parseopt_usage, parseopt_opts);
|
||||||
|
|
||||||
|
strbuf_init(&sb, 0);
|
||||||
|
/* get the usage up to the first line with a -- on it */
|
||||||
|
for (;;) {
|
||||||
|
if (strbuf_getline(&sb, stdin, '\n') == EOF)
|
||||||
|
die("premature end of input");
|
||||||
|
ALLOC_GROW(usage, unb + 1, usz);
|
||||||
|
if (!strcmp("--", sb.buf)) {
|
||||||
|
if (unb < 1)
|
||||||
|
die("no usage string given before the `--' separator");
|
||||||
|
usage[unb] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usage[unb++] = strbuf_detach(&sb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */
|
||||||
|
while (strbuf_getline(&sb, stdin, '\n') != EOF) {
|
||||||
|
const char *s;
|
||||||
|
struct option *o;
|
||||||
|
|
||||||
|
if (!sb.len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ALLOC_GROW(opts, onb + 1, osz);
|
||||||
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
||||||
|
|
||||||
|
o = &opts[onb++];
|
||||||
|
s = strchr(sb.buf, ' ');
|
||||||
|
if (!s || *sb.buf == ' ') {
|
||||||
|
o->type = OPTION_GROUP;
|
||||||
|
o->help = xstrdup(skipspaces(s));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
o->type = OPTION_CALLBACK;
|
||||||
|
o->help = xstrdup(skipspaces(s));
|
||||||
|
o->value = &parsed;
|
||||||
|
o->callback = &parseopt_dump;
|
||||||
|
switch (s[-1]) {
|
||||||
|
case '=':
|
||||||
|
s--;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
o->flags = PARSE_OPT_OPTARG;
|
||||||
|
s--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
o->flags = PARSE_OPT_NOARG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s - sb.buf == 1) /* short option only */
|
||||||
|
o->short_name = *sb.buf;
|
||||||
|
else if (sb.buf[1] != ',') /* long option only */
|
||||||
|
o->long_name = xmemdupz(sb.buf, s - sb.buf);
|
||||||
|
else {
|
||||||
|
o->short_name = *sb.buf;
|
||||||
|
o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strbuf_release(&sb);
|
||||||
|
|
||||||
|
/* put an OPT_END() */
|
||||||
|
ALLOC_GROW(opts, onb + 1, osz);
|
||||||
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
||||||
|
argc = parse_options(argc, argv, opts, usage,
|
||||||
|
keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
|
||||||
|
|
||||||
|
strbuf_addf(&parsed, " --");
|
||||||
|
sq_quote_argv(&parsed, argv, argc, 0);
|
||||||
|
puts(parsed.buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i, as_is = 0, verify = 0;
|
int i, as_is = 0, verify = 0;
|
||||||
|
@ -216,6 +339,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
|
|
||||||
|
if (argc > 1 && !strcmp("--parseopt", argv[1]))
|
||||||
|
return cmd_parseopt(argc - 1, argv + 1, prefix);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue