From: Junio C Hamano Date: Mon, 13 Feb 2012 06:42:06 +0000 (-0800) Subject: Merge branch 'jk/maint-tag-show-fixes' X-Git-Tag: v1.7.10-rc0~102 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=1efb73322ad800cc679496124e8a1f498b52e5cb;hp=-c;p=git.git Merge branch 'jk/maint-tag-show-fixes' * jk/maint-tag-show-fixes: tag: do not show non-tag contents with "-n" tag: die when listing missing or corrupt objects tag: fix output of "tag -n" when errors occur Conflicts: t/t7004-tag.sh --- 1efb73322ad800cc679496124e8a1f498b52e5cb diff --combined builtin/tag.c index 31f02e80f,6ca53e331..03df16ac6 --- a/builtin/tag.c +++ b/builtin/tag.c @@@ -14,7 -14,6 +14,7 @@@ #include "parse-options.h" #include "diff.h" #include "revision.h" +#include "gpg-interface.h" static const char * const git_tag_usage[] = { "git tag [-a|-s|-u ] [-f] [-m |-F ] []", @@@ -24,6 -23,8 +24,6 @@@ NULL }; -static char signingkey[1000]; - struct tag_filter { const char **patterns; int lines; @@@ -83,18 -84,51 +83,51 @@@ static int contains(struct commit *cand return contains_recurse(candidate, want); } + static void show_tag_lines(const unsigned char *sha1, int lines) + { + int i; + unsigned long size; + enum object_type type; + char *buf, *sp, *eol; + size_t len; + + buf = read_sha1_file(sha1, &type, &size); + if (!buf) + die_errno("unable to read object %s", sha1_to_hex(sha1)); + if (type != OBJ_COMMIT && type != OBJ_TAG) + goto free_return; + if (!size) + die("an empty %s object %s?", + typename(type), sha1_to_hex(sha1)); + + /* skip header */ + sp = strstr(buf, "\n\n"); + if (!sp) + goto free_return; + + /* only take up to "lines" lines, and strip the signature from a tag */ + if (type == OBJ_TAG) + size = parse_signature(buf, size); + for (i = 0, sp += 2; i < lines && sp < buf + size; i++) { + if (i) + printf("\n "); + eol = memchr(sp, '\n', size - (sp - buf)); + len = eol ? eol - sp : size - (sp - buf); + fwrite(sp, len, 1, stdout); + if (!eol) + break; + sp = eol + 1; + } + free_return: + free(buf); + } + static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct tag_filter *filter = cb_data; if (match_pattern(filter->patterns, refname)) { - int i; - unsigned long size; - enum object_type type; - char *buf, *sp, *eol; - size_t len; - if (filter->with_commit) { struct commit *commit; @@@ -110,33 -144,8 +143,8 @@@ return 0; } printf("%-15s ", refname); - - buf = read_sha1_file(sha1, &type, &size); - if (!buf || !size) - return 0; - - /* skip header */ - sp = strstr(buf, "\n\n"); - if (!sp) { - free(buf); - return 0; - } - /* only take up to "lines" lines, and strip the signature */ - size = parse_signature(buf, size); - for (i = 0, sp += 2; - i < filter->lines && sp < buf + size; - i++) { - if (i) - printf("\n "); - eol = memchr(sp, '\n', size - (sp - buf)); - len = eol ? eol - sp : size - (sp - buf); - fwrite(sp, len, 1, stdout); - if (!eol) - break; - sp = eol + 1; - } + show_tag_lines(sha1, filter->lines); putchar('\n'); - free(buf); } return 0; @@@ -173,7 -182,7 +181,7 @@@ static int for_each_tag_name(const cha had_error = 1; continue; } - if (!resolve_ref(ref, sha1, 1, NULL)) { + if (read_ref(ref, sha1)) { error(_("tag '%s' not found."), *p); had_error = 1; continue; @@@ -207,29 -216,83 +215,29 @@@ static int verify_tag(const char *name static int do_sign(struct strbuf *buffer) { - struct child_process gpg; - const char *args[4]; - char *bracket; - int len; - int i, j; - - if (!*signingkey) { - if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME), - sizeof(signingkey)) > sizeof(signingkey) - 1) - return error(_("committer info too long.")); - bracket = strchr(signingkey, '>'); - if (bracket) - bracket[1] = '\0'; - } - - /* When the username signingkey is bad, program could be terminated - * because gpg exits without reading and then write gets SIGPIPE. */ - signal(SIGPIPE, SIG_IGN); - - memset(&gpg, 0, sizeof(gpg)); - gpg.argv = args; - gpg.in = -1; - gpg.out = -1; - args[0] = "gpg"; - args[1] = "-bsau"; - args[2] = signingkey; - args[3] = NULL; - - if (start_command(&gpg)) - return error(_("could not run gpg.")); - - if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) { - close(gpg.in); - close(gpg.out); - finish_command(&gpg); - return error(_("gpg did not accept the tag data")); - } - close(gpg.in); - len = strbuf_read(buffer, gpg.out, 1024); - close(gpg.out); - - if (finish_command(&gpg) || !len || len < 0) - return error(_("gpg failed to sign the tag")); - - /* Strip CR from the line endings, in case we are on Windows. */ - for (i = j = 0; i < buffer->len; i++) - if (buffer->buf[i] != '\r') { - if (i != j) - buffer->buf[j] = buffer->buf[i]; - j++; - } - strbuf_setlen(buffer, j); - - return 0; + return sign_buffer(buffer, buffer, get_signing_key()); } static const char tag_template[] = N_("\n" "#\n" "# Write a tag message\n" + "# Lines starting with '#' will be ignored.\n" "#\n"); -static void set_signingkey(const char *value) -{ - if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey)) - die(_("signing key value too long (%.10s...)"), value); -} +static const char tag_template_nocleanup[] = + N_("\n" + "#\n" + "# Write a tag message\n" + "# Lines starting with '#' will be kept; you may remove them" + " yourself if you want to.\n" + "#\n"); static int git_tag_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, "user.signingkey")) { - if (!value) - return config_error_nonbool(var); - set_signingkey(value); - return 0; - } - + int status = git_gpg_config(var, value, cb); + if (status) + return status; return git_default_config(var, value, cb); } @@@ -264,18 -327,8 +272,18 @@@ static int build_tag_object(struct strb return 0; } +struct create_tag_options { + unsigned int message_given:1; + unsigned int sign; + enum { + CLEANUP_NONE, + CLEANUP_SPACE, + CLEANUP_ALL + } cleanup_mode; +}; + static void create_tag(const unsigned char *object, const char *tag, - struct strbuf *buf, int message, int sign, + struct strbuf *buf, struct create_tag_options *opt, unsigned char *prev, unsigned char *result) { enum object_type type; @@@ -300,7 -353,7 +308,7 @@@ if (header_len > sizeof(header_buf) - 1) die(_("tag header too big.")); - if (!message) { + if (!opt->message_given) { int fd; /* write the template message before editing: */ @@@ -311,12 -364,8 +319,12 @@@ if (!is_null_sha1(prev)) write_tag_body(fd, prev); + else if (opt->cleanup_mode == CLEANUP_ALL) + write_or_die(fd, _(tag_template), + strlen(_(tag_template))); else - write_or_die(fd, _(tag_template), strlen(_(tag_template))); + write_or_die(fd, _(tag_template_nocleanup), + strlen(_(tag_template_nocleanup))); close(fd); if (launch_editor(path, buf, NULL)) { @@@ -326,15 -375,14 +334,15 @@@ } } - stripspace(buf, 1); + if (opt->cleanup_mode != CLEANUP_NONE) + stripspace(buf, opt->cleanup_mode == CLEANUP_ALL); - if (!message && !buf->len) + if (!opt->message_given && !buf->len) die(_("no tag message?")); strbuf_insert(buf, 0, header_buf, header_len); - if (build_tag_object(buf, sign, result) < 0) { + if (build_tag_object(buf, opt->sign, result) < 0) { if (path) fprintf(stderr, _("The tag message has been left in %s\n"), path); @@@ -367,12 -415,12 +375,12 @@@ static int parse_msg_arg(const struct o static int strbuf_check_tag_ref(struct strbuf *sb, const char *name) { if (name[0] == '-') - return CHECK_REF_FORMAT_ERROR; + return -1; strbuf_reset(sb); strbuf_addf(sb, "refs/tags/%s", name); - return check_ref_format(sb->buf); + return check_refname_format(sb->buf, 0); } int cmd_tag(int argc, const char **argv, const char *prefix) @@@ -382,31 -430,28 +390,31 @@@ unsigned char object[20], prev[20]; const char *object_ref, *tag; struct ref_lock *lock; - - int annotate = 0, sign = 0, force = 0, lines = -1, - list = 0, delete = 0, verify = 0; + struct create_tag_options opt; + char *cleanup_arg = NULL; + int annotate = 0, force = 0, lines = -1, list = 0, + delete = 0, verify = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct commit_list *with_commit = NULL; struct option options[] = { - OPT_BOOLEAN('l', NULL, &list, "list tag names"), + OPT_BOOLEAN('l', "list", &list, "list tag names"), { OPTION_INTEGER, 'n', NULL, &lines, "n", "print lines of each tag message", PARSE_OPT_OPTARG, NULL, 1 }, - OPT_BOOLEAN('d', NULL, &delete, "delete tags"), - OPT_BOOLEAN('v', NULL, &verify, "verify tags"), + OPT_BOOLEAN('d', "delete", &delete, "delete tags"), + OPT_BOOLEAN('v', "verify", &verify, "verify tags"), OPT_GROUP("Tag creation options"), - OPT_BOOLEAN('a', NULL, &annotate, + OPT_BOOLEAN('a', "annotate", &annotate, "annotated tag, needs a message"), - OPT_CALLBACK('m', NULL, &msg, "message", + OPT_CALLBACK('m', "message", &msg, "message", "tag message", parse_msg_arg), - OPT_FILENAME('F', NULL, &msgfile, "read message from file"), - OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), - OPT_STRING('u', NULL, &keyid, "key-id", + OPT_FILENAME('F', "file", &msgfile, "read message from file"), + OPT_BOOLEAN('s', "sign", &opt.sign, "annotated and GPG-signed tag"), + OPT_STRING(0, "cleanup", &cleanup_arg, "mode", + "how to strip spaces and #comments from message"), + OPT_STRING('u', "local-user", &keyid, "key-id", "use another key to sign the tag"), OPT__FORCE(&force, "replace the tag if exists"), @@@ -422,15 -467,13 +430,15 @@@ git_config(git_tag_config, NULL); + memset(&opt, 0, sizeof(opt)); + argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0); if (keyid) { - sign = 1; - set_signingkey(keyid); + opt.sign = 1; + set_signing_key(keyid); } - if (sign) + if (opt.sign) annotate = 1; if (argc == 0 && !(delete || verify)) list = 1; @@@ -483,24 -526,14 +491,24 @@@ if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); - if (!resolve_ref(ref.buf, prev, 1, NULL)) + if (read_ref(ref.buf, prev)) hashclr(prev); else if (!force) die(_("tag '%s' already exists"), tag); + opt.message_given = msg.given || msgfile; + + if (!cleanup_arg || !strcmp(cleanup_arg, "strip")) + opt.cleanup_mode = CLEANUP_ALL; + else if (!strcmp(cleanup_arg, "verbatim")) + opt.cleanup_mode = CLEANUP_NONE; + else if (!strcmp(cleanup_arg, "whitespace")) + opt.cleanup_mode = CLEANUP_SPACE; + else + die(_("Invalid cleanup mode %s"), cleanup_arg); + if (annotate) - create_tag(object, tag, &buf, msg.given || msgfile, - sign, prev, object); + create_tag(object, tag, &buf, &opt, prev, object); lock = lock_any_ref_for_update(ref.buf, prev, 0); if (!lock) diff --combined t/t7004-tag.sh index e93ac7382,7687e62cc..4ef79aabc --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@@ -8,7 -8,6 +8,7 @@@ test_description='git ta Tests for operations with tags.' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh # creating and listing lightweight tags: @@@ -586,6 -585,37 +586,19 @@@ test_expect_success test_cmp expect actual ' + test_expect_success 'annotations for blobs are empty' ' + blob=$(git hash-object -w --stdin <<-\EOF + Blob paragraph 1. + + Blob paragraph 2. + EOF + ) && + git tag tag-blob $blob && + echo "tag-blob " >expect && + git tag -n1 -l tag-blob >actual && + test_cmp expect actual + ' + -# subsequent tests require gpg; check if it is available -gpg --version >/dev/null 2>/dev/null -if [ $? -eq 127 ]; then - say "# gpg not found - skipping tag signing and verification tests" -else - # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19 - # the gpg version 1.0.6 didn't parse trust packets correctly, so for - # that version, creation of signed tags using the generated key fails. - case "$(gpg --version)" in - 'gpg (GnuPG) 1.0.6'*) - say "Skipping signed tag tests, because a bug in 1.0.6 version" - ;; - *) - test_set_prereq GPG - ;; - esac -fi - # trying to verify annotated non-signed tags: test_expect_success GPG \ @@@ -608,6 -638,16 +621,6 @@@ test_expect_success GPG # creating and verifying signed tags: -# key generation info: gpg --homedir t/t7004 --gen-key -# Type DSA and Elgamal, size 2048 bits, no expiration date. -# Name and email: C O Mitter -# No password given, to enable non-interactive operation. - -cp -R "$TEST_DIRECTORY"/t7004 ./gpghome -chmod 0700 gpghome -GNUPGHOME="$(pwd)/gpghome" -export GNUPGHOME - get_tag_header signed-tag $commit commit $time >expect echo 'A signed tag message' >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect