Make git tag a builtin.
[git/jnareb-git.git] / builtin-tag.c
blob507f51076da92f241859ed940e5332f79278e092
1 /*
2 * Builtin "git tag"
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 */
9 #include "cache.h"
10 #include "builtin.h"
11 #include "refs.h"
12 #include "tag.h"
13 #include "run-command.h"
15 static 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>]";
18 static char signingkey[1000];
20 static void launch_editor(const char *path, char **buffer, unsigned long *len)
22 const char *editor, *terminal;
23 struct child_process child;
24 const char *args[3];
25 int fd;
27 editor = getenv("VISUAL");
28 if (!editor)
29 editor = getenv("EDITOR");
31 terminal = getenv("TERM");
32 if (!editor && (!terminal || !strcmp(terminal, "dumb"))) {
33 fprintf(stderr,
34 "Terminal is dumb but no VISUAL nor EDITOR defined.\n"
35 "Please supply the message using either -m or -F option.\n");
36 exit(1);
39 if (!editor)
40 editor = "vi";
42 memset(&child, 0, sizeof(child));
43 child.argv = args;
44 args[0] = editor;
45 args[1] = path;
46 args[2] = NULL;
48 if (run_command(&child))
49 die("There was a problem with the editor %s.", editor);
51 fd = open(path, O_RDONLY);
52 if (fd < 0)
53 die("could not open '%s': %s", path, strerror(errno));
54 if (read_fd(fd, buffer, len)) {
55 free(*buffer);
56 die("could not read message file '%s': %s",
57 path, strerror(errno));
59 close(fd);
62 struct tag_filter {
63 const char *pattern;
64 int lines;
67 #define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
69 static int show_reference(const char *refname, const unsigned char *sha1,
70 int flag, void *cb_data)
72 struct tag_filter *filter = cb_data;
74 if (!fnmatch(filter->pattern, refname, 0)) {
75 int i;
76 unsigned long size;
77 enum object_type type;
78 char *buf, *sp, *eol;
79 size_t len;
81 if (!filter->lines) {
82 printf("%s\n", refname);
83 return 0;
85 printf("%-15s ", refname);
87 sp = buf = read_sha1_file(sha1, &type, &size);
88 if (!buf || !size)
89 return 0;
90 /* skip header */
91 while (sp + 1 < buf + size &&
92 !(sp[0] == '\n' && sp[1] == '\n'))
93 sp++;
94 /* only take up to "lines" lines, and strip the signature */
95 for (i = 0, sp += 2; i < filter->lines && sp < buf + size &&
96 prefixcmp(sp, PGP_SIGNATURE "\n");
97 i++) {
98 if (i)
99 printf("\n ");
100 eol = memchr(sp, '\n', size - (sp - buf));
101 len = eol ? eol - sp : size - (sp - buf);
102 fwrite(sp, len, 1, stdout);
103 if (!eol)
104 break;
105 sp = eol + 1;
107 putchar('\n');
108 free(buf);
111 return 0;
114 static int list_tags(const char *pattern, int lines)
116 struct tag_filter filter;
117 char *newpattern;
119 if (pattern == NULL)
120 pattern = "";
122 /* prepend/append * to the shell pattern: */
123 newpattern = xmalloc(strlen(pattern) + 3);
124 sprintf(newpattern, "*%s*", pattern);
126 filter.pattern = newpattern;
127 filter.lines = lines;
129 for_each_tag_ref(show_reference, (void *) &filter);
131 free(newpattern);
133 return 0;
136 typedef int (*func_tag)(const char *name, const char *ref,
137 const unsigned char *sha1);
139 static int do_tag_names(const char **argv, func_tag fn)
141 const char **p;
142 char ref[PATH_MAX];
143 int had_error = 0;
144 unsigned char sha1[20];
146 for (p = argv; *p; p++) {
147 if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
148 >= sizeof(ref)) {
149 error("tag name too long: %.*s...", 50, *p);
150 had_error = 1;
151 continue;
153 if (!resolve_ref(ref, sha1, 1, NULL)) {
154 error("tag '%s' not found.", *p);
155 had_error = 1;
156 continue;
158 if (fn(*p, ref, sha1))
159 had_error = 1;
161 return had_error;
164 static int delete_tag(const char *name, const char *ref,
165 const unsigned char *sha1)
167 if (delete_ref(ref, sha1))
168 return 1;
169 printf("Deleted tag '%s'\n", name);
170 return 0;
173 static int verify_tag(const char *name, const char *ref,
174 const unsigned char *sha1)
176 const char *argv_verify_tag[] = {"git-verify-tag",
177 "-v", "SHA1_HEX", NULL};
178 argv_verify_tag[2] = sha1_to_hex(sha1);
180 if (run_command_v_opt(argv_verify_tag, 0))
181 return error("could not verify the tag '%s'", name);
182 return 0;
185 static ssize_t do_sign(char *buffer, size_t size, size_t max)
187 struct child_process gpg;
188 const char *args[4];
189 char *bracket;
190 int len;
192 if (!*signingkey) {
193 if (strlcpy(signingkey, git_committer_info(1),
194 sizeof(signingkey)) >= sizeof(signingkey))
195 return error("committer info too long.");
196 bracket = strchr(signingkey, '>');
197 if (bracket)
198 bracket[1] = '\0';
201 memset(&gpg, 0, sizeof(gpg));
202 gpg.argv = args;
203 gpg.in = -1;
204 gpg.out = -1;
205 args[0] = "gpg";
206 args[1] = "-bsau";
207 args[2] = signingkey;
208 args[3] = NULL;
210 if (start_command(&gpg))
211 return error("could not run gpg.");
213 write_or_die(gpg.in, buffer, size);
214 close(gpg.in);
215 gpg.close_in = 0;
216 len = read_in_full(gpg.out, buffer + size, max - size);
218 finish_command(&gpg);
220 if (len == max - size)
221 return error("could not read the entire signature from gpg.");
223 return size + len;
226 static const char tag_template[] =
227 "\n"
228 "#\n"
229 "# Write a tag message\n"
230 "#\n";
232 static int git_tag_config(const char *var, const char *value)
234 if (!strcmp(var, "user.signingkey")) {
235 if (!value)
236 die("user.signingkey without value");
237 if (strlcpy(signingkey, value, sizeof(signingkey))
238 >= sizeof(signingkey))
239 die("user.signingkey value too long");
240 return 0;
243 return git_default_config(var, value);
246 #define MAX_SIGNATURE_LENGTH 1024
247 /* message must be NULL or allocated, it will be reallocated and freed */
248 static void create_tag(const unsigned char *object, const char *tag,
249 char *message, int sign, unsigned char *result)
251 enum object_type type;
252 char header_buf[1024], *buffer;
253 int header_len, max_size;
254 unsigned long size;
256 type = sha1_object_info(object, NULL);
257 if (type <= 0)
258 die("bad object type.");
260 header_len = snprintf(header_buf, sizeof(header_buf),
261 "object %s\n"
262 "type %s\n"
263 "tag %s\n"
264 "tagger %s\n\n",
265 sha1_to_hex(object),
266 typename(type),
267 tag,
268 git_committer_info(1));
270 if (header_len >= sizeof(header_buf))
271 die("tag header too big.");
273 if (!message) {
274 char *path;
275 int fd;
277 /* write the template message before editing: */
278 path = xstrdup(git_path("TAG_EDITMSG"));
279 fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
280 if (fd < 0)
281 die("could not create file '%s': %s",
282 path, strerror(errno));
283 write_or_die(fd, tag_template, strlen(tag_template));
284 close(fd);
286 launch_editor(path, &buffer, &size);
288 unlink(path);
289 free(path);
291 else {
292 buffer = message;
293 size = strlen(message);
296 size = stripspace(buffer, size, 1);
298 if (!message && !size)
299 die("no tag message?");
301 /* insert the header and add the '\n' if needed: */
302 max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
303 buffer = xrealloc(buffer, max_size);
304 if (size)
305 buffer[size++] = '\n';
306 memmove(buffer + header_len, buffer, size);
307 memcpy(buffer, header_buf, header_len);
308 size += header_len;
310 if (sign) {
311 size = do_sign(buffer, size, max_size);
312 if (size < 0)
313 die("unable to sign the tag");
316 if (write_sha1_file(buffer, size, tag_type, result) < 0)
317 die("unable to write tag file");
318 free(buffer);
321 int cmd_tag(int argc, const char **argv, const char *prefix)
323 unsigned char object[20], prev[20];
324 int annotate = 0, sign = 0, force = 0, lines = 0;
325 char *message = NULL;
326 char ref[PATH_MAX];
327 const char *object_ref, *tag;
328 int i;
329 struct ref_lock *lock;
331 git_config(git_tag_config);
333 for (i = 1; i < argc; i++) {
334 const char *arg = argv[i];
336 if (arg[0] != '-')
337 break;
338 if (!strcmp(arg, "-a")) {
339 annotate = 1;
340 continue;
342 if (!strcmp(arg, "-s")) {
343 annotate = 1;
344 sign = 1;
345 continue;
347 if (!strcmp(arg, "-f")) {
348 force = 1;
349 continue;
351 if (!strcmp(arg, "-n")) {
352 if (i + 1 == argc || *argv[i + 1] == '-')
353 /* no argument */
354 lines = 1;
355 else
356 lines = isdigit(*argv[++i]) ?
357 atoi(argv[i]) : 1;
358 continue;
360 if (!strcmp(arg, "-m")) {
361 annotate = 1;
362 i++;
363 if (i == argc)
364 die("option -m needs an argument.");
365 message = xstrdup(argv[i]);
366 continue;
368 if (!strcmp(arg, "-F")) {
369 unsigned long len;
370 int fd;
372 annotate = 1;
373 i++;
374 if (i == argc)
375 die("option -F needs an argument.");
377 if (!strcmp(argv[i], "-"))
378 fd = 0;
379 else {
380 fd = open(argv[i], O_RDONLY);
381 if (fd < 0)
382 die("could not open '%s': %s",
383 argv[i], strerror(errno));
385 len = 1024;
386 message = xmalloc(len);
387 if (read_fd(fd, &message, &len)) {
388 free(message);
389 die("cannot read %s", argv[i]);
391 continue;
393 if (!strcmp(arg, "-u")) {
394 annotate = 1;
395 sign = 1;
396 i++;
397 if (i == argc)
398 die("option -u needs an argument.");
399 if (strlcpy(signingkey, argv[i], sizeof(signingkey))
400 >= sizeof(signingkey))
401 die("argument to option -u too long");
402 continue;
404 if (!strcmp(arg, "-l")) {
405 return list_tags(argv[i + 1], lines);
407 if (!strcmp(arg, "-d")) {
408 return do_tag_names(argv + i + 1, delete_tag);
410 if (!strcmp(arg, "-v")) {
411 return do_tag_names(argv + i + 1, verify_tag);
413 usage(builtin_tag_usage);
416 if (i == argc) {
417 if (annotate)
418 usage(builtin_tag_usage);
419 return list_tags(NULL, lines);
421 tag = argv[i++];
423 object_ref = i < argc ? argv[i] : "HEAD";
424 if (i + 1 < argc)
425 die("too many params");
427 if (get_sha1(object_ref, object))
428 die("Failed to resolve '%s' as a valid ref.", object_ref);
430 if (snprintf(ref, sizeof(ref), "refs/tags/%s", tag) >= sizeof(ref))
431 die("tag name too long: %.*s...", 50, tag);
432 if (check_ref_format(ref))
433 die("'%s' is not a valid tag name.", tag);
435 if (!resolve_ref(ref, prev, 1, NULL))
436 hashclr(prev);
437 else if (!force)
438 die("tag '%s' already exists", tag);
440 if (annotate)
441 create_tag(object, tag, message, sign, object);
443 lock = lock_any_ref_for_update(ref, prev, 0);
444 if (!lock)
445 die("%s: cannot lock the ref", ref);
446 if (write_ref_sha1(lock, object, NULL) < 0)
447 die("%s: cannot update the ref", ref);
449 return 0;