Sync with maint
[git] / builtin / mktag.c
1 #include "builtin.h"
2 #include "parse-options.h"
3 #include "tag.h"
4 #include "replace-object.h"
5 #include "object-store.h"
6 #include "fsck.h"
7 #include "config.h"
8
9 static char const * const builtin_mktag_usage[] = {
10         N_("git mktag"),
11         NULL
12 };
13 static int option_strict = 1;
14
15 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
16
17 static int mktag_config(const char *var, const char *value, void *cb)
18 {
19         return fsck_config_internal(var, value, cb, &fsck_options);
20 }
21
22 static int mktag_fsck_error_func(struct fsck_options *o,
23                                  const struct object_id *oid,
24                                  enum object_type object_type,
25                                  int msg_type, const char *message)
26 {
27         switch (msg_type) {
28         case FSCK_WARN:
29                 if (!option_strict) {
30                         fprintf_ln(stderr, _("warning: tag input does not pass fsck: %s"), message);
31                         return 0;
32
33                 }
34                 /* fallthrough */
35         case FSCK_ERROR:
36                 /*
37                  * We treat both warnings and errors as errors, things
38                  * like missing "tagger" lines are "only" warnings
39                  * under fsck, we've always considered them an error.
40                  */
41                 fprintf_ln(stderr, _("error: tag input does not pass fsck: %s"), message);
42                 return 1;
43         default:
44                 BUG(_("%d (FSCK_IGNORE?) should never trigger this callback"),
45                     msg_type);
46         }
47 }
48
49 static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
50 {
51         int ret;
52         enum object_type type;
53         unsigned long size;
54         void *buffer;
55         const struct object_id *repl;
56
57         buffer = read_object_file(tagged_oid, &type, &size);
58         if (!buffer)
59                 die(_("could not read tagged object '%s'"),
60                     oid_to_hex(tagged_oid));
61         if (type != *tagged_type)
62                 die(_("object '%s' tagged as '%s', but is a '%s' type"),
63                     oid_to_hex(tagged_oid),
64                     type_name(*tagged_type), type_name(type));
65
66         repl = lookup_replace_object(the_repository, tagged_oid);
67         ret = check_object_signature(the_repository, repl,
68                                      buffer, size, type_name(*tagged_type));
69         free(buffer);
70
71         return ret;
72 }
73
74 int cmd_mktag(int argc, const char **argv, const char *prefix)
75 {
76         static struct option builtin_mktag_options[] = {
77                 OPT_BOOL(0, "strict", &option_strict,
78                          N_("enable more strict checking")),
79                 OPT_END(),
80         };
81         struct strbuf buf = STRBUF_INIT;
82         struct object_id tagged_oid;
83         int tagged_type;
84         struct object_id result;
85
86         argc = parse_options(argc, argv, NULL,
87                              builtin_mktag_options,
88                              builtin_mktag_usage, 0);
89
90         if (strbuf_read(&buf, 0, 0) < 0)
91                 die_errno(_("could not read from stdin"));
92
93         fsck_options.error_func = mktag_fsck_error_func;
94         fsck_set_msg_type(&fsck_options, "extraheaderentry", "warn");
95         /* config might set fsck.extraHeaderEntry=* again */
96         git_config(mktag_config, NULL);
97         if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
98                                 &tagged_oid, &tagged_type))
99                 die(_("tag on stdin did not pass our strict fsck check"));
100
101         if (verify_object_in_tag(&tagged_oid, &tagged_type))
102                 die(_("tag on stdin did not refer to a valid object"));
103
104         if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
105                 die(_("unable to write tag file"));
106
107         strbuf_release(&buf);
108         puts(oid_to_hex(&result));
109         return 0;
110 }