X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-tag.c;h=03e70155fc676a8dd38ca5cef800ed4a446e921a;hb=b2979ff599a6bcf9dbf5e2ef1e32b81a1b88e115;hp=cbb0f04e85627a5509bb2ba8cbf04a54d4d20c41;hpb=b52e985a4f824128d01220473b04057a4876060d;p=git.git diff --git a/builtin-tag.c b/builtin-tag.c index cbb0f04e8..03e70155f 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -11,17 +11,21 @@ #include "refs.h" #include "tag.h" #include "run-command.h" - -static const char builtin_tag_usage[] = - "git-tag [-n []] -l [] | [-a | -s | -u ] [-f | -d | -v] [-m | -F ] []"; +#include "parse-options.h" + +static const char * const git_tag_usage[] = { + "git-tag [-a|-s|-u ] [-f] [-m |-F ] []", + "git-tag -d ...", + "git-tag -l [-n []] []", + "git-tag -v ...", + NULL +}; static char signingkey[1000]; -static void launch_editor(const char *path, struct strbuf *buffer) +void launch_editor(const char *path, struct strbuf *buffer, const char *const *env) { const char *editor, *terminal; - struct child_process child; - const char *args[3]; editor = getenv("GIT_EDITOR"); if (!editor && editor_program) @@ -42,15 +46,27 @@ static void launch_editor(const char *path, struct strbuf *buffer) if (!editor) editor = "vi"; - memset(&child, 0, sizeof(child)); - child.argv = args; - args[0] = editor; - args[1] = path; - args[2] = NULL; + if (strcmp(editor, ":")) { + size_t len = strlen(editor); + int i = 0; + const char *args[6]; - if (run_command(&child)) - die("There was a problem with the editor %s.", editor); + if (strcspn(editor, "$ \t'") != len) { + /* there are specials */ + args[i++] = "sh"; + args[i++] = "-c"; + args[i++] = "$0 \"$@\""; + } + args[i++] = editor; + args[i++] = path; + args[i] = NULL; + + if (run_command_v_opt_cd_env(args, 0, NULL, env)) + die("There was a problem with the editor %s.", editor); + } + if (!buffer) + return; if (strbuf_read_file(buffer, path, 0) < 0) die("could not read message file '%s': %s", path, strerror(errno)); @@ -184,7 +200,7 @@ static int do_sign(struct strbuf *buffer) int len; if (!*signingkey) { - if (strlcpy(signingkey, git_committer_info(1), + 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, '>'); @@ -232,14 +248,18 @@ static const char tag_template[] = "# Write a tag message\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 int git_tag_config(const char *var, const char *value) { if (!strcmp(var, "user.signingkey")) { if (!value) die("user.signingkey without value"); - if (strlcpy(signingkey, value, sizeof(signingkey)) - >= sizeof(signingkey)) - die("user.signingkey value too long"); + set_signingkey(value); return 0; } @@ -276,7 +296,7 @@ static void write_tag_body(int fd, const unsigned char *sha1) static void create_tag(const unsigned char *object, const char *tag, struct strbuf *buf, int message, int sign, - unsigned char *prev, unsigned char *result) + unsigned char *prev, unsigned char *result) { enum object_type type; char header_buf[1024]; @@ -294,7 +314,7 @@ static void create_tag(const unsigned char *object, const char *tag, sha1_to_hex(object), typename(type), tag, - git_committer_info(1)); + git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (header_len > sizeof(header_buf) - 1) die("tag header too big."); @@ -316,7 +336,7 @@ static void create_tag(const unsigned char *object, const char *tag, write_or_die(fd, tag_template, strlen(tag_template)); close(fd); - launch_editor(path, buf); + launch_editor(path, buf, NULL); unlink(path); free(path); @@ -335,105 +355,103 @@ static void create_tag(const unsigned char *object, const char *tag, die("unable to write tag file"); } +struct msg_arg { + int given; + struct strbuf buf; +}; + +static int parse_msg_arg(const struct option *opt, const char *arg, int unset) +{ + struct msg_arg *msg = opt->value; + + if (!arg) + return -1; + if (msg->buf.len) + strbuf_addstr(&(msg->buf), "\n\n"); + strbuf_addstr(&(msg->buf), arg); + msg->given = 1; + return 0; +} + int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf; unsigned char object[20], prev[20]; - int annotate = 0, sign = 0, force = 0, lines = 0, message = 0; char ref[PATH_MAX]; const char *object_ref, *tag; - int i; struct ref_lock *lock; + int annotate = 0, sign = 0, force = 0, lines = 0, + list = 0, delete = 0, verify = 0; + char *msgfile = NULL, *keyid = NULL; + struct msg_arg msg = { 0, STRBUF_INIT }; + struct option options[] = { + OPT_BOOLEAN('l', NULL, &list, "list tag names"), + { OPTION_INTEGER, 'n', NULL, &lines, NULL, + "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_GROUP("Tag creation options"), + OPT_BOOLEAN('a', NULL, &annotate, + "annotated tag, needs a message"), + OPT_CALLBACK('m', NULL, &msg, "msg", + "message for the tag", parse_msg_arg), + OPT_STRING('F', NULL, &msgfile, "file", "message in a file"), + OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), + OPT_STRING('u', NULL, &keyid, "key-id", + "use another key to sign the tag"), + OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"), + OPT_END() + }; + git_config(git_tag_config); - strbuf_init(&buf, 0); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; + argc = parse_options(argc, argv, options, git_tag_usage, 0); - if (arg[0] != '-') - break; - if (!strcmp(arg, "-a")) { - annotate = 1; - continue; - } - if (!strcmp(arg, "-s")) { - annotate = 1; - sign = 1; - continue; - } - if (!strcmp(arg, "-f")) { - force = 1; - continue; - } - if (!strcmp(arg, "-n")) { - if (i + 1 == argc || *argv[i + 1] == '-') - /* no argument */ - lines = 1; - else - lines = isdigit(*argv[++i]) ? - atoi(argv[i]) : 1; - continue; - } - if (!strcmp(arg, "-m")) { - annotate = 1; - i++; - if (i == argc) - die("option -m needs an argument."); - if (message) - die("only one -F or -m option is allowed."); - strbuf_addstr(&buf, argv[i]); - message = 1; - continue; - } - if (!strcmp(arg, "-F")) { - annotate = 1; - i++; - if (i == argc) - die("option -F needs an argument."); - if (message) - die("only one -F or -m option is allowed."); - - if (!strcmp(argv[i], "-")) { + if (keyid) { + sign = 1; + set_signingkey(keyid); + } + if (sign) + annotate = 1; + + if (list) + return list_tags(argv[0], lines); + if (delete) + return for_each_tag_name(argv, delete_tag); + if (verify) + return for_each_tag_name(argv, verify_tag); + + strbuf_init(&buf, 0); + if (msg.given || msgfile) { + if (msg.given && msgfile) + die("only one -F or -m option is allowed."); + annotate = 1; + if (msg.given) + strbuf_addbuf(&buf, &(msg.buf)); + else { + if (!strcmp(msgfile, "-")) { if (strbuf_read(&buf, 0, 1024) < 0) - die("cannot read %s", argv[i]); + die("cannot read %s", msgfile); } else { - if (strbuf_read_file(&buf, argv[i], 1024) < 0) + if (strbuf_read_file(&buf, msgfile, 1024) < 0) die("could not open or read '%s': %s", - argv[i], strerror(errno)); + msgfile, strerror(errno)); } - message = 1; - continue; - } - if (!strcmp(arg, "-u")) { - annotate = 1; - sign = 1; - i++; - if (i == argc) - die("option -u needs an argument."); - if (strlcpy(signingkey, argv[i], sizeof(signingkey)) - >= sizeof(signingkey)) - die("argument to option -u too long"); - continue; } - if (!strcmp(arg, "-l")) - return list_tags(argv[i + 1], lines); - if (!strcmp(arg, "-d")) - return for_each_tag_name(argv + i + 1, delete_tag); - if (!strcmp(arg, "-v")) - return for_each_tag_name(argv + i + 1, verify_tag); - usage(builtin_tag_usage); } - if (i == argc) { + if (argc == 0) { if (annotate) - usage(builtin_tag_usage); + usage_with_options(git_tag_usage, options); return list_tags(NULL, lines); } - tag = argv[i++]; + tag = argv[0]; - object_ref = i < argc ? argv[i] : "HEAD"; - if (i + 1 < argc) + object_ref = argc == 2 ? argv[1] : "HEAD"; + if (argc > 2) die("too many params"); if (get_sha1(object_ref, object)) @@ -450,7 +468,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die("tag '%s' already exists", tag); if (annotate) - create_tag(object, tag, &buf, message, sign, prev, object); + create_tag(object, tag, &buf, msg.given || msgfile, + sign, prev, object); lock = lock_any_ref_for_update(ref, prev, 0); if (!lock)