Make git tag a builtin.
[git/git.git] / builtin-tag.c
CommitLineData
62e09ce9
CR
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
20static void launch_editor(const char *path, char **buffer, unsigned long *len)
21{
22 const char *editor, *terminal;
23 struct child_process child;
24 const char *args[3];
25 int fd;
26
27 editor = getenv("VISUAL");
28 if (!editor)
29 editor = getenv("EDITOR");
30
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);
37 }
38
39 if (!editor)
40 editor = "vi";
41
42 memset(&child, 0, sizeof(child));
43 child.argv = args;
44 args[0] = editor;
45 args[1] = path;
46 args[2] = NULL;
47
48 if (run_command(&child))
49 die("There was a problem with the editor %s.", editor);
50
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));
58 }
59 close(fd);
60}
61
62struct tag_filter {
63 const char *pattern;
64 int lines;
65};
66
67#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
68
69static int show_reference(const char *refname, const unsigned char *sha1,
70 int flag, void *cb_data)
71{
72 struct tag_filter *filter = cb_data;
73
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;
80
81 if (!filter->lines) {
82 printf("%s\n", refname);
83 return 0;
84 }
85 printf("%-15s ", refname);
86
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;
106 }
107 putchar('\n');
108 free(buf);
109 }
110
111 return 0;
112}
113
114static int list_tags(const char *pattern, int lines)
115{
116 struct tag_filter filter;
117 char *newpattern;
118
119 if (pattern == NULL)
120 pattern = "";
121
122 /* prepend/append * to the shell pattern: */
123 newpattern = xmalloc(strlen(pattern) + 3);
124 sprintf(newpattern, "*%s*", pattern);
125
126 filter.pattern = newpattern;
127 filter.lines = lines;
128
129 for_each_tag_ref(show_reference, (void *) &filter);
130
131 free(newpattern);
132
133 return 0;
134}
135
136typedef int (*func_tag)(const char *name, const char *ref,
137 const unsigned char *sha1);
138
139static int do_tag_names(const char **argv, func_tag fn)
140{
141 const char **p;
142 char ref[PATH_MAX];
143 int had_error = 0;
144 unsigned char sha1[20];
145
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;
152 }
153 if (!resolve_ref(ref, sha1, 1, NULL)) {
154 error("tag '%s' not found.", *p);
155 had_error = 1;
156 continue;
157 }
158 if (fn(*p, ref, sha1))
159 had_error = 1;
160 }
161 return had_error;
162}
163
164static int delete_tag(const char *name, const char *ref,
165 const unsigned char *sha1)
166{
167 if (delete_ref(ref, sha1))
168 return 1;
169 printf("Deleted tag '%s'\n", name);
170 return 0;
171}
172
173static int verify_tag(const char *name, const char *ref,
174 const unsigned char *sha1)
175{
176 const char *argv_verify_tag[] = {"git-verify-tag",
177 "-v", "SHA1_HEX", NULL};
178 argv_verify_tag[2] = sha1_to_hex(sha1);
179
180 if (run_command_v_opt(argv_verify_tag, 0))
181 return error("could not verify the tag '%s'", name);
182 return 0;
183}
184
185static ssize_t do_sign(char *buffer, size_t size, size_t max)
186{
187 struct child_process gpg;
188 const char *args[4];
189 char *bracket;
190 int len;
191
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';
199 }
200
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;
209
210 if (start_command(&gpg))
211 return error("could not run gpg.");
212
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);
217
218 finish_command(&gpg);
219
220 if (len == max - size)
221 return error("could not read the entire signature from gpg.");
222
223 return size + len;
224}
225
226static const char tag_template[] =
227 "\n"
228 "#\n"
229 "# Write a tag message\n"
230 "#\n";
231
232static int git_tag_config(const char *var, const char *value)
233{
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;
241 }
242
243 return git_default_config(var, value);
244}
245
246#define MAX_SIGNATURE_LENGTH 1024
247/* message must be NULL or allocated, it will be reallocated and freed */
248static void create_tag(const unsigned char *object, const char *tag,
249 char *message, int sign, unsigned char *result)
250{
251 enum object_type type;
252 char header_buf[1024], *buffer;
253 int header_len, max_size;
254 unsigned long size;
255
256 type = sha1_object_info(object, NULL);
257 if (type <= 0)
258 die("bad object type.");
259
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));
269
270 if (header_len >= sizeof(header_buf))
271 die("tag header too big.");
272
273 if (!message) {
274 char *path;
275 int fd;
276
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);
285
286 launch_editor(path, &buffer, &size);
287
288 unlink(path);
289 free(path);
290 }
291 else {
292 buffer = message;
293 size = strlen(message);
294 }
295
296 size = stripspace(buffer, size, 1);
297
298 if (!message && !size)
299 die("no tag message?");
300
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;
309
310 if (sign) {
311 size = do_sign(buffer, size, max_size);
312 if (size < 0)
313 die("unable to sign the tag");
314 }
315
316 if (write_sha1_file(buffer, size, tag_type, result) < 0)
317 die("unable to write tag file");
318 free(buffer);
319}
320
321int cmd_tag(int argc, const char **argv, const char *prefix)
322{
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;
330
331 git_config(git_tag_config);
332
333 for (i = 1; i < argc; i++) {
334 const char *arg = argv[i];
335
336 if (arg[0] != '-')
337 break;
338 if (!strcmp(arg, "-a")) {
339 annotate = 1;
340 continue;
341 }
342 if (!strcmp(arg, "-s")) {
343 annotate = 1;
344 sign = 1;
345 continue;
346 }
347 if (!strcmp(arg, "-f")) {
348 force = 1;
349 continue;
350 }
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;
359 }
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;
367 }
368 if (!strcmp(arg, "-F")) {
369 unsigned long len;
370 int fd;
371
372 annotate = 1;
373 i++;
374 if (i == argc)
375 die("option -F needs an argument.");
376
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));
384 }
385 len = 1024;
386 message = xmalloc(len);
387 if (read_fd(fd, &message, &len)) {
388 free(message);
389 die("cannot read %s", argv[i]);
390 }
391 continue;
392 }
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;
403 }
404 if (!strcmp(arg, "-l")) {
405 return list_tags(argv[i + 1], lines);
406 }
407 if (!strcmp(arg, "-d")) {
408 return do_tag_names(argv + i + 1, delete_tag);
409 }
410 if (!strcmp(arg, "-v")) {
411 return do_tag_names(argv + i + 1, verify_tag);
412 }
413 usage(builtin_tag_usage);
414 }
415
416 if (i == argc) {
417 if (annotate)
418 usage(builtin_tag_usage);
419 return list_tags(NULL, lines);
420 }
421 tag = argv[i++];
422
423 object_ref = i < argc ? argv[i] : "HEAD";
424 if (i + 1 < argc)
425 die("too many params");
426
427 if (get_sha1(object_ref, object))
428 die("Failed to resolve '%s' as a valid ref.", object_ref);
429
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);
434
435 if (!resolve_ref(ref, prev, 1, NULL))
436 hashclr(prev);
437 else if (!force)
438 die("tag '%s' already exists", tag);
439
440 if (annotate)
441 create_tag(object, tag, message, sign, object);
442
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);
448
449 return 0;
450}