* [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter)
@ 2007-12-17 18:23 Pierre Habouzit
2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git
Here is a series that aims at fixing the various issues with
parse-options that were raised recently.
* preliminary patch:
[PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset`
* teach git parse-options to allow callbacks to ignore arguments that
don't seem to be theirs, refactors:
[PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use.
[PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well.
[PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments.
* Document this (my previous proposal + Junio's squashed):
[PATCH 5/7] parse-options: Add a gitcli(5) man page.
* Implement my `{}` proposal, a sed -e s/{}/_/ will replace {} with _
as a wildcard. Contains documentation for this placeholder.
[PATCH 6/7] parse-options: have a `use default value` wildcard.
* Somehow unrelated patch, but still parse-option related (resend):
[PATCH 7/7] git-tag: fix -l switch handling regression.
This has been pushed as my ph/parseopt branch on
git://git.madism.org/git.git.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset`
2007-12-17 18:23 [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter) Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit
2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
0 siblings, 2 replies; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
builtin-branch.c | 2 +-
builtin-commit.c | 4 ++--
builtin-fast-export.c | 4 ++--
builtin-for-each-ref.c | 2 +-
builtin-tag.c | 2 +-
parse-options.c | 37 ++++++++++++++++---------------------
parse-options.h | 7 ++++++-
7 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index 089cae5..677eee5 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -531,7 +531,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
die("Branch is renamed, but update of config-file failed");
}
-static int opt_parse_with_commit(const struct option *opt, const char *arg, int unset)
+static int opt_parse_with_commit(const struct option *opt, const char *arg, int flags)
{
unsigned char sha1[20];
struct commit *commit;
diff --git a/builtin-commit.c b/builtin-commit.c
index 0a91013..ca18a5c 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -52,10 +52,10 @@ static int no_edit, initial_commit, in_merge;
const char *only_include_assumed;
struct strbuf message;
-static int opt_parse_m(const struct option *opt, const char *arg, int unset)
+static int opt_parse_m(const struct option *opt, const char *arg, int flags)
{
struct strbuf *buf = opt->value;
- if (unset)
+ if (flags & PARSE_OPT_UNSET)
strbuf_setlen(buf, 0);
else {
strbuf_addstr(buf, arg);
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index ef27eee..9f914b9 100755
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -26,9 +26,9 @@ static int progress;
static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT;
static int parse_opt_signed_tag_mode(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int flags)
{
- if (unset || !strcmp(arg, "abort"))
+ if (flags & PARSE_OPT_UNSET || !strcmp(arg, "abort"))
signed_tag_mode = ABORT;
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
signed_tag_mode = VERBATIM;
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index f36a43c..3eecfe9 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -802,7 +802,7 @@ static struct ref_sort *default_sort(void)
return sort;
}
-int opt_parse_sort(const struct option *opt, const char *arg, int unset)
+int opt_parse_sort(const struct option *opt, const char *arg, int flags)
{
struct ref_sort **sort_tail = opt->value;
struct ref_sort *s;
diff --git a/builtin-tag.c b/builtin-tag.c
index 274901a..fd44b2e 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -348,7 +348,7 @@ struct msg_arg {
struct strbuf buf;
};
-static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
+static int parse_msg_arg(const struct option *opt, const char *arg, int flags)
{
struct msg_arg *msg = opt->value;
diff --git a/parse-options.c b/parse-options.c
index e12b428..8f70e5d 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -1,9 +1,6 @@
#include "git-compat-util.h"
#include "parse-options.h"
-#define OPT_SHORT 1
-#define OPT_UNSET 2
-
struct optparse_t {
const char **argv;
int argc;
@@ -29,9 +26,9 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
static int opterror(const struct option *opt, const char *reason, int flags)
{
- if (flags & OPT_SHORT)
+ if (flags & PARSE_OPT_SHORT)
return error("switch `%c' %s", opt->short_name, reason);
- if (flags & OPT_UNSET)
+ if (flags & PARSE_OPT_UNSET)
return error("option `no-%s' %s", opt->long_name, reason);
return error("option `%s' %s", opt->long_name, reason);
}
@@ -40,14 +37,14 @@ static int get_value(struct optparse_t *p,
const struct option *opt, int flags)
{
const char *s, *arg;
- const int unset = flags & OPT_UNSET;
+ const int unset = flags & PARSE_OPT_UNSET;
if (unset && p->opt)
return opterror(opt, "takes no value", flags);
if (unset && (opt->flags & PARSE_OPT_NONEG))
return opterror(opt, "isn't available", flags);
- if (!(flags & OPT_SHORT) && p->opt) {
+ if (!(flags & PARSE_OPT_SHORT) && p->opt) {
switch (opt->type) {
case OPTION_CALLBACK:
if (!(opt->flags & PARSE_OPT_NOARG))
@@ -99,15 +96,13 @@ static int get_value(struct optparse_t *p,
return 0;
case OPTION_CALLBACK:
- if (unset)
- return (*opt->callback)(opt, NULL, 1);
- if (opt->flags & PARSE_OPT_NOARG)
- return (*opt->callback)(opt, NULL, 0);
+ if (unset || (opt->flags & PARSE_OPT_NOARG))
+ return (*opt->callback)(opt, NULL, flags);
if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
- return (*opt->callback)(opt, NULL, 0);
+ return (*opt->callback)(opt, NULL, flags);
if (!arg)
return opterror(opt, "requires a value", flags);
- return (*opt->callback)(opt, get_arg(p), 0);
+ return (*opt->callback)(opt, get_arg(p), flags);
case OPTION_INTEGER:
if (unset) {
@@ -135,7 +130,7 @@ static int parse_short_opt(struct optparse_t *p, const struct option *options)
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
- return get_value(p, options, OPT_SHORT);
+ return get_value(p, options, PARSE_OPT_SHORT);
}
}
return error("unknown switch `%c'", *p->opt);
@@ -173,7 +168,7 @@ is_abbreviated:
ambiguous_option = abbrev_option;
ambiguous_flags = abbrev_flags;
}
- if (!(flags & OPT_UNSET) && *arg_end)
+ if (!(flags & PARSE_OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
abbrev_flags = flags;
@@ -181,13 +176,13 @@ is_abbreviated:
}
/* negated and abbreviated very much? */
if (!prefixcmp("no-", arg)) {
- flags |= OPT_UNSET;
+ flags |= PARSE_OPT_UNSET;
goto is_abbreviated;
}
/* negated? */
if (strncmp(arg, "no-", 3))
continue;
- flags |= OPT_UNSET;
+ flags |= PARSE_OPT_UNSET;
rest = skip_prefix(arg + 3, options->long_name);
/* abbreviated and negated? */
if (!rest && !prefixcmp(options->long_name, arg + 3))
@@ -207,9 +202,9 @@ is_abbreviated:
return error("Ambiguous option: %s "
"(could be --%s%s or --%s%s)",
arg,
- (ambiguous_flags & OPT_UNSET) ? "no-" : "",
+ (ambiguous_flags & PARSE_OPT_UNSET) ? "no-" : "",
ambiguous_option->long_name,
- (abbrev_flags & OPT_UNSET) ? "no-" : "",
+ (abbrev_flags & PARSE_OPT_UNSET) ? "no-" : "",
abbrev_option->long_name);
if (abbrev_option)
return get_value(p, abbrev_option, abbrev_flags);
@@ -351,12 +346,12 @@ void usage_with_options(const char * const *usagestr,
/*----- some often used options -----*/
#include "cache.h"
-int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
+int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int flags)
{
int v;
if (!arg) {
- v = unset ? 0 : DEFAULT_ABBREV;
+ v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV;
} else {
v = strtol(arg, (char **)&arg, 10);
if (*arg)
diff --git a/parse-options.h b/parse-options.h
index 102ac31..ae6b3ca 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -27,8 +27,13 @@ enum parse_opt_option_flags {
PARSE_OPT_HIDDEN = 8,
};
+enum parse_opt_cbflags {
+ PARSE_OPT_SHORT = 1,
+ PARSE_OPT_UNSET = 2,
+};
+
struct option;
-typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+typedef int parse_opt_cb(const struct option *, const char *arg, int flags);
/*
* `type`::
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use.
2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit
2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
1 sibling, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
parse-options.c | 22 +++++++++++++++-------
parse-options.h | 7 +++++++
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/parse-options.c b/parse-options.c
index 8f70e5d..d716ccc 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -38,7 +38,10 @@ static int get_value(struct optparse_t *p,
{
const char *s, *arg;
const int unset = flags & PARSE_OPT_UNSET;
+ int may_ign = 0, res;
+ if (!unset && !p->opt && (opt->flags & PARSE_OPT_OPTARG))
+ may_ign = PARSE_OPT_MAY_IGN;
if (unset && p->opt)
return opterror(opt, "takes no value", flags);
if (unset && (opt->flags & PARSE_OPT_NONEG))
@@ -86,7 +89,7 @@ static int get_value(struct optparse_t *p,
*(const char **)opt->value = NULL;
return 0;
}
- if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
+ if (may_ign && (!arg || *arg == '-')) {
*(const char **)opt->value = (const char *)opt->defval;
return 0;
}
@@ -98,18 +101,23 @@ static int get_value(struct optparse_t *p,
case OPTION_CALLBACK:
if (unset || (opt->flags & PARSE_OPT_NOARG))
return (*opt->callback)(opt, NULL, flags);
- if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
- return (*opt->callback)(opt, NULL, flags);
- if (!arg)
+ if (!may_ign && !arg)
return opterror(opt, "requires a value", flags);
- return (*opt->callback)(opt, get_arg(p), flags);
+ if (may_ign && arg && arg[0] == '-' && arg[1])
+ return (*opt->callback)(opt, NULL, flags);
+ res = (*opt->callback)(opt, arg, flags);
+ if (!may_ign && res == PARSE_OPT_IGNORE)
+ die("should not happen: MAY_IGN unset, but arg was IGNOREd");
+ if (res == PARSE_OPT_IGNORE)
+ get_arg(p);
+ return res;
case OPTION_INTEGER:
if (unset) {
*(int *)opt->value = 0;
return 0;
}
- if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
+ if (may_ign && (!arg || !isdigit(*arg))) {
*(int *)opt->value = opt->defval;
return 0;
}
@@ -251,7 +259,7 @@ int parse_options(int argc, const char **argv, const struct option *options,
usage_with_options_internal(usagestr, options, 1);
if (!strcmp(arg + 2, "help"))
usage_with_options(usagestr, options);
- if (parse_long_opt(&args, arg + 2, options))
+ if (parse_long_opt(&args, arg + 2, options) < 0)
usage_with_options(usagestr, options);
}
diff --git a/parse-options.h b/parse-options.h
index ae6b3ca..eeb40a4 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -27,9 +27,16 @@ enum parse_opt_option_flags {
PARSE_OPT_HIDDEN = 8,
};
+enum parse_opt_cbres {
+ PARSE_OPT_ERR = -1,
+ PARSE_OPT_OK = 0,
+ PARSE_OPT_IGNORE = 1,
+};
+
enum parse_opt_cbflags {
PARSE_OPT_SHORT = 1,
PARSE_OPT_UNSET = 2,
+ PARSE_OPT_MAY_IGN = 4,
};
struct option;
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well.
2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
parse-options.c | 115 ++++++++++++++++++++++++++++---------------------------
1 files changed, 59 insertions(+), 56 deletions(-)
diff --git a/parse-options.c b/parse-options.c
index d716ccc..f3f0f2a 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -7,15 +7,14 @@ struct optparse_t {
const char *opt;
};
-static inline const char *get_arg(struct optparse_t *p)
+static inline void use_arg(struct optparse_t *p)
{
if (p->opt) {
- const char *res = p->opt;
p->opt = NULL;
- return res;
+ } else {
+ p->argc--;
+ ++p->argv;
}
- p->argc--;
- return *++p->argv;
}
static inline const char *skip_prefix(const char *str, const char *prefix)
@@ -33,15 +32,62 @@ static int opterror(const struct option *opt, const char *reason, int flags)
return error("option `%s' %s", opt->long_name, reason);
}
+static int parse_opt_string(const struct option *opt,
+ const char *arg, int flags)
+{
+ *(const char **)opt->value = flags & PARSE_OPT_UNSET ? NULL : arg;
+ return 0;
+}
+
+static int parse_opt_integer(const struct option *opt,
+ const char *arg, int flags)
+{
+ int v = flags & PARSE_OPT_UNSET ? 0 : opt->defval;
+ if (arg) {
+ v = strtol(arg, (char **)&arg, 10);
+ if (*arg) {
+ if (flags & PARSE_OPT_MAY_IGN) {
+ *(int *)opt->value = opt->defval;
+ return PARSE_OPT_IGNORE;
+ }
+ return opterror(opt, "expects a numerical value", 0);
+ }
+ }
+ *(int *)opt->value = v;
+ return 0;
+}
+
+static int run_callback(struct optparse_t *p, parse_opt_cb *cb,
+ const struct option *opt, int flags)
+{
+ const char *arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
+ int may_ign = 0;
+
+ if (!p->opt && (opt->flags & PARSE_OPT_OPTARG))
+ may_ign = PARSE_OPT_MAY_IGN;
+ if ((flags & PARSE_OPT_UNSET) || (opt->flags & PARSE_OPT_NOARG))
+ return (*cb)(opt, NULL, flags);
+ if (!may_ign && !arg)
+ return opterror(opt, "requires a value", flags);
+ if (may_ign && arg && arg[0] == '-' && arg[1])
+ return (*cb)(opt, NULL, flags);
+ switch ((*cb)(opt, arg, flags | may_ign)) {
+ case PARSE_OPT_OK:
+ use_arg(p);
+ return PARSE_OPT_OK;
+ case PARSE_OPT_IGNORE:
+ if (!may_ign)
+ die("should not happen: MAY_IGN unset, but arg was IGNOREd");
+ return PARSE_OPT_IGNORE;
+ default:
+ return PARSE_OPT_ERR;
+ }
+}
+
static int get_value(struct optparse_t *p,
const struct option *opt, int flags)
{
- const char *s, *arg;
const int unset = flags & PARSE_OPT_UNSET;
- int may_ign = 0, res;
-
- if (!unset && !p->opt && (opt->flags & PARSE_OPT_OPTARG))
- may_ign = PARSE_OPT_MAY_IGN;
if (unset && p->opt)
return opterror(opt, "takes no value", flags);
if (unset && (opt->flags & PARSE_OPT_NONEG))
@@ -63,7 +109,6 @@ static int get_value(struct optparse_t *p,
}
}
- arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
switch (opt->type) {
case OPTION_BIT:
if (unset)
@@ -71,63 +116,21 @@ static int get_value(struct optparse_t *p,
else
*(int *)opt->value |= opt->defval;
return 0;
-
case OPTION_BOOLEAN:
*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
return 0;
-
case OPTION_SET_INT:
*(int *)opt->value = unset ? 0 : opt->defval;
return 0;
-
case OPTION_SET_PTR:
*(void **)opt->value = unset ? NULL : (void *)opt->defval;
return 0;
-
case OPTION_STRING:
- if (unset) {
- *(const char **)opt->value = NULL;
- return 0;
- }
- if (may_ign && (!arg || *arg == '-')) {
- *(const char **)opt->value = (const char *)opt->defval;
- return 0;
- }
- if (!arg)
- return opterror(opt, "requires a value", flags);
- *(const char **)opt->value = get_arg(p);
- return 0;
-
+ return run_callback(p, &parse_opt_string, opt, flags);
case OPTION_CALLBACK:
- if (unset || (opt->flags & PARSE_OPT_NOARG))
- return (*opt->callback)(opt, NULL, flags);
- if (!may_ign && !arg)
- return opterror(opt, "requires a value", flags);
- if (may_ign && arg && arg[0] == '-' && arg[1])
- return (*opt->callback)(opt, NULL, flags);
- res = (*opt->callback)(opt, arg, flags);
- if (!may_ign && res == PARSE_OPT_IGNORE)
- die("should not happen: MAY_IGN unset, but arg was IGNOREd");
- if (res == PARSE_OPT_IGNORE)
- get_arg(p);
- return res;
-
+ return run_callback(p, opt->callback, opt, flags);
case OPTION_INTEGER:
- if (unset) {
- *(int *)opt->value = 0;
- return 0;
- }
- if (may_ign && (!arg || !isdigit(*arg))) {
- *(int *)opt->value = opt->defval;
- return 0;
- }
- if (!arg)
- return opterror(opt, "requires a value", flags);
- *(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
- if (*s)
- return opterror(opt, "expects a numerical value", flags);
- return 0;
-
+ return run_callback(p, &parse_opt_integer, opt, flags);
default:
die("should not happen, someone must be hit on the forehead");
}
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments.
2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
parse-options.c | 16 +++++++++-------
1 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/parse-options.c b/parse-options.c
index f3f0f2a..679a963 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -359,19 +359,21 @@ void usage_with_options(const char * const *usagestr,
int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int flags)
{
- int v;
-
- if (!arg) {
- v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV;
- } else {
+ int v = flags & PARSE_OPT_UNSET ? 0 : DEFAULT_ABBREV;
+ if (arg) {
v = strtol(arg, (char **)&arg, 10);
- if (*arg)
+ if (*arg) {
+ if (flags & PARSE_OPT_MAY_IGN) {
+ *(int *)opt->value = DEFAULT_ABBREV;
+ return PARSE_OPT_IGNORE;
+ }
return opterror(opt, "expects a numerical value", 0);
+ }
if (v && v < MINIMUM_ABBREV)
v = MINIMUM_ABBREV;
else if (v > 40)
v = 40;
}
- *(int *)(opt->value) = v;
+ *(int *)opt->value = v;
return 0;
}
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/7] parse-options: Add a gitcli(5) man page.
2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit
2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison
0 siblings, 2 replies; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
This page should hold every information about the git ways to parse command
lines, and best practices to be used for scripting.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
Documentation/Makefile | 2 +-
Documentation/gitcli.txt | 113 ++++++++++++++++++++++++++++++++++++++++++++++
Makefile | 1 +
3 files changed, 115 insertions(+), 1 deletions(-)
create mode 100644 Documentation/gitcli.txt
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 76df06c..c4486d3 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -2,7 +2,7 @@ MAN1_TXT= \
$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
$(wildcard git-*.txt)) \
gitk.txt
-MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt
+MAN5_TXT=gitattributes.txt gitignore.txt gitcli.txt gitmodules.txt
MAN7_TXT=git.txt
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
new file mode 100644
index 0000000..b7dcf9c
--- /dev/null
+++ b/Documentation/gitcli.txt
@@ -0,0 +1,113 @@
+gitcli(5)
+=========
+
+NAME
+----
+gitcli - git command line interface and conventions
+
+SYNOPSIS
+--------
+gitcli
+
+
+DESCRIPTION
+-----------
+
+This manual describes best practice in how to use git CLI. Here are
+the rules that you should follow when you are scripting git:
+
+ * it's preferred to use the non dashed form of git commands, which means that
+ you should prefer `"git foo"` to `"git-foo"`.
+
+ * splitting short options to separate words (prefer `"git foo -a -b"`
+ to `"git foo -ab"`, the latter may not even work).
+
+ * when a command line option takes an argument, use the 'sticked' form. In
+ other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short
+ options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"`
+ for long options. An option that takes optional option-argument must be
+ written in the 'sticked' form.
+
+ * when you give a revision parameter to a command, make sure the parameter is
+ not ambiguous with a name of a file in the work tree. E.g. do not write
+ `"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work
+ if you happen to have a file called `HEAD` in the work tree.
+
+
+ENHANCED CLI
+------------
+From the git 1.5.4 series and further, many git commands (not all of them at the
+time of the writing though) come with an enhanced option parser.
+
+Here is an exhaustive list of the facilities provided by this option parser.
+
+
+Magic Options
+~~~~~~~~~~~~~
+Commands which have the enhanced option parser activated all understand a
+couple of magic command line options:
+
+-h::
+ gives a pretty printed usage of the command.
++
+---------------------------------------------
+$ git describe -h
+usage: git-describe [options] <committish>*
+
+ --contains find the tag that comes after the commit
+ --debug debug search strategy on stderr
+ --all use any ref in .git/refs
+ --tags use any tag in .git/refs/tags
+ --abbrev [<n>] use <n> digits to display SHA-1s
+ --candidates <n> consider <n> most recent tags (default: 10)
+---------------------------------------------
+
+--help-all::
+ Some git commands take options that are only used for plumbing or that
+ are deprecated, and such options are hidden from the default usage. This
+ option gives the full list of options.
+
+
+Negating options
+~~~~~~~~~~~~~~~~
+Options with long option names can be negated by prefixing `"--no-"`. For
+example, `"git branch"` has the option `"--track"` which is 'on' by default. You
+can use `"--no-track"` to override that behaviour. The same goes for `"--color"`
+and `"--no-color"`.
+
+
+Aggregating short options
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Commands that support the enhanced option parser allow you to aggregate short
+options. This means that you can for example use `"git rm -rf"` or
+`"git clean -fdx"`.
+
+
+Separating argument from the option
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can write the mandatory option parameter to an option as a separate
+word on the command line. That means that all the following uses work:
+
+----------------------------
+$ git foo --long-opt=Arg
+$ git foo --long-opt Arg
+$ git foo -oArg
+$ git foo -o Arg
+----------------------------
+
+However, this is *NOT* allowed for switches with an optionnal value, where the
+'sticked' form must be used:
+----------------------------
+$ git describe --abbrev HEAD # correct
+$ git describe --abbrev=10 HEAD # correct
+$ git describe --abbrev 10 HEAD # NOT WHAT YOU MEANT
+----------------------------
+
+
+Documentation
+-------------
+Documentation by Pierre Habouzit.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Makefile b/Makefile
index 7776077..eda7b1a 100644
--- a/Makefile
+++ b/Makefile
@@ -1172,6 +1172,7 @@ check-docs::
documented,gitattributes | \
documented,gitignore | \
documented,gitmodules | \
+ documented,gitcli | \
documented,git-tools | \
sentinel,not,matching,is,ok ) continue ;; \
esac; \
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/7] parse-options: have a `use default value` wildcard.
2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit
2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison
1 sibling, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
Documentation/gitcli.txt | 20 +++++++++++++++-----
parse-options.c | 10 ++++++++--
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index b7dcf9c..a304072 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -95,14 +95,24 @@ $ git foo -oArg
$ git foo -o Arg
----------------------------
-However, this is *NOT* allowed for switches with an optionnal value, where the
-'sticked' form must be used:
+However, this may become ambiguous for switches with an optional value. The
+enhanced option parser provides a placeholder `{}` that tells to the option
+parser that it should not try to find an argument to this switch. Though if
+you use '{}' sticked to the option, `{}` is passed as the value.
----------------------------
-$ git describe --abbrev HEAD # correct
-$ git describe --abbrev=10 HEAD # correct
-$ git describe --abbrev 10 HEAD # NOT WHAT YOU MEANT
+# all the following uses work
+$ git describe --abbrev HEAD
+$ git describe --abbrev {} HEAD
+$ git describe --abbrev=10 HEAD
+$ git describe --abbrev 10 HEAD
+
+# doesn't work
+$ git describe --abbrev={} HEAD
----------------------------
+Note that an optional switch will never try to use the next token as an
+argument if it starts with a dash and is not `-`.
+
Documentation
-------------
diff --git a/parse-options.c b/parse-options.c
index 679a963..8734bb1 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -69,8 +69,14 @@ static int run_callback(struct optparse_t *p, parse_opt_cb *cb,
return (*cb)(opt, NULL, flags);
if (!may_ign && !arg)
return opterror(opt, "requires a value", flags);
- if (may_ign && arg && arg[0] == '-' && arg[1])
- return (*cb)(opt, NULL, flags);
+ if (may_ign && arg) {
+ if (arg[0] == '-' && arg[1])
+ return (*cb)(opt, NULL, flags);
+ if (!strcmp(arg, "{}")) {
+ use_arg(p);
+ return (*cb)(opt, NULL, flags);
+ }
+ }
switch ((*cb)(opt, arg, flags | may_ign)) {
case PARSE_OPT_OK:
use_arg(p);
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/7] git-tag: fix -l switch handling regression.
2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit
@ 2007-12-17 18:23 ` Pierre Habouzit
2007-12-17 18:56 ` Pierre Habouzit
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:23 UTC (permalink / raw)
To: gitster; +Cc: git, Pierre Habouzit
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
builtin-tag.c | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/builtin-tag.c b/builtin-tag.c
index fd44b2e..c7a1563 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -16,7 +16,7 @@
static const char * const git_tag_usage[] = {
"git-tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
"git-tag -d <tagname>...",
- "git-tag [-n [<num>]] -l [<pattern>]",
+ "git-tag -l [-n [<num>]] [<pattern>]",
"git-tag -v <tagname>...",
NULL
};
@@ -370,13 +370,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct ref_lock *lock;
int annotate = 0, sign = 0, force = 0, lines = 0,
- delete = 0, verify = 0;
- char *list = NULL, *msgfile = NULL, *keyid = NULL;
- const char *no_pattern = "NO_PATTERN";
+ list = 0, delete = 0, verify = 0;
+ char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct option options[] = {
- { OPTION_STRING, 'l', NULL, &list, "pattern", "list tag names",
- PARSE_OPT_OPTARG, NULL, (intptr_t) no_pattern },
+ OPT_INTEGER('l', NULL, &list, "list tag names"),
{ OPTION_INTEGER, 'n', NULL, &lines, NULL,
"print n lines of each tag message",
PARSE_OPT_OPTARG, NULL, 1 },
@@ -408,7 +406,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
annotate = 1;
if (list)
- return list_tags(list == no_pattern ? NULL : list, lines);
+ return list_tags(argv[0], lines);
if (delete)
return for_each_tag_name(argv, delete_tag);
if (verify)
--
1.5.4.rc0.1148.ga3ab1-dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset`
2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit
@ 2007-12-17 18:54 ` Pierre Habouzit
1 sibling, 0 replies; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:54 UTC (permalink / raw)
To: gitster; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 774 bytes --]
And of course here is the MadBug #1, to be squashed:
---
builtin-rev-parse.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 20d1789..3e8ee62 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -210,10 +210,10 @@ static int try_difference(const char *arg)
return 0;
}
-static int parseopt_dump(const struct option *o, const char *arg, int unset)
+static int parseopt_dump(const struct option *o, const char *arg, int flags)
{
struct strbuf *parsed = o->value;
- if (unset)
+ if (flags & PARSE_OPT_UNSET)
strbuf_addf(parsed, " --no-%s", o->long_name);
else if (o->short_name)
strbuf_addf(parsed, " -%c", o->short_name);
--
1.5.4.rc0.1151.g102b0
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression.
2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit
@ 2007-12-17 18:56 ` Pierre Habouzit
2007-12-17 19:03 ` Pierre Habouzit
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 18:56 UTC (permalink / raw)
To: gitster; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 530 bytes --]
And I managed to resend the broken version, hurray myself.
> + OPT_INTEGER('l', NULL, &list, "list tag names"),
OPT_BOOLEAN
Both these last minute fixes are applied to my public git.git.
Let's now write 1000 times: I will run the test-suite before I send
patches, I will rune the test-suite before I send patches, …
--
·O· Pierre Habouzit
··O madcoder@debian.org
OOO http://www.madism.org
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression.
2007-12-17 18:56 ` Pierre Habouzit
@ 2007-12-17 19:03 ` Pierre Habouzit
2007-12-17 20:13 ` Junio C Hamano
0 siblings, 1 reply; 13+ messages in thread
From: Pierre Habouzit @ 2007-12-17 19:03 UTC (permalink / raw)
To: gitster, git
[-- Attachment #1: Type: text/plain, Size: 918 bytes --]
On Mon, Dec 17, 2007 at 06:56:52PM +0000, Pierre Habouzit wrote:
> And I managed to resend the broken version, hurray myself.
>
> > + OPT_INTEGER('l', NULL, &list, "list tag names"),
> OPT_BOOLEAN
>
>
>
> Both these last minute fixes are applied to my public git.git.
>
> Let's now write 1000 times: I will run the test-suite before I send
> patches, I will rune the test-suite before I send patches, …
oh and t7004 doesn't pass anymore because of the:
git -n xxx -l or git -n "" -l tests. If we really want to allow that
(but it _REALLY_ feels wrong to me) we have to make '-l' a callback that
groks non integers as 0. Else the test also has to be fixed, I'm not
sure what to do here.
--
·O· Pierre Habouzit
··O madcoder@debian.org
OOO http://www.madism.org
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] git-tag: fix -l switch handling regression.
2007-12-17 19:03 ` Pierre Habouzit
@ 2007-12-17 20:13 ` Junio C Hamano
0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2007-12-17 20:13 UTC (permalink / raw)
To: Pierre Habouzit; +Cc: git
Pierre Habouzit <madcoder@debian.org> writes:
> On Mon, Dec 17, 2007 at 06:56:52PM +0000, Pierre Habouzit wrote:
>> And I managed to resend the broken version, hurray myself.
>>
>> > + OPT_INTEGER('l', NULL, &list, "list tag names"),
>> OPT_BOOLEAN
>>
>>
>>
>> Both these last minute fixes are applied to my public git.git.
>>
>> Let's now write 1000 times: I will run the test-suite before I send
>> patches, I will rune the test-suite before I send patches, …
>
> oh and t7004 doesn't pass anymore because of the:
>
> git -n xxx -l or git -n "" -l tests. If we really want to allow that
> (but it _REALLY_ feels wrong to me) we have to make '-l' a callback that
> groks non integers as 0. Else the test also has to be fixed, I'm not
> sure what to do here.
I did not understand what "git tag -n xxx" was meant to do, either.
Time to run blame and ask the responsible party?
I suspect "-n ''" there might be meant as a way to spell the "no
argument here -- use our default" instruction. It looks slightly nicer
than that '{}' but not quite.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/7] parse-options: Add a gitcli(5) man page.
2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit
2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit
@ 2007-12-18 2:00 ` Wayne Davison
1 sibling, 0 replies; 13+ messages in thread
From: Wayne Davison @ 2007-12-18 2:00 UTC (permalink / raw)
To: Pierre Habouzit; +Cc: git
On Mon, Dec 17, 2007 at 07:23:15PM +0100, Pierre Habouzit wrote:
> + * when a command line option takes an argument, use the 'sticked' form.
A minor issue: the word "sticked" reads very strangely to me (in this
spot and several others in your text). I think something like joined or
attached (or even abutted) would be better, as seen in this altered text
for the spot cited above (with a few other improvements thrown in):
* when a command line option takes an argument, it is best to use the
'joined' form. In other words, write `"git foo -oArg"` instead of
`"git foo -o Arg"` for short options, and `"git foo --long-opt=Arg"`
instead of `"git foo --long-opt Arg"` for long options. If an option
takes an optional option-argument, it MUST be written using the
'joined' form when providing the option-argument.
..wayne..
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2007-12-18 2:01 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-17 18:23 [proposal] make parse-options nicer wrt optional arguments (supersedes all my recent posts on the matter) Pierre Habouzit
2007-12-17 18:23 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
2007-12-17 18:23 ` [PATCH 2/7] parse-options: allow callbacks to ignore arguments they don't need to use Pierre Habouzit
2007-12-17 18:23 ` [PATCH 3/7] parse-options: Let the integer/string cases be callbacks as well Pierre Habouzit
2007-12-17 18:23 ` [PATCH 4/7] parse-options: let OPT__ABBREV ignore arguments Pierre Habouzit
2007-12-17 18:23 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Pierre Habouzit
2007-12-17 18:23 ` [PATCH 6/7] parse-options: have a `use default value` wildcard Pierre Habouzit
2007-12-17 18:23 ` [PATCH 7/7] git-tag: fix -l switch handling regression Pierre Habouzit
2007-12-17 18:56 ` Pierre Habouzit
2007-12-17 19:03 ` Pierre Habouzit
2007-12-17 20:13 ` Junio C Hamano
2007-12-18 2:00 ` [PATCH 5/7] parse-options: Add a gitcli(5) man page Wayne Davison
2007-12-17 18:54 ` [PATCH 1/7] parse-options: Make callbacks take flags instead of boolean `unset` Pierre Habouzit
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).