diff options
Diffstat (limited to 'builtin/tag.c')
-rw-r--r-- | builtin/tag.c | 163 |
1 files changed, 69 insertions, 94 deletions
diff --git a/builtin/tag.c b/builtin/tag.c index 667515e527..31f02e80f6 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -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 <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", @@ -23,8 +24,6 @@ static const char * const git_tag_usage[] = { NULL }; -static char signingkey[1000]; - struct tag_filter { const char **patterns; int lines; @@ -174,7 +173,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn) 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; @@ -208,83 +207,29 @@ static int verify_tag(const char *name, const char *ref, 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); } @@ -319,8 +264,18 @@ static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result) 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; @@ -345,7 +300,7 @@ static void create_tag(const unsigned char *object, const char *tag, 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: */ @@ -356,8 +311,12 @@ static void create_tag(const unsigned char *object, const char *tag, 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)) { @@ -367,14 +326,15 @@ static void create_tag(const unsigned char *object, const char *tag, } } - 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); @@ -407,12 +367,12 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) 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) @@ -422,28 +382,31 @@ int cmd_tag(int argc, const char **argv, const char *prefix) 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 <n> 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"), @@ -459,13 +422,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix) 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; @@ -518,14 +483,24 @@ int cmd_tag(int argc, const char **argv, const char *prefix) 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) |