builtin-tag.con commit git-add -i: add help text for list-and-choose UI (7e018be)
   1/*
   2 * Builtin "git tag"
   3 *
   4 * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
   5 *                    Carlos Rica <jasampler@gmail.com>
   6 * Based on git-tag.sh and mktag.c by Linus Torvalds.
   7 */
   8
   9#include "cache.h"
  10#include "builtin.h"
  11#include "refs.h"
  12#include "tag.h"
  13#include "run-command.h"
  14
  15static const char builtin_tag_usage[] =
  16  "git-tag [-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>] <tagname> [<head>]";
  17
  18static char signingkey[1000];
  19
  20void launch_editor(const char *path, struct strbuf *buffer)
  21{
  22        const char *editor, *terminal;
  23
  24        editor = getenv("GIT_EDITOR");
  25        if (!editor && editor_program)
  26                editor = editor_program;
  27        if (!editor)
  28                editor = getenv("VISUAL");
  29        if (!editor)
  30                editor = getenv("EDITOR");
  31
  32        terminal = getenv("TERM");
  33        if (!editor && (!terminal || !strcmp(terminal, "dumb"))) {
  34                fprintf(stderr,
  35                "Terminal is dumb but no VISUAL nor EDITOR defined.\n"
  36                "Please supply the message using either -m or -F option.\n");
  37                exit(1);
  38        }
  39
  40        if (!editor)
  41                editor = "vi";
  42
  43        if (strcmp(editor, ":")) {
  44                const char *args[] = { editor, path, NULL };
  45
  46                if (run_command_v_opt(args, 0))
  47                        die("There was a problem with the editor %s.", editor);
  48        }
  49
  50        if (strbuf_read_file(buffer, path, 0) < 0)
  51                die("could not read message file '%s': %s",
  52                    path, strerror(errno));
  53}
  54
  55struct tag_filter {
  56        const char *pattern;
  57        int lines;
  58};
  59
  60#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
  61
  62static int show_reference(const char *refname, const unsigned char *sha1,
  63                          int flag, void *cb_data)
  64{
  65        struct tag_filter *filter = cb_data;
  66
  67        if (!fnmatch(filter->pattern, refname, 0)) {
  68                int i;
  69                unsigned long size;
  70                enum object_type type;
  71                char *buf, *sp, *eol;
  72                size_t len;
  73
  74                if (!filter->lines) {
  75                        printf("%s\n", refname);
  76                        return 0;
  77                }
  78                printf("%-15s ", refname);
  79
  80                buf = read_sha1_file(sha1, &type, &size);
  81                if (!buf || !size)
  82                        return 0;
  83
  84                /* skip header */
  85                sp = strstr(buf, "\n\n");
  86                if (!sp) {
  87                        free(buf);
  88                        return 0;
  89                }
  90                /* only take up to "lines" lines, and strip the signature */
  91                for (i = 0, sp += 2;
  92                                i < filter->lines && sp < buf + size &&
  93                                prefixcmp(sp, PGP_SIGNATURE "\n");
  94                                i++) {
  95                        if (i)
  96                                printf("\n    ");
  97                        eol = memchr(sp, '\n', size - (sp - buf));
  98                        len = eol ? eol - sp : size - (sp - buf);
  99                        fwrite(sp, len, 1, stdout);
 100                        if (!eol)
 101                                break;
 102                        sp = eol + 1;
 103                }
 104                putchar('\n');
 105                free(buf);
 106        }
 107
 108        return 0;
 109}
 110
 111static int list_tags(const char *pattern, int lines)
 112{
 113        struct tag_filter filter;
 114
 115        if (pattern == NULL)
 116                pattern = "*";
 117
 118        filter.pattern = pattern;
 119        filter.lines = lines;
 120
 121        for_each_tag_ref(show_reference, (void *) &filter);
 122
 123        return 0;
 124}
 125
 126typedef int (*each_tag_name_fn)(const char *name, const char *ref,
 127                                const unsigned char *sha1);
 128
 129static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
 130{
 131        const char **p;
 132        char ref[PATH_MAX];
 133        int had_error = 0;
 134        unsigned char sha1[20];
 135
 136        for (p = argv; *p; p++) {
 137                if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
 138                                        >= sizeof(ref)) {
 139                        error("tag name too long: %.*s...", 50, *p);
 140                        had_error = 1;
 141                        continue;
 142                }
 143                if (!resolve_ref(ref, sha1, 1, NULL)) {
 144                        error("tag '%s' not found.", *p);
 145                        had_error = 1;
 146                        continue;
 147                }
 148                if (fn(*p, ref, sha1))
 149                        had_error = 1;
 150        }
 151        return had_error;
 152}
 153
 154static int delete_tag(const char *name, const char *ref,
 155                                const unsigned char *sha1)
 156{
 157        if (delete_ref(ref, sha1))
 158                return 1;
 159        printf("Deleted tag '%s'\n", name);
 160        return 0;
 161}
 162
 163static int verify_tag(const char *name, const char *ref,
 164                                const unsigned char *sha1)
 165{
 166        const char *argv_verify_tag[] = {"git-verify-tag",
 167                                        "-v", "SHA1_HEX", NULL};
 168        argv_verify_tag[2] = sha1_to_hex(sha1);
 169
 170        if (run_command_v_opt(argv_verify_tag, 0))
 171                return error("could not verify the tag '%s'", name);
 172        return 0;
 173}
 174
 175static int do_sign(struct strbuf *buffer)
 176{
 177        struct child_process gpg;
 178        const char *args[4];
 179        char *bracket;
 180        int len;
 181
 182        if (!*signingkey) {
 183                if (strlcpy(signingkey, git_committer_info(1),
 184                                sizeof(signingkey)) > sizeof(signingkey) - 1)
 185                        return error("committer info too long.");
 186                bracket = strchr(signingkey, '>');
 187                if (bracket)
 188                        bracket[1] = '\0';
 189        }
 190
 191        /* When the username signingkey is bad, program could be terminated
 192         * because gpg exits without reading and then write gets SIGPIPE. */
 193        signal(SIGPIPE, SIG_IGN);
 194
 195        memset(&gpg, 0, sizeof(gpg));
 196        gpg.argv = args;
 197        gpg.in = -1;
 198        gpg.out = -1;
 199        args[0] = "gpg";
 200        args[1] = "-bsau";
 201        args[2] = signingkey;
 202        args[3] = NULL;
 203
 204        if (start_command(&gpg))
 205                return error("could not run gpg.");
 206
 207        if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
 208                close(gpg.in);
 209                finish_command(&gpg);
 210                return error("gpg did not accept the tag data");
 211        }
 212        close(gpg.in);
 213        gpg.close_in = 0;
 214        len = strbuf_read(buffer, gpg.out, 1024);
 215
 216        if (finish_command(&gpg) || !len || len < 0)
 217                return error("gpg failed to sign the tag");
 218
 219        if (len < 0)
 220                return error("could not read the entire signature from gpg.");
 221
 222        return 0;
 223}
 224
 225static const char tag_template[] =
 226        "\n"
 227        "#\n"
 228        "# Write a tag message\n"
 229        "#\n";
 230
 231static int git_tag_config(const char *var, const char *value)
 232{
 233        if (!strcmp(var, "user.signingkey")) {
 234                if (!value)
 235                        die("user.signingkey without value");
 236                if (strlcpy(signingkey, value, sizeof(signingkey))
 237                                                >= sizeof(signingkey))
 238                        die("user.signingkey value too long");
 239                return 0;
 240        }
 241
 242        return git_default_config(var, value);
 243}
 244
 245static void write_tag_body(int fd, const unsigned char *sha1)
 246{
 247        unsigned long size;
 248        enum object_type type;
 249        char *buf, *sp, *eob;
 250        size_t len;
 251
 252        buf = read_sha1_file(sha1, &type, &size);
 253        if (!buf)
 254                return;
 255        /* skip header */
 256        sp = strstr(buf, "\n\n");
 257
 258        if (!sp || !size || type != OBJ_TAG) {
 259                free(buf);
 260                return;
 261        }
 262        sp += 2; /* skip the 2 LFs */
 263        eob = strstr(sp, "\n" PGP_SIGNATURE "\n");
 264        if (eob)
 265                len = eob - sp;
 266        else
 267                len = buf + size - sp;
 268        write_or_die(fd, sp, len);
 269
 270        free(buf);
 271}
 272
 273static void create_tag(const unsigned char *object, const char *tag,
 274                       struct strbuf *buf, int message, int sign,
 275                           unsigned char *prev, unsigned char *result)
 276{
 277        enum object_type type;
 278        char header_buf[1024];
 279        int header_len;
 280
 281        type = sha1_object_info(object, NULL);
 282        if (type <= OBJ_NONE)
 283            die("bad object type.");
 284
 285        header_len = snprintf(header_buf, sizeof(header_buf),
 286                          "object %s\n"
 287                          "type %s\n"
 288                          "tag %s\n"
 289                          "tagger %s\n\n",
 290                          sha1_to_hex(object),
 291                          typename(type),
 292                          tag,
 293                          git_committer_info(1));
 294
 295        if (header_len > sizeof(header_buf) - 1)
 296                die("tag header too big.");
 297
 298        if (!message) {
 299                char *path;
 300                int fd;
 301
 302                /* write the template message before editing: */
 303                path = xstrdup(git_path("TAG_EDITMSG"));
 304                fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 305                if (fd < 0)
 306                        die("could not create file '%s': %s",
 307                                                path, strerror(errno));
 308
 309                if (!is_null_sha1(prev))
 310                        write_tag_body(fd, prev);
 311                else
 312                        write_or_die(fd, tag_template, strlen(tag_template));
 313                close(fd);
 314
 315                launch_editor(path, buf);
 316
 317                unlink(path);
 318                free(path);
 319        }
 320
 321        stripspace(buf, 1);
 322
 323        if (!message && !buf->len)
 324                die("no tag message?");
 325
 326        strbuf_insert(buf, 0, header_buf, header_len);
 327
 328        if (sign && do_sign(buf) < 0)
 329                die("unable to sign the tag");
 330        if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
 331                die("unable to write tag file");
 332}
 333
 334int cmd_tag(int argc, const char **argv, const char *prefix)
 335{
 336        struct strbuf buf;
 337        unsigned char object[20], prev[20];
 338        int annotate = 0, sign = 0, force = 0, lines = 0, message = 0;
 339        char ref[PATH_MAX];
 340        const char *object_ref, *tag;
 341        int i;
 342        struct ref_lock *lock;
 343
 344        git_config(git_tag_config);
 345        strbuf_init(&buf, 0);
 346
 347        for (i = 1; i < argc; i++) {
 348                const char *arg = argv[i];
 349
 350                if (arg[0] != '-')
 351                        break;
 352                if (!strcmp(arg, "-a")) {
 353                        annotate = 1;
 354                        continue;
 355                }
 356                if (!strcmp(arg, "-s")) {
 357                        annotate = 1;
 358                        sign = 1;
 359                        continue;
 360                }
 361                if (!strcmp(arg, "-f")) {
 362                        force = 1;
 363                        continue;
 364                }
 365                if (!strcmp(arg, "-n")) {
 366                        if (i + 1 == argc || *argv[i + 1] == '-')
 367                                /* no argument */
 368                                lines = 1;
 369                        else
 370                                lines = isdigit(*argv[++i]) ?
 371                                        atoi(argv[i]) : 1;
 372                        continue;
 373                }
 374                if (!strcmp(arg, "-m")) {
 375                        annotate = 1;
 376                        i++;
 377                        if (i == argc)
 378                                die("option -m needs an argument.");
 379                        if (message)
 380                                die("only one -F or -m option is allowed.");
 381                        strbuf_addstr(&buf, argv[i]);
 382                        message = 1;
 383                        continue;
 384                }
 385                if (!strcmp(arg, "-F")) {
 386                        annotate = 1;
 387                        i++;
 388                        if (i == argc)
 389                                die("option -F needs an argument.");
 390                        if (message)
 391                                die("only one -F or -m option is allowed.");
 392
 393                        if (!strcmp(argv[i], "-")) {
 394                                if (strbuf_read(&buf, 0, 1024) < 0)
 395                                        die("cannot read %s", argv[i]);
 396                        } else {
 397                                if (strbuf_read_file(&buf, argv[i], 1024) < 0)
 398                                        die("could not open or read '%s': %s",
 399                                                argv[i], strerror(errno));
 400                        }
 401                        message = 1;
 402                        continue;
 403                }
 404                if (!strcmp(arg, "-u")) {
 405                        annotate = 1;
 406                        sign = 1;
 407                        i++;
 408                        if (i == argc)
 409                                die("option -u needs an argument.");
 410                        if (strlcpy(signingkey, argv[i], sizeof(signingkey))
 411                                                        >= sizeof(signingkey))
 412                                die("argument to option -u too long");
 413                        continue;
 414                }
 415                if (!strcmp(arg, "-l"))
 416                        return list_tags(argv[i + 1], lines);
 417                if (!strcmp(arg, "-d"))
 418                        return for_each_tag_name(argv + i + 1, delete_tag);
 419                if (!strcmp(arg, "-v"))
 420                        return for_each_tag_name(argv + i + 1, verify_tag);
 421                usage(builtin_tag_usage);
 422        }
 423
 424        if (i == argc) {
 425                if (annotate)
 426                        usage(builtin_tag_usage);
 427                return list_tags(NULL, lines);
 428        }
 429        tag = argv[i++];
 430
 431        object_ref = i < argc ? argv[i] : "HEAD";
 432        if (i + 1 < argc)
 433                die("too many params");
 434
 435        if (get_sha1(object_ref, object))
 436                die("Failed to resolve '%s' as a valid ref.", object_ref);
 437
 438        if (snprintf(ref, sizeof(ref), "refs/tags/%s", tag) > sizeof(ref) - 1)
 439                die("tag name too long: %.*s...", 50, tag);
 440        if (check_ref_format(ref))
 441                die("'%s' is not a valid tag name.", tag);
 442
 443        if (!resolve_ref(ref, prev, 1, NULL))
 444                hashclr(prev);
 445        else if (!force)
 446                die("tag '%s' already exists", tag);
 447
 448        if (annotate)
 449                create_tag(object, tag, &buf, message, sign, prev, object);
 450
 451        lock = lock_any_ref_for_update(ref, prev, 0);
 452        if (!lock)
 453                die("%s: cannot lock the ref", ref);
 454        if (write_ref_sha1(lock, object, NULL) < 0)
 455                die("%s: cannot update the ref", ref);
 456
 457        strbuf_release(&buf);
 458        return 0;
 459}