Merge branch 'sb/userdiff-dts'
[git] / builtin / commit-graph.c
1 #include "builtin.h"
2 #include "config.h"
3 #include "dir.h"
4 #include "lockfile.h"
5 #include "parse-options.h"
6 #include "repository.h"
7 #include "commit-graph.h"
8 #include "object-store.h"
9
10 static char const * const builtin_commit_graph_usage[] = {
11         N_("git commit-graph [--object-dir <objdir>]"),
12         N_("git commit-graph read [--object-dir <objdir>]"),
13         N_("git commit-graph verify [--object-dir <objdir>] [--shallow]"),
14         N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] <split options>"),
15         NULL
16 };
17
18 static const char * const builtin_commit_graph_verify_usage[] = {
19         N_("git commit-graph verify [--object-dir <objdir>] [--shallow]"),
20         NULL
21 };
22
23 static const char * const builtin_commit_graph_read_usage[] = {
24         N_("git commit-graph read [--object-dir <objdir>]"),
25         NULL
26 };
27
28 static const char * const builtin_commit_graph_write_usage[] = {
29         N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] <split options>"),
30         NULL
31 };
32
33 static struct opts_commit_graph {
34         const char *obj_dir;
35         int reachable;
36         int stdin_packs;
37         int stdin_commits;
38         int append;
39         int split;
40         int shallow;
41 } opts;
42
43 static int graph_verify(int argc, const char **argv)
44 {
45         struct commit_graph *graph = NULL;
46         char *graph_name;
47         int open_ok;
48         int fd;
49         struct stat st;
50         int flags = 0;
51
52         static struct option builtin_commit_graph_verify_options[] = {
53                 OPT_STRING(0, "object-dir", &opts.obj_dir,
54                            N_("dir"),
55                            N_("The object directory to store the graph")),
56                 OPT_BOOL(0, "shallow", &opts.shallow,
57                          N_("if the commit-graph is split, only verify the tip file")),
58                 OPT_END(),
59         };
60
61         argc = parse_options(argc, argv, NULL,
62                              builtin_commit_graph_verify_options,
63                              builtin_commit_graph_verify_usage, 0);
64
65         if (!opts.obj_dir)
66                 opts.obj_dir = get_object_directory();
67         if (opts.shallow)
68                 flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
69
70         graph_name = get_commit_graph_filename(opts.obj_dir);
71         open_ok = open_commit_graph(graph_name, &fd, &st);
72         if (!open_ok && errno != ENOENT)
73                 die_errno(_("Could not open commit-graph '%s'"), graph_name);
74
75         FREE_AND_NULL(graph_name);
76
77         if (open_ok)
78                 graph = load_commit_graph_one_fd_st(fd, &st);
79          else
80                 graph = read_commit_graph_one(the_repository, opts.obj_dir);
81
82         /* Return failure if open_ok predicted success */
83         if (!graph)
84                 return !!open_ok;
85
86         UNLEAK(graph);
87         return verify_commit_graph(the_repository, graph, flags);
88 }
89
90 static int graph_read(int argc, const char **argv)
91 {
92         struct commit_graph *graph = NULL;
93         char *graph_name;
94         int open_ok;
95         int fd;
96         struct stat st;
97
98         static struct option builtin_commit_graph_read_options[] = {
99                 OPT_STRING(0, "object-dir", &opts.obj_dir,
100                         N_("dir"),
101                         N_("The object directory to store the graph")),
102                 OPT_END(),
103         };
104
105         argc = parse_options(argc, argv, NULL,
106                              builtin_commit_graph_read_options,
107                              builtin_commit_graph_read_usage, 0);
108
109         if (!opts.obj_dir)
110                 opts.obj_dir = get_object_directory();
111
112         graph_name = get_commit_graph_filename(opts.obj_dir);
113
114         open_ok = open_commit_graph(graph_name, &fd, &st);
115         if (!open_ok)
116                 die_errno(_("Could not open commit-graph '%s'"), graph_name);
117
118         graph = load_commit_graph_one_fd_st(fd, &st);
119         if (!graph)
120                 return 1;
121
122         FREE_AND_NULL(graph_name);
123
124         printf("header: %08x %d %d %d %d\n",
125                 ntohl(*(uint32_t*)graph->data),
126                 *(unsigned char*)(graph->data + 4),
127                 *(unsigned char*)(graph->data + 5),
128                 *(unsigned char*)(graph->data + 6),
129                 *(unsigned char*)(graph->data + 7));
130         printf("num_commits: %u\n", graph->num_commits);
131         printf("chunks:");
132
133         if (graph->chunk_oid_fanout)
134                 printf(" oid_fanout");
135         if (graph->chunk_oid_lookup)
136                 printf(" oid_lookup");
137         if (graph->chunk_commit_data)
138                 printf(" commit_metadata");
139         if (graph->chunk_extra_edges)
140                 printf(" extra_edges");
141         printf("\n");
142
143         UNLEAK(graph);
144
145         return 0;
146 }
147
148 extern int read_replace_refs;
149 static struct split_commit_graph_opts split_opts;
150
151 static int graph_write(int argc, const char **argv)
152 {
153         struct string_list *pack_indexes = NULL;
154         struct string_list *commit_hex = NULL;
155         struct string_list lines;
156         int result = 0;
157         enum commit_graph_write_flags flags = COMMIT_GRAPH_WRITE_PROGRESS;
158
159         static struct option builtin_commit_graph_write_options[] = {
160                 OPT_STRING(0, "object-dir", &opts.obj_dir,
161                         N_("dir"),
162                         N_("The object directory to store the graph")),
163                 OPT_BOOL(0, "reachable", &opts.reachable,
164                         N_("start walk at all refs")),
165                 OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
166                         N_("scan pack-indexes listed by stdin for commits")),
167                 OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
168                         N_("start walk at commits listed by stdin")),
169                 OPT_BOOL(0, "append", &opts.append,
170                         N_("include all commits already in the commit-graph file")),
171                 OPT_BOOL(0, "split", &opts.split,
172                         N_("allow writing an incremental commit-graph file")),
173                 OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
174                         N_("maximum number of commits in a non-base split commit-graph")),
175                 OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
176                         N_("maximum ratio between two levels of a split commit-graph")),
177                 OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
178                         N_("maximum number of commits in a non-base split commit-graph")),
179                 OPT_END(),
180         };
181
182         split_opts.size_multiple = 2;
183         split_opts.max_commits = 0;
184         split_opts.expire_time = 0;
185
186         argc = parse_options(argc, argv, NULL,
187                              builtin_commit_graph_write_options,
188                              builtin_commit_graph_write_usage, 0);
189
190         if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
191                 die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
192         if (!opts.obj_dir)
193                 opts.obj_dir = get_object_directory();
194         if (opts.append)
195                 flags |= COMMIT_GRAPH_WRITE_APPEND;
196         if (opts.split)
197                 flags |= COMMIT_GRAPH_WRITE_SPLIT;
198
199         read_replace_refs = 0;
200
201         if (opts.reachable) {
202                 if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
203                         return 1;
204                 return 0;
205         }
206
207         string_list_init(&lines, 0);
208         if (opts.stdin_packs || opts.stdin_commits) {
209                 struct strbuf buf = STRBUF_INIT;
210
211                 while (strbuf_getline(&buf, stdin) != EOF)
212                         string_list_append(&lines, strbuf_detach(&buf, NULL));
213
214                 if (opts.stdin_packs)
215                         pack_indexes = &lines;
216                 if (opts.stdin_commits) {
217                         commit_hex = &lines;
218                         flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
219                 }
220
221                 UNLEAK(buf);
222         }
223
224         if (write_commit_graph(opts.obj_dir,
225                                pack_indexes,
226                                commit_hex,
227                                flags,
228                                &split_opts))
229                 result = 1;
230
231         UNLEAK(lines);
232         return result;
233 }
234
235 int cmd_commit_graph(int argc, const char **argv, const char *prefix)
236 {
237         static struct option builtin_commit_graph_options[] = {
238                 OPT_STRING(0, "object-dir", &opts.obj_dir,
239                         N_("dir"),
240                         N_("The object directory to store the graph")),
241                 OPT_END(),
242         };
243
244         if (argc == 2 && !strcmp(argv[1], "-h"))
245                 usage_with_options(builtin_commit_graph_usage,
246                                    builtin_commit_graph_options);
247
248         git_config(git_default_config, NULL);
249         argc = parse_options(argc, argv, prefix,
250                              builtin_commit_graph_options,
251                              builtin_commit_graph_usage,
252                              PARSE_OPT_STOP_AT_NON_OPTION);
253
254         if (argc > 0) {
255                 if (!strcmp(argv[0], "read"))
256                         return graph_read(argc, argv);
257                 if (!strcmp(argv[0], "verify"))
258                         return graph_verify(argc, argv);
259                 if (!strcmp(argv[0], "write"))
260                         return graph_write(argc, argv);
261         }
262
263         usage_with_options(builtin_commit_graph_usage,
264                            builtin_commit_graph_options);
265 }