From: Pierre Habouzit <madcoder@debian.org>
To: gitster@pobox.com
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, Pierre Habouzit <madcoder@debian.org>
Subject: [PATCH 01/10] Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.
Date: Sun, 4 Nov 2007 11:30:53 +0100 [thread overview]
Message-ID: <1194172262-1563-2-git-send-email-madcoder@debian.org> (raw)
In-Reply-To: <1194172262-1563-1-git-send-email-madcoder@debian.org>
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
Documentation/git-rev-parse.txt | 75 ++++++++++++++++++++++-
builtin-rev-parse.c | 126 +++++++++++++++++++++++++++++++++++++++
2 files changed, 199 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4758c33..6811656 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -23,6 +23,13 @@ distinguish between them.
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::
Do not output flags and parameters not meant for
`git-rev-list` command.
@@ -288,10 +295,74 @@ Here are a handful examples:
C^@ I J 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 ouput a line suitable for `sh(1)` `eval`
+to replace the arguments with normalized ones. In case of error, it ouputs
+usage on the standard error stream, and exits with code 129.
+
+Input Format
+~~~~~~~~~~~~
+
+`git-ref-parse --parseopt` input format is fully text based. It has two parts,
+separated by a line that contains only `--`. The lines before (should be more
+than one) are used for the usage. The lines after 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 optionnal one (`?` though its use is discouraged) or none
+ (no `<arg_spec>` in that case).
+
+The rest of the line after as many spaces up to the ending line feed 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 purposely create such
+lines).
+
+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 optionnal argument"
+
+eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
+------------
+
+
Author
------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Written by Linus Torvalds <torvalds@osdl.org> .
+Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
Documentation
--------------
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 8d78b69..054519b 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -8,6 +8,7 @@
#include "refs.h"
#include "quote.h"
#include "builtin.h"
+#include "parse-options.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -209,6 +210,128 @@ static int try_difference(const char *arg)
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 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);
+ if (argc > 1 && !strcmp("--parseopt", argv[1]))
+ return cmd_parseopt(argc - 1, argv + 1, prefix);
+
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
--
1.5.3.5.1509.g66d41
next prev parent reply other threads:[~2007-11-04 10:31 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-04 10:30 ph/parseopt-sh reloaded Pierre Habouzit
2007-11-04 10:30 ` Pierre Habouzit [this message]
2007-11-04 10:30 ` [PATCH 02/10] Update git-sh-setup(1) to allow transparent use of git-rev-parse --parseopt Pierre Habouzit
2007-11-04 10:30 ` [PATCH 03/10] Migrate git-clean.sh to use " Pierre Habouzit
2007-11-04 10:30 ` [PATCH 04/10] Migrate git-clone " Pierre Habouzit
2007-11-04 10:30 ` [PATCH 05/10] Migrate git-am.sh " Pierre Habouzit
2007-11-04 10:30 ` [PATCH 06/10] Migrate git-merge.sh " Pierre Habouzit
2007-11-04 10:30 ` [PATCH 07/10] Migrate git-instaweb.sh " Pierre Habouzit
2007-11-04 10:31 ` [PATCH 08/10] Migrate git-checkout.sh to use git-rev-parse --parseopt --keep-dashdash Pierre Habouzit
2007-11-04 10:31 ` [PATCH 09/10] Migrate git-quiltimport.sh to use git-rev-parse --parseopt Pierre Habouzit
2007-11-04 10:31 ` [PATCH 10/10] Migrate git-repack.sh " Pierre Habouzit
2007-11-04 14:49 ` [PATCH 04/10] Migrate git-clone " Pierre Habouzit
2007-11-06 19:04 ` Nicolas Pitre
2007-11-06 19:32 ` Junio C Hamano
2007-11-06 19:44 ` Nicolas Pitre
2007-11-06 19:39 ` Junio C Hamano
2007-11-04 11:29 ` [PATCH 01/10] Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts Ralf Wildenhues
2007-11-04 11:31 ` Ralf Wildenhues
2007-11-04 22:58 ` Junio C Hamano
2007-11-04 23:14 ` Pierre Habouzit
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1194172262-1563-2-git-send-email-madcoder@debian.org \
--to=madcoder@debian.org \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).