As a porcelain author I'm finding it difficult to keep track of what features I can use in git-gui. Newer versions of Git have newer capabilities but they don't always immediately get newer version numbers that I can easily test for. This is a simple plumbing option that lets a porcelain ask the plumbing for its capabilities, at which point the porcelain can work around anything missing, or recommend to the user that they upgrade their plumbing layer. Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx> --- Because 'maint' does not support `git-blame -w` I can't apply your recent (and insanely good idea) 'git-gui: use "blame -w -C -C" for "where did it come from, originally?"' without something like the following, so I know that `git blame -w -C -C` will be accepted by the underlying plumbing. ;-) help.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++- t/t0000-basic.sh | 16 +++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/help.c b/help.c index 1cd33ec..9f24a0f 100644 --- a/help.c +++ b/help.c @@ -9,6 +9,11 @@ #include "common-cmds.h" #include <sys/ioctl.h> +static const char *supported_features[] = { + "blame-ignore-whitespace", + "list-features", +}; + /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) { @@ -190,10 +195,78 @@ void help_unknown_cmd(const char *cmd) exit(1); } +static int is_feature_name_sane(const char *a) +{ + if (!*a || *a == '-') + return 0; + for (; *a; a++) { + if (! ((*a >= 'a' && *a <= 'z') + || (*a >= '0' && *a <= '9') + || *a == '-')) + return 0; + } + return 1; +} + +static int cmp_feature(const void *a_, const void *b_) +{ + const char *a = *((const char **)a_); + const char *b = *((const char **)b_); + return strcmp(a, b); +} + +static void list_features() +{ + unsigned cnt = ARRAY_SIZE(supported_features); + unsigned i; + + qsort(supported_features, cnt, + sizeof(supported_features[0]), cmp_feature); + for (i = 0; i < cnt; i++) { + const char *f = supported_features[i]; + if (!is_feature_name_sane(f)) + die("feature name \"%s\" is bogus", f); + printf("%s\n", f); + } +} + +static int supports_feature(const char *the_feature) +{ + unsigned cnt = ARRAY_SIZE(supported_features); + unsigned i; + + for (i = 0; i < cnt; i++) { + if (!strcmp(supported_features[i], the_feature)) + return 0; + } + return 1; +} + +static const char version_usage[] = +"git-version [(--list-features | --supports-feature=<name>*)]"; + int cmd_version(int argc, const char **argv, const char *prefix) { - printf("git version %s\n", git_version_string); - return 0; + int i, ret = 0, list = 0, test = 0; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!strcmp(arg, "--list-features")) + list = 1; + else if (!prefixcmp(arg, "--supports-feature=")) { + test = 1; + ret |= supports_feature(arg + 19); + } else + usage(version_usage); + } + + if (list && test) + die("cannot use both --list-features and --supports-feature"); + if (list) + list_features(); + if (!list && !test) + printf("git version %s\n", git_version_string); + return ret; } int cmd_help(int argc, const char **argv, const char *prefix) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 8bfe832..9fc5824 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -31,6 +31,22 @@ fi . ./test-lib.sh ################################################################ +# git version + +test_expect_success \ + 'git version is functional' \ + 'git version' +test_expect_success \ + 'git version --list-features' \ + 'git version --list-features' +test_expect_success \ + 'feature "list-features" is supported' \ + 'git version --supports-feature=list-features' +test_expect_failure \ + 'feature "THISNEVERWILLBEAGITFEATURE" is not supported' \ + 'git version --supports-feature=THISNEVERWILLBEAGITFEATURE' + +################################################################ # git-init has been done in an empty repository. # make sure it is empty. -- 1.5.2.2.1050.g51a8b - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html