Blame


1 624411d2 2023-07-08 jrick /*
2 624411d2 2023-07-08 jrick * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 624411d2 2023-07-08 jrick * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 624411d2 2023-07-08 jrick * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 3d1b16d1 2023-07-08 jrick * Copyright (C) 2023 Josh Rickmar <jrick@zettaport.com>
6 624411d2 2023-07-08 jrick *
7 624411d2 2023-07-08 jrick * Permission to use, copy, modify, and distribute this software for any
8 624411d2 2023-07-08 jrick * purpose with or without fee is hereby granted, provided that the above
9 624411d2 2023-07-08 jrick * copyright notice and this permission notice appear in all copies.
10 624411d2 2023-07-08 jrick *
11 624411d2 2023-07-08 jrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 624411d2 2023-07-08 jrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 624411d2 2023-07-08 jrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 624411d2 2023-07-08 jrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 624411d2 2023-07-08 jrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 624411d2 2023-07-08 jrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 624411d2 2023-07-08 jrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 624411d2 2023-07-08 jrick */
19 624411d2 2023-07-08 jrick
20 624411d2 2023-07-08 jrick #include <sys/queue.h>
21 624411d2 2023-07-08 jrick #include <sys/time.h>
22 624411d2 2023-07-08 jrick #include <sys/types.h>
23 624411d2 2023-07-08 jrick #include <sys/stat.h>
24 624411d2 2023-07-08 jrick #include <sys/wait.h>
25 624411d2 2023-07-08 jrick
26 624411d2 2023-07-08 jrick #include <err.h>
27 624411d2 2023-07-08 jrick #include <errno.h>
28 624411d2 2023-07-08 jrick #include <fcntl.h>
29 624411d2 2023-07-08 jrick #include <limits.h>
30 624411d2 2023-07-08 jrick #include <locale.h>
31 624411d2 2023-07-08 jrick #include <ctype.h>
32 624411d2 2023-07-08 jrick #include <sha1.h>
33 624411d2 2023-07-08 jrick #include <sha2.h>
34 624411d2 2023-07-08 jrick #include <signal.h>
35 624411d2 2023-07-08 jrick #include <stdio.h>
36 624411d2 2023-07-08 jrick #include <stdlib.h>
37 624411d2 2023-07-08 jrick #include <string.h>
38 624411d2 2023-07-08 jrick #include <unistd.h>
39 624411d2 2023-07-08 jrick #include <libgen.h>
40 624411d2 2023-07-08 jrick #include <time.h>
41 624411d2 2023-07-08 jrick #include <paths.h>
42 624411d2 2023-07-08 jrick #include <regex.h>
43 624411d2 2023-07-08 jrick #include <getopt.h>
44 624411d2 2023-07-08 jrick #include <util.h>
45 624411d2 2023-07-08 jrick
46 624411d2 2023-07-08 jrick #include "got_version.h"
47 624411d2 2023-07-08 jrick #include "got_error.h"
48 624411d2 2023-07-08 jrick #include "got_object.h"
49 624411d2 2023-07-08 jrick #include "got_reference.h"
50 624411d2 2023-07-08 jrick #include "got_repository.h"
51 624411d2 2023-07-08 jrick #include "got_path.h"
52 624411d2 2023-07-08 jrick #include "got_cancel.h"
53 624411d2 2023-07-08 jrick #include "got_worktree.h"
54 3d1b16d1 2023-07-08 jrick #include "got_worktree_cvg.h"
55 624411d2 2023-07-08 jrick #include "got_diff.h"
56 624411d2 2023-07-08 jrick #include "got_commit_graph.h"
57 624411d2 2023-07-08 jrick #include "got_fetch.h"
58 624411d2 2023-07-08 jrick #include "got_send.h"
59 624411d2 2023-07-08 jrick #include "got_blame.h"
60 624411d2 2023-07-08 jrick #include "got_privsep.h"
61 624411d2 2023-07-08 jrick #include "got_opentemp.h"
62 624411d2 2023-07-08 jrick #include "got_gotconfig.h"
63 624411d2 2023-07-08 jrick #include "got_dial.h"
64 624411d2 2023-07-08 jrick #include "got_patch.h"
65 624411d2 2023-07-08 jrick #include "got_sigs.h"
66 624411d2 2023-07-08 jrick #include "got_date.h"
67 624411d2 2023-07-08 jrick
68 624411d2 2023-07-08 jrick #ifndef nitems
69 624411d2 2023-07-08 jrick #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
70 624411d2 2023-07-08 jrick #endif
71 624411d2 2023-07-08 jrick
72 624411d2 2023-07-08 jrick static volatile sig_atomic_t sigint_received;
73 624411d2 2023-07-08 jrick static volatile sig_atomic_t sigpipe_received;
74 624411d2 2023-07-08 jrick
75 624411d2 2023-07-08 jrick static void
76 624411d2 2023-07-08 jrick catch_sigint(int signo)
77 624411d2 2023-07-08 jrick {
78 624411d2 2023-07-08 jrick sigint_received = 1;
79 624411d2 2023-07-08 jrick }
80 624411d2 2023-07-08 jrick
81 624411d2 2023-07-08 jrick static void
82 624411d2 2023-07-08 jrick catch_sigpipe(int signo)
83 624411d2 2023-07-08 jrick {
84 624411d2 2023-07-08 jrick sigpipe_received = 1;
85 624411d2 2023-07-08 jrick }
86 624411d2 2023-07-08 jrick
87 624411d2 2023-07-08 jrick
88 624411d2 2023-07-08 jrick struct got_cmd {
89 624411d2 2023-07-08 jrick const char *cmd_name;
90 624411d2 2023-07-08 jrick const struct got_error *(*cmd_main)(int, char *[]);
91 624411d2 2023-07-08 jrick void (*cmd_usage)(void);
92 624411d2 2023-07-08 jrick const char *cmd_alias;
93 624411d2 2023-07-08 jrick };
94 624411d2 2023-07-08 jrick
95 624411d2 2023-07-08 jrick __dead static void usage(int, int);
96 624411d2 2023-07-08 jrick __dead static void usage_import(void);
97 624411d2 2023-07-08 jrick __dead static void usage_clone(void);
98 624411d2 2023-07-08 jrick __dead static void usage_fetch(void);
99 624411d2 2023-07-08 jrick __dead static void usage_checkout(void);
100 624411d2 2023-07-08 jrick __dead static void usage_update(void);
101 624411d2 2023-07-08 jrick __dead static void usage_log(void);
102 624411d2 2023-07-08 jrick __dead static void usage_diff(void);
103 624411d2 2023-07-08 jrick __dead static void usage_blame(void);
104 624411d2 2023-07-08 jrick __dead static void usage_tree(void);
105 624411d2 2023-07-08 jrick __dead static void usage_status(void);
106 624411d2 2023-07-08 jrick __dead static void usage_ref(void);
107 624411d2 2023-07-08 jrick __dead static void usage_branch(void);
108 624411d2 2023-07-08 jrick __dead static void usage_tag(void);
109 624411d2 2023-07-08 jrick __dead static void usage_add(void);
110 624411d2 2023-07-08 jrick __dead static void usage_remove(void);
111 624411d2 2023-07-08 jrick __dead static void usage_patch(void);
112 624411d2 2023-07-08 jrick __dead static void usage_revert(void);
113 624411d2 2023-07-08 jrick __dead static void usage_commit(void);
114 624411d2 2023-07-08 jrick __dead static void usage_send(void);
115 624411d2 2023-07-08 jrick __dead static void usage_cherrypick(void);
116 624411d2 2023-07-08 jrick __dead static void usage_backout(void);
117 624411d2 2023-07-08 jrick __dead static void usage_rebase(void);
118 624411d2 2023-07-08 jrick __dead static void usage_histedit(void);
119 624411d2 2023-07-08 jrick __dead static void usage_integrate(void);
120 624411d2 2023-07-08 jrick __dead static void usage_merge(void);
121 624411d2 2023-07-08 jrick __dead static void usage_stage(void);
122 624411d2 2023-07-08 jrick __dead static void usage_unstage(void);
123 624411d2 2023-07-08 jrick __dead static void usage_cat(void);
124 624411d2 2023-07-08 jrick __dead static void usage_info(void);
125 624411d2 2023-07-08 jrick
126 624411d2 2023-07-08 jrick static const struct got_error* cmd_import(int, char *[]);
127 624411d2 2023-07-08 jrick static const struct got_error* cmd_clone(int, char *[]);
128 624411d2 2023-07-08 jrick static const struct got_error* cmd_fetch(int, char *[]);
129 624411d2 2023-07-08 jrick static const struct got_error* cmd_checkout(int, char *[]);
130 624411d2 2023-07-08 jrick static const struct got_error* cmd_update(int, char *[]);
131 624411d2 2023-07-08 jrick static const struct got_error* cmd_log(int, char *[]);
132 624411d2 2023-07-08 jrick static const struct got_error* cmd_diff(int, char *[]);
133 624411d2 2023-07-08 jrick static const struct got_error* cmd_blame(int, char *[]);
134 624411d2 2023-07-08 jrick static const struct got_error* cmd_tree(int, char *[]);
135 624411d2 2023-07-08 jrick static const struct got_error* cmd_status(int, char *[]);
136 624411d2 2023-07-08 jrick static const struct got_error* cmd_ref(int, char *[]);
137 624411d2 2023-07-08 jrick static const struct got_error* cmd_branch(int, char *[]);
138 624411d2 2023-07-08 jrick static const struct got_error* cmd_tag(int, char *[]);
139 624411d2 2023-07-08 jrick static const struct got_error* cmd_add(int, char *[]);
140 624411d2 2023-07-08 jrick static const struct got_error* cmd_remove(int, char *[]);
141 624411d2 2023-07-08 jrick static const struct got_error* cmd_patch(int, char *[]);
142 624411d2 2023-07-08 jrick static const struct got_error* cmd_revert(int, char *[]);
143 624411d2 2023-07-08 jrick static const struct got_error* cmd_commit(int, char *[]);
144 624411d2 2023-07-08 jrick static const struct got_error* cmd_send(int, char *[]);
145 624411d2 2023-07-08 jrick static const struct got_error* cmd_cherrypick(int, char *[]);
146 624411d2 2023-07-08 jrick static const struct got_error* cmd_backout(int, char *[]);
147 624411d2 2023-07-08 jrick static const struct got_error* cmd_rebase(int, char *[]);
148 624411d2 2023-07-08 jrick static const struct got_error* cmd_histedit(int, char *[]);
149 624411d2 2023-07-08 jrick static const struct got_error* cmd_integrate(int, char *[]);
150 624411d2 2023-07-08 jrick static const struct got_error* cmd_merge(int, char *[]);
151 624411d2 2023-07-08 jrick static const struct got_error* cmd_stage(int, char *[]);
152 624411d2 2023-07-08 jrick static const struct got_error* cmd_unstage(int, char *[]);
153 624411d2 2023-07-08 jrick static const struct got_error* cmd_cat(int, char *[]);
154 624411d2 2023-07-08 jrick static const struct got_error* cmd_info(int, char *[]);
155 624411d2 2023-07-08 jrick
156 624411d2 2023-07-08 jrick static const struct got_cmd got_commands[] = {
157 624411d2 2023-07-08 jrick { "import", cmd_import, usage_import, "im" },
158 624411d2 2023-07-08 jrick { "clone", cmd_clone, usage_clone, "cl" },
159 3d1b16d1 2023-07-08 jrick /*{ "fetch", cmd_fetch, usage_fetch, "fe" },*/ /* rolled into update */
160 624411d2 2023-07-08 jrick { "checkout", cmd_checkout, usage_checkout, "co" },
161 624411d2 2023-07-08 jrick { "update", cmd_update, usage_update, "up" },
162 624411d2 2023-07-08 jrick { "log", cmd_log, usage_log, "" },
163 624411d2 2023-07-08 jrick { "diff", cmd_diff, usage_diff, "di" },
164 624411d2 2023-07-08 jrick { "blame", cmd_blame, usage_blame, "bl" },
165 624411d2 2023-07-08 jrick { "tree", cmd_tree, usage_tree, "tr" },
166 624411d2 2023-07-08 jrick { "status", cmd_status, usage_status, "st" },
167 624411d2 2023-07-08 jrick { "ref", cmd_ref, usage_ref, "" },
168 3d1b16d1 2023-07-08 jrick /*{ "branch", cmd_branch, usage_branch, "br" },*/
169 624411d2 2023-07-08 jrick { "tag", cmd_tag, usage_tag, "" },
170 624411d2 2023-07-08 jrick { "add", cmd_add, usage_add, "" },
171 624411d2 2023-07-08 jrick { "remove", cmd_remove, usage_remove, "rm" },
172 624411d2 2023-07-08 jrick { "patch", cmd_patch, usage_patch, "pa" },
173 624411d2 2023-07-08 jrick { "revert", cmd_revert, usage_revert, "rv" },
174 624411d2 2023-07-08 jrick { "commit", cmd_commit, usage_commit, "ci" },
175 3d1b16d1 2023-07-08 jrick /*{ "send", cmd_send, usage_send, "se" },*/ /* part of commit */
176 624411d2 2023-07-08 jrick { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
177 624411d2 2023-07-08 jrick { "backout", cmd_backout, usage_backout, "bo" },
178 3d1b16d1 2023-07-08 jrick /*{ "rebase", cmd_rebase, usage_rebase, "rb" },*/
179 3d1b16d1 2023-07-08 jrick /*{ "histedit", cmd_histedit, usage_histedit, "he" },*/
180 3d1b16d1 2023-07-08 jrick /*{ "integrate", cmd_integrate, usage_integrate,"ig" },*/
181 3d1b16d1 2023-07-08 jrick /*{ "merge", cmd_merge, usage_merge, "mg" },*/
182 3d1b16d1 2023-07-08 jrick /*{ "stage", cmd_stage, usage_stage, "sg" },*/
183 3d1b16d1 2023-07-08 jrick /*{ "unstage", cmd_unstage, usage_unstage, "ug" },*/
184 624411d2 2023-07-08 jrick { "cat", cmd_cat, usage_cat, "" },
185 624411d2 2023-07-08 jrick { "info", cmd_info, usage_info, "" },
186 624411d2 2023-07-08 jrick };
187 624411d2 2023-07-08 jrick
188 624411d2 2023-07-08 jrick static void
189 624411d2 2023-07-08 jrick list_commands(FILE *fp)
190 624411d2 2023-07-08 jrick {
191 624411d2 2023-07-08 jrick size_t i;
192 624411d2 2023-07-08 jrick
193 624411d2 2023-07-08 jrick fprintf(fp, "commands:");
194 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
195 624411d2 2023-07-08 jrick const struct got_cmd *cmd = &got_commands[i];
196 624411d2 2023-07-08 jrick fprintf(fp, " %s", cmd->cmd_name);
197 624411d2 2023-07-08 jrick }
198 624411d2 2023-07-08 jrick fputc('\n', fp);
199 624411d2 2023-07-08 jrick }
200 624411d2 2023-07-08 jrick
201 624411d2 2023-07-08 jrick __dead static void
202 624411d2 2023-07-08 jrick option_conflict(char a, char b)
203 624411d2 2023-07-08 jrick {
204 624411d2 2023-07-08 jrick errx(1, "-%c and -%c options are mutually exclusive", a, b);
205 624411d2 2023-07-08 jrick }
206 624411d2 2023-07-08 jrick
207 624411d2 2023-07-08 jrick int
208 624411d2 2023-07-08 jrick main(int argc, char *argv[])
209 624411d2 2023-07-08 jrick {
210 624411d2 2023-07-08 jrick const struct got_cmd *cmd;
211 624411d2 2023-07-08 jrick size_t i;
212 624411d2 2023-07-08 jrick int ch;
213 624411d2 2023-07-08 jrick int hflag = 0, Vflag = 0;
214 624411d2 2023-07-08 jrick static const struct option longopts[] = {
215 624411d2 2023-07-08 jrick { "version", no_argument, NULL, 'V' },
216 624411d2 2023-07-08 jrick { NULL, 0, NULL, 0 }
217 624411d2 2023-07-08 jrick };
218 624411d2 2023-07-08 jrick
219 624411d2 2023-07-08 jrick setlocale(LC_CTYPE, "");
220 624411d2 2023-07-08 jrick
221 624411d2 2023-07-08 jrick while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
222 624411d2 2023-07-08 jrick switch (ch) {
223 624411d2 2023-07-08 jrick case 'h':
224 624411d2 2023-07-08 jrick hflag = 1;
225 624411d2 2023-07-08 jrick break;
226 624411d2 2023-07-08 jrick case 'V':
227 624411d2 2023-07-08 jrick Vflag = 1;
228 624411d2 2023-07-08 jrick break;
229 624411d2 2023-07-08 jrick default:
230 624411d2 2023-07-08 jrick usage(hflag, 1);
231 624411d2 2023-07-08 jrick /* NOTREACHED */
232 624411d2 2023-07-08 jrick }
233 624411d2 2023-07-08 jrick }
234 624411d2 2023-07-08 jrick
235 624411d2 2023-07-08 jrick argc -= optind;
236 624411d2 2023-07-08 jrick argv += optind;
237 624411d2 2023-07-08 jrick optind = 1;
238 624411d2 2023-07-08 jrick optreset = 1;
239 624411d2 2023-07-08 jrick
240 624411d2 2023-07-08 jrick if (Vflag) {
241 624411d2 2023-07-08 jrick got_version_print_str();
242 624411d2 2023-07-08 jrick return 0;
243 624411d2 2023-07-08 jrick }
244 624411d2 2023-07-08 jrick
245 624411d2 2023-07-08 jrick if (argc <= 0)
246 624411d2 2023-07-08 jrick usage(hflag, hflag ? 0 : 1);
247 624411d2 2023-07-08 jrick
248 624411d2 2023-07-08 jrick signal(SIGINT, catch_sigint);
249 624411d2 2023-07-08 jrick signal(SIGPIPE, catch_sigpipe);
250 624411d2 2023-07-08 jrick
251 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
252 624411d2 2023-07-08 jrick const struct got_error *error;
253 624411d2 2023-07-08 jrick
254 624411d2 2023-07-08 jrick cmd = &got_commands[i];
255 624411d2 2023-07-08 jrick
256 624411d2 2023-07-08 jrick if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
257 624411d2 2023-07-08 jrick strcmp(cmd->cmd_alias, argv[0]) != 0)
258 624411d2 2023-07-08 jrick continue;
259 624411d2 2023-07-08 jrick
260 624411d2 2023-07-08 jrick if (hflag)
261 624411d2 2023-07-08 jrick cmd->cmd_usage();
262 624411d2 2023-07-08 jrick
263 624411d2 2023-07-08 jrick error = cmd->cmd_main(argc, argv);
264 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_CANCELLED &&
265 624411d2 2023-07-08 jrick error->code != GOT_ERR_PRIVSEP_EXIT &&
266 624411d2 2023-07-08 jrick !(sigpipe_received &&
267 624411d2 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
268 624411d2 2023-07-08 jrick !(sigint_received &&
269 624411d2 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EINTR)) {
270 624411d2 2023-07-08 jrick fflush(stdout);
271 624411d2 2023-07-08 jrick fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
272 624411d2 2023-07-08 jrick return 1;
273 624411d2 2023-07-08 jrick }
274 624411d2 2023-07-08 jrick
275 624411d2 2023-07-08 jrick return 0;
276 624411d2 2023-07-08 jrick }
277 624411d2 2023-07-08 jrick
278 624411d2 2023-07-08 jrick fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
279 624411d2 2023-07-08 jrick list_commands(stderr);
280 624411d2 2023-07-08 jrick return 1;
281 624411d2 2023-07-08 jrick }
282 624411d2 2023-07-08 jrick
283 624411d2 2023-07-08 jrick __dead static void
284 624411d2 2023-07-08 jrick usage(int hflag, int status)
285 624411d2 2023-07-08 jrick {
286 624411d2 2023-07-08 jrick FILE *fp = (status == 0) ? stdout : stderr;
287 624411d2 2023-07-08 jrick
288 624411d2 2023-07-08 jrick fprintf(fp, "usage: %s [-hV] command [arg ...]\n",
289 624411d2 2023-07-08 jrick getprogname());
290 624411d2 2023-07-08 jrick if (hflag)
291 624411d2 2023-07-08 jrick list_commands(fp);
292 624411d2 2023-07-08 jrick exit(status);
293 624411d2 2023-07-08 jrick }
294 624411d2 2023-07-08 jrick
295 624411d2 2023-07-08 jrick static const struct got_error *
296 624411d2 2023-07-08 jrick get_editor(char **abspath)
297 624411d2 2023-07-08 jrick {
298 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
299 624411d2 2023-07-08 jrick const char *editor;
300 624411d2 2023-07-08 jrick
301 624411d2 2023-07-08 jrick *abspath = NULL;
302 624411d2 2023-07-08 jrick
303 624411d2 2023-07-08 jrick editor = getenv("VISUAL");
304 624411d2 2023-07-08 jrick if (editor == NULL)
305 624411d2 2023-07-08 jrick editor = getenv("EDITOR");
306 624411d2 2023-07-08 jrick
307 624411d2 2023-07-08 jrick if (editor) {
308 624411d2 2023-07-08 jrick err = got_path_find_prog(abspath, editor);
309 624411d2 2023-07-08 jrick if (err)
310 624411d2 2023-07-08 jrick return err;
311 624411d2 2023-07-08 jrick }
312 624411d2 2023-07-08 jrick
313 624411d2 2023-07-08 jrick if (*abspath == NULL) {
314 624411d2 2023-07-08 jrick *abspath = strdup("/usr/bin/vi");
315 624411d2 2023-07-08 jrick if (*abspath == NULL)
316 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
317 624411d2 2023-07-08 jrick }
318 624411d2 2023-07-08 jrick
319 624411d2 2023-07-08 jrick return NULL;
320 624411d2 2023-07-08 jrick }
321 624411d2 2023-07-08 jrick
322 624411d2 2023-07-08 jrick static const struct got_error *
323 624411d2 2023-07-08 jrick apply_unveil(const char *repo_path, int repo_read_only,
324 624411d2 2023-07-08 jrick const char *worktree_path)
325 624411d2 2023-07-08 jrick {
326 624411d2 2023-07-08 jrick const struct got_error *err;
327 624411d2 2023-07-08 jrick
328 624411d2 2023-07-08 jrick #ifdef PROFILE
329 624411d2 2023-07-08 jrick if (unveil("gmon.out", "rwc") != 0)
330 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", "gmon.out");
331 624411d2 2023-07-08 jrick #endif
332 624411d2 2023-07-08 jrick if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
333 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", repo_path);
334 624411d2 2023-07-08 jrick
335 624411d2 2023-07-08 jrick if (worktree_path && unveil(worktree_path, "rwc") != 0)
336 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", worktree_path);
337 624411d2 2023-07-08 jrick
338 624411d2 2023-07-08 jrick if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
339 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
340 624411d2 2023-07-08 jrick
341 624411d2 2023-07-08 jrick err = got_privsep_unveil_exec_helpers();
342 624411d2 2023-07-08 jrick if (err != NULL)
343 624411d2 2023-07-08 jrick return err;
344 624411d2 2023-07-08 jrick
345 624411d2 2023-07-08 jrick if (unveil(NULL, NULL) != 0)
346 624411d2 2023-07-08 jrick return got_error_from_errno("unveil");
347 624411d2 2023-07-08 jrick
348 624411d2 2023-07-08 jrick return NULL;
349 624411d2 2023-07-08 jrick }
350 624411d2 2023-07-08 jrick
351 624411d2 2023-07-08 jrick __dead static void
352 624411d2 2023-07-08 jrick usage_import(void)
353 624411d2 2023-07-08 jrick {
354 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] "
355 624411d2 2023-07-08 jrick "[-r repository-path] directory\n", getprogname());
356 624411d2 2023-07-08 jrick exit(1);
357 624411d2 2023-07-08 jrick }
358 624411d2 2023-07-08 jrick
359 624411d2 2023-07-08 jrick static int
360 624411d2 2023-07-08 jrick spawn_editor(const char *editor, const char *file)
361 624411d2 2023-07-08 jrick {
362 624411d2 2023-07-08 jrick pid_t pid;
363 624411d2 2023-07-08 jrick sig_t sighup, sigint, sigquit;
364 624411d2 2023-07-08 jrick int st = -1;
365 624411d2 2023-07-08 jrick
366 624411d2 2023-07-08 jrick sighup = signal(SIGHUP, SIG_IGN);
367 624411d2 2023-07-08 jrick sigint = signal(SIGINT, SIG_IGN);
368 624411d2 2023-07-08 jrick sigquit = signal(SIGQUIT, SIG_IGN);
369 624411d2 2023-07-08 jrick
370 624411d2 2023-07-08 jrick switch (pid = fork()) {
371 624411d2 2023-07-08 jrick case -1:
372 624411d2 2023-07-08 jrick goto doneediting;
373 624411d2 2023-07-08 jrick case 0:
374 624411d2 2023-07-08 jrick execl(editor, editor, file, (char *)NULL);
375 624411d2 2023-07-08 jrick _exit(127);
376 624411d2 2023-07-08 jrick }
377 624411d2 2023-07-08 jrick
378 624411d2 2023-07-08 jrick while (waitpid(pid, &st, 0) == -1)
379 624411d2 2023-07-08 jrick if (errno != EINTR)
380 624411d2 2023-07-08 jrick break;
381 624411d2 2023-07-08 jrick
382 624411d2 2023-07-08 jrick doneediting:
383 624411d2 2023-07-08 jrick (void)signal(SIGHUP, sighup);
384 624411d2 2023-07-08 jrick (void)signal(SIGINT, sigint);
385 624411d2 2023-07-08 jrick (void)signal(SIGQUIT, sigquit);
386 624411d2 2023-07-08 jrick
387 624411d2 2023-07-08 jrick if (!WIFEXITED(st)) {
388 624411d2 2023-07-08 jrick errno = EINTR;
389 624411d2 2023-07-08 jrick return -1;
390 624411d2 2023-07-08 jrick }
391 624411d2 2023-07-08 jrick
392 624411d2 2023-07-08 jrick return WEXITSTATUS(st);
393 624411d2 2023-07-08 jrick }
394 624411d2 2023-07-08 jrick
395 624411d2 2023-07-08 jrick static const struct got_error *
396 624411d2 2023-07-08 jrick read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize)
397 624411d2 2023-07-08 jrick {
398 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
399 624411d2 2023-07-08 jrick char *line = NULL;
400 624411d2 2023-07-08 jrick size_t linesize = 0;
401 624411d2 2023-07-08 jrick
402 624411d2 2023-07-08 jrick *logmsg = NULL;
403 624411d2 2023-07-08 jrick *len = 0;
404 624411d2 2023-07-08 jrick
405 624411d2 2023-07-08 jrick if (fseeko(fp, 0L, SEEK_SET) == -1)
406 624411d2 2023-07-08 jrick return got_error_from_errno("fseeko");
407 624411d2 2023-07-08 jrick
408 624411d2 2023-07-08 jrick *logmsg = malloc(filesize + 1);
409 624411d2 2023-07-08 jrick if (*logmsg == NULL)
410 624411d2 2023-07-08 jrick return got_error_from_errno("malloc");
411 624411d2 2023-07-08 jrick (*logmsg)[0] = '\0';
412 624411d2 2023-07-08 jrick
413 624411d2 2023-07-08 jrick while (getline(&line, &linesize, fp) != -1) {
414 624411d2 2023-07-08 jrick if (line[0] == '#' || (*len == 0 && line[0] == '\n'))
415 624411d2 2023-07-08 jrick continue; /* remove comments and leading empty lines */
416 624411d2 2023-07-08 jrick *len = strlcat(*logmsg, line, filesize + 1);
417 624411d2 2023-07-08 jrick if (*len >= filesize + 1) {
418 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
419 624411d2 2023-07-08 jrick goto done;
420 624411d2 2023-07-08 jrick }
421 624411d2 2023-07-08 jrick }
422 624411d2 2023-07-08 jrick if (ferror(fp)) {
423 624411d2 2023-07-08 jrick err = got_ferror(fp, GOT_ERR_IO);
424 624411d2 2023-07-08 jrick goto done;
425 624411d2 2023-07-08 jrick }
426 624411d2 2023-07-08 jrick
427 624411d2 2023-07-08 jrick while (*len > 0 && (*logmsg)[*len - 1] == '\n') {
428 624411d2 2023-07-08 jrick (*logmsg)[*len - 1] = '\0';
429 624411d2 2023-07-08 jrick (*len)--;
430 624411d2 2023-07-08 jrick }
431 624411d2 2023-07-08 jrick done:
432 624411d2 2023-07-08 jrick free(line);
433 624411d2 2023-07-08 jrick if (err) {
434 624411d2 2023-07-08 jrick free(*logmsg);
435 624411d2 2023-07-08 jrick *logmsg = NULL;
436 624411d2 2023-07-08 jrick *len = 0;
437 624411d2 2023-07-08 jrick }
438 624411d2 2023-07-08 jrick return err;
439 624411d2 2023-07-08 jrick }
440 624411d2 2023-07-08 jrick
441 624411d2 2023-07-08 jrick static const struct got_error *
442 624411d2 2023-07-08 jrick edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
443 624411d2 2023-07-08 jrick const char *initial_content, size_t initial_content_len,
444 624411d2 2023-07-08 jrick int require_modification)
445 624411d2 2023-07-08 jrick {
446 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
447 624411d2 2023-07-08 jrick struct stat st, st2;
448 624411d2 2023-07-08 jrick FILE *fp = NULL;
449 624411d2 2023-07-08 jrick size_t logmsg_len;
450 624411d2 2023-07-08 jrick
451 624411d2 2023-07-08 jrick *logmsg = NULL;
452 624411d2 2023-07-08 jrick
453 624411d2 2023-07-08 jrick if (stat(logmsg_path, &st) == -1)
454 624411d2 2023-07-08 jrick return got_error_from_errno2("stat", logmsg_path);
455 624411d2 2023-07-08 jrick
456 624411d2 2023-07-08 jrick if (spawn_editor(editor, logmsg_path) == -1)
457 624411d2 2023-07-08 jrick return got_error_from_errno("failed spawning editor");
458 624411d2 2023-07-08 jrick
459 624411d2 2023-07-08 jrick if (require_modification) {
460 624411d2 2023-07-08 jrick struct timespec timeout;
461 624411d2 2023-07-08 jrick
462 624411d2 2023-07-08 jrick timeout.tv_sec = 0;
463 624411d2 2023-07-08 jrick timeout.tv_nsec = 1;
464 624411d2 2023-07-08 jrick nanosleep(&timeout, NULL);
465 624411d2 2023-07-08 jrick }
466 624411d2 2023-07-08 jrick
467 624411d2 2023-07-08 jrick if (stat(logmsg_path, &st2) == -1)
468 624411d2 2023-07-08 jrick return got_error_from_errno("stat");
469 624411d2 2023-07-08 jrick
470 624411d2 2023-07-08 jrick if (require_modification && st.st_size == st2.st_size &&
471 624411d2 2023-07-08 jrick timespeccmp(&st.st_mtim, &st2.st_mtim, ==))
472 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
473 624411d2 2023-07-08 jrick "no changes made to commit message, aborting");
474 624411d2 2023-07-08 jrick
475 624411d2 2023-07-08 jrick fp = fopen(logmsg_path, "re");
476 624411d2 2023-07-08 jrick if (fp == NULL) {
477 624411d2 2023-07-08 jrick err = got_error_from_errno("fopen");
478 624411d2 2023-07-08 jrick goto done;
479 624411d2 2023-07-08 jrick }
480 624411d2 2023-07-08 jrick
481 624411d2 2023-07-08 jrick /* strip comments and leading/trailing newlines */
482 624411d2 2023-07-08 jrick err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size);
483 624411d2 2023-07-08 jrick if (err)
484 624411d2 2023-07-08 jrick goto done;
485 624411d2 2023-07-08 jrick if (logmsg_len == 0) {
486 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
487 624411d2 2023-07-08 jrick "commit message cannot be empty, aborting");
488 624411d2 2023-07-08 jrick goto done;
489 624411d2 2023-07-08 jrick }
490 624411d2 2023-07-08 jrick done:
491 624411d2 2023-07-08 jrick if (fp && fclose(fp) == EOF && err == NULL)
492 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
493 624411d2 2023-07-08 jrick if (err) {
494 624411d2 2023-07-08 jrick free(*logmsg);
495 624411d2 2023-07-08 jrick *logmsg = NULL;
496 624411d2 2023-07-08 jrick }
497 624411d2 2023-07-08 jrick return err;
498 624411d2 2023-07-08 jrick }
499 624411d2 2023-07-08 jrick
500 624411d2 2023-07-08 jrick static const struct got_error *
501 624411d2 2023-07-08 jrick collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
502 624411d2 2023-07-08 jrick const char *path_dir, const char *branch_name)
503 624411d2 2023-07-08 jrick {
504 624411d2 2023-07-08 jrick char *initial_content = NULL;
505 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
506 624411d2 2023-07-08 jrick int initial_content_len;
507 624411d2 2023-07-08 jrick int fd = -1;
508 624411d2 2023-07-08 jrick
509 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
510 624411d2 2023-07-08 jrick "\n# %s to be imported to branch %s\n", path_dir,
511 624411d2 2023-07-08 jrick branch_name);
512 624411d2 2023-07-08 jrick if (initial_content_len == -1)
513 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
514 624411d2 2023-07-08 jrick
515 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(logmsg_path, &fd,
516 624411d2 2023-07-08 jrick GOT_TMPDIR_STR "/got-importmsg", "");
517 624411d2 2023-07-08 jrick if (err)
518 624411d2 2023-07-08 jrick goto done;
519 624411d2 2023-07-08 jrick
520 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
521 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", *logmsg_path);
522 624411d2 2023-07-08 jrick goto done;
523 624411d2 2023-07-08 jrick }
524 624411d2 2023-07-08 jrick if (close(fd) == -1) {
525 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
526 624411d2 2023-07-08 jrick goto done;
527 624411d2 2023-07-08 jrick }
528 624411d2 2023-07-08 jrick fd = -1;
529 624411d2 2023-07-08 jrick
530 624411d2 2023-07-08 jrick err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
531 624411d2 2023-07-08 jrick initial_content_len, 1);
532 624411d2 2023-07-08 jrick done:
533 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
534 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
535 624411d2 2023-07-08 jrick free(initial_content);
536 624411d2 2023-07-08 jrick if (err) {
537 624411d2 2023-07-08 jrick free(*logmsg_path);
538 624411d2 2023-07-08 jrick *logmsg_path = NULL;
539 624411d2 2023-07-08 jrick }
540 624411d2 2023-07-08 jrick return err;
541 624411d2 2023-07-08 jrick }
542 624411d2 2023-07-08 jrick
543 624411d2 2023-07-08 jrick static const struct got_error *
544 624411d2 2023-07-08 jrick import_progress(void *arg, const char *path)
545 624411d2 2023-07-08 jrick {
546 624411d2 2023-07-08 jrick printf("A %s\n", path);
547 624411d2 2023-07-08 jrick return NULL;
548 624411d2 2023-07-08 jrick }
549 624411d2 2023-07-08 jrick
550 624411d2 2023-07-08 jrick static const struct got_error *
551 624411d2 2023-07-08 jrick valid_author(const char *author)
552 624411d2 2023-07-08 jrick {
553 624411d2 2023-07-08 jrick const char *email = author;
554 624411d2 2023-07-08 jrick
555 624411d2 2023-07-08 jrick /*
556 624411d2 2023-07-08 jrick * Git' expects the author (or committer) to be in the form
557 624411d2 2023-07-08 jrick * "name <email>", which are mostly free form (see the
558 624411d2 2023-07-08 jrick * "committer" description in git-fast-import(1)). We're only
559 624411d2 2023-07-08 jrick * doing this to avoid git's object parser breaking on commits
560 624411d2 2023-07-08 jrick * we create.
561 624411d2 2023-07-08 jrick */
562 624411d2 2023-07-08 jrick
563 624411d2 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
564 624411d2 2023-07-08 jrick author++;
565 624411d2 2023-07-08 jrick if (author != email && *author == '<' && *(author - 1) != ' ')
566 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space "
567 624411d2 2023-07-08 jrick "between author name and email required", email);
568 624411d2 2023-07-08 jrick if (*author++ != '<')
569 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
570 624411d2 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
571 624411d2 2023-07-08 jrick author++;
572 624411d2 2023-07-08 jrick if (strcmp(author, ">") != 0)
573 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
574 624411d2 2023-07-08 jrick return NULL;
575 624411d2 2023-07-08 jrick }
576 624411d2 2023-07-08 jrick
577 624411d2 2023-07-08 jrick static const struct got_error *
578 624411d2 2023-07-08 jrick get_author(char **author, struct got_repository *repo,
579 624411d2 2023-07-08 jrick struct got_worktree *worktree)
580 624411d2 2023-07-08 jrick {
581 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
582 624411d2 2023-07-08 jrick const char *got_author = NULL, *name, *email;
583 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
584 624411d2 2023-07-08 jrick
585 624411d2 2023-07-08 jrick *author = NULL;
586 624411d2 2023-07-08 jrick
587 624411d2 2023-07-08 jrick if (worktree)
588 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
589 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
590 624411d2 2023-07-08 jrick
591 624411d2 2023-07-08 jrick /*
592 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
593 624411d2 2023-07-08 jrick * significant to least significant:
594 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
595 624411d2 2023-07-08 jrick * 2) repository's got.conf file
596 624411d2 2023-07-08 jrick * 3) repository's git config file
597 624411d2 2023-07-08 jrick * 4) environment variables
598 624411d2 2023-07-08 jrick * 5) global git config files (in user's home directory or /etc)
599 624411d2 2023-07-08 jrick */
600 624411d2 2023-07-08 jrick
601 624411d2 2023-07-08 jrick if (worktree_conf)
602 624411d2 2023-07-08 jrick got_author = got_gotconfig_get_author(worktree_conf);
603 624411d2 2023-07-08 jrick if (got_author == NULL)
604 624411d2 2023-07-08 jrick got_author = got_gotconfig_get_author(repo_conf);
605 624411d2 2023-07-08 jrick if (got_author == NULL) {
606 624411d2 2023-07-08 jrick name = got_repo_get_gitconfig_author_name(repo);
607 624411d2 2023-07-08 jrick email = got_repo_get_gitconfig_author_email(repo);
608 624411d2 2023-07-08 jrick if (name && email) {
609 624411d2 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email) == -1)
610 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
611 624411d2 2023-07-08 jrick return NULL;
612 624411d2 2023-07-08 jrick }
613 624411d2 2023-07-08 jrick
614 624411d2 2023-07-08 jrick got_author = getenv("GOT_AUTHOR");
615 624411d2 2023-07-08 jrick if (got_author == NULL) {
616 624411d2 2023-07-08 jrick name = got_repo_get_global_gitconfig_author_name(repo);
617 624411d2 2023-07-08 jrick email = got_repo_get_global_gitconfig_author_email(
618 624411d2 2023-07-08 jrick repo);
619 624411d2 2023-07-08 jrick if (name && email) {
620 624411d2 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email)
621 624411d2 2023-07-08 jrick == -1)
622 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
623 624411d2 2023-07-08 jrick return NULL;
624 624411d2 2023-07-08 jrick }
625 624411d2 2023-07-08 jrick /* TODO: Look up user in password database? */
626 624411d2 2023-07-08 jrick return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
627 624411d2 2023-07-08 jrick }
628 624411d2 2023-07-08 jrick }
629 624411d2 2023-07-08 jrick
630 624411d2 2023-07-08 jrick *author = strdup(got_author);
631 624411d2 2023-07-08 jrick if (*author == NULL)
632 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
633 624411d2 2023-07-08 jrick
634 624411d2 2023-07-08 jrick err = valid_author(*author);
635 624411d2 2023-07-08 jrick if (err) {
636 624411d2 2023-07-08 jrick free(*author);
637 624411d2 2023-07-08 jrick *author = NULL;
638 624411d2 2023-07-08 jrick }
639 624411d2 2023-07-08 jrick return err;
640 624411d2 2023-07-08 jrick }
641 624411d2 2023-07-08 jrick
642 624411d2 2023-07-08 jrick static const struct got_error *
643 624411d2 2023-07-08 jrick get_allowed_signers(char **allowed_signers, struct got_repository *repo,
644 624411d2 2023-07-08 jrick struct got_worktree *worktree)
645 624411d2 2023-07-08 jrick {
646 624411d2 2023-07-08 jrick const char *got_allowed_signers = NULL;
647 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
648 624411d2 2023-07-08 jrick
649 624411d2 2023-07-08 jrick *allowed_signers = NULL;
650 624411d2 2023-07-08 jrick
651 624411d2 2023-07-08 jrick if (worktree)
652 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
653 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
654 624411d2 2023-07-08 jrick
655 624411d2 2023-07-08 jrick /*
656 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
657 624411d2 2023-07-08 jrick * significant to least significant:
658 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
659 624411d2 2023-07-08 jrick * 2) repository's got.conf file
660 624411d2 2023-07-08 jrick */
661 624411d2 2023-07-08 jrick
662 624411d2 2023-07-08 jrick if (worktree_conf)
663 624411d2 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
664 624411d2 2023-07-08 jrick worktree_conf);
665 624411d2 2023-07-08 jrick if (got_allowed_signers == NULL)
666 624411d2 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
667 624411d2 2023-07-08 jrick repo_conf);
668 624411d2 2023-07-08 jrick
669 624411d2 2023-07-08 jrick if (got_allowed_signers) {
670 624411d2 2023-07-08 jrick *allowed_signers = strdup(got_allowed_signers);
671 624411d2 2023-07-08 jrick if (*allowed_signers == NULL)
672 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
673 624411d2 2023-07-08 jrick }
674 624411d2 2023-07-08 jrick return NULL;
675 624411d2 2023-07-08 jrick }
676 624411d2 2023-07-08 jrick
677 624411d2 2023-07-08 jrick static const struct got_error *
678 624411d2 2023-07-08 jrick get_revoked_signers(char **revoked_signers, struct got_repository *repo,
679 624411d2 2023-07-08 jrick struct got_worktree *worktree)
680 624411d2 2023-07-08 jrick {
681 624411d2 2023-07-08 jrick const char *got_revoked_signers = NULL;
682 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
683 624411d2 2023-07-08 jrick
684 624411d2 2023-07-08 jrick *revoked_signers = NULL;
685 624411d2 2023-07-08 jrick
686 624411d2 2023-07-08 jrick if (worktree)
687 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
688 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
689 624411d2 2023-07-08 jrick
690 624411d2 2023-07-08 jrick /*
691 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
692 624411d2 2023-07-08 jrick * significant to least significant:
693 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
694 624411d2 2023-07-08 jrick * 2) repository's got.conf file
695 624411d2 2023-07-08 jrick */
696 624411d2 2023-07-08 jrick
697 624411d2 2023-07-08 jrick if (worktree_conf)
698 624411d2 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
699 624411d2 2023-07-08 jrick worktree_conf);
700 624411d2 2023-07-08 jrick if (got_revoked_signers == NULL)
701 624411d2 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
702 624411d2 2023-07-08 jrick repo_conf);
703 624411d2 2023-07-08 jrick
704 624411d2 2023-07-08 jrick if (got_revoked_signers) {
705 624411d2 2023-07-08 jrick *revoked_signers = strdup(got_revoked_signers);
706 624411d2 2023-07-08 jrick if (*revoked_signers == NULL)
707 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
708 624411d2 2023-07-08 jrick }
709 624411d2 2023-07-08 jrick return NULL;
710 624411d2 2023-07-08 jrick }
711 624411d2 2023-07-08 jrick
712 624411d2 2023-07-08 jrick static const char *
713 624411d2 2023-07-08 jrick get_signer_id(struct got_repository *repo, struct got_worktree *worktree)
714 624411d2 2023-07-08 jrick {
715 624411d2 2023-07-08 jrick const char *got_signer_id = NULL;
716 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
717 624411d2 2023-07-08 jrick
718 624411d2 2023-07-08 jrick if (worktree)
719 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
720 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
721 624411d2 2023-07-08 jrick
722 624411d2 2023-07-08 jrick /*
723 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
724 624411d2 2023-07-08 jrick * significant to least significant:
725 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
726 624411d2 2023-07-08 jrick * 2) repository's got.conf file
727 624411d2 2023-07-08 jrick */
728 624411d2 2023-07-08 jrick
729 624411d2 2023-07-08 jrick if (worktree_conf)
730 624411d2 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(worktree_conf);
731 624411d2 2023-07-08 jrick if (got_signer_id == NULL)
732 624411d2 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(repo_conf);
733 624411d2 2023-07-08 jrick
734 624411d2 2023-07-08 jrick return got_signer_id;
735 624411d2 2023-07-08 jrick }
736 624411d2 2023-07-08 jrick
737 624411d2 2023-07-08 jrick static const struct got_error *
738 624411d2 2023-07-08 jrick get_gitconfig_path(char **gitconfig_path)
739 624411d2 2023-07-08 jrick {
740 624411d2 2023-07-08 jrick const char *homedir = getenv("HOME");
741 624411d2 2023-07-08 jrick
742 624411d2 2023-07-08 jrick *gitconfig_path = NULL;
743 624411d2 2023-07-08 jrick if (homedir) {
744 624411d2 2023-07-08 jrick if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
745 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
746 624411d2 2023-07-08 jrick
747 624411d2 2023-07-08 jrick }
748 624411d2 2023-07-08 jrick return NULL;
749 624411d2 2023-07-08 jrick }
750 624411d2 2023-07-08 jrick
751 624411d2 2023-07-08 jrick static const struct got_error *
752 624411d2 2023-07-08 jrick cmd_import(int argc, char *argv[])
753 624411d2 2023-07-08 jrick {
754 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
755 624411d2 2023-07-08 jrick char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
756 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
757 624411d2 2023-07-08 jrick const char *branch_name = NULL;
758 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg_path = NULL;
759 624411d2 2023-07-08 jrick char refname[PATH_MAX] = "refs/heads/";
760 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
761 624411d2 2023-07-08 jrick struct got_reference *branch_ref = NULL, *head_ref = NULL;
762 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id = NULL;
763 624411d2 2023-07-08 jrick int ch, n = 0;
764 624411d2 2023-07-08 jrick struct got_pathlist_head ignores;
765 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
766 624411d2 2023-07-08 jrick int preserve_logmsg = 0;
767 624411d2 2023-07-08 jrick int *pack_fds = NULL;
768 624411d2 2023-07-08 jrick
769 624411d2 2023-07-08 jrick TAILQ_INIT(&ignores);
770 624411d2 2023-07-08 jrick
771 624411d2 2023-07-08 jrick #ifndef PROFILE
772 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
773 624411d2 2023-07-08 jrick "unveil",
774 624411d2 2023-07-08 jrick NULL) == -1)
775 624411d2 2023-07-08 jrick err(1, "pledge");
776 624411d2 2023-07-08 jrick #endif
777 624411d2 2023-07-08 jrick
778 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) {
779 624411d2 2023-07-08 jrick switch (ch) {
780 624411d2 2023-07-08 jrick case 'b':
781 624411d2 2023-07-08 jrick branch_name = optarg;
782 624411d2 2023-07-08 jrick break;
783 624411d2 2023-07-08 jrick case 'I':
784 624411d2 2023-07-08 jrick if (optarg[0] == '\0')
785 624411d2 2023-07-08 jrick break;
786 624411d2 2023-07-08 jrick error = got_pathlist_insert(&pe, &ignores, optarg,
787 624411d2 2023-07-08 jrick NULL);
788 624411d2 2023-07-08 jrick if (error)
789 624411d2 2023-07-08 jrick goto done;
790 624411d2 2023-07-08 jrick break;
791 624411d2 2023-07-08 jrick case 'm':
792 624411d2 2023-07-08 jrick logmsg = strdup(optarg);
793 624411d2 2023-07-08 jrick if (logmsg == NULL) {
794 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
795 624411d2 2023-07-08 jrick goto done;
796 624411d2 2023-07-08 jrick }
797 624411d2 2023-07-08 jrick break;
798 624411d2 2023-07-08 jrick case 'r':
799 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
800 624411d2 2023-07-08 jrick if (repo_path == NULL) {
801 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
802 624411d2 2023-07-08 jrick optarg);
803 624411d2 2023-07-08 jrick goto done;
804 624411d2 2023-07-08 jrick }
805 624411d2 2023-07-08 jrick break;
806 624411d2 2023-07-08 jrick default:
807 624411d2 2023-07-08 jrick usage_import();
808 624411d2 2023-07-08 jrick /* NOTREACHED */
809 624411d2 2023-07-08 jrick }
810 624411d2 2023-07-08 jrick }
811 624411d2 2023-07-08 jrick
812 624411d2 2023-07-08 jrick argc -= optind;
813 624411d2 2023-07-08 jrick argv += optind;
814 624411d2 2023-07-08 jrick
815 624411d2 2023-07-08 jrick if (argc != 1)
816 624411d2 2023-07-08 jrick usage_import();
817 624411d2 2023-07-08 jrick
818 624411d2 2023-07-08 jrick if (repo_path == NULL) {
819 624411d2 2023-07-08 jrick repo_path = getcwd(NULL, 0);
820 624411d2 2023-07-08 jrick if (repo_path == NULL)
821 624411d2 2023-07-08 jrick return got_error_from_errno("getcwd");
822 624411d2 2023-07-08 jrick }
823 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
824 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
825 624411d2 2023-07-08 jrick if (error)
826 624411d2 2023-07-08 jrick goto done;
827 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
828 624411d2 2023-07-08 jrick if (error != NULL)
829 624411d2 2023-07-08 jrick goto done;
830 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds);
831 624411d2 2023-07-08 jrick if (error)
832 624411d2 2023-07-08 jrick goto done;
833 624411d2 2023-07-08 jrick
834 624411d2 2023-07-08 jrick error = get_author(&author, repo, NULL);
835 624411d2 2023-07-08 jrick if (error)
836 624411d2 2023-07-08 jrick return error;
837 624411d2 2023-07-08 jrick
838 624411d2 2023-07-08 jrick /*
839 624411d2 2023-07-08 jrick * Don't let the user create a branch name with a leading '-'.
840 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
841 624411d2 2023-07-08 jrick * an unintended typo.
842 624411d2 2023-07-08 jrick */
843 624411d2 2023-07-08 jrick if (branch_name && branch_name[0] == '-')
844 624411d2 2023-07-08 jrick return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
845 624411d2 2023-07-08 jrick
846 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
847 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_REF)
848 624411d2 2023-07-08 jrick goto done;
849 624411d2 2023-07-08 jrick
850 624411d2 2023-07-08 jrick if (branch_name)
851 624411d2 2023-07-08 jrick n = strlcat(refname, branch_name, sizeof(refname));
852 624411d2 2023-07-08 jrick else if (head_ref && got_ref_is_symbolic(head_ref))
853 624411d2 2023-07-08 jrick n = strlcpy(refname, got_ref_get_symref_target(head_ref),
854 624411d2 2023-07-08 jrick sizeof(refname));
855 624411d2 2023-07-08 jrick else
856 624411d2 2023-07-08 jrick n = strlcat(refname, "main", sizeof(refname));
857 624411d2 2023-07-08 jrick if (n >= sizeof(refname)) {
858 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NO_SPACE);
859 624411d2 2023-07-08 jrick goto done;
860 624411d2 2023-07-08 jrick }
861 624411d2 2023-07-08 jrick
862 624411d2 2023-07-08 jrick error = got_ref_open(&branch_ref, repo, refname, 0);
863 624411d2 2023-07-08 jrick if (error) {
864 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
865 624411d2 2023-07-08 jrick goto done;
866 624411d2 2023-07-08 jrick } else {
867 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
868 624411d2 2023-07-08 jrick "import target branch already exists");
869 624411d2 2023-07-08 jrick goto done;
870 624411d2 2023-07-08 jrick }
871 624411d2 2023-07-08 jrick
872 624411d2 2023-07-08 jrick path_dir = realpath(argv[0], NULL);
873 624411d2 2023-07-08 jrick if (path_dir == NULL) {
874 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
875 624411d2 2023-07-08 jrick goto done;
876 624411d2 2023-07-08 jrick }
877 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(path_dir);
878 624411d2 2023-07-08 jrick
879 624411d2 2023-07-08 jrick /*
880 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have
881 624411d2 2023-07-08 jrick * to apply unveil after the log message has been written.
882 624411d2 2023-07-08 jrick */
883 624411d2 2023-07-08 jrick if (logmsg == NULL || *logmsg == '\0') {
884 624411d2 2023-07-08 jrick error = get_editor(&editor);
885 624411d2 2023-07-08 jrick if (error)
886 624411d2 2023-07-08 jrick goto done;
887 624411d2 2023-07-08 jrick free(logmsg);
888 624411d2 2023-07-08 jrick error = collect_import_msg(&logmsg, &logmsg_path, editor,
889 624411d2 2023-07-08 jrick path_dir, refname);
890 624411d2 2023-07-08 jrick if (error) {
891 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
892 624411d2 2023-07-08 jrick logmsg_path != NULL)
893 624411d2 2023-07-08 jrick preserve_logmsg = 1;
894 624411d2 2023-07-08 jrick goto done;
895 624411d2 2023-07-08 jrick }
896 624411d2 2023-07-08 jrick }
897 624411d2 2023-07-08 jrick
898 624411d2 2023-07-08 jrick if (unveil(path_dir, "r") != 0) {
899 624411d2 2023-07-08 jrick error = got_error_from_errno2("unveil", path_dir);
900 624411d2 2023-07-08 jrick if (logmsg_path)
901 624411d2 2023-07-08 jrick preserve_logmsg = 1;
902 624411d2 2023-07-08 jrick goto done;
903 624411d2 2023-07-08 jrick }
904 624411d2 2023-07-08 jrick
905 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
906 624411d2 2023-07-08 jrick if (error) {
907 624411d2 2023-07-08 jrick if (logmsg_path)
908 624411d2 2023-07-08 jrick preserve_logmsg = 1;
909 624411d2 2023-07-08 jrick goto done;
910 624411d2 2023-07-08 jrick }
911 624411d2 2023-07-08 jrick
912 624411d2 2023-07-08 jrick error = got_repo_import(&new_commit_id, path_dir, logmsg,
913 624411d2 2023-07-08 jrick author, &ignores, repo, import_progress, NULL);
914 624411d2 2023-07-08 jrick if (error) {
915 624411d2 2023-07-08 jrick if (logmsg_path)
916 624411d2 2023-07-08 jrick preserve_logmsg = 1;
917 624411d2 2023-07-08 jrick goto done;
918 624411d2 2023-07-08 jrick }
919 624411d2 2023-07-08 jrick
920 624411d2 2023-07-08 jrick error = got_ref_alloc(&branch_ref, refname, new_commit_id);
921 624411d2 2023-07-08 jrick if (error) {
922 624411d2 2023-07-08 jrick if (logmsg_path)
923 624411d2 2023-07-08 jrick preserve_logmsg = 1;
924 624411d2 2023-07-08 jrick goto done;
925 624411d2 2023-07-08 jrick }
926 624411d2 2023-07-08 jrick
927 624411d2 2023-07-08 jrick error = got_ref_write(branch_ref, repo);
928 624411d2 2023-07-08 jrick if (error) {
929 624411d2 2023-07-08 jrick if (logmsg_path)
930 624411d2 2023-07-08 jrick preserve_logmsg = 1;
931 624411d2 2023-07-08 jrick goto done;
932 624411d2 2023-07-08 jrick }
933 624411d2 2023-07-08 jrick
934 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, new_commit_id);
935 624411d2 2023-07-08 jrick if (error) {
936 624411d2 2023-07-08 jrick if (logmsg_path)
937 624411d2 2023-07-08 jrick preserve_logmsg = 1;
938 624411d2 2023-07-08 jrick goto done;
939 624411d2 2023-07-08 jrick }
940 624411d2 2023-07-08 jrick
941 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
942 624411d2 2023-07-08 jrick if (error) {
943 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF) {
944 624411d2 2023-07-08 jrick if (logmsg_path)
945 624411d2 2023-07-08 jrick preserve_logmsg = 1;
946 624411d2 2023-07-08 jrick goto done;
947 624411d2 2023-07-08 jrick }
948 624411d2 2023-07-08 jrick
949 624411d2 2023-07-08 jrick error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
950 624411d2 2023-07-08 jrick branch_ref);
951 624411d2 2023-07-08 jrick if (error) {
952 624411d2 2023-07-08 jrick if (logmsg_path)
953 624411d2 2023-07-08 jrick preserve_logmsg = 1;
954 624411d2 2023-07-08 jrick goto done;
955 624411d2 2023-07-08 jrick }
956 624411d2 2023-07-08 jrick
957 624411d2 2023-07-08 jrick error = got_ref_write(head_ref, repo);
958 624411d2 2023-07-08 jrick if (error) {
959 624411d2 2023-07-08 jrick if (logmsg_path)
960 624411d2 2023-07-08 jrick preserve_logmsg = 1;
961 624411d2 2023-07-08 jrick goto done;
962 624411d2 2023-07-08 jrick }
963 624411d2 2023-07-08 jrick }
964 624411d2 2023-07-08 jrick
965 624411d2 2023-07-08 jrick printf("Created branch %s with commit %s\n",
966 624411d2 2023-07-08 jrick got_ref_get_name(branch_ref), id_str);
967 624411d2 2023-07-08 jrick done:
968 624411d2 2023-07-08 jrick if (pack_fds) {
969 624411d2 2023-07-08 jrick const struct got_error *pack_err =
970 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
971 624411d2 2023-07-08 jrick if (error == NULL)
972 624411d2 2023-07-08 jrick error = pack_err;
973 624411d2 2023-07-08 jrick }
974 624411d2 2023-07-08 jrick if (repo) {
975 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
976 624411d2 2023-07-08 jrick if (error == NULL)
977 624411d2 2023-07-08 jrick error = close_err;
978 624411d2 2023-07-08 jrick }
979 624411d2 2023-07-08 jrick if (preserve_logmsg) {
980 624411d2 2023-07-08 jrick fprintf(stderr, "%s: log message preserved in %s\n",
981 624411d2 2023-07-08 jrick getprogname(), logmsg_path);
982 624411d2 2023-07-08 jrick } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
983 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", logmsg_path);
984 624411d2 2023-07-08 jrick free(logmsg);
985 624411d2 2023-07-08 jrick free(logmsg_path);
986 624411d2 2023-07-08 jrick free(repo_path);
987 624411d2 2023-07-08 jrick free(editor);
988 624411d2 2023-07-08 jrick free(new_commit_id);
989 624411d2 2023-07-08 jrick free(id_str);
990 624411d2 2023-07-08 jrick free(author);
991 624411d2 2023-07-08 jrick free(gitconfig_path);
992 624411d2 2023-07-08 jrick if (branch_ref)
993 624411d2 2023-07-08 jrick got_ref_close(branch_ref);
994 624411d2 2023-07-08 jrick if (head_ref)
995 624411d2 2023-07-08 jrick got_ref_close(head_ref);
996 624411d2 2023-07-08 jrick return error;
997 624411d2 2023-07-08 jrick }
998 624411d2 2023-07-08 jrick
999 624411d2 2023-07-08 jrick __dead static void
1000 624411d2 2023-07-08 jrick usage_clone(void)
1001 624411d2 2023-07-08 jrick {
1002 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s clone [-almqv] [-b branch] [-R reference] "
1003 624411d2 2023-07-08 jrick "repository-URL [directory]\n", getprogname());
1004 624411d2 2023-07-08 jrick exit(1);
1005 624411d2 2023-07-08 jrick }
1006 624411d2 2023-07-08 jrick
1007 624411d2 2023-07-08 jrick struct got_fetch_progress_arg {
1008 624411d2 2023-07-08 jrick char last_scaled_size[FMT_SCALED_STRSIZE];
1009 624411d2 2023-07-08 jrick int last_p_indexed;
1010 624411d2 2023-07-08 jrick int last_p_resolved;
1011 624411d2 2023-07-08 jrick int verbosity;
1012 624411d2 2023-07-08 jrick
1013 624411d2 2023-07-08 jrick struct got_repository *repo;
1014 624411d2 2023-07-08 jrick
1015 624411d2 2023-07-08 jrick int create_configs;
1016 624411d2 2023-07-08 jrick int configs_created;
1017 624411d2 2023-07-08 jrick struct {
1018 624411d2 2023-07-08 jrick struct got_pathlist_head *symrefs;
1019 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches;
1020 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs;
1021 624411d2 2023-07-08 jrick const char *proto;
1022 624411d2 2023-07-08 jrick const char *host;
1023 624411d2 2023-07-08 jrick const char *port;
1024 624411d2 2023-07-08 jrick const char *remote_repo_path;
1025 624411d2 2023-07-08 jrick const char *git_url;
1026 624411d2 2023-07-08 jrick int fetch_all_branches;
1027 624411d2 2023-07-08 jrick int mirror_references;
1028 624411d2 2023-07-08 jrick } config_info;
1029 624411d2 2023-07-08 jrick };
1030 624411d2 2023-07-08 jrick
1031 624411d2 2023-07-08 jrick /* XXX forward declaration */
1032 624411d2 2023-07-08 jrick static const struct got_error *
1033 624411d2 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1034 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1035 624411d2 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1036 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1037 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo);
1038 624411d2 2023-07-08 jrick
1039 624411d2 2023-07-08 jrick static const struct got_error *
1040 624411d2 2023-07-08 jrick fetch_progress(void *arg, const char *message, off_t packfile_size,
1041 624411d2 2023-07-08 jrick int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
1042 624411d2 2023-07-08 jrick {
1043 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1044 624411d2 2023-07-08 jrick struct got_fetch_progress_arg *a = arg;
1045 624411d2 2023-07-08 jrick char scaled_size[FMT_SCALED_STRSIZE];
1046 624411d2 2023-07-08 jrick int p_indexed, p_resolved;
1047 624411d2 2023-07-08 jrick int print_size = 0, print_indexed = 0, print_resolved = 0;
1048 624411d2 2023-07-08 jrick
1049 624411d2 2023-07-08 jrick /*
1050 624411d2 2023-07-08 jrick * In order to allow a failed clone to be resumed with 'got fetch'
1051 624411d2 2023-07-08 jrick * we try to create configuration files as soon as possible.
1052 624411d2 2023-07-08 jrick * Once the server has sent information about its default branch
1053 624411d2 2023-07-08 jrick * we have all required information.
1054 624411d2 2023-07-08 jrick */
1055 624411d2 2023-07-08 jrick if (a->create_configs && !a->configs_created &&
1056 624411d2 2023-07-08 jrick !TAILQ_EMPTY(a->config_info.symrefs)) {
1057 624411d2 2023-07-08 jrick err = create_config_files(a->config_info.proto,
1058 624411d2 2023-07-08 jrick a->config_info.host, a->config_info.port,
1059 624411d2 2023-07-08 jrick a->config_info.remote_repo_path,
1060 624411d2 2023-07-08 jrick a->config_info.git_url,
1061 624411d2 2023-07-08 jrick a->config_info.fetch_all_branches,
1062 624411d2 2023-07-08 jrick a->config_info.mirror_references,
1063 624411d2 2023-07-08 jrick a->config_info.symrefs,
1064 624411d2 2023-07-08 jrick a->config_info.wanted_branches,
1065 624411d2 2023-07-08 jrick a->config_info.wanted_refs, a->repo);
1066 624411d2 2023-07-08 jrick if (err)
1067 624411d2 2023-07-08 jrick return err;
1068 624411d2 2023-07-08 jrick a->configs_created = 1;
1069 624411d2 2023-07-08 jrick }
1070 624411d2 2023-07-08 jrick
1071 624411d2 2023-07-08 jrick if (a->verbosity < 0)
1072 624411d2 2023-07-08 jrick return NULL;
1073 624411d2 2023-07-08 jrick
1074 624411d2 2023-07-08 jrick if (message && message[0] != '\0') {
1075 624411d2 2023-07-08 jrick printf("\rserver: %s", message);
1076 624411d2 2023-07-08 jrick fflush(stdout);
1077 624411d2 2023-07-08 jrick return NULL;
1078 624411d2 2023-07-08 jrick }
1079 624411d2 2023-07-08 jrick
1080 624411d2 2023-07-08 jrick if (packfile_size > 0 || nobj_indexed > 0) {
1081 624411d2 2023-07-08 jrick if (fmt_scaled(packfile_size, scaled_size) == 0 &&
1082 624411d2 2023-07-08 jrick (a->last_scaled_size[0] == '\0' ||
1083 624411d2 2023-07-08 jrick strcmp(scaled_size, a->last_scaled_size)) != 0) {
1084 624411d2 2023-07-08 jrick print_size = 1;
1085 624411d2 2023-07-08 jrick if (strlcpy(a->last_scaled_size, scaled_size,
1086 624411d2 2023-07-08 jrick FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
1087 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
1088 624411d2 2023-07-08 jrick }
1089 624411d2 2023-07-08 jrick if (nobj_indexed > 0) {
1090 624411d2 2023-07-08 jrick p_indexed = (nobj_indexed * 100) / nobj_total;
1091 624411d2 2023-07-08 jrick if (p_indexed != a->last_p_indexed) {
1092 624411d2 2023-07-08 jrick a->last_p_indexed = p_indexed;
1093 624411d2 2023-07-08 jrick print_indexed = 1;
1094 624411d2 2023-07-08 jrick print_size = 1;
1095 624411d2 2023-07-08 jrick }
1096 624411d2 2023-07-08 jrick }
1097 624411d2 2023-07-08 jrick if (nobj_resolved > 0) {
1098 624411d2 2023-07-08 jrick p_resolved = (nobj_resolved * 100) /
1099 624411d2 2023-07-08 jrick (nobj_total - nobj_loose);
1100 624411d2 2023-07-08 jrick if (p_resolved != a->last_p_resolved) {
1101 624411d2 2023-07-08 jrick a->last_p_resolved = p_resolved;
1102 624411d2 2023-07-08 jrick print_resolved = 1;
1103 624411d2 2023-07-08 jrick print_indexed = 1;
1104 624411d2 2023-07-08 jrick print_size = 1;
1105 624411d2 2023-07-08 jrick }
1106 624411d2 2023-07-08 jrick }
1107 624411d2 2023-07-08 jrick
1108 624411d2 2023-07-08 jrick }
1109 624411d2 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1110 624411d2 2023-07-08 jrick printf("\r");
1111 624411d2 2023-07-08 jrick if (print_size)
1112 624411d2 2023-07-08 jrick printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size);
1113 624411d2 2023-07-08 jrick if (print_indexed)
1114 624411d2 2023-07-08 jrick printf("; indexing %d%%", p_indexed);
1115 624411d2 2023-07-08 jrick if (print_resolved)
1116 624411d2 2023-07-08 jrick printf("; resolving deltas %d%%", p_resolved);
1117 624411d2 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1118 624411d2 2023-07-08 jrick fflush(stdout);
1119 624411d2 2023-07-08 jrick
1120 624411d2 2023-07-08 jrick return NULL;
1121 624411d2 2023-07-08 jrick }
1122 624411d2 2023-07-08 jrick
1123 624411d2 2023-07-08 jrick static const struct got_error *
1124 624411d2 2023-07-08 jrick create_symref(const char *refname, struct got_reference *target_ref,
1125 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
1126 624411d2 2023-07-08 jrick {
1127 624411d2 2023-07-08 jrick const struct got_error *err;
1128 624411d2 2023-07-08 jrick struct got_reference *head_symref;
1129 624411d2 2023-07-08 jrick
1130 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1131 624411d2 2023-07-08 jrick if (err)
1132 624411d2 2023-07-08 jrick return err;
1133 624411d2 2023-07-08 jrick
1134 624411d2 2023-07-08 jrick err = got_ref_write(head_symref, repo);
1135 624411d2 2023-07-08 jrick if (err == NULL && verbosity > 0) {
1136 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n", GOT_REF_HEAD,
1137 624411d2 2023-07-08 jrick got_ref_get_name(target_ref));
1138 624411d2 2023-07-08 jrick }
1139 624411d2 2023-07-08 jrick got_ref_close(head_symref);
1140 624411d2 2023-07-08 jrick return err;
1141 624411d2 2023-07-08 jrick }
1142 624411d2 2023-07-08 jrick
1143 624411d2 2023-07-08 jrick static const struct got_error *
1144 624411d2 2023-07-08 jrick list_remote_refs(struct got_pathlist_head *symrefs,
1145 624411d2 2023-07-08 jrick struct got_pathlist_head *refs)
1146 624411d2 2023-07-08 jrick {
1147 624411d2 2023-07-08 jrick const struct got_error *err;
1148 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1149 624411d2 2023-07-08 jrick
1150 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1151 624411d2 2023-07-08 jrick const char *refname = pe->path;
1152 624411d2 2023-07-08 jrick const char *targetref = pe->data;
1153 624411d2 2023-07-08 jrick
1154 624411d2 2023-07-08 jrick printf("%s: %s\n", refname, targetref);
1155 624411d2 2023-07-08 jrick }
1156 624411d2 2023-07-08 jrick
1157 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, refs, entry) {
1158 624411d2 2023-07-08 jrick const char *refname = pe->path;
1159 624411d2 2023-07-08 jrick struct got_object_id *id = pe->data;
1160 624411d2 2023-07-08 jrick char *id_str;
1161 624411d2 2023-07-08 jrick
1162 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1163 624411d2 2023-07-08 jrick if (err)
1164 624411d2 2023-07-08 jrick return err;
1165 624411d2 2023-07-08 jrick printf("%s: %s\n", refname, id_str);
1166 624411d2 2023-07-08 jrick free(id_str);
1167 624411d2 2023-07-08 jrick }
1168 624411d2 2023-07-08 jrick
1169 624411d2 2023-07-08 jrick return NULL;
1170 624411d2 2023-07-08 jrick }
1171 624411d2 2023-07-08 jrick
1172 624411d2 2023-07-08 jrick static const struct got_error *
1173 624411d2 2023-07-08 jrick create_ref(const char *refname, struct got_object_id *id,
1174 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
1175 624411d2 2023-07-08 jrick {
1176 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1177 624411d2 2023-07-08 jrick struct got_reference *ref;
1178 624411d2 2023-07-08 jrick char *id_str;
1179 624411d2 2023-07-08 jrick
1180 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1181 624411d2 2023-07-08 jrick if (err)
1182 624411d2 2023-07-08 jrick return err;
1183 624411d2 2023-07-08 jrick
1184 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, id);
1185 624411d2 2023-07-08 jrick if (err)
1186 624411d2 2023-07-08 jrick goto done;
1187 624411d2 2023-07-08 jrick
1188 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1189 624411d2 2023-07-08 jrick got_ref_close(ref);
1190 624411d2 2023-07-08 jrick
1191 624411d2 2023-07-08 jrick if (err == NULL && verbosity >= 0)
1192 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n", refname, id_str);
1193 624411d2 2023-07-08 jrick done:
1194 624411d2 2023-07-08 jrick free(id_str);
1195 624411d2 2023-07-08 jrick return err;
1196 624411d2 2023-07-08 jrick }
1197 624411d2 2023-07-08 jrick
1198 624411d2 2023-07-08 jrick static int
1199 624411d2 2023-07-08 jrick match_wanted_ref(const char *refname, const char *wanted_ref)
1200 624411d2 2023-07-08 jrick {
1201 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) != 0)
1202 624411d2 2023-07-08 jrick return 0;
1203 624411d2 2023-07-08 jrick refname += 5;
1204 624411d2 2023-07-08 jrick
1205 624411d2 2023-07-08 jrick /*
1206 624411d2 2023-07-08 jrick * Prevent fetching of references that won't make any
1207 624411d2 2023-07-08 jrick * sense outside of the remote repository's context.
1208 624411d2 2023-07-08 jrick */
1209 624411d2 2023-07-08 jrick if (strncmp(refname, "got/", 4) == 0)
1210 624411d2 2023-07-08 jrick return 0;
1211 624411d2 2023-07-08 jrick if (strncmp(refname, "remotes/", 8) == 0)
1212 624411d2 2023-07-08 jrick return 0;
1213 624411d2 2023-07-08 jrick
1214 624411d2 2023-07-08 jrick if (strncmp(wanted_ref, "refs/", 5) == 0)
1215 624411d2 2023-07-08 jrick wanted_ref += 5;
1216 624411d2 2023-07-08 jrick
1217 624411d2 2023-07-08 jrick /* Allow prefix match. */
1218 624411d2 2023-07-08 jrick if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1219 624411d2 2023-07-08 jrick return 1;
1220 624411d2 2023-07-08 jrick
1221 624411d2 2023-07-08 jrick /* Allow exact match. */
1222 624411d2 2023-07-08 jrick return (strcmp(refname, wanted_ref) == 0);
1223 624411d2 2023-07-08 jrick }
1224 624411d2 2023-07-08 jrick
1225 624411d2 2023-07-08 jrick static int
1226 624411d2 2023-07-08 jrick is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1227 624411d2 2023-07-08 jrick {
1228 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1229 624411d2 2023-07-08 jrick
1230 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1231 624411d2 2023-07-08 jrick if (match_wanted_ref(refname, pe->path))
1232 624411d2 2023-07-08 jrick return 1;
1233 624411d2 2023-07-08 jrick }
1234 624411d2 2023-07-08 jrick
1235 624411d2 2023-07-08 jrick return 0;
1236 624411d2 2023-07-08 jrick }
1237 624411d2 2023-07-08 jrick
1238 624411d2 2023-07-08 jrick static const struct got_error *
1239 624411d2 2023-07-08 jrick create_wanted_ref(const char *refname, struct got_object_id *id,
1240 624411d2 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
1241 624411d2 2023-07-08 jrick {
1242 624411d2 2023-07-08 jrick const struct got_error *err;
1243 624411d2 2023-07-08 jrick char *remote_refname;
1244 624411d2 2023-07-08 jrick
1245 624411d2 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
1246 624411d2 2023-07-08 jrick refname += 5;
1247 624411d2 2023-07-08 jrick
1248 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1249 624411d2 2023-07-08 jrick remote_repo_name, refname) == -1)
1250 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
1251 624411d2 2023-07-08 jrick
1252 624411d2 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
1253 624411d2 2023-07-08 jrick free(remote_refname);
1254 624411d2 2023-07-08 jrick return err;
1255 624411d2 2023-07-08 jrick }
1256 624411d2 2023-07-08 jrick
1257 624411d2 2023-07-08 jrick static const struct got_error *
1258 624411d2 2023-07-08 jrick create_gotconfig(const char *proto, const char *host, const char *port,
1259 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *default_branch,
1260 624411d2 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1261 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1262 624411d2 2023-07-08 jrick struct got_repository *repo)
1263 624411d2 2023-07-08 jrick {
1264 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1265 624411d2 2023-07-08 jrick char *gotconfig_path = NULL;
1266 624411d2 2023-07-08 jrick char *gotconfig = NULL;
1267 624411d2 2023-07-08 jrick FILE *gotconfig_file = NULL;
1268 624411d2 2023-07-08 jrick const char *branchname = NULL;
1269 624411d2 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1270 624411d2 2023-07-08 jrick ssize_t n;
1271 624411d2 2023-07-08 jrick
1272 624411d2 2023-07-08 jrick if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
1273 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1274 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1275 624411d2 2023-07-08 jrick char *s;
1276 624411d2 2023-07-08 jrick branchname = pe->path;
1277 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1278 624411d2 2023-07-08 jrick branchname += 11;
1279 624411d2 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1280 624411d2 2023-07-08 jrick branches ? branches : "", branchname) == -1) {
1281 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1282 624411d2 2023-07-08 jrick goto done;
1283 624411d2 2023-07-08 jrick }
1284 624411d2 2023-07-08 jrick free(branches);
1285 624411d2 2023-07-08 jrick branches = s;
1286 624411d2 2023-07-08 jrick }
1287 624411d2 2023-07-08 jrick } else if (!fetch_all_branches && default_branch) {
1288 624411d2 2023-07-08 jrick branchname = default_branch;
1289 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1290 624411d2 2023-07-08 jrick branchname += 11;
1291 624411d2 2023-07-08 jrick if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1292 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1293 624411d2 2023-07-08 jrick goto done;
1294 624411d2 2023-07-08 jrick }
1295 624411d2 2023-07-08 jrick }
1296 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1297 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1298 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1299 624411d2 2023-07-08 jrick char *s;
1300 624411d2 2023-07-08 jrick const char *refname = pe->path;
1301 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1302 624411d2 2023-07-08 jrick branchname += 5;
1303 624411d2 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1304 624411d2 2023-07-08 jrick refs ? refs : "", refname) == -1) {
1305 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1306 624411d2 2023-07-08 jrick goto done;
1307 624411d2 2023-07-08 jrick }
1308 624411d2 2023-07-08 jrick free(refs);
1309 624411d2 2023-07-08 jrick refs = s;
1310 624411d2 2023-07-08 jrick }
1311 624411d2 2023-07-08 jrick }
1312 624411d2 2023-07-08 jrick
1313 624411d2 2023-07-08 jrick /* Create got.conf(5). */
1314 624411d2 2023-07-08 jrick gotconfig_path = got_repo_get_path_gotconfig(repo);
1315 624411d2 2023-07-08 jrick if (gotconfig_path == NULL) {
1316 624411d2 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gotconfig");
1317 624411d2 2023-07-08 jrick goto done;
1318 624411d2 2023-07-08 jrick }
1319 624411d2 2023-07-08 jrick gotconfig_file = fopen(gotconfig_path, "ae");
1320 624411d2 2023-07-08 jrick if (gotconfig_file == NULL) {
1321 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", gotconfig_path);
1322 624411d2 2023-07-08 jrick goto done;
1323 624411d2 2023-07-08 jrick }
1324 624411d2 2023-07-08 jrick if (asprintf(&gotconfig,
1325 624411d2 2023-07-08 jrick "remote \"%s\" {\n"
1326 624411d2 2023-07-08 jrick "\tserver %s\n"
1327 624411d2 2023-07-08 jrick "\tprotocol %s\n"
1328 624411d2 2023-07-08 jrick "%s%s%s"
1329 624411d2 2023-07-08 jrick "\trepository \"%s\"\n"
1330 624411d2 2023-07-08 jrick "%s%s%s"
1331 624411d2 2023-07-08 jrick "%s%s%s"
1332 624411d2 2023-07-08 jrick "%s"
1333 624411d2 2023-07-08 jrick "%s"
1334 624411d2 2023-07-08 jrick "}\n",
1335 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
1336 624411d2 2023-07-08 jrick port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1337 624411d2 2023-07-08 jrick remote_repo_path, branches ? "\tbranch { " : "",
1338 624411d2 2023-07-08 jrick branches ? branches : "", branches ? "}\n" : "",
1339 624411d2 2023-07-08 jrick refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1340 624411d2 2023-07-08 jrick mirror_references ? "\tmirror_references yes\n" : "",
1341 624411d2 2023-07-08 jrick fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) {
1342 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1343 624411d2 2023-07-08 jrick goto done;
1344 624411d2 2023-07-08 jrick }
1345 624411d2 2023-07-08 jrick n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1346 624411d2 2023-07-08 jrick if (n != strlen(gotconfig)) {
1347 624411d2 2023-07-08 jrick err = got_ferror(gotconfig_file, GOT_ERR_IO);
1348 624411d2 2023-07-08 jrick goto done;
1349 624411d2 2023-07-08 jrick }
1350 624411d2 2023-07-08 jrick
1351 624411d2 2023-07-08 jrick done:
1352 624411d2 2023-07-08 jrick if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
1353 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", gotconfig_path);
1354 624411d2 2023-07-08 jrick free(gotconfig_path);
1355 624411d2 2023-07-08 jrick free(branches);
1356 624411d2 2023-07-08 jrick return err;
1357 624411d2 2023-07-08 jrick }
1358 624411d2 2023-07-08 jrick
1359 624411d2 2023-07-08 jrick static const struct got_error *
1360 624411d2 2023-07-08 jrick create_gitconfig(const char *git_url, const char *default_branch,
1361 624411d2 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1362 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1363 624411d2 2023-07-08 jrick struct got_repository *repo)
1364 624411d2 2023-07-08 jrick {
1365 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1366 624411d2 2023-07-08 jrick char *gitconfig_path = NULL;
1367 624411d2 2023-07-08 jrick char *gitconfig = NULL;
1368 624411d2 2023-07-08 jrick FILE *gitconfig_file = NULL;
1369 624411d2 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1370 624411d2 2023-07-08 jrick const char *branchname;
1371 624411d2 2023-07-08 jrick ssize_t n;
1372 624411d2 2023-07-08 jrick
1373 624411d2 2023-07-08 jrick /* Create a config file Git can understand. */
1374 624411d2 2023-07-08 jrick gitconfig_path = got_repo_get_path_gitconfig(repo);
1375 624411d2 2023-07-08 jrick if (gitconfig_path == NULL) {
1376 624411d2 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gitconfig");
1377 624411d2 2023-07-08 jrick goto done;
1378 624411d2 2023-07-08 jrick }
1379 624411d2 2023-07-08 jrick gitconfig_file = fopen(gitconfig_path, "ae");
1380 624411d2 2023-07-08 jrick if (gitconfig_file == NULL) {
1381 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", gitconfig_path);
1382 624411d2 2023-07-08 jrick goto done;
1383 624411d2 2023-07-08 jrick }
1384 624411d2 2023-07-08 jrick if (fetch_all_branches) {
1385 624411d2 2023-07-08 jrick if (mirror_references) {
1386 624411d2 2023-07-08 jrick if (asprintf(&branches,
1387 624411d2 2023-07-08 jrick "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1388 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1389 624411d2 2023-07-08 jrick goto done;
1390 624411d2 2023-07-08 jrick }
1391 624411d2 2023-07-08 jrick } else if (asprintf(&branches,
1392 624411d2 2023-07-08 jrick "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1393 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1394 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1395 624411d2 2023-07-08 jrick goto done;
1396 624411d2 2023-07-08 jrick }
1397 624411d2 2023-07-08 jrick } else if (!TAILQ_EMPTY(wanted_branches)) {
1398 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1399 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1400 624411d2 2023-07-08 jrick char *s;
1401 624411d2 2023-07-08 jrick branchname = pe->path;
1402 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1403 624411d2 2023-07-08 jrick branchname += 11;
1404 624411d2 2023-07-08 jrick if (mirror_references) {
1405 624411d2 2023-07-08 jrick if (asprintf(&s,
1406 624411d2 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1407 624411d2 2023-07-08 jrick branches ? branches : "",
1408 624411d2 2023-07-08 jrick branchname, branchname) == -1) {
1409 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1410 624411d2 2023-07-08 jrick goto done;
1411 624411d2 2023-07-08 jrick }
1412 624411d2 2023-07-08 jrick } else if (asprintf(&s,
1413 624411d2 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1414 624411d2 2023-07-08 jrick branches ? branches : "",
1415 624411d2 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1416 624411d2 2023-07-08 jrick branchname) == -1) {
1417 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1418 624411d2 2023-07-08 jrick goto done;
1419 624411d2 2023-07-08 jrick }
1420 624411d2 2023-07-08 jrick free(branches);
1421 624411d2 2023-07-08 jrick branches = s;
1422 624411d2 2023-07-08 jrick }
1423 624411d2 2023-07-08 jrick } else {
1424 624411d2 2023-07-08 jrick /*
1425 624411d2 2023-07-08 jrick * If the server specified a default branch, use just that one.
1426 624411d2 2023-07-08 jrick * Otherwise fall back to fetching all branches on next fetch.
1427 624411d2 2023-07-08 jrick */
1428 624411d2 2023-07-08 jrick if (default_branch) {
1429 624411d2 2023-07-08 jrick branchname = default_branch;
1430 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1431 624411d2 2023-07-08 jrick branchname += 11;
1432 624411d2 2023-07-08 jrick } else
1433 624411d2 2023-07-08 jrick branchname = "*"; /* fall back to all branches */
1434 624411d2 2023-07-08 jrick if (mirror_references) {
1435 624411d2 2023-07-08 jrick if (asprintf(&branches,
1436 624411d2 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/heads/%s\n",
1437 624411d2 2023-07-08 jrick branchname, branchname) == -1) {
1438 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1439 624411d2 2023-07-08 jrick goto done;
1440 624411d2 2023-07-08 jrick }
1441 624411d2 2023-07-08 jrick } else if (asprintf(&branches,
1442 624411d2 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1443 624411d2 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1444 624411d2 2023-07-08 jrick branchname) == -1) {
1445 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1446 624411d2 2023-07-08 jrick goto done;
1447 624411d2 2023-07-08 jrick }
1448 624411d2 2023-07-08 jrick }
1449 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1450 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1451 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1452 624411d2 2023-07-08 jrick char *s;
1453 624411d2 2023-07-08 jrick const char *refname = pe->path;
1454 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1455 624411d2 2023-07-08 jrick refname += 5;
1456 624411d2 2023-07-08 jrick if (mirror_references) {
1457 624411d2 2023-07-08 jrick if (asprintf(&s,
1458 624411d2 2023-07-08 jrick "%s\tfetch = refs/%s:refs/%s\n",
1459 624411d2 2023-07-08 jrick refs ? refs : "", refname, refname) == -1) {
1460 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1461 624411d2 2023-07-08 jrick goto done;
1462 624411d2 2023-07-08 jrick }
1463 624411d2 2023-07-08 jrick } else if (asprintf(&s,
1464 624411d2 2023-07-08 jrick "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1465 624411d2 2023-07-08 jrick refs ? refs : "",
1466 624411d2 2023-07-08 jrick refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1467 624411d2 2023-07-08 jrick refname) == -1) {
1468 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1469 624411d2 2023-07-08 jrick goto done;
1470 624411d2 2023-07-08 jrick }
1471 624411d2 2023-07-08 jrick free(refs);
1472 624411d2 2023-07-08 jrick refs = s;
1473 624411d2 2023-07-08 jrick }
1474 624411d2 2023-07-08 jrick }
1475 624411d2 2023-07-08 jrick
1476 624411d2 2023-07-08 jrick if (asprintf(&gitconfig,
1477 624411d2 2023-07-08 jrick "[remote \"%s\"]\n"
1478 624411d2 2023-07-08 jrick "\turl = %s\n"
1479 624411d2 2023-07-08 jrick "%s"
1480 624411d2 2023-07-08 jrick "%s"
1481 624411d2 2023-07-08 jrick "\tfetch = refs/tags/*:refs/tags/*\n",
1482 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
1483 624411d2 2023-07-08 jrick refs ? refs : "") == -1) {
1484 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1485 624411d2 2023-07-08 jrick goto done;
1486 624411d2 2023-07-08 jrick }
1487 624411d2 2023-07-08 jrick n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1488 624411d2 2023-07-08 jrick if (n != strlen(gitconfig)) {
1489 624411d2 2023-07-08 jrick err = got_ferror(gitconfig_file, GOT_ERR_IO);
1490 624411d2 2023-07-08 jrick goto done;
1491 624411d2 2023-07-08 jrick }
1492 624411d2 2023-07-08 jrick done:
1493 624411d2 2023-07-08 jrick if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
1494 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", gitconfig_path);
1495 624411d2 2023-07-08 jrick free(gitconfig_path);
1496 624411d2 2023-07-08 jrick free(branches);
1497 624411d2 2023-07-08 jrick return err;
1498 624411d2 2023-07-08 jrick }
1499 624411d2 2023-07-08 jrick
1500 624411d2 2023-07-08 jrick static const struct got_error *
1501 624411d2 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1502 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1503 624411d2 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1504 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1505 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1506 624411d2 2023-07-08 jrick {
1507 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1508 624411d2 2023-07-08 jrick const char *default_branch = NULL;
1509 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1510 624411d2 2023-07-08 jrick
1511 624411d2 2023-07-08 jrick /*
1512 624411d2 2023-07-08 jrick * If we asked for a set of wanted branches then use the first
1513 624411d2 2023-07-08 jrick * one of those.
1514 624411d2 2023-07-08 jrick */
1515 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_branches)) {
1516 624411d2 2023-07-08 jrick pe = TAILQ_FIRST(wanted_branches);
1517 624411d2 2023-07-08 jrick default_branch = pe->path;
1518 624411d2 2023-07-08 jrick } else {
1519 624411d2 2023-07-08 jrick /* First HEAD ref listed by server is the default branch. */
1520 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1521 624411d2 2023-07-08 jrick const char *refname = pe->path;
1522 624411d2 2023-07-08 jrick const char *target = pe->data;
1523 624411d2 2023-07-08 jrick
1524 624411d2 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1525 624411d2 2023-07-08 jrick continue;
1526 624411d2 2023-07-08 jrick
1527 624411d2 2023-07-08 jrick default_branch = target;
1528 624411d2 2023-07-08 jrick break;
1529 624411d2 2023-07-08 jrick }
1530 624411d2 2023-07-08 jrick }
1531 624411d2 2023-07-08 jrick
1532 624411d2 2023-07-08 jrick /* Create got.conf(5). */
1533 624411d2 2023-07-08 jrick err = create_gotconfig(proto, host, port, remote_repo_path,
1534 624411d2 2023-07-08 jrick default_branch, fetch_all_branches, wanted_branches,
1535 624411d2 2023-07-08 jrick wanted_refs, mirror_references, repo);
1536 624411d2 2023-07-08 jrick if (err)
1537 624411d2 2023-07-08 jrick return err;
1538 624411d2 2023-07-08 jrick
1539 624411d2 2023-07-08 jrick /* Create a config file Git can understand. */
1540 624411d2 2023-07-08 jrick return create_gitconfig(git_url, default_branch, fetch_all_branches,
1541 624411d2 2023-07-08 jrick wanted_branches, wanted_refs, mirror_references, repo);
1542 624411d2 2023-07-08 jrick }
1543 624411d2 2023-07-08 jrick
1544 624411d2 2023-07-08 jrick static const struct got_error *
1545 624411d2 2023-07-08 jrick cmd_clone(int argc, char *argv[])
1546 624411d2 2023-07-08 jrick {
1547 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
1548 624411d2 2023-07-08 jrick const char *uri, *dirname;
1549 624411d2 2023-07-08 jrick char *proto, *host, *port, *repo_name, *server_path;
1550 624411d2 2023-07-08 jrick char *default_destdir = NULL, *id_str = NULL;
1551 624411d2 2023-07-08 jrick const char *repo_path;
1552 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
1553 624411d2 2023-07-08 jrick struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1554 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1555 624411d2 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
1556 624411d2 2023-07-08 jrick int ch, fetchfd = -1, fetchstatus;
1557 624411d2 2023-07-08 jrick pid_t fetchpid = -1;
1558 624411d2 2023-07-08 jrick struct got_fetch_progress_arg fpa;
1559 624411d2 2023-07-08 jrick char *git_url = NULL;
1560 624411d2 2023-07-08 jrick int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1561 624411d2 2023-07-08 jrick int bflag = 0, list_refs_only = 0;
1562 624411d2 2023-07-08 jrick int *pack_fds = NULL;
1563 624411d2 2023-07-08 jrick
1564 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
1565 624411d2 2023-07-08 jrick TAILQ_INIT(&symrefs);
1566 624411d2 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
1567 624411d2 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
1568 624411d2 2023-07-08 jrick
1569 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "ab:lmqR:v")) != -1) {
1570 624411d2 2023-07-08 jrick switch (ch) {
1571 624411d2 2023-07-08 jrick case 'a':
1572 624411d2 2023-07-08 jrick fetch_all_branches = 1;
1573 624411d2 2023-07-08 jrick break;
1574 624411d2 2023-07-08 jrick case 'b':
1575 624411d2 2023-07-08 jrick error = got_pathlist_append(&wanted_branches,
1576 624411d2 2023-07-08 jrick optarg, NULL);
1577 624411d2 2023-07-08 jrick if (error)
1578 624411d2 2023-07-08 jrick return error;
1579 624411d2 2023-07-08 jrick bflag = 1;
1580 624411d2 2023-07-08 jrick break;
1581 624411d2 2023-07-08 jrick case 'l':
1582 624411d2 2023-07-08 jrick list_refs_only = 1;
1583 624411d2 2023-07-08 jrick break;
1584 624411d2 2023-07-08 jrick case 'm':
1585 624411d2 2023-07-08 jrick mirror_references = 1;
1586 624411d2 2023-07-08 jrick break;
1587 624411d2 2023-07-08 jrick case 'q':
1588 624411d2 2023-07-08 jrick verbosity = -1;
1589 624411d2 2023-07-08 jrick break;
1590 624411d2 2023-07-08 jrick case 'R':
1591 624411d2 2023-07-08 jrick error = got_pathlist_append(&wanted_refs,
1592 624411d2 2023-07-08 jrick optarg, NULL);
1593 624411d2 2023-07-08 jrick if (error)
1594 624411d2 2023-07-08 jrick return error;
1595 624411d2 2023-07-08 jrick break;
1596 624411d2 2023-07-08 jrick case 'v':
1597 624411d2 2023-07-08 jrick if (verbosity < 0)
1598 624411d2 2023-07-08 jrick verbosity = 0;
1599 624411d2 2023-07-08 jrick else if (verbosity < 3)
1600 624411d2 2023-07-08 jrick verbosity++;
1601 624411d2 2023-07-08 jrick break;
1602 624411d2 2023-07-08 jrick default:
1603 624411d2 2023-07-08 jrick usage_clone();
1604 624411d2 2023-07-08 jrick break;
1605 624411d2 2023-07-08 jrick }
1606 624411d2 2023-07-08 jrick }
1607 624411d2 2023-07-08 jrick argc -= optind;
1608 624411d2 2023-07-08 jrick argv += optind;
1609 624411d2 2023-07-08 jrick
1610 624411d2 2023-07-08 jrick if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1611 624411d2 2023-07-08 jrick option_conflict('a', 'b');
1612 624411d2 2023-07-08 jrick if (list_refs_only) {
1613 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_branches))
1614 624411d2 2023-07-08 jrick option_conflict('l', 'b');
1615 624411d2 2023-07-08 jrick if (fetch_all_branches)
1616 624411d2 2023-07-08 jrick option_conflict('l', 'a');
1617 624411d2 2023-07-08 jrick if (mirror_references)
1618 624411d2 2023-07-08 jrick option_conflict('l', 'm');
1619 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_refs))
1620 624411d2 2023-07-08 jrick option_conflict('l', 'R');
1621 624411d2 2023-07-08 jrick }
1622 624411d2 2023-07-08 jrick
1623 624411d2 2023-07-08 jrick uri = argv[0];
1624 624411d2 2023-07-08 jrick
1625 624411d2 2023-07-08 jrick if (argc == 1)
1626 624411d2 2023-07-08 jrick dirname = NULL;
1627 624411d2 2023-07-08 jrick else if (argc == 2)
1628 624411d2 2023-07-08 jrick dirname = argv[1];
1629 624411d2 2023-07-08 jrick else
1630 624411d2 2023-07-08 jrick usage_clone();
1631 624411d2 2023-07-08 jrick
1632 624411d2 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
1633 624411d2 2023-07-08 jrick &repo_name, uri);
1634 624411d2 2023-07-08 jrick if (error)
1635 624411d2 2023-07-08 jrick goto done;
1636 624411d2 2023-07-08 jrick
1637 624411d2 2023-07-08 jrick if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1638 624411d2 2023-07-08 jrick host, port ? ":" : "", port ? port : "",
1639 624411d2 2023-07-08 jrick server_path[0] != '/' ? "/" : "", server_path) == -1) {
1640 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1641 624411d2 2023-07-08 jrick goto done;
1642 624411d2 2023-07-08 jrick }
1643 624411d2 2023-07-08 jrick
1644 624411d2 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
1645 624411d2 2023-07-08 jrick #ifndef PROFILE
1646 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1647 624411d2 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
1648 624411d2 2023-07-08 jrick err(1, "pledge");
1649 624411d2 2023-07-08 jrick #endif
1650 624411d2 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
1651 624411d2 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
1652 624411d2 2023-07-08 jrick #ifndef PROFILE
1653 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1654 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
1655 624411d2 2023-07-08 jrick err(1, "pledge");
1656 624411d2 2023-07-08 jrick #endif
1657 624411d2 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
1658 624411d2 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
1659 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1660 624411d2 2023-07-08 jrick goto done;
1661 624411d2 2023-07-08 jrick } else {
1662 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1663 624411d2 2023-07-08 jrick goto done;
1664 624411d2 2023-07-08 jrick }
1665 624411d2 2023-07-08 jrick if (dirname == NULL) {
1666 624411d2 2023-07-08 jrick if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1667 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1668 624411d2 2023-07-08 jrick goto done;
1669 624411d2 2023-07-08 jrick }
1670 624411d2 2023-07-08 jrick repo_path = default_destdir;
1671 624411d2 2023-07-08 jrick } else
1672 624411d2 2023-07-08 jrick repo_path = dirname;
1673 624411d2 2023-07-08 jrick
1674 624411d2 2023-07-08 jrick if (!list_refs_only) {
1675 624411d2 2023-07-08 jrick error = got_path_mkdir(repo_path);
1676 624411d2 2023-07-08 jrick if (error &&
1677 624411d2 2023-07-08 jrick (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
1678 624411d2 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST)))
1679 624411d2 2023-07-08 jrick goto done;
1680 624411d2 2023-07-08 jrick if (!got_path_dir_is_empty(repo_path)) {
1681 624411d2 2023-07-08 jrick error = got_error_path(repo_path,
1682 624411d2 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
1683 624411d2 2023-07-08 jrick goto done;
1684 624411d2 2023-07-08 jrick }
1685 624411d2 2023-07-08 jrick }
1686 624411d2 2023-07-08 jrick
1687 624411d2 2023-07-08 jrick error = got_dial_apply_unveil(proto);
1688 624411d2 2023-07-08 jrick if (error)
1689 624411d2 2023-07-08 jrick goto done;
1690 624411d2 2023-07-08 jrick
1691 624411d2 2023-07-08 jrick error = apply_unveil(repo_path, 0, NULL);
1692 624411d2 2023-07-08 jrick if (error)
1693 624411d2 2023-07-08 jrick goto done;
1694 624411d2 2023-07-08 jrick
1695 624411d2 2023-07-08 jrick if (verbosity >= 0)
1696 624411d2 2023-07-08 jrick printf("Connecting to %s\n", git_url);
1697 624411d2 2023-07-08 jrick
1698 624411d2 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1699 624411d2 2023-07-08 jrick server_path, verbosity);
1700 624411d2 2023-07-08 jrick if (error)
1701 624411d2 2023-07-08 jrick goto done;
1702 624411d2 2023-07-08 jrick
1703 624411d2 2023-07-08 jrick if (!list_refs_only) {
1704 624411d2 2023-07-08 jrick error = got_repo_init(repo_path, NULL);
1705 624411d2 2023-07-08 jrick if (error)
1706 624411d2 2023-07-08 jrick goto done;
1707 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
1708 624411d2 2023-07-08 jrick if (error != NULL)
1709 624411d2 2023-07-08 jrick goto done;
1710 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
1711 624411d2 2023-07-08 jrick if (error)
1712 624411d2 2023-07-08 jrick goto done;
1713 624411d2 2023-07-08 jrick }
1714 624411d2 2023-07-08 jrick
1715 624411d2 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
1716 624411d2 2023-07-08 jrick fpa.last_p_indexed = -1;
1717 624411d2 2023-07-08 jrick fpa.last_p_resolved = -1;
1718 624411d2 2023-07-08 jrick fpa.verbosity = verbosity;
1719 624411d2 2023-07-08 jrick fpa.create_configs = 1;
1720 624411d2 2023-07-08 jrick fpa.configs_created = 0;
1721 624411d2 2023-07-08 jrick fpa.repo = repo;
1722 624411d2 2023-07-08 jrick fpa.config_info.symrefs = &symrefs;
1723 624411d2 2023-07-08 jrick fpa.config_info.wanted_branches = &wanted_branches;
1724 624411d2 2023-07-08 jrick fpa.config_info.wanted_refs = &wanted_refs;
1725 624411d2 2023-07-08 jrick fpa.config_info.proto = proto;
1726 624411d2 2023-07-08 jrick fpa.config_info.host = host;
1727 624411d2 2023-07-08 jrick fpa.config_info.port = port;
1728 624411d2 2023-07-08 jrick fpa.config_info.remote_repo_path = server_path;
1729 624411d2 2023-07-08 jrick fpa.config_info.git_url = git_url;
1730 624411d2 2023-07-08 jrick fpa.config_info.fetch_all_branches = fetch_all_branches;
1731 624411d2 2023-07-08 jrick fpa.config_info.mirror_references = mirror_references;
1732 624411d2 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1733 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1734 624411d2 2023-07-08 jrick fetch_all_branches, &wanted_branches, &wanted_refs,
1735 624411d2 2023-07-08 jrick list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag,
1736 624411d2 2023-07-08 jrick fetch_progress, &fpa);
1737 624411d2 2023-07-08 jrick if (error)
1738 624411d2 2023-07-08 jrick goto done;
1739 624411d2 2023-07-08 jrick
1740 624411d2 2023-07-08 jrick if (list_refs_only) {
1741 624411d2 2023-07-08 jrick error = list_remote_refs(&symrefs, &refs);
1742 624411d2 2023-07-08 jrick goto done;
1743 624411d2 2023-07-08 jrick }
1744 624411d2 2023-07-08 jrick
1745 624411d2 2023-07-08 jrick if (pack_hash == NULL) {
1746 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s",
1747 624411d2 2023-07-08 jrick "server sent an empty pack file");
1748 624411d2 2023-07-08 jrick goto done;
1749 624411d2 2023-07-08 jrick }
1750 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
1751 624411d2 2023-07-08 jrick if (error)
1752 624411d2 2023-07-08 jrick goto done;
1753 624411d2 2023-07-08 jrick if (verbosity >= 0)
1754 624411d2 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
1755 624411d2 2023-07-08 jrick free(id_str);
1756 624411d2 2023-07-08 jrick
1757 624411d2 2023-07-08 jrick /* Set up references provided with the pack file. */
1758 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
1759 624411d2 2023-07-08 jrick const char *refname = pe->path;
1760 624411d2 2023-07-08 jrick struct got_object_id *id = pe->data;
1761 624411d2 2023-07-08 jrick char *remote_refname;
1762 624411d2 2023-07-08 jrick
1763 624411d2 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname) &&
1764 624411d2 2023-07-08 jrick !mirror_references) {
1765 624411d2 2023-07-08 jrick error = create_wanted_ref(refname, id,
1766 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME,
1767 624411d2 2023-07-08 jrick verbosity - 1, repo);
1768 624411d2 2023-07-08 jrick if (error)
1769 624411d2 2023-07-08 jrick goto done;
1770 624411d2 2023-07-08 jrick continue;
1771 624411d2 2023-07-08 jrick }
1772 624411d2 2023-07-08 jrick
1773 624411d2 2023-07-08 jrick error = create_ref(refname, id, verbosity - 1, repo);
1774 624411d2 2023-07-08 jrick if (error)
1775 624411d2 2023-07-08 jrick goto done;
1776 624411d2 2023-07-08 jrick
1777 624411d2 2023-07-08 jrick if (mirror_references)
1778 624411d2 2023-07-08 jrick continue;
1779 624411d2 2023-07-08 jrick
1780 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", refname, 11) != 0)
1781 624411d2 2023-07-08 jrick continue;
1782 624411d2 2023-07-08 jrick
1783 624411d2 2023-07-08 jrick if (asprintf(&remote_refname,
1784 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1785 624411d2 2023-07-08 jrick refname + 11) == -1) {
1786 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1787 624411d2 2023-07-08 jrick goto done;
1788 624411d2 2023-07-08 jrick }
1789 624411d2 2023-07-08 jrick error = create_ref(remote_refname, id, verbosity - 1, repo);
1790 624411d2 2023-07-08 jrick free(remote_refname);
1791 624411d2 2023-07-08 jrick if (error)
1792 624411d2 2023-07-08 jrick goto done;
1793 624411d2 2023-07-08 jrick }
1794 624411d2 2023-07-08 jrick
1795 624411d2 2023-07-08 jrick /* Set the HEAD reference if the server provided one. */
1796 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &symrefs, entry) {
1797 624411d2 2023-07-08 jrick struct got_reference *target_ref;
1798 624411d2 2023-07-08 jrick const char *refname = pe->path;
1799 624411d2 2023-07-08 jrick const char *target = pe->data;
1800 624411d2 2023-07-08 jrick char *remote_refname = NULL, *remote_target = NULL;
1801 624411d2 2023-07-08 jrick
1802 624411d2 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1803 624411d2 2023-07-08 jrick continue;
1804 624411d2 2023-07-08 jrick
1805 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1806 624411d2 2023-07-08 jrick if (error) {
1807 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1808 624411d2 2023-07-08 jrick error = NULL;
1809 624411d2 2023-07-08 jrick continue;
1810 624411d2 2023-07-08 jrick }
1811 624411d2 2023-07-08 jrick goto done;
1812 624411d2 2023-07-08 jrick }
1813 624411d2 2023-07-08 jrick
1814 624411d2 2023-07-08 jrick error = create_symref(refname, target_ref, verbosity, repo);
1815 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1816 624411d2 2023-07-08 jrick if (error)
1817 624411d2 2023-07-08 jrick goto done;
1818 624411d2 2023-07-08 jrick
1819 624411d2 2023-07-08 jrick if (mirror_references)
1820 624411d2 2023-07-08 jrick continue;
1821 624411d2 2023-07-08 jrick
1822 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", target, 11) != 0)
1823 624411d2 2023-07-08 jrick continue;
1824 624411d2 2023-07-08 jrick
1825 624411d2 2023-07-08 jrick if (asprintf(&remote_refname,
1826 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1827 624411d2 2023-07-08 jrick refname) == -1) {
1828 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1829 624411d2 2023-07-08 jrick goto done;
1830 624411d2 2023-07-08 jrick }
1831 624411d2 2023-07-08 jrick if (asprintf(&remote_target,
1832 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1833 624411d2 2023-07-08 jrick target + 11) == -1) {
1834 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1835 624411d2 2023-07-08 jrick free(remote_refname);
1836 624411d2 2023-07-08 jrick goto done;
1837 624411d2 2023-07-08 jrick }
1838 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, remote_target, 0);
1839 624411d2 2023-07-08 jrick if (error) {
1840 624411d2 2023-07-08 jrick free(remote_refname);
1841 624411d2 2023-07-08 jrick free(remote_target);
1842 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1843 624411d2 2023-07-08 jrick error = NULL;
1844 624411d2 2023-07-08 jrick continue;
1845 624411d2 2023-07-08 jrick }
1846 624411d2 2023-07-08 jrick goto done;
1847 624411d2 2023-07-08 jrick }
1848 624411d2 2023-07-08 jrick error = create_symref(remote_refname, target_ref,
1849 624411d2 2023-07-08 jrick verbosity - 1, repo);
1850 624411d2 2023-07-08 jrick free(remote_refname);
1851 624411d2 2023-07-08 jrick free(remote_target);
1852 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1853 624411d2 2023-07-08 jrick if (error)
1854 624411d2 2023-07-08 jrick goto done;
1855 624411d2 2023-07-08 jrick }
1856 624411d2 2023-07-08 jrick if (pe == NULL) {
1857 624411d2 2023-07-08 jrick /*
1858 624411d2 2023-07-08 jrick * We failed to set the HEAD reference. If we asked for
1859 624411d2 2023-07-08 jrick * a set of wanted branches use the first of one of those
1860 624411d2 2023-07-08 jrick * which could be fetched instead.
1861 624411d2 2023-07-08 jrick */
1862 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &wanted_branches, entry) {
1863 624411d2 2023-07-08 jrick const char *target = pe->path;
1864 624411d2 2023-07-08 jrick struct got_reference *target_ref;
1865 624411d2 2023-07-08 jrick
1866 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1867 624411d2 2023-07-08 jrick if (error) {
1868 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1869 624411d2 2023-07-08 jrick error = NULL;
1870 624411d2 2023-07-08 jrick continue;
1871 624411d2 2023-07-08 jrick }
1872 624411d2 2023-07-08 jrick goto done;
1873 624411d2 2023-07-08 jrick }
1874 624411d2 2023-07-08 jrick
1875 624411d2 2023-07-08 jrick error = create_symref(GOT_REF_HEAD, target_ref,
1876 624411d2 2023-07-08 jrick verbosity, repo);
1877 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1878 624411d2 2023-07-08 jrick if (error)
1879 624411d2 2023-07-08 jrick goto done;
1880 624411d2 2023-07-08 jrick break;
1881 624411d2 2023-07-08 jrick }
1882 624411d2 2023-07-08 jrick
1883 624411d2 2023-07-08 jrick if (!fpa.configs_created && pe != NULL) {
1884 624411d2 2023-07-08 jrick error = create_config_files(fpa.config_info.proto,
1885 624411d2 2023-07-08 jrick fpa.config_info.host, fpa.config_info.port,
1886 624411d2 2023-07-08 jrick fpa.config_info.remote_repo_path,
1887 624411d2 2023-07-08 jrick fpa.config_info.git_url,
1888 624411d2 2023-07-08 jrick fpa.config_info.fetch_all_branches,
1889 624411d2 2023-07-08 jrick fpa.config_info.mirror_references,
1890 624411d2 2023-07-08 jrick fpa.config_info.symrefs,
1891 624411d2 2023-07-08 jrick fpa.config_info.wanted_branches,
1892 624411d2 2023-07-08 jrick fpa.config_info.wanted_refs, fpa.repo);
1893 624411d2 2023-07-08 jrick if (error)
1894 624411d2 2023-07-08 jrick goto done;
1895 624411d2 2023-07-08 jrick }
1896 624411d2 2023-07-08 jrick }
1897 624411d2 2023-07-08 jrick
1898 624411d2 2023-07-08 jrick if (verbosity >= 0)
1899 624411d2 2023-07-08 jrick printf("Created %s repository '%s'\n",
1900 624411d2 2023-07-08 jrick mirror_references ? "mirrored" : "cloned", repo_path);
1901 624411d2 2023-07-08 jrick done:
1902 624411d2 2023-07-08 jrick if (pack_fds) {
1903 624411d2 2023-07-08 jrick const struct got_error *pack_err =
1904 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
1905 624411d2 2023-07-08 jrick if (error == NULL)
1906 624411d2 2023-07-08 jrick error = pack_err;
1907 624411d2 2023-07-08 jrick }
1908 624411d2 2023-07-08 jrick if (fetchpid > 0) {
1909 624411d2 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
1910 624411d2 2023-07-08 jrick error = got_error_from_errno("kill");
1911 624411d2 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1912 624411d2 2023-07-08 jrick error = got_error_from_errno("waitpid");
1913 624411d2 2023-07-08 jrick }
1914 624411d2 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1915 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
1916 624411d2 2023-07-08 jrick if (repo) {
1917 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
1918 624411d2 2023-07-08 jrick if (error == NULL)
1919 624411d2 2023-07-08 jrick error = close_err;
1920 624411d2 2023-07-08 jrick }
1921 624411d2 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
1922 624411d2 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
1923 624411d2 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
1924 624411d2 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
1925 624411d2 2023-07-08 jrick free(pack_hash);
1926 624411d2 2023-07-08 jrick free(proto);
1927 624411d2 2023-07-08 jrick free(host);
1928 624411d2 2023-07-08 jrick free(port);
1929 624411d2 2023-07-08 jrick free(server_path);
1930 624411d2 2023-07-08 jrick free(repo_name);
1931 624411d2 2023-07-08 jrick free(default_destdir);
1932 624411d2 2023-07-08 jrick free(git_url);
1933 624411d2 2023-07-08 jrick return error;
1934 624411d2 2023-07-08 jrick }
1935 624411d2 2023-07-08 jrick
1936 624411d2 2023-07-08 jrick static const struct got_error *
1937 624411d2 2023-07-08 jrick update_ref(struct got_reference *ref, struct got_object_id *new_id,
1938 624411d2 2023-07-08 jrick int replace_tags, int verbosity, struct got_repository *repo)
1939 624411d2 2023-07-08 jrick {
1940 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1941 624411d2 2023-07-08 jrick char *new_id_str = NULL;
1942 624411d2 2023-07-08 jrick struct got_object_id *old_id = NULL;
1943 624411d2 2023-07-08 jrick
1944 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
1945 624411d2 2023-07-08 jrick if (err)
1946 624411d2 2023-07-08 jrick goto done;
1947 624411d2 2023-07-08 jrick
1948 624411d2 2023-07-08 jrick if (!replace_tags &&
1949 624411d2 2023-07-08 jrick strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1950 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1951 624411d2 2023-07-08 jrick if (err)
1952 624411d2 2023-07-08 jrick goto done;
1953 624411d2 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1954 624411d2 2023-07-08 jrick goto done;
1955 624411d2 2023-07-08 jrick if (verbosity >= 0) {
1956 624411d2 2023-07-08 jrick printf("Rejecting update of existing tag %s: %s\n",
1957 624411d2 2023-07-08 jrick got_ref_get_name(ref), new_id_str);
1958 624411d2 2023-07-08 jrick }
1959 624411d2 2023-07-08 jrick goto done;
1960 624411d2 2023-07-08 jrick }
1961 624411d2 2023-07-08 jrick
1962 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
1963 624411d2 2023-07-08 jrick if (verbosity >= 0) {
1964 624411d2 2023-07-08 jrick printf("Replacing reference %s: %s\n",
1965 624411d2 2023-07-08 jrick got_ref_get_name(ref),
1966 624411d2 2023-07-08 jrick got_ref_get_symref_target(ref));
1967 624411d2 2023-07-08 jrick }
1968 624411d2 2023-07-08 jrick err = got_ref_change_symref_to_ref(ref, new_id);
1969 624411d2 2023-07-08 jrick if (err)
1970 624411d2 2023-07-08 jrick goto done;
1971 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1972 624411d2 2023-07-08 jrick if (err)
1973 624411d2 2023-07-08 jrick goto done;
1974 624411d2 2023-07-08 jrick } else {
1975 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1976 624411d2 2023-07-08 jrick if (err)
1977 624411d2 2023-07-08 jrick goto done;
1978 624411d2 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1979 624411d2 2023-07-08 jrick goto done;
1980 624411d2 2023-07-08 jrick
1981 624411d2 2023-07-08 jrick err = got_ref_change_ref(ref, new_id);
1982 624411d2 2023-07-08 jrick if (err)
1983 624411d2 2023-07-08 jrick goto done;
1984 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1985 624411d2 2023-07-08 jrick if (err)
1986 624411d2 2023-07-08 jrick goto done;
1987 624411d2 2023-07-08 jrick }
1988 624411d2 2023-07-08 jrick
1989 624411d2 2023-07-08 jrick if (verbosity >= 0)
1990 624411d2 2023-07-08 jrick printf("Updated %s: %s\n", got_ref_get_name(ref),
1991 624411d2 2023-07-08 jrick new_id_str);
1992 624411d2 2023-07-08 jrick done:
1993 624411d2 2023-07-08 jrick free(old_id);
1994 624411d2 2023-07-08 jrick free(new_id_str);
1995 624411d2 2023-07-08 jrick return err;
1996 624411d2 2023-07-08 jrick }
1997 624411d2 2023-07-08 jrick
1998 624411d2 2023-07-08 jrick static const struct got_error *
1999 624411d2 2023-07-08 jrick update_symref(const char *refname, struct got_reference *target_ref,
2000 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2001 624411d2 2023-07-08 jrick {
2002 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *unlock_err;
2003 624411d2 2023-07-08 jrick struct got_reference *symref;
2004 624411d2 2023-07-08 jrick int symref_is_locked = 0;
2005 624411d2 2023-07-08 jrick
2006 624411d2 2023-07-08 jrick err = got_ref_open(&symref, repo, refname, 1);
2007 624411d2 2023-07-08 jrick if (err) {
2008 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2009 624411d2 2023-07-08 jrick return err;
2010 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&symref, refname, target_ref);
2011 624411d2 2023-07-08 jrick if (err)
2012 624411d2 2023-07-08 jrick goto done;
2013 624411d2 2023-07-08 jrick
2014 624411d2 2023-07-08 jrick err = got_ref_write(symref, repo);
2015 624411d2 2023-07-08 jrick if (err)
2016 624411d2 2023-07-08 jrick goto done;
2017 624411d2 2023-07-08 jrick
2018 624411d2 2023-07-08 jrick if (verbosity >= 0)
2019 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n",
2020 624411d2 2023-07-08 jrick got_ref_get_name(symref),
2021 624411d2 2023-07-08 jrick got_ref_get_symref_target(symref));
2022 624411d2 2023-07-08 jrick } else {
2023 624411d2 2023-07-08 jrick symref_is_locked = 1;
2024 624411d2 2023-07-08 jrick
2025 624411d2 2023-07-08 jrick if (strcmp(got_ref_get_symref_target(symref),
2026 624411d2 2023-07-08 jrick got_ref_get_name(target_ref)) == 0)
2027 624411d2 2023-07-08 jrick goto done;
2028 624411d2 2023-07-08 jrick
2029 624411d2 2023-07-08 jrick err = got_ref_change_symref(symref,
2030 624411d2 2023-07-08 jrick got_ref_get_name(target_ref));
2031 624411d2 2023-07-08 jrick if (err)
2032 624411d2 2023-07-08 jrick goto done;
2033 624411d2 2023-07-08 jrick
2034 624411d2 2023-07-08 jrick err = got_ref_write(symref, repo);
2035 624411d2 2023-07-08 jrick if (err)
2036 624411d2 2023-07-08 jrick goto done;
2037 624411d2 2023-07-08 jrick
2038 624411d2 2023-07-08 jrick if (verbosity >= 0)
2039 624411d2 2023-07-08 jrick printf("Updated %s: %s\n", got_ref_get_name(symref),
2040 624411d2 2023-07-08 jrick got_ref_get_symref_target(symref));
2041 624411d2 2023-07-08 jrick
2042 624411d2 2023-07-08 jrick }
2043 624411d2 2023-07-08 jrick done:
2044 624411d2 2023-07-08 jrick if (symref_is_locked) {
2045 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(symref);
2046 624411d2 2023-07-08 jrick if (unlock_err && err == NULL)
2047 624411d2 2023-07-08 jrick err = unlock_err;
2048 624411d2 2023-07-08 jrick }
2049 624411d2 2023-07-08 jrick got_ref_close(symref);
2050 624411d2 2023-07-08 jrick return err;
2051 624411d2 2023-07-08 jrick }
2052 624411d2 2023-07-08 jrick
2053 624411d2 2023-07-08 jrick __dead static void
2054 624411d2 2023-07-08 jrick usage_fetch(void)
2055 624411d2 2023-07-08 jrick {
2056 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s fetch [-adlqtvX] [-b branch] "
2057 624411d2 2023-07-08 jrick "[-R reference] [-r repository-path] [remote-repository]\n",
2058 624411d2 2023-07-08 jrick getprogname());
2059 624411d2 2023-07-08 jrick exit(1);
2060 624411d2 2023-07-08 jrick }
2061 624411d2 2023-07-08 jrick
2062 624411d2 2023-07-08 jrick static const struct got_error *
2063 624411d2 2023-07-08 jrick delete_missing_ref(struct got_reference *ref,
2064 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2065 624411d2 2023-07-08 jrick {
2066 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2067 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
2068 624411d2 2023-07-08 jrick char *id_str = NULL;
2069 624411d2 2023-07-08 jrick
2070 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
2071 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2072 624411d2 2023-07-08 jrick if (err)
2073 624411d2 2023-07-08 jrick return err;
2074 624411d2 2023-07-08 jrick if (verbosity >= 0) {
2075 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n",
2076 624411d2 2023-07-08 jrick got_ref_get_name(ref),
2077 624411d2 2023-07-08 jrick got_ref_get_symref_target(ref));
2078 624411d2 2023-07-08 jrick }
2079 624411d2 2023-07-08 jrick } else {
2080 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
2081 624411d2 2023-07-08 jrick if (err)
2082 624411d2 2023-07-08 jrick return err;
2083 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
2084 624411d2 2023-07-08 jrick if (err)
2085 624411d2 2023-07-08 jrick goto done;
2086 624411d2 2023-07-08 jrick
2087 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2088 624411d2 2023-07-08 jrick if (err)
2089 624411d2 2023-07-08 jrick goto done;
2090 624411d2 2023-07-08 jrick if (verbosity >= 0) {
2091 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n",
2092 624411d2 2023-07-08 jrick got_ref_get_name(ref), id_str);
2093 624411d2 2023-07-08 jrick }
2094 624411d2 2023-07-08 jrick }
2095 624411d2 2023-07-08 jrick done:
2096 624411d2 2023-07-08 jrick free(id);
2097 624411d2 2023-07-08 jrick free(id_str);
2098 624411d2 2023-07-08 jrick return err;
2099 624411d2 2023-07-08 jrick }
2100 624411d2 2023-07-08 jrick
2101 624411d2 2023-07-08 jrick static const struct got_error *
2102 624411d2 2023-07-08 jrick delete_missing_refs(struct got_pathlist_head *their_refs,
2103 624411d2 2023-07-08 jrick struct got_pathlist_head *their_symrefs,
2104 624411d2 2023-07-08 jrick const struct got_remote_repo *remote,
2105 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2106 624411d2 2023-07-08 jrick {
2107 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *unlock_err;
2108 624411d2 2023-07-08 jrick struct got_reflist_head my_refs;
2109 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
2110 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
2111 624411d2 2023-07-08 jrick char *remote_namespace = NULL;
2112 624411d2 2023-07-08 jrick char *local_refname = NULL;
2113 624411d2 2023-07-08 jrick
2114 624411d2 2023-07-08 jrick TAILQ_INIT(&my_refs);
2115 624411d2 2023-07-08 jrick
2116 624411d2 2023-07-08 jrick if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
2117 624411d2 2023-07-08 jrick == -1)
2118 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
2119 624411d2 2023-07-08 jrick
2120 624411d2 2023-07-08 jrick err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
2121 624411d2 2023-07-08 jrick if (err)
2122 624411d2 2023-07-08 jrick goto done;
2123 624411d2 2023-07-08 jrick
2124 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &my_refs, entry) {
2125 624411d2 2023-07-08 jrick const char *refname = got_ref_get_name(re->ref);
2126 624411d2 2023-07-08 jrick const char *their_refname;
2127 624411d2 2023-07-08 jrick
2128 624411d2 2023-07-08 jrick if (remote->mirror_references) {
2129 624411d2 2023-07-08 jrick their_refname = refname;
2130 624411d2 2023-07-08 jrick } else {
2131 624411d2 2023-07-08 jrick if (strncmp(refname, remote_namespace,
2132 624411d2 2023-07-08 jrick strlen(remote_namespace)) == 0) {
2133 624411d2 2023-07-08 jrick if (strcmp(refname + strlen(remote_namespace),
2134 624411d2 2023-07-08 jrick GOT_REF_HEAD) == 0)
2135 624411d2 2023-07-08 jrick continue;
2136 624411d2 2023-07-08 jrick if (asprintf(&local_refname, "refs/heads/%s",
2137 624411d2 2023-07-08 jrick refname + strlen(remote_namespace)) == -1) {
2138 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
2139 624411d2 2023-07-08 jrick goto done;
2140 624411d2 2023-07-08 jrick }
2141 624411d2 2023-07-08 jrick } else if (strncmp(refname, "refs/tags/", 10) != 0)
2142 624411d2 2023-07-08 jrick continue;
2143 624411d2 2023-07-08 jrick
2144 624411d2 2023-07-08 jrick their_refname = local_refname;
2145 624411d2 2023-07-08 jrick }
2146 624411d2 2023-07-08 jrick
2147 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, their_refs, entry) {
2148 624411d2 2023-07-08 jrick if (strcmp(their_refname, pe->path) == 0)
2149 624411d2 2023-07-08 jrick break;
2150 624411d2 2023-07-08 jrick }
2151 624411d2 2023-07-08 jrick if (pe != NULL)
2152 624411d2 2023-07-08 jrick continue;
2153 624411d2 2023-07-08 jrick
2154 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, their_symrefs, entry) {
2155 624411d2 2023-07-08 jrick if (strcmp(their_refname, pe->path) == 0)
2156 624411d2 2023-07-08 jrick break;
2157 624411d2 2023-07-08 jrick }
2158 624411d2 2023-07-08 jrick if (pe != NULL)
2159 624411d2 2023-07-08 jrick continue;
2160 624411d2 2023-07-08 jrick
2161 624411d2 2023-07-08 jrick err = delete_missing_ref(re->ref, verbosity, repo);
2162 624411d2 2023-07-08 jrick if (err)
2163 624411d2 2023-07-08 jrick break;
2164 624411d2 2023-07-08 jrick
2165 624411d2 2023-07-08 jrick if (local_refname) {
2166 624411d2 2023-07-08 jrick struct got_reference *ref;
2167 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, local_refname, 1);
2168 624411d2 2023-07-08 jrick if (err) {
2169 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2170 624411d2 2023-07-08 jrick break;
2171 624411d2 2023-07-08 jrick free(local_refname);
2172 624411d2 2023-07-08 jrick local_refname = NULL;
2173 624411d2 2023-07-08 jrick continue;
2174 624411d2 2023-07-08 jrick }
2175 624411d2 2023-07-08 jrick err = delete_missing_ref(ref, verbosity, repo);
2176 624411d2 2023-07-08 jrick if (err)
2177 624411d2 2023-07-08 jrick break;
2178 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
2179 624411d2 2023-07-08 jrick got_ref_close(ref);
2180 624411d2 2023-07-08 jrick if (unlock_err && err == NULL) {
2181 624411d2 2023-07-08 jrick err = unlock_err;
2182 624411d2 2023-07-08 jrick break;
2183 624411d2 2023-07-08 jrick }
2184 624411d2 2023-07-08 jrick
2185 624411d2 2023-07-08 jrick free(local_refname);
2186 624411d2 2023-07-08 jrick local_refname = NULL;
2187 624411d2 2023-07-08 jrick }
2188 624411d2 2023-07-08 jrick }
2189 624411d2 2023-07-08 jrick done:
2190 624411d2 2023-07-08 jrick got_ref_list_free(&my_refs);
2191 624411d2 2023-07-08 jrick free(remote_namespace);
2192 624411d2 2023-07-08 jrick free(local_refname);
2193 624411d2 2023-07-08 jrick return err;
2194 624411d2 2023-07-08 jrick }
2195 624411d2 2023-07-08 jrick
2196 624411d2 2023-07-08 jrick static const struct got_error *
2197 624411d2 2023-07-08 jrick update_wanted_ref(const char *refname, struct got_object_id *id,
2198 624411d2 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
2199 624411d2 2023-07-08 jrick {
2200 624411d2 2023-07-08 jrick const struct got_error *err, *unlock_err;
2201 624411d2 2023-07-08 jrick char *remote_refname;
2202 624411d2 2023-07-08 jrick struct got_reference *ref;
2203 624411d2 2023-07-08 jrick
2204 624411d2 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
2205 624411d2 2023-07-08 jrick refname += 5;
2206 624411d2 2023-07-08 jrick
2207 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2208 624411d2 2023-07-08 jrick remote_repo_name, refname) == -1)
2209 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
2210 624411d2 2023-07-08 jrick
2211 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, remote_refname, 1);
2212 624411d2 2023-07-08 jrick if (err) {
2213 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2214 624411d2 2023-07-08 jrick goto done;
2215 624411d2 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
2216 624411d2 2023-07-08 jrick } else {
2217 624411d2 2023-07-08 jrick err = update_ref(ref, id, 0, verbosity, repo);
2218 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
2219 624411d2 2023-07-08 jrick if (unlock_err && err == NULL)
2220 624411d2 2023-07-08 jrick err = unlock_err;
2221 624411d2 2023-07-08 jrick got_ref_close(ref);
2222 624411d2 2023-07-08 jrick }
2223 624411d2 2023-07-08 jrick done:
2224 624411d2 2023-07-08 jrick free(remote_refname);
2225 624411d2 2023-07-08 jrick return err;
2226 624411d2 2023-07-08 jrick }
2227 624411d2 2023-07-08 jrick
2228 624411d2 2023-07-08 jrick static const struct got_error *
2229 624411d2 2023-07-08 jrick delete_ref(struct got_repository *repo, struct got_reference *ref)
2230 624411d2 2023-07-08 jrick {
2231 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2232 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
2233 624411d2 2023-07-08 jrick char *id_str = NULL;
2234 624411d2 2023-07-08 jrick const char *target;
2235 624411d2 2023-07-08 jrick
2236 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
2237 624411d2 2023-07-08 jrick target = got_ref_get_symref_target(ref);
2238 624411d2 2023-07-08 jrick } else {
2239 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
2240 624411d2 2023-07-08 jrick if (err)
2241 624411d2 2023-07-08 jrick goto done;
2242 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
2243 624411d2 2023-07-08 jrick if (err)
2244 624411d2 2023-07-08 jrick goto done;
2245 624411d2 2023-07-08 jrick target = id_str;
2246 624411d2 2023-07-08 jrick }
2247 624411d2 2023-07-08 jrick
2248 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2249 624411d2 2023-07-08 jrick if (err)
2250 624411d2 2023-07-08 jrick goto done;
2251 624411d2 2023-07-08 jrick
2252 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n", got_ref_get_name(ref), target);
2253 624411d2 2023-07-08 jrick done:
2254 624411d2 2023-07-08 jrick free(id);
2255 624411d2 2023-07-08 jrick free(id_str);
2256 624411d2 2023-07-08 jrick return err;
2257 624411d2 2023-07-08 jrick }
2258 624411d2 2023-07-08 jrick
2259 624411d2 2023-07-08 jrick static const struct got_error *
2260 624411d2 2023-07-08 jrick delete_refs_for_remote(struct got_repository *repo, const char *remote_name)
2261 624411d2 2023-07-08 jrick {
2262 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2263 624411d2 2023-07-08 jrick struct got_reflist_head refs;
2264 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
2265 624411d2 2023-07-08 jrick char *prefix;
2266 624411d2 2023-07-08 jrick
2267 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
2268 624411d2 2023-07-08 jrick
2269 624411d2 2023-07-08 jrick if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) {
2270 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
2271 624411d2 2023-07-08 jrick goto done;
2272 624411d2 2023-07-08 jrick }
2273 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL);
2274 624411d2 2023-07-08 jrick if (err)
2275 624411d2 2023-07-08 jrick goto done;
2276 624411d2 2023-07-08 jrick
2277 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
2278 624411d2 2023-07-08 jrick delete_ref(repo, re->ref);
2279 624411d2 2023-07-08 jrick done:
2280 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
2281 624411d2 2023-07-08 jrick return err;
2282 624411d2 2023-07-08 jrick }
2283 624411d2 2023-07-08 jrick
2284 624411d2 2023-07-08 jrick
2285 624411d2 2023-07-08 jrick
2286 624411d2 2023-07-08 jrick __dead static void
2287 624411d2 2023-07-08 jrick usage_checkout(void)
2288 624411d2 2023-07-08 jrick {
2289 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
2290 624411d2 2023-07-08 jrick "[-p path-prefix] repository-path [work-tree-path]\n",
2291 624411d2 2023-07-08 jrick getprogname());
2292 624411d2 2023-07-08 jrick exit(1);
2293 624411d2 2023-07-08 jrick }
2294 624411d2 2023-07-08 jrick
2295 624411d2 2023-07-08 jrick static void
2296 624411d2 2023-07-08 jrick show_worktree_base_ref_warning(void)
2297 624411d2 2023-07-08 jrick {
2298 624411d2 2023-07-08 jrick fprintf(stderr, "%s: warning: could not create a reference "
2299 624411d2 2023-07-08 jrick "to the work tree's base commit; the commit could be "
2300 624411d2 2023-07-08 jrick "garbage-collected by Git or 'gotadmin cleanup'; making the "
2301 624411d2 2023-07-08 jrick "repository writable and running 'got update' will prevent this\n",
2302 624411d2 2023-07-08 jrick getprogname());
2303 624411d2 2023-07-08 jrick }
2304 624411d2 2023-07-08 jrick
2305 624411d2 2023-07-08 jrick struct got_checkout_progress_arg {
2306 624411d2 2023-07-08 jrick const char *worktree_path;
2307 624411d2 2023-07-08 jrick int had_base_commit_ref_error;
2308 624411d2 2023-07-08 jrick int verbosity;
2309 624411d2 2023-07-08 jrick };
2310 624411d2 2023-07-08 jrick
2311 624411d2 2023-07-08 jrick static const struct got_error *
2312 624411d2 2023-07-08 jrick checkout_progress(void *arg, unsigned char status, const char *path)
2313 624411d2 2023-07-08 jrick {
2314 624411d2 2023-07-08 jrick struct got_checkout_progress_arg *a = arg;
2315 624411d2 2023-07-08 jrick
2316 624411d2 2023-07-08 jrick /* Base commit bump happens silently. */
2317 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2318 624411d2 2023-07-08 jrick return NULL;
2319 624411d2 2023-07-08 jrick
2320 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BASE_REF_ERR) {
2321 624411d2 2023-07-08 jrick a->had_base_commit_ref_error = 1;
2322 624411d2 2023-07-08 jrick return NULL;
2323 624411d2 2023-07-08 jrick }
2324 624411d2 2023-07-08 jrick
2325 624411d2 2023-07-08 jrick while (path[0] == '/')
2326 624411d2 2023-07-08 jrick path++;
2327 624411d2 2023-07-08 jrick
2328 624411d2 2023-07-08 jrick if (a->verbosity >= 0)
2329 624411d2 2023-07-08 jrick printf("%c %s/%s\n", status, a->worktree_path, path);
2330 624411d2 2023-07-08 jrick
2331 624411d2 2023-07-08 jrick return NULL;
2332 624411d2 2023-07-08 jrick }
2333 624411d2 2023-07-08 jrick
2334 624411d2 2023-07-08 jrick static const struct got_error *
2335 624411d2 2023-07-08 jrick check_cancelled(void *arg)
2336 624411d2 2023-07-08 jrick {
2337 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
2338 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
2339 624411d2 2023-07-08 jrick return NULL;
2340 624411d2 2023-07-08 jrick }
2341 624411d2 2023-07-08 jrick
2342 624411d2 2023-07-08 jrick static const struct got_error *
2343 624411d2 2023-07-08 jrick check_linear_ancestry(struct got_object_id *commit_id,
2344 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2345 624411d2 2023-07-08 jrick struct got_repository *repo)
2346 624411d2 2023-07-08 jrick {
2347 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2348 624411d2 2023-07-08 jrick struct got_object_id *yca_id;
2349 624411d2 2023-07-08 jrick
2350 624411d2 2023-07-08 jrick err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2351 624411d2 2023-07-08 jrick commit_id, base_commit_id, 1, repo, check_cancelled, NULL);
2352 624411d2 2023-07-08 jrick if (err)
2353 624411d2 2023-07-08 jrick return err;
2354 624411d2 2023-07-08 jrick
2355 624411d2 2023-07-08 jrick if (yca_id == NULL)
2356 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2357 624411d2 2023-07-08 jrick
2358 624411d2 2023-07-08 jrick /*
2359 624411d2 2023-07-08 jrick * Require a straight line of history between the target commit
2360 624411d2 2023-07-08 jrick * and the work tree's base commit.
2361 624411d2 2023-07-08 jrick *
2362 624411d2 2023-07-08 jrick * Non-linear situations such as this require a rebase:
2363 624411d2 2023-07-08 jrick *
2364 624411d2 2023-07-08 jrick * (commit) D F (base_commit)
2365 624411d2 2023-07-08 jrick * \ /
2366 624411d2 2023-07-08 jrick * C E
2367 624411d2 2023-07-08 jrick * \ /
2368 624411d2 2023-07-08 jrick * B (yca)
2369 624411d2 2023-07-08 jrick * |
2370 624411d2 2023-07-08 jrick * A
2371 624411d2 2023-07-08 jrick *
2372 624411d2 2023-07-08 jrick * 'got update' only handles linear cases:
2373 624411d2 2023-07-08 jrick * Update forwards in time: A (base/yca) - B - C - D (commit)
2374 624411d2 2023-07-08 jrick * Update backwards in time: D (base) - C - B - A (commit/yca)
2375 624411d2 2023-07-08 jrick */
2376 624411d2 2023-07-08 jrick if (allow_forwards_in_time_only) {
2377 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2378 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2379 624411d2 2023-07-08 jrick } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2380 624411d2 2023-07-08 jrick got_object_id_cmp(base_commit_id, yca_id) != 0)
2381 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2382 624411d2 2023-07-08 jrick
2383 624411d2 2023-07-08 jrick free(yca_id);
2384 624411d2 2023-07-08 jrick return NULL;
2385 624411d2 2023-07-08 jrick }
2386 624411d2 2023-07-08 jrick
2387 624411d2 2023-07-08 jrick static const struct got_error *
2388 624411d2 2023-07-08 jrick check_same_branch(struct got_object_id *commit_id,
2389 624411d2 2023-07-08 jrick struct got_reference *head_ref, struct got_repository *repo)
2390 624411d2 2023-07-08 jrick {
2391 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2392 624411d2 2023-07-08 jrick struct got_commit_graph *graph = NULL;
2393 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
2394 624411d2 2023-07-08 jrick
2395 624411d2 2023-07-08 jrick err = got_ref_resolve(&head_commit_id, repo, head_ref);
2396 624411d2 2023-07-08 jrick if (err)
2397 624411d2 2023-07-08 jrick goto done;
2398 624411d2 2023-07-08 jrick
2399 624411d2 2023-07-08 jrick if (got_object_id_cmp(head_commit_id, commit_id) == 0)
2400 624411d2 2023-07-08 jrick goto done;
2401 624411d2 2023-07-08 jrick
2402 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, "/", 1);
2403 624411d2 2023-07-08 jrick if (err)
2404 624411d2 2023-07-08 jrick goto done;
2405 624411d2 2023-07-08 jrick
2406 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2407 624411d2 2023-07-08 jrick check_cancelled, NULL);
2408 624411d2 2023-07-08 jrick if (err)
2409 624411d2 2023-07-08 jrick goto done;
2410 624411d2 2023-07-08 jrick
2411 624411d2 2023-07-08 jrick for (;;) {
2412 624411d2 2023-07-08 jrick struct got_object_id id;
2413 624411d2 2023-07-08 jrick
2414 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&id, graph, repo,
2415 624411d2 2023-07-08 jrick check_cancelled, NULL);
2416 624411d2 2023-07-08 jrick if (err) {
2417 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED)
2418 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_ANCESTRY);
2419 624411d2 2023-07-08 jrick break;
2420 624411d2 2023-07-08 jrick }
2421 624411d2 2023-07-08 jrick
2422 624411d2 2023-07-08 jrick if (got_object_id_cmp(&id, commit_id) == 0)
2423 624411d2 2023-07-08 jrick break;
2424 624411d2 2023-07-08 jrick }
2425 624411d2 2023-07-08 jrick done:
2426 624411d2 2023-07-08 jrick if (graph)
2427 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
2428 624411d2 2023-07-08 jrick free(head_commit_id);
2429 624411d2 2023-07-08 jrick return err;
2430 624411d2 2023-07-08 jrick }
2431 624411d2 2023-07-08 jrick
2432 624411d2 2023-07-08 jrick static const struct got_error *
2433 624411d2 2023-07-08 jrick checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2434 624411d2 2023-07-08 jrick {
2435 624411d2 2023-07-08 jrick static char msg[512];
2436 624411d2 2023-07-08 jrick const char *branch_name;
2437 624411d2 2023-07-08 jrick
2438 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref))
2439 624411d2 2023-07-08 jrick branch_name = got_ref_get_symref_target(ref);
2440 624411d2 2023-07-08 jrick else
2441 624411d2 2023-07-08 jrick branch_name = got_ref_get_name(ref);
2442 624411d2 2023-07-08 jrick
2443 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", branch_name, 11) == 0)
2444 624411d2 2023-07-08 jrick branch_name += 11;
2445 624411d2 2023-07-08 jrick
2446 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
2447 624411d2 2023-07-08 jrick "target commit is not contained in branch '%s'; "
2448 624411d2 2023-07-08 jrick "the branch to use must be specified with -b; "
2449 624411d2 2023-07-08 jrick "if necessary a new branch can be created for "
2450 624411d2 2023-07-08 jrick "this commit with 'got branch -c %s BRANCH_NAME'",
2451 624411d2 2023-07-08 jrick branch_name, commit_id_str);
2452 624411d2 2023-07-08 jrick
2453 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_ANCESTRY, msg);
2454 624411d2 2023-07-08 jrick }
2455 624411d2 2023-07-08 jrick
2456 624411d2 2023-07-08 jrick static const struct got_error *
2457 624411d2 2023-07-08 jrick cmd_checkout(int argc, char *argv[])
2458 624411d2 2023-07-08 jrick {
2459 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
2460 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
2461 624411d2 2023-07-08 jrick struct got_reference *head_ref = NULL, *ref = NULL;
2462 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
2463 624411d2 2023-07-08 jrick char *repo_path = NULL;
2464 624411d2 2023-07-08 jrick char *worktree_path = NULL;
2465 624411d2 2023-07-08 jrick const char *path_prefix = "";
2466 624411d2 2023-07-08 jrick const char *branch_name = GOT_REF_HEAD, *refname = NULL;
2467 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
2468 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2469 624411d2 2023-07-08 jrick char *cwd = NULL;
2470 624411d2 2023-07-08 jrick int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0;
2471 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
2472 624411d2 2023-07-08 jrick struct got_checkout_progress_arg cpa;
2473 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2474 624411d2 2023-07-08 jrick
2475 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
2476 624411d2 2023-07-08 jrick
2477 624411d2 2023-07-08 jrick #ifndef PROFILE
2478 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2479 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
2480 624411d2 2023-07-08 jrick err(1, "pledge");
2481 624411d2 2023-07-08 jrick #endif
2482 624411d2 2023-07-08 jrick
2483 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) {
2484 624411d2 2023-07-08 jrick switch (ch) {
2485 624411d2 2023-07-08 jrick case 'b':
2486 624411d2 2023-07-08 jrick branch_name = optarg;
2487 624411d2 2023-07-08 jrick break;
2488 624411d2 2023-07-08 jrick case 'c':
2489 624411d2 2023-07-08 jrick commit_id_str = strdup(optarg);
2490 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
2491 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
2492 624411d2 2023-07-08 jrick break;
2493 624411d2 2023-07-08 jrick case 'E':
2494 624411d2 2023-07-08 jrick allow_nonempty = 1;
2495 624411d2 2023-07-08 jrick break;
2496 624411d2 2023-07-08 jrick case 'p':
2497 624411d2 2023-07-08 jrick path_prefix = optarg;
2498 624411d2 2023-07-08 jrick break;
2499 624411d2 2023-07-08 jrick case 'q':
2500 624411d2 2023-07-08 jrick verbosity = -1;
2501 624411d2 2023-07-08 jrick break;
2502 624411d2 2023-07-08 jrick default:
2503 624411d2 2023-07-08 jrick usage_checkout();
2504 624411d2 2023-07-08 jrick /* NOTREACHED */
2505 624411d2 2023-07-08 jrick }
2506 624411d2 2023-07-08 jrick }
2507 624411d2 2023-07-08 jrick
2508 624411d2 2023-07-08 jrick argc -= optind;
2509 624411d2 2023-07-08 jrick argv += optind;
2510 624411d2 2023-07-08 jrick
2511 624411d2 2023-07-08 jrick if (argc == 1) {
2512 624411d2 2023-07-08 jrick char *base, *dotgit;
2513 624411d2 2023-07-08 jrick const char *path;
2514 624411d2 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2515 624411d2 2023-07-08 jrick if (repo_path == NULL)
2516 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath", argv[0]);
2517 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
2518 624411d2 2023-07-08 jrick if (cwd == NULL) {
2519 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
2520 624411d2 2023-07-08 jrick goto done;
2521 624411d2 2023-07-08 jrick }
2522 624411d2 2023-07-08 jrick if (path_prefix[0])
2523 624411d2 2023-07-08 jrick path = path_prefix;
2524 624411d2 2023-07-08 jrick else
2525 624411d2 2023-07-08 jrick path = repo_path;
2526 624411d2 2023-07-08 jrick error = got_path_basename(&base, path);
2527 624411d2 2023-07-08 jrick if (error)
2528 624411d2 2023-07-08 jrick goto done;
2529 624411d2 2023-07-08 jrick dotgit = strstr(base, ".git");
2530 624411d2 2023-07-08 jrick if (dotgit)
2531 624411d2 2023-07-08 jrick *dotgit = '\0';
2532 624411d2 2023-07-08 jrick if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2533 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
2534 624411d2 2023-07-08 jrick free(base);
2535 624411d2 2023-07-08 jrick goto done;
2536 624411d2 2023-07-08 jrick }
2537 624411d2 2023-07-08 jrick free(base);
2538 624411d2 2023-07-08 jrick } else if (argc == 2) {
2539 624411d2 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2540 624411d2 2023-07-08 jrick if (repo_path == NULL) {
2541 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
2542 624411d2 2023-07-08 jrick goto done;
2543 624411d2 2023-07-08 jrick }
2544 624411d2 2023-07-08 jrick worktree_path = realpath(argv[1], NULL);
2545 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
2546 624411d2 2023-07-08 jrick if (errno != ENOENT) {
2547 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
2548 624411d2 2023-07-08 jrick argv[1]);
2549 624411d2 2023-07-08 jrick goto done;
2550 624411d2 2023-07-08 jrick }
2551 624411d2 2023-07-08 jrick worktree_path = strdup(argv[1]);
2552 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
2553 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
2554 624411d2 2023-07-08 jrick goto done;
2555 624411d2 2023-07-08 jrick }
2556 624411d2 2023-07-08 jrick }
2557 624411d2 2023-07-08 jrick } else
2558 624411d2 2023-07-08 jrick usage_checkout();
2559 624411d2 2023-07-08 jrick
2560 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
2561 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(worktree_path);
2562 624411d2 2023-07-08 jrick
2563 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
2564 624411d2 2023-07-08 jrick if (error != NULL)
2565 624411d2 2023-07-08 jrick goto done;
2566 624411d2 2023-07-08 jrick
2567 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
2568 624411d2 2023-07-08 jrick if (error != NULL)
2569 624411d2 2023-07-08 jrick goto done;
2570 624411d2 2023-07-08 jrick
2571 624411d2 2023-07-08 jrick /* Pre-create work tree path for unveil(2) */
2572 624411d2 2023-07-08 jrick error = got_path_mkdir(worktree_path);
2573 624411d2 2023-07-08 jrick if (error) {
2574 624411d2 2023-07-08 jrick if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2575 624411d2 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2576 624411d2 2023-07-08 jrick goto done;
2577 624411d2 2023-07-08 jrick if (!allow_nonempty &&
2578 624411d2 2023-07-08 jrick !got_path_dir_is_empty(worktree_path)) {
2579 624411d2 2023-07-08 jrick error = got_error_path(worktree_path,
2580 624411d2 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
2581 624411d2 2023-07-08 jrick goto done;
2582 624411d2 2023-07-08 jrick }
2583 624411d2 2023-07-08 jrick }
2584 624411d2 2023-07-08 jrick
2585 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2586 624411d2 2023-07-08 jrick if (error)
2587 624411d2 2023-07-08 jrick goto done;
2588 624411d2 2023-07-08 jrick
2589 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, branch_name, 0);
2590 624411d2 2023-07-08 jrick if (error != NULL)
2591 624411d2 2023-07-08 jrick goto done;
2592 624411d2 2023-07-08 jrick
2593 624411d2 2023-07-08 jrick error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2594 624411d2 2023-07-08 jrick if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2595 624411d2 2023-07-08 jrick goto done;
2596 624411d2 2023-07-08 jrick
2597 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, worktree_path);
2598 624411d2 2023-07-08 jrick if (error != NULL)
2599 624411d2 2023-07-08 jrick goto done;
2600 624411d2 2023-07-08 jrick
2601 624411d2 2023-07-08 jrick error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2602 624411d2 2023-07-08 jrick path_prefix);
2603 624411d2 2023-07-08 jrick if (error != NULL)
2604 624411d2 2023-07-08 jrick goto done;
2605 624411d2 2023-07-08 jrick if (!same_path_prefix) {
2606 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_PATH_PREFIX);
2607 624411d2 2023-07-08 jrick goto done;
2608 624411d2 2023-07-08 jrick }
2609 624411d2 2023-07-08 jrick
2610 624411d2 2023-07-08 jrick if (commit_id_str) {
2611 624411d2 2023-07-08 jrick struct got_reflist_head refs;
2612 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
2613 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2614 624411d2 2023-07-08 jrick NULL);
2615 624411d2 2023-07-08 jrick if (error)
2616 624411d2 2023-07-08 jrick goto done;
2617 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
2618 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2619 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
2620 624411d2 2023-07-08 jrick if (error)
2621 624411d2 2023-07-08 jrick goto done;
2622 624411d2 2023-07-08 jrick error = check_linear_ancestry(commit_id,
2623 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2624 624411d2 2023-07-08 jrick if (error != NULL) {
2625 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2626 624411d2 2023-07-08 jrick error = checkout_ancestry_error(
2627 624411d2 2023-07-08 jrick head_ref, commit_id_str);
2628 624411d2 2023-07-08 jrick }
2629 624411d2 2023-07-08 jrick goto done;
2630 624411d2 2023-07-08 jrick }
2631 624411d2 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
2632 624411d2 2023-07-08 jrick if (error) {
2633 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2634 624411d2 2023-07-08 jrick error = checkout_ancestry_error(
2635 624411d2 2023-07-08 jrick head_ref, commit_id_str);
2636 624411d2 2023-07-08 jrick }
2637 624411d2 2023-07-08 jrick goto done;
2638 624411d2 2023-07-08 jrick }
2639 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
2640 624411d2 2023-07-08 jrick commit_id);
2641 624411d2 2023-07-08 jrick if (error)
2642 624411d2 2023-07-08 jrick goto done;
2643 624411d2 2023-07-08 jrick /* Expand potentially abbreviated commit ID string. */
2644 624411d2 2023-07-08 jrick free(commit_id_str);
2645 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2646 624411d2 2023-07-08 jrick if (error)
2647 624411d2 2023-07-08 jrick goto done;
2648 624411d2 2023-07-08 jrick } else {
2649 624411d2 2023-07-08 jrick commit_id = got_object_id_dup(
2650 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
2651 624411d2 2023-07-08 jrick if (commit_id == NULL) {
2652 624411d2 2023-07-08 jrick error = got_error_from_errno("got_object_id_dup");
2653 624411d2 2023-07-08 jrick goto done;
2654 624411d2 2023-07-08 jrick }
2655 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2656 624411d2 2023-07-08 jrick if (error)
2657 624411d2 2023-07-08 jrick goto done;
2658 624411d2 2023-07-08 jrick }
2659 624411d2 2023-07-08 jrick
2660 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
2661 624411d2 2023-07-08 jrick if (error)
2662 624411d2 2023-07-08 jrick goto done;
2663 624411d2 2023-07-08 jrick cpa.worktree_path = worktree_path;
2664 624411d2 2023-07-08 jrick cpa.had_base_commit_ref_error = 0;
2665 624411d2 2023-07-08 jrick cpa.verbosity = verbosity;
2666 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
2667 624411d2 2023-07-08 jrick checkout_progress, &cpa, check_cancelled, NULL);
2668 624411d2 2023-07-08 jrick if (error != NULL)
2669 624411d2 2023-07-08 jrick goto done;
2670 624411d2 2023-07-08 jrick
2671 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(head_ref)) {
2672 624411d2 2023-07-08 jrick error = got_ref_resolve_symbolic(&ref, repo, head_ref);
2673 624411d2 2023-07-08 jrick if (error)
2674 624411d2 2023-07-08 jrick goto done;
2675 624411d2 2023-07-08 jrick refname = got_ref_get_name(ref);
2676 624411d2 2023-07-08 jrick } else
2677 624411d2 2023-07-08 jrick refname = got_ref_get_name(head_ref);
2678 624411d2 2023-07-08 jrick printf("Checked out %s: %s\n", refname, commit_id_str);
2679 624411d2 2023-07-08 jrick printf("Now shut up and hack\n");
2680 624411d2 2023-07-08 jrick if (cpa.had_base_commit_ref_error)
2681 624411d2 2023-07-08 jrick show_worktree_base_ref_warning();
2682 624411d2 2023-07-08 jrick done:
2683 624411d2 2023-07-08 jrick if (pack_fds) {
2684 624411d2 2023-07-08 jrick const struct got_error *pack_err =
2685 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2686 624411d2 2023-07-08 jrick if (error == NULL)
2687 624411d2 2023-07-08 jrick error = pack_err;
2688 624411d2 2023-07-08 jrick }
2689 624411d2 2023-07-08 jrick if (head_ref)
2690 624411d2 2023-07-08 jrick got_ref_close(head_ref);
2691 624411d2 2023-07-08 jrick if (ref)
2692 624411d2 2023-07-08 jrick got_ref_close(ref);
2693 624411d2 2023-07-08 jrick if (repo) {
2694 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2695 624411d2 2023-07-08 jrick if (error == NULL)
2696 624411d2 2023-07-08 jrick error = close_err;
2697 624411d2 2023-07-08 jrick }
2698 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
2699 624411d2 2023-07-08 jrick free(commit_id_str);
2700 624411d2 2023-07-08 jrick free(commit_id);
2701 624411d2 2023-07-08 jrick free(repo_path);
2702 624411d2 2023-07-08 jrick free(worktree_path);
2703 624411d2 2023-07-08 jrick free(cwd);
2704 624411d2 2023-07-08 jrick return error;
2705 624411d2 2023-07-08 jrick }
2706 624411d2 2023-07-08 jrick
2707 624411d2 2023-07-08 jrick struct got_update_progress_arg {
2708 624411d2 2023-07-08 jrick int did_something;
2709 624411d2 2023-07-08 jrick int conflicts;
2710 624411d2 2023-07-08 jrick int obstructed;
2711 624411d2 2023-07-08 jrick int not_updated;
2712 624411d2 2023-07-08 jrick int missing;
2713 624411d2 2023-07-08 jrick int not_deleted;
2714 624411d2 2023-07-08 jrick int unversioned;
2715 624411d2 2023-07-08 jrick int verbosity;
2716 624411d2 2023-07-08 jrick };
2717 624411d2 2023-07-08 jrick
2718 624411d2 2023-07-08 jrick static void
2719 624411d2 2023-07-08 jrick print_update_progress_stats(struct got_update_progress_arg *upa)
2720 624411d2 2023-07-08 jrick {
2721 624411d2 2023-07-08 jrick if (!upa->did_something)
2722 624411d2 2023-07-08 jrick return;
2723 624411d2 2023-07-08 jrick
2724 624411d2 2023-07-08 jrick if (upa->conflicts > 0)
2725 624411d2 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2726 624411d2 2023-07-08 jrick if (upa->obstructed > 0)
2727 624411d2 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2728 624411d2 2023-07-08 jrick upa->obstructed);
2729 624411d2 2023-07-08 jrick if (upa->not_updated > 0)
2730 624411d2 2023-07-08 jrick printf("Files not updated because of existing merge "
2731 624411d2 2023-07-08 jrick "conflicts: %d\n", upa->not_updated);
2732 624411d2 2023-07-08 jrick }
2733 624411d2 2023-07-08 jrick
2734 624411d2 2023-07-08 jrick /*
2735 624411d2 2023-07-08 jrick * The meaning of some status codes differs between merge-style operations and
2736 624411d2 2023-07-08 jrick * update operations. For example, the ! status code means "file was missing"
2737 624411d2 2023-07-08 jrick * if changes were merged into the work tree, and "missing file was restored"
2738 624411d2 2023-07-08 jrick * if the work tree was updated. This function should be used by any operation
2739 624411d2 2023-07-08 jrick * which merges changes into the work tree without updating the work tree.
2740 624411d2 2023-07-08 jrick */
2741 624411d2 2023-07-08 jrick static void
2742 624411d2 2023-07-08 jrick print_merge_progress_stats(struct got_update_progress_arg *upa)
2743 624411d2 2023-07-08 jrick {
2744 624411d2 2023-07-08 jrick if (!upa->did_something)
2745 624411d2 2023-07-08 jrick return;
2746 624411d2 2023-07-08 jrick
2747 624411d2 2023-07-08 jrick if (upa->conflicts > 0)
2748 624411d2 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2749 624411d2 2023-07-08 jrick if (upa->obstructed > 0)
2750 624411d2 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2751 624411d2 2023-07-08 jrick upa->obstructed);
2752 624411d2 2023-07-08 jrick if (upa->missing > 0)
2753 624411d2 2023-07-08 jrick printf("Files which had incoming changes but could not be "
2754 624411d2 2023-07-08 jrick "found in the work tree: %d\n", upa->missing);
2755 624411d2 2023-07-08 jrick if (upa->not_deleted > 0)
2756 624411d2 2023-07-08 jrick printf("Files not deleted due to differences in deleted "
2757 624411d2 2023-07-08 jrick "content: %d\n", upa->not_deleted);
2758 624411d2 2023-07-08 jrick if (upa->unversioned > 0)
2759 624411d2 2023-07-08 jrick printf("Files not merged because an unversioned file was "
2760 624411d2 2023-07-08 jrick "found in the work tree: %d\n", upa->unversioned);
2761 624411d2 2023-07-08 jrick }
2762 624411d2 2023-07-08 jrick
2763 624411d2 2023-07-08 jrick __dead static void
2764 624411d2 2023-07-08 jrick usage_update(void)
2765 624411d2 2023-07-08 jrick {
2766 3d1b16d1 2023-07-08 jrick fprintf(stderr, "usage: %s update [-qtvX] [-c commit] [-r remote] "
2767 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
2768 624411d2 2023-07-08 jrick exit(1);
2769 624411d2 2023-07-08 jrick }
2770 624411d2 2023-07-08 jrick
2771 624411d2 2023-07-08 jrick static const struct got_error *
2772 624411d2 2023-07-08 jrick update_progress(void *arg, unsigned char status, const char *path)
2773 624411d2 2023-07-08 jrick {
2774 624411d2 2023-07-08 jrick struct got_update_progress_arg *upa = arg;
2775 624411d2 2023-07-08 jrick
2776 624411d2 2023-07-08 jrick if (status == GOT_STATUS_EXISTS ||
2777 624411d2 2023-07-08 jrick status == GOT_STATUS_BASE_REF_ERR)
2778 624411d2 2023-07-08 jrick return NULL;
2779 624411d2 2023-07-08 jrick
2780 624411d2 2023-07-08 jrick upa->did_something = 1;
2781 624411d2 2023-07-08 jrick
2782 624411d2 2023-07-08 jrick /* Base commit bump happens silently. */
2783 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2784 624411d2 2023-07-08 jrick return NULL;
2785 624411d2 2023-07-08 jrick
2786 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CONFLICT)
2787 624411d2 2023-07-08 jrick upa->conflicts++;
2788 624411d2 2023-07-08 jrick if (status == GOT_STATUS_OBSTRUCTED)
2789 624411d2 2023-07-08 jrick upa->obstructed++;
2790 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_UPDATE)
2791 624411d2 2023-07-08 jrick upa->not_updated++;
2792 624411d2 2023-07-08 jrick if (status == GOT_STATUS_MISSING)
2793 624411d2 2023-07-08 jrick upa->missing++;
2794 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_DELETE)
2795 624411d2 2023-07-08 jrick upa->not_deleted++;
2796 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
2797 624411d2 2023-07-08 jrick upa->unversioned++;
2798 624411d2 2023-07-08 jrick
2799 624411d2 2023-07-08 jrick while (path[0] == '/')
2800 624411d2 2023-07-08 jrick path++;
2801 624411d2 2023-07-08 jrick if (upa->verbosity >= 0)
2802 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
2803 624411d2 2023-07-08 jrick
2804 624411d2 2023-07-08 jrick return NULL;
2805 624411d2 2023-07-08 jrick }
2806 624411d2 2023-07-08 jrick
2807 624411d2 2023-07-08 jrick static const struct got_error *
2808 624411d2 2023-07-08 jrick switch_head_ref(struct got_reference *head_ref,
2809 624411d2 2023-07-08 jrick struct got_object_id *commit_id, struct got_worktree *worktree,
2810 624411d2 2023-07-08 jrick struct got_repository *repo)
2811 624411d2 2023-07-08 jrick {
2812 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2813 624411d2 2023-07-08 jrick char *base_id_str;
2814 624411d2 2023-07-08 jrick int ref_has_moved = 0;
2815 624411d2 2023-07-08 jrick
2816 624411d2 2023-07-08 jrick /* Trivial case: switching between two different references. */
2817 624411d2 2023-07-08 jrick if (strcmp(got_ref_get_name(head_ref),
2818 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree)) != 0) {
2819 624411d2 2023-07-08 jrick printf("Switching work tree from %s to %s\n",
2820 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
2821 624411d2 2023-07-08 jrick got_ref_get_name(head_ref));
2822 624411d2 2023-07-08 jrick return got_worktree_set_head_ref(worktree, head_ref);
2823 624411d2 2023-07-08 jrick }
2824 624411d2 2023-07-08 jrick
2825 624411d2 2023-07-08 jrick err = check_linear_ancestry(commit_id,
2826 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2827 624411d2 2023-07-08 jrick if (err) {
2828 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_ANCESTRY)
2829 624411d2 2023-07-08 jrick return err;
2830 624411d2 2023-07-08 jrick ref_has_moved = 1;
2831 624411d2 2023-07-08 jrick }
2832 624411d2 2023-07-08 jrick if (!ref_has_moved)
2833 624411d2 2023-07-08 jrick return NULL;
2834 624411d2 2023-07-08 jrick
2835 624411d2 2023-07-08 jrick /* Switching to a rebased branch with the same reference name. */
2836 624411d2 2023-07-08 jrick err = got_object_id_str(&base_id_str,
2837 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
2838 624411d2 2023-07-08 jrick if (err)
2839 624411d2 2023-07-08 jrick return err;
2840 624411d2 2023-07-08 jrick printf("Reference %s now points at a different branch\n",
2841 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
2842 624411d2 2023-07-08 jrick printf("Switching work tree from %s to %s\n", base_id_str,
2843 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
2844 624411d2 2023-07-08 jrick return NULL;
2845 624411d2 2023-07-08 jrick }
2846 624411d2 2023-07-08 jrick
2847 624411d2 2023-07-08 jrick static const struct got_error *
2848 624411d2 2023-07-08 jrick check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
2849 624411d2 2023-07-08 jrick {
2850 624411d2 2023-07-08 jrick const struct got_error *err;
2851 624411d2 2023-07-08 jrick int in_progress;
2852 624411d2 2023-07-08 jrick
2853 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&in_progress, worktree);
2854 624411d2 2023-07-08 jrick if (err)
2855 624411d2 2023-07-08 jrick return err;
2856 624411d2 2023-07-08 jrick if (in_progress)
2857 624411d2 2023-07-08 jrick return got_error(GOT_ERR_REBASING);
2858 624411d2 2023-07-08 jrick
2859 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&in_progress, worktree);
2860 624411d2 2023-07-08 jrick if (err)
2861 624411d2 2023-07-08 jrick return err;
2862 624411d2 2023-07-08 jrick if (in_progress)
2863 624411d2 2023-07-08 jrick return got_error(GOT_ERR_HISTEDIT_BUSY);
2864 624411d2 2023-07-08 jrick
2865 624411d2 2023-07-08 jrick return NULL;
2866 624411d2 2023-07-08 jrick }
2867 624411d2 2023-07-08 jrick
2868 624411d2 2023-07-08 jrick static const struct got_error *
2869 624411d2 2023-07-08 jrick check_merge_in_progress(struct got_worktree *worktree,
2870 624411d2 2023-07-08 jrick struct got_repository *repo)
2871 624411d2 2023-07-08 jrick {
2872 624411d2 2023-07-08 jrick const struct got_error *err;
2873 624411d2 2023-07-08 jrick int in_progress;
2874 624411d2 2023-07-08 jrick
2875 624411d2 2023-07-08 jrick err = got_worktree_merge_in_progress(&in_progress, worktree, repo);
2876 624411d2 2023-07-08 jrick if (err)
2877 624411d2 2023-07-08 jrick return err;
2878 624411d2 2023-07-08 jrick if (in_progress)
2879 624411d2 2023-07-08 jrick return got_error(GOT_ERR_MERGE_BUSY);
2880 624411d2 2023-07-08 jrick
2881 624411d2 2023-07-08 jrick return NULL;
2882 624411d2 2023-07-08 jrick }
2883 624411d2 2023-07-08 jrick
2884 624411d2 2023-07-08 jrick static const struct got_error *
2885 624411d2 2023-07-08 jrick get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
2886 624411d2 2023-07-08 jrick char *argv[], struct got_worktree *worktree)
2887 624411d2 2023-07-08 jrick {
2888 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2889 624411d2 2023-07-08 jrick char *path;
2890 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
2891 624411d2 2023-07-08 jrick int i;
2892 624411d2 2023-07-08 jrick
2893 624411d2 2023-07-08 jrick if (argc == 0) {
2894 624411d2 2023-07-08 jrick path = strdup("");
2895 624411d2 2023-07-08 jrick if (path == NULL)
2896 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
2897 624411d2 2023-07-08 jrick return got_pathlist_append(paths, path, NULL);
2898 624411d2 2023-07-08 jrick }
2899 624411d2 2023-07-08 jrick
2900 624411d2 2023-07-08 jrick for (i = 0; i < argc; i++) {
2901 624411d2 2023-07-08 jrick err = got_worktree_resolve_path(&path, worktree, argv[i]);
2902 624411d2 2023-07-08 jrick if (err)
2903 624411d2 2023-07-08 jrick break;
2904 624411d2 2023-07-08 jrick err = got_pathlist_insert(&new, paths, path, NULL);
2905 624411d2 2023-07-08 jrick if (err || new == NULL /* duplicate */) {
2906 624411d2 2023-07-08 jrick free(path);
2907 624411d2 2023-07-08 jrick if (err)
2908 624411d2 2023-07-08 jrick break;
2909 624411d2 2023-07-08 jrick }
2910 624411d2 2023-07-08 jrick }
2911 624411d2 2023-07-08 jrick
2912 624411d2 2023-07-08 jrick return err;
2913 624411d2 2023-07-08 jrick }
2914 624411d2 2023-07-08 jrick
2915 624411d2 2023-07-08 jrick static const struct got_error *
2916 624411d2 2023-07-08 jrick wrap_not_worktree_error(const struct got_error *orig_err,
2917 624411d2 2023-07-08 jrick const char *cmdname, const char *path)
2918 624411d2 2023-07-08 jrick {
2919 624411d2 2023-07-08 jrick const struct got_error *err;
2920 624411d2 2023-07-08 jrick struct got_repository *repo;
2921 624411d2 2023-07-08 jrick static char msg[512];
2922 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2923 624411d2 2023-07-08 jrick
2924 624411d2 2023-07-08 jrick err = got_repo_pack_fds_open(&pack_fds);
2925 624411d2 2023-07-08 jrick if (err)
2926 624411d2 2023-07-08 jrick return err;
2927 624411d2 2023-07-08 jrick
2928 624411d2 2023-07-08 jrick err = got_repo_open(&repo, path, NULL, pack_fds);
2929 624411d2 2023-07-08 jrick if (err)
2930 624411d2 2023-07-08 jrick return orig_err;
2931 624411d2 2023-07-08 jrick
2932 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
2933 624411d2 2023-07-08 jrick "'got %s' needs a work tree in addition to a git repository\n"
2934 624411d2 2023-07-08 jrick "Work trees can be checked out from this Git repository with "
2935 624411d2 2023-07-08 jrick "'got checkout'.\n"
2936 624411d2 2023-07-08 jrick "The got(1) manual page contains more information.", cmdname);
2937 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
2938 624411d2 2023-07-08 jrick if (repo) {
2939 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2940 624411d2 2023-07-08 jrick if (err == NULL)
2941 624411d2 2023-07-08 jrick err = close_err;
2942 624411d2 2023-07-08 jrick }
2943 624411d2 2023-07-08 jrick if (pack_fds) {
2944 624411d2 2023-07-08 jrick const struct got_error *pack_err =
2945 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2946 624411d2 2023-07-08 jrick if (err == NULL)
2947 624411d2 2023-07-08 jrick err = pack_err;
2948 624411d2 2023-07-08 jrick }
2949 624411d2 2023-07-08 jrick return err;
2950 624411d2 2023-07-08 jrick }
2951 624411d2 2023-07-08 jrick
2952 624411d2 2023-07-08 jrick static const struct got_error *
2953 624411d2 2023-07-08 jrick cmd_update(int argc, char *argv[])
2954 624411d2 2023-07-08 jrick {
2955 3d1b16d1 2023-07-08 jrick const struct got_error *error = NULL, *unlock_err;
2956 3d1b16d1 2023-07-08 jrick char *worktree_path = NULL;
2957 3d1b16d1 2023-07-08 jrick const char *repo_path = NULL;
2958 3d1b16d1 2023-07-08 jrick const char *remote_name = NULL;
2959 3d1b16d1 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
2960 3d1b16d1 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
2961 3d1b16d1 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
2962 3d1b16d1 2023-07-08 jrick int nremotes;
2963 3d1b16d1 2023-07-08 jrick char *id_str = NULL;
2964 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
2965 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
2966 3d1b16d1 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
2967 3d1b16d1 2023-07-08 jrick struct got_pathlist_head paths, refs, symrefs;
2968 3d1b16d1 2023-07-08 jrick struct got_pathlist_head wanted_branches, wanted_refs;
2969 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
2970 3d1b16d1 2023-07-08 jrick struct got_reflist_head remote_refs;
2971 3d1b16d1 2023-07-08 jrick struct got_reflist_entry *re;
2972 3d1b16d1 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
2973 3d1b16d1 2023-07-08 jrick int i, ch, fetchfd = -1, fetchstatus;
2974 3d1b16d1 2023-07-08 jrick pid_t fetchpid = -1;
2975 3d1b16d1 2023-07-08 jrick struct got_fetch_progress_arg fpa;
2976 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
2977 3d1b16d1 2023-07-08 jrick int verbosity = 0;
2978 3d1b16d1 2023-07-08 jrick int delete_remote = 0;
2979 3d1b16d1 2023-07-08 jrick int replace_tags = 0;
2980 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2981 3d1b16d1 2023-07-08 jrick const char *remote_head = NULL, *worktree_branch = NULL;
2982 3d1b16d1 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2983 3d1b16d1 2023-07-08 jrick char *commit_id_str = NULL;
2984 3d1b16d1 2023-07-08 jrick const char *refname;
2985 3d1b16d1 2023-07-08 jrick struct got_reference *head_ref = NULL;
2986 624411d2 2023-07-08 jrick
2987 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
2988 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&refs);
2989 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&symrefs);
2990 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&remote_refs);
2991 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
2992 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
2993 624411d2 2023-07-08 jrick
2994 3d1b16d1 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:qr:vX")) != -1) {
2995 624411d2 2023-07-08 jrick switch (ch) {
2996 624411d2 2023-07-08 jrick case 'c':
2997 624411d2 2023-07-08 jrick commit_id_str = strdup(optarg);
2998 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
2999 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
3000 624411d2 2023-07-08 jrick break;
3001 3d1b16d1 2023-07-08 jrick case 't':
3002 3d1b16d1 2023-07-08 jrick replace_tags = 1;
3003 3d1b16d1 2023-07-08 jrick break;
3004 624411d2 2023-07-08 jrick case 'q':
3005 624411d2 2023-07-08 jrick verbosity = -1;
3006 624411d2 2023-07-08 jrick break;
3007 3d1b16d1 2023-07-08 jrick case 'r':
3008 3d1b16d1 2023-07-08 jrick remote_name = optarg;
3009 3d1b16d1 2023-07-08 jrick break;
3010 3d1b16d1 2023-07-08 jrick case 'v':
3011 3d1b16d1 2023-07-08 jrick if (verbosity < 0)
3012 3d1b16d1 2023-07-08 jrick verbosity = 0;
3013 3d1b16d1 2023-07-08 jrick else if (verbosity < 3)
3014 3d1b16d1 2023-07-08 jrick verbosity++;
3015 3d1b16d1 2023-07-08 jrick break;
3016 3d1b16d1 2023-07-08 jrick case 'X':
3017 3d1b16d1 2023-07-08 jrick delete_remote = 1;
3018 3d1b16d1 2023-07-08 jrick break;
3019 624411d2 2023-07-08 jrick default:
3020 624411d2 2023-07-08 jrick usage_update();
3021 3d1b16d1 2023-07-08 jrick break;
3022 624411d2 2023-07-08 jrick }
3023 624411d2 2023-07-08 jrick }
3024 624411d2 2023-07-08 jrick argc -= optind;
3025 624411d2 2023-07-08 jrick argv += optind;
3026 624411d2 2023-07-08 jrick
3027 3d1b16d1 2023-07-08 jrick if (delete_remote) {
3028 3d1b16d1 2023-07-08 jrick if (replace_tags)
3029 3d1b16d1 2023-07-08 jrick option_conflict('X', 't');
3030 3d1b16d1 2023-07-08 jrick if (remote_name == NULL)
3031 3d1b16d1 2023-07-08 jrick errx(1, "-X option requires a remote name");
3032 3d1b16d1 2023-07-08 jrick }
3033 3d1b16d1 2023-07-08 jrick if (remote_name == NULL)
3034 3d1b16d1 2023-07-08 jrick remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
3035 3d1b16d1 2023-07-08 jrick
3036 624411d2 2023-07-08 jrick worktree_path = getcwd(NULL, 0);
3037 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
3038 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
3039 624411d2 2023-07-08 jrick goto done;
3040 624411d2 2023-07-08 jrick }
3041 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, worktree_path);
3042 624411d2 2023-07-08 jrick if (error) {
3043 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
3044 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "update",
3045 624411d2 2023-07-08 jrick worktree_path);
3046 624411d2 2023-07-08 jrick goto done;
3047 624411d2 2023-07-08 jrick }
3048 3d1b16d1 2023-07-08 jrick repo_path = got_worktree_get_repo_path(worktree);
3049 624411d2 2023-07-08 jrick
3050 3d1b16d1 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
3051 3d1b16d1 2023-07-08 jrick if (error != NULL)
3052 3d1b16d1 2023-07-08 jrick goto done;
3053 3d1b16d1 2023-07-08 jrick
3054 3d1b16d1 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
3055 3d1b16d1 2023-07-08 jrick if (error)
3056 3d1b16d1 2023-07-08 jrick goto done;
3057 3d1b16d1 2023-07-08 jrick
3058 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
3059 624411d2 2023-07-08 jrick if (error)
3060 624411d2 2023-07-08 jrick goto done;
3061 3d1b16d1 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
3062 3d1b16d1 2023-07-08 jrick if (error)
3063 3d1b16d1 2023-07-08 jrick goto done;
3064 624411d2 2023-07-08 jrick
3065 3d1b16d1 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
3066 3d1b16d1 2023-07-08 jrick if (error)
3067 624411d2 2023-07-08 jrick goto done;
3068 624411d2 2023-07-08 jrick
3069 3d1b16d1 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
3070 3d1b16d1 2023-07-08 jrick if (worktree_conf) {
3071 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
3072 3d1b16d1 2023-07-08 jrick worktree_conf);
3073 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3074 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3075 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3076 3d1b16d1 2023-07-08 jrick break;
3077 3d1b16d1 2023-07-08 jrick }
3078 3d1b16d1 2023-07-08 jrick }
3079 3d1b16d1 2023-07-08 jrick }
3080 3d1b16d1 2023-07-08 jrick
3081 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3082 3d1b16d1 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
3083 3d1b16d1 2023-07-08 jrick if (repo_conf) {
3084 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
3085 3d1b16d1 2023-07-08 jrick repo_conf);
3086 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3087 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3088 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3089 3d1b16d1 2023-07-08 jrick break;
3090 3d1b16d1 2023-07-08 jrick }
3091 3d1b16d1 2023-07-08 jrick }
3092 3d1b16d1 2023-07-08 jrick }
3093 3d1b16d1 2023-07-08 jrick }
3094 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3095 3d1b16d1 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
3096 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3097 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3098 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3099 3d1b16d1 2023-07-08 jrick break;
3100 3d1b16d1 2023-07-08 jrick }
3101 3d1b16d1 2023-07-08 jrick }
3102 3d1b16d1 2023-07-08 jrick }
3103 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3104 3d1b16d1 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
3105 3d1b16d1 2023-07-08 jrick goto done;
3106 3d1b16d1 2023-07-08 jrick }
3107 3d1b16d1 2023-07-08 jrick
3108 3d1b16d1 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
3109 3d1b16d1 2023-07-08 jrick &repo_name, remote->fetch_url);
3110 3d1b16d1 2023-07-08 jrick if (error)
3111 3d1b16d1 2023-07-08 jrick goto done;
3112 3d1b16d1 2023-07-08 jrick
3113 3d1b16d1 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
3114 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
3115 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
3116 3d1b16d1 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
3117 3d1b16d1 2023-07-08 jrick err(1, "pledge");
3118 3d1b16d1 2023-07-08 jrick #endif
3119 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
3120 3d1b16d1 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
3121 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
3122 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
3123 3d1b16d1 2023-07-08 jrick "sendfd unveil", NULL) == -1)
3124 3d1b16d1 2023-07-08 jrick err(1, "pledge");
3125 3d1b16d1 2023-07-08 jrick #endif
3126 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
3127 3d1b16d1 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
3128 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
3129 3d1b16d1 2023-07-08 jrick goto done;
3130 3d1b16d1 2023-07-08 jrick } else {
3131 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
3132 3d1b16d1 2023-07-08 jrick goto done;
3133 3d1b16d1 2023-07-08 jrick }
3134 3d1b16d1 2023-07-08 jrick
3135 3d1b16d1 2023-07-08 jrick error = got_dial_apply_unveil(proto);
3136 3d1b16d1 2023-07-08 jrick if (error)
3137 3d1b16d1 2023-07-08 jrick goto done;
3138 3d1b16d1 2023-07-08 jrick
3139 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
3140 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
3141 624411d2 2023-07-08 jrick if (error)
3142 624411d2 2023-07-08 jrick goto done;
3143 624411d2 2023-07-08 jrick
3144 3d1b16d1 2023-07-08 jrick if (verbosity >= 0) {
3145 3d1b16d1 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
3146 3d1b16d1 2023-07-08 jrick remote->name, proto, host,
3147 3d1b16d1 2023-07-08 jrick port ? ":" : "", port ? port : "",
3148 3d1b16d1 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
3149 3d1b16d1 2023-07-08 jrick }
3150 3d1b16d1 2023-07-08 jrick
3151 3d1b16d1 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
3152 3d1b16d1 2023-07-08 jrick server_path, verbosity);
3153 624411d2 2023-07-08 jrick if (error)
3154 624411d2 2023-07-08 jrick goto done;
3155 624411d2 2023-07-08 jrick
3156 3d1b16d1 2023-07-08 jrick /*
3157 3d1b16d1 2023-07-08 jrick * If set, get this remote's HEAD ref target so
3158 3d1b16d1 2023-07-08 jrick * if it has changed on the server we can fetch it.
3159 3d1b16d1 2023-07-08 jrick */
3160 3d1b16d1 2023-07-08 jrick error = got_ref_list(&remote_refs, repo, "refs/remotes",
3161 3d1b16d1 2023-07-08 jrick got_ref_cmp_by_name, repo);
3162 624411d2 2023-07-08 jrick if (error)
3163 624411d2 2023-07-08 jrick goto done;
3164 624411d2 2023-07-08 jrick
3165 3d1b16d1 2023-07-08 jrick TAILQ_FOREACH(re, &remote_refs, entry) {
3166 3d1b16d1 2023-07-08 jrick const char *remote_refname, *remote_target;
3167 3d1b16d1 2023-07-08 jrick size_t remote_name_len;
3168 3d1b16d1 2023-07-08 jrick
3169 3d1b16d1 2023-07-08 jrick if (!got_ref_is_symbolic(re->ref))
3170 3d1b16d1 2023-07-08 jrick continue;
3171 3d1b16d1 2023-07-08 jrick
3172 3d1b16d1 2023-07-08 jrick remote_name_len = strlen(remote->name);
3173 3d1b16d1 2023-07-08 jrick remote_refname = got_ref_get_name(re->ref);
3174 3d1b16d1 2023-07-08 jrick
3175 3d1b16d1 2023-07-08 jrick /* we only want refs/remotes/$remote->name/HEAD */
3176 3d1b16d1 2023-07-08 jrick if (strncmp(remote_refname + 13, remote->name,
3177 3d1b16d1 2023-07-08 jrick remote_name_len) != 0)
3178 3d1b16d1 2023-07-08 jrick continue;
3179 3d1b16d1 2023-07-08 jrick
3180 3d1b16d1 2023-07-08 jrick if (strcmp(remote_refname + remote_name_len + 14,
3181 3d1b16d1 2023-07-08 jrick GOT_REF_HEAD) != 0)
3182 3d1b16d1 2023-07-08 jrick continue;
3183 3d1b16d1 2023-07-08 jrick
3184 3d1b16d1 2023-07-08 jrick /*
3185 3d1b16d1 2023-07-08 jrick * Take the name itself because we already
3186 3d1b16d1 2023-07-08 jrick * only match with refs/heads/ in fetch_pack().
3187 3d1b16d1 2023-07-08 jrick */
3188 3d1b16d1 2023-07-08 jrick remote_target = got_ref_get_symref_target(re->ref);
3189 3d1b16d1 2023-07-08 jrick remote_head = remote_target + remote_name_len + 14;
3190 3d1b16d1 2023-07-08 jrick break;
3191 3d1b16d1 2023-07-08 jrick }
3192 3d1b16d1 2023-07-08 jrick
3193 3d1b16d1 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
3194 3d1b16d1 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
3195 3d1b16d1 2023-07-08 jrick worktree_branch = refname;
3196 3d1b16d1 2023-07-08 jrick
3197 3d1b16d1 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
3198 3d1b16d1 2023-07-08 jrick fpa.last_p_indexed = -1;
3199 3d1b16d1 2023-07-08 jrick fpa.last_p_resolved = -1;
3200 3d1b16d1 2023-07-08 jrick fpa.verbosity = verbosity;
3201 3d1b16d1 2023-07-08 jrick fpa.repo = repo;
3202 3d1b16d1 2023-07-08 jrick fpa.create_configs = 0;
3203 3d1b16d1 2023-07-08 jrick fpa.configs_created = 0;
3204 3d1b16d1 2023-07-08 jrick memset(&fpa.config_info, 0, sizeof(fpa.config_info));
3205 3d1b16d1 2023-07-08 jrick
3206 3d1b16d1 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
3207 3d1b16d1 2023-07-08 jrick remote->mirror_references, 0, &wanted_branches, &wanted_refs,
3208 3d1b16d1 2023-07-08 jrick 0, verbosity, fetchfd, repo, worktree_branch, remote_head,
3209 3d1b16d1 2023-07-08 jrick 0, fetch_progress, &fpa);
3210 3d1b16d1 2023-07-08 jrick if (error)
3211 3d1b16d1 2023-07-08 jrick goto done;
3212 3d1b16d1 2023-07-08 jrick
3213 3d1b16d1 2023-07-08 jrick if (pack_hash != NULL && verbosity >= 0) {
3214 3d1b16d1 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
3215 3d1b16d1 2023-07-08 jrick if (error)
3216 3d1b16d1 2023-07-08 jrick goto done;
3217 3d1b16d1 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
3218 3d1b16d1 2023-07-08 jrick free(id_str);
3219 3d1b16d1 2023-07-08 jrick id_str = NULL;
3220 3d1b16d1 2023-07-08 jrick }
3221 3d1b16d1 2023-07-08 jrick
3222 3d1b16d1 2023-07-08 jrick /* Update references provided with the pack file. */
3223 3d1b16d1 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
3224 3d1b16d1 2023-07-08 jrick const char *refname = pe->path;
3225 3d1b16d1 2023-07-08 jrick struct got_object_id *id = pe->data;
3226 3d1b16d1 2023-07-08 jrick struct got_reference *ref;
3227 3d1b16d1 2023-07-08 jrick
3228 3d1b16d1 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname)) {
3229 3d1b16d1 2023-07-08 jrick error = update_wanted_ref(refname, id,
3230 3d1b16d1 2023-07-08 jrick remote->name, verbosity, repo);
3231 3d1b16d1 2023-07-08 jrick if (error)
3232 3d1b16d1 2023-07-08 jrick goto done;
3233 3d1b16d1 2023-07-08 jrick continue;
3234 3d1b16d1 2023-07-08 jrick }
3235 3d1b16d1 2023-07-08 jrick
3236 3d1b16d1 2023-07-08 jrick error = got_ref_open(&ref, repo, refname, 1);
3237 3d1b16d1 2023-07-08 jrick if (error) {
3238 3d1b16d1 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
3239 3d1b16d1 2023-07-08 jrick goto done;
3240 3d1b16d1 2023-07-08 jrick error = create_ref(refname, id, verbosity,
3241 3d1b16d1 2023-07-08 jrick repo);
3242 3d1b16d1 2023-07-08 jrick if (error)
3243 3d1b16d1 2023-07-08 jrick goto done;
3244 3d1b16d1 2023-07-08 jrick } else {
3245 3d1b16d1 2023-07-08 jrick error = update_ref(ref, id, replace_tags,
3246 3d1b16d1 2023-07-08 jrick verbosity-1, repo);
3247 3d1b16d1 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
3248 3d1b16d1 2023-07-08 jrick if (unlock_err && error == NULL)
3249 3d1b16d1 2023-07-08 jrick error = unlock_err;
3250 3d1b16d1 2023-07-08 jrick got_ref_close(ref);
3251 3d1b16d1 2023-07-08 jrick if (error)
3252 3d1b16d1 2023-07-08 jrick goto done;
3253 3d1b16d1 2023-07-08 jrick }
3254 3d1b16d1 2023-07-08 jrick }
3255 3d1b16d1 2023-07-08 jrick
3256 3d1b16d1 2023-07-08 jrick /* Update worktree */
3257 3d1b16d1 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
3258 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
3259 624411d2 2023-07-08 jrick if (error != NULL)
3260 624411d2 2023-07-08 jrick goto done;
3261 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
3262 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
3263 624411d2 2023-07-08 jrick if (error != NULL)
3264 624411d2 2023-07-08 jrick goto done;
3265 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
3266 624411d2 2023-07-08 jrick if (error != NULL)
3267 624411d2 2023-07-08 jrick goto done;
3268 624411d2 2023-07-08 jrick } else {
3269 624411d2 2023-07-08 jrick struct got_reflist_head refs;
3270 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
3271 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
3272 624411d2 2023-07-08 jrick NULL);
3273 624411d2 2023-07-08 jrick if (error)
3274 624411d2 2023-07-08 jrick goto done;
3275 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
3276 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
3277 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
3278 624411d2 2023-07-08 jrick free(commit_id_str);
3279 624411d2 2023-07-08 jrick commit_id_str = NULL;
3280 624411d2 2023-07-08 jrick if (error)
3281 624411d2 2023-07-08 jrick goto done;
3282 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
3283 624411d2 2023-07-08 jrick if (error)
3284 624411d2 2023-07-08 jrick goto done;
3285 624411d2 2023-07-08 jrick }
3286 624411d2 2023-07-08 jrick
3287 3d1b16d1 2023-07-08 jrick
3288 3d1b16d1 2023-07-08 jrick error = check_linear_ancestry(commit_id,
3289 3d1b16d1 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
3290 3d1b16d1 2023-07-08 jrick if (error != NULL) {
3291 3d1b16d1 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY)
3292 3d1b16d1 2023-07-08 jrick error = got_error(GOT_ERR_BRANCH_MOVED);
3293 3d1b16d1 2023-07-08 jrick goto done;
3294 624411d2 2023-07-08 jrick }
3295 3d1b16d1 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
3296 3d1b16d1 2023-07-08 jrick if (error)
3297 3d1b16d1 2023-07-08 jrick goto done;
3298 624411d2 2023-07-08 jrick
3299 624411d2 2023-07-08 jrick if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
3300 624411d2 2023-07-08 jrick commit_id) != 0) {
3301 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
3302 624411d2 2023-07-08 jrick commit_id);
3303 624411d2 2023-07-08 jrick if (error)
3304 624411d2 2023-07-08 jrick goto done;
3305 624411d2 2023-07-08 jrick }
3306 624411d2 2023-07-08 jrick
3307 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
3308 624411d2 2023-07-08 jrick upa.verbosity = verbosity;
3309 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
3310 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
3311 624411d2 2023-07-08 jrick if (error != NULL)
3312 624411d2 2023-07-08 jrick goto done;
3313 624411d2 2023-07-08 jrick
3314 624411d2 2023-07-08 jrick if (upa.did_something) {
3315 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
3316 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), commit_id_str);
3317 624411d2 2023-07-08 jrick } else
3318 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
3319 624411d2 2023-07-08 jrick
3320 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
3321 624411d2 2023-07-08 jrick done:
3322 3d1b16d1 2023-07-08 jrick if (fetchpid > 0) {
3323 3d1b16d1 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
3324 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("kill");
3325 3d1b16d1 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
3326 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("waitpid");
3327 624411d2 2023-07-08 jrick }
3328 3d1b16d1 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
3329 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("close");
3330 624411d2 2023-07-08 jrick if (repo) {
3331 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
3332 624411d2 2023-07-08 jrick if (error == NULL)
3333 624411d2 2023-07-08 jrick error = close_err;
3334 624411d2 2023-07-08 jrick }
3335 3d1b16d1 2023-07-08 jrick if (worktree)
3336 3d1b16d1 2023-07-08 jrick got_worktree_close(worktree);
3337 3d1b16d1 2023-07-08 jrick if (pack_fds) {
3338 3d1b16d1 2023-07-08 jrick const struct got_error *pack_err =
3339 3d1b16d1 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
3340 3d1b16d1 2023-07-08 jrick if (error == NULL)
3341 3d1b16d1 2023-07-08 jrick error = pack_err;
3342 3d1b16d1 2023-07-08 jrick }
3343 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
3344 3d1b16d1 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
3345 3d1b16d1 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
3346 3d1b16d1 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
3347 3d1b16d1 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
3348 3d1b16d1 2023-07-08 jrick got_ref_list_free(&remote_refs);
3349 3d1b16d1 2023-07-08 jrick free(id_str);
3350 3d1b16d1 2023-07-08 jrick free(worktree_path);
3351 3d1b16d1 2023-07-08 jrick free(pack_hash);
3352 3d1b16d1 2023-07-08 jrick free(proto);
3353 3d1b16d1 2023-07-08 jrick free(host);
3354 3d1b16d1 2023-07-08 jrick free(port);
3355 3d1b16d1 2023-07-08 jrick free(server_path);
3356 3d1b16d1 2023-07-08 jrick free(repo_name);
3357 624411d2 2023-07-08 jrick free(commit_id);
3358 624411d2 2023-07-08 jrick free(commit_id_str);
3359 624411d2 2023-07-08 jrick return error;
3360 624411d2 2023-07-08 jrick }
3361 624411d2 2023-07-08 jrick
3362 624411d2 2023-07-08 jrick static const struct got_error *
3363 624411d2 2023-07-08 jrick diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3364 624411d2 2023-07-08 jrick const char *path, int diff_context, int ignore_whitespace,
3365 624411d2 2023-07-08 jrick int force_text_diff, struct got_diffstat_cb_arg *dsa,
3366 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3367 624411d2 2023-07-08 jrick {
3368 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3369 624411d2 2023-07-08 jrick struct got_blob_object *blob1 = NULL, *blob2 = NULL;
3370 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3371 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3372 624411d2 2023-07-08 jrick
3373 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3374 624411d2 2023-07-08 jrick if (fd1 == -1)
3375 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
3376 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3377 624411d2 2023-07-08 jrick if (fd2 == -1) {
3378 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3379 624411d2 2023-07-08 jrick goto done;
3380 624411d2 2023-07-08 jrick }
3381 624411d2 2023-07-08 jrick
3382 624411d2 2023-07-08 jrick if (blob_id1) {
3383 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192,
3384 624411d2 2023-07-08 jrick fd1);
3385 624411d2 2023-07-08 jrick if (err)
3386 624411d2 2023-07-08 jrick goto done;
3387 624411d2 2023-07-08 jrick }
3388 624411d2 2023-07-08 jrick
3389 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2);
3390 624411d2 2023-07-08 jrick if (err)
3391 624411d2 2023-07-08 jrick goto done;
3392 624411d2 2023-07-08 jrick
3393 624411d2 2023-07-08 jrick f1 = got_opentemp();
3394 624411d2 2023-07-08 jrick if (f1 == NULL) {
3395 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3396 624411d2 2023-07-08 jrick goto done;
3397 624411d2 2023-07-08 jrick }
3398 624411d2 2023-07-08 jrick f2 = got_opentemp();
3399 624411d2 2023-07-08 jrick if (f2 == NULL) {
3400 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3401 624411d2 2023-07-08 jrick goto done;
3402 624411d2 2023-07-08 jrick }
3403 624411d2 2023-07-08 jrick
3404 624411d2 2023-07-08 jrick while (path[0] == '/')
3405 624411d2 2023-07-08 jrick path++;
3406 624411d2 2023-07-08 jrick err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path,
3407 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace,
3408 624411d2 2023-07-08 jrick force_text_diff, dsa, outfile);
3409 624411d2 2023-07-08 jrick done:
3410 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3411 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3412 624411d2 2023-07-08 jrick if (blob1)
3413 624411d2 2023-07-08 jrick got_object_blob_close(blob1);
3414 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3415 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3416 624411d2 2023-07-08 jrick if (blob2)
3417 624411d2 2023-07-08 jrick got_object_blob_close(blob2);
3418 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3419 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3420 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3421 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3422 624411d2 2023-07-08 jrick return err;
3423 624411d2 2023-07-08 jrick }
3424 624411d2 2023-07-08 jrick
3425 624411d2 2023-07-08 jrick static const struct got_error *
3426 624411d2 2023-07-08 jrick diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
3427 624411d2 2023-07-08 jrick const char *path, int diff_context, int ignore_whitespace,
3428 624411d2 2023-07-08 jrick int force_text_diff, struct got_diffstat_cb_arg *dsa,
3429 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3430 624411d2 2023-07-08 jrick {
3431 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3432 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3433 624411d2 2023-07-08 jrick struct got_diff_blob_output_unidiff_arg arg;
3434 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3435 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3436 624411d2 2023-07-08 jrick
3437 624411d2 2023-07-08 jrick if (tree_id1) {
3438 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo, tree_id1);
3439 624411d2 2023-07-08 jrick if (err)
3440 624411d2 2023-07-08 jrick goto done;
3441 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3442 624411d2 2023-07-08 jrick if (fd1 == -1) {
3443 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3444 624411d2 2023-07-08 jrick goto done;
3445 624411d2 2023-07-08 jrick }
3446 624411d2 2023-07-08 jrick }
3447 624411d2 2023-07-08 jrick
3448 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo, tree_id2);
3449 624411d2 2023-07-08 jrick if (err)
3450 624411d2 2023-07-08 jrick goto done;
3451 624411d2 2023-07-08 jrick
3452 624411d2 2023-07-08 jrick f1 = got_opentemp();
3453 624411d2 2023-07-08 jrick if (f1 == NULL) {
3454 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3455 624411d2 2023-07-08 jrick goto done;
3456 624411d2 2023-07-08 jrick }
3457 624411d2 2023-07-08 jrick
3458 624411d2 2023-07-08 jrick f2 = got_opentemp();
3459 624411d2 2023-07-08 jrick if (f2 == NULL) {
3460 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3461 624411d2 2023-07-08 jrick goto done;
3462 624411d2 2023-07-08 jrick }
3463 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3464 624411d2 2023-07-08 jrick if (fd2 == -1) {
3465 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3466 624411d2 2023-07-08 jrick goto done;
3467 624411d2 2023-07-08 jrick }
3468 624411d2 2023-07-08 jrick arg.diff_context = diff_context;
3469 624411d2 2023-07-08 jrick arg.ignore_whitespace = ignore_whitespace;
3470 624411d2 2023-07-08 jrick arg.force_text_diff = force_text_diff;
3471 624411d2 2023-07-08 jrick arg.diffstat = dsa;
3472 624411d2 2023-07-08 jrick arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
3473 624411d2 2023-07-08 jrick arg.outfile = outfile;
3474 624411d2 2023-07-08 jrick arg.lines = NULL;
3475 624411d2 2023-07-08 jrick arg.nlines = 0;
3476 624411d2 2023-07-08 jrick while (path[0] == '/')
3477 624411d2 2023-07-08 jrick path++;
3478 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, path, path, repo,
3479 624411d2 2023-07-08 jrick got_diff_blob_output_unidiff, &arg, 1);
3480 624411d2 2023-07-08 jrick done:
3481 624411d2 2023-07-08 jrick if (tree1)
3482 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
3483 624411d2 2023-07-08 jrick if (tree2)
3484 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
3485 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3486 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3487 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3488 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3489 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3490 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3491 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3492 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3493 624411d2 2023-07-08 jrick return err;
3494 624411d2 2023-07-08 jrick }
3495 624411d2 2023-07-08 jrick
3496 624411d2 2023-07-08 jrick static const struct got_error *
3497 624411d2 2023-07-08 jrick get_changed_paths(struct got_pathlist_head *paths,
3498 624411d2 2023-07-08 jrick struct got_commit_object *commit, struct got_repository *repo,
3499 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *dsa)
3500 624411d2 2023-07-08 jrick {
3501 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3502 624411d2 2023-07-08 jrick struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3503 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3504 624411d2 2023-07-08 jrick struct got_object_qid *qid;
3505 624411d2 2023-07-08 jrick got_diff_blob_cb cb = got_diff_tree_collect_changed_paths;
3506 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3507 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3508 624411d2 2023-07-08 jrick
3509 624411d2 2023-07-08 jrick if (dsa) {
3510 624411d2 2023-07-08 jrick cb = got_diff_tree_compute_diffstat;
3511 624411d2 2023-07-08 jrick
3512 624411d2 2023-07-08 jrick f1 = got_opentemp();
3513 624411d2 2023-07-08 jrick if (f1 == NULL) {
3514 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3515 624411d2 2023-07-08 jrick goto done;
3516 624411d2 2023-07-08 jrick }
3517 624411d2 2023-07-08 jrick f2 = got_opentemp();
3518 624411d2 2023-07-08 jrick if (f2 == NULL) {
3519 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3520 624411d2 2023-07-08 jrick goto done;
3521 624411d2 2023-07-08 jrick }
3522 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3523 624411d2 2023-07-08 jrick if (fd1 == -1) {
3524 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3525 624411d2 2023-07-08 jrick goto done;
3526 624411d2 2023-07-08 jrick }
3527 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3528 624411d2 2023-07-08 jrick if (fd2 == -1) {
3529 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3530 624411d2 2023-07-08 jrick goto done;
3531 624411d2 2023-07-08 jrick }
3532 624411d2 2023-07-08 jrick }
3533 624411d2 2023-07-08 jrick
3534 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3535 624411d2 2023-07-08 jrick if (qid != NULL) {
3536 624411d2 2023-07-08 jrick struct got_commit_object *pcommit;
3537 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo,
3538 624411d2 2023-07-08 jrick &qid->id);
3539 624411d2 2023-07-08 jrick if (err)
3540 624411d2 2023-07-08 jrick return err;
3541 624411d2 2023-07-08 jrick
3542 624411d2 2023-07-08 jrick tree_id1 = got_object_id_dup(
3543 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(pcommit));
3544 624411d2 2023-07-08 jrick if (tree_id1 == NULL) {
3545 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3546 624411d2 2023-07-08 jrick return got_error_from_errno("got_object_id_dup");
3547 624411d2 2023-07-08 jrick }
3548 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3549 624411d2 2023-07-08 jrick
3550 624411d2 2023-07-08 jrick }
3551 624411d2 2023-07-08 jrick
3552 624411d2 2023-07-08 jrick if (tree_id1) {
3553 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo, tree_id1);
3554 624411d2 2023-07-08 jrick if (err)
3555 624411d2 2023-07-08 jrick goto done;
3556 624411d2 2023-07-08 jrick }
3557 624411d2 2023-07-08 jrick
3558 624411d2 2023-07-08 jrick tree_id2 = got_object_commit_get_tree_id(commit);
3559 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo, tree_id2);
3560 624411d2 2023-07-08 jrick if (err)
3561 624411d2 2023-07-08 jrick goto done;
3562 624411d2 2023-07-08 jrick
3563 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3564 624411d2 2023-07-08 jrick cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0);
3565 624411d2 2023-07-08 jrick done:
3566 624411d2 2023-07-08 jrick if (tree1)
3567 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
3568 624411d2 2023-07-08 jrick if (tree2)
3569 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
3570 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3571 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3572 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3573 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3574 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3575 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3576 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3577 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3578 624411d2 2023-07-08 jrick free(tree_id1);
3579 624411d2 2023-07-08 jrick return err;
3580 624411d2 2023-07-08 jrick }
3581 624411d2 2023-07-08 jrick
3582 624411d2 2023-07-08 jrick static const struct got_error *
3583 624411d2 2023-07-08 jrick print_patch(struct got_commit_object *commit, struct got_object_id *id,
3584 624411d2 2023-07-08 jrick const char *path, int diff_context, struct got_diffstat_cb_arg *dsa,
3585 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3586 624411d2 2023-07-08 jrick {
3587 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3588 624411d2 2023-07-08 jrick struct got_commit_object *pcommit = NULL;
3589 624411d2 2023-07-08 jrick char *id_str1 = NULL, *id_str2 = NULL;
3590 624411d2 2023-07-08 jrick struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL;
3591 624411d2 2023-07-08 jrick struct got_object_qid *qid;
3592 624411d2 2023-07-08 jrick
3593 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3594 624411d2 2023-07-08 jrick if (qid != NULL) {
3595 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo,
3596 624411d2 2023-07-08 jrick &qid->id);
3597 624411d2 2023-07-08 jrick if (err)
3598 624411d2 2023-07-08 jrick return err;
3599 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str1, &qid->id);
3600 624411d2 2023-07-08 jrick if (err)
3601 624411d2 2023-07-08 jrick goto done;
3602 624411d2 2023-07-08 jrick }
3603 624411d2 2023-07-08 jrick
3604 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str2, id);
3605 624411d2 2023-07-08 jrick if (err)
3606 624411d2 2023-07-08 jrick goto done;
3607 624411d2 2023-07-08 jrick
3608 624411d2 2023-07-08 jrick if (path && path[0] != '\0') {
3609 624411d2 2023-07-08 jrick int obj_type;
3610 624411d2 2023-07-08 jrick err = got_object_id_by_path(&obj_id2, repo, commit, path);
3611 624411d2 2023-07-08 jrick if (err)
3612 624411d2 2023-07-08 jrick goto done;
3613 624411d2 2023-07-08 jrick if (pcommit) {
3614 624411d2 2023-07-08 jrick err = got_object_id_by_path(&obj_id1, repo,
3615 624411d2 2023-07-08 jrick pcommit, path);
3616 624411d2 2023-07-08 jrick if (err) {
3617 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NO_TREE_ENTRY) {
3618 624411d2 2023-07-08 jrick free(obj_id2);
3619 624411d2 2023-07-08 jrick goto done;
3620 624411d2 2023-07-08 jrick }
3621 624411d2 2023-07-08 jrick }
3622 624411d2 2023-07-08 jrick }
3623 624411d2 2023-07-08 jrick err = got_object_get_type(&obj_type, repo, obj_id2);
3624 624411d2 2023-07-08 jrick if (err) {
3625 624411d2 2023-07-08 jrick free(obj_id2);
3626 624411d2 2023-07-08 jrick goto done;
3627 624411d2 2023-07-08 jrick }
3628 624411d2 2023-07-08 jrick fprintf(outfile,
3629 624411d2 2023-07-08 jrick "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3630 624411d2 2023-07-08 jrick fprintf(outfile, "commit - %s\n",
3631 624411d2 2023-07-08 jrick id_str1 ? id_str1 : "/dev/null");
3632 624411d2 2023-07-08 jrick fprintf(outfile, "commit + %s\n", id_str2);
3633 624411d2 2023-07-08 jrick switch (obj_type) {
3634 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
3635 624411d2 2023-07-08 jrick err = diff_blobs(obj_id1, obj_id2, path, diff_context,
3636 624411d2 2023-07-08 jrick 0, 0, dsa, repo, outfile);
3637 624411d2 2023-07-08 jrick break;
3638 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
3639 624411d2 2023-07-08 jrick err = diff_trees(obj_id1, obj_id2, path, diff_context,
3640 624411d2 2023-07-08 jrick 0, 0, dsa, repo, outfile);
3641 624411d2 2023-07-08 jrick break;
3642 624411d2 2023-07-08 jrick default:
3643 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_OBJ_TYPE);
3644 624411d2 2023-07-08 jrick break;
3645 624411d2 2023-07-08 jrick }
3646 624411d2 2023-07-08 jrick free(obj_id1);
3647 624411d2 2023-07-08 jrick free(obj_id2);
3648 624411d2 2023-07-08 jrick } else {
3649 624411d2 2023-07-08 jrick obj_id2 = got_object_commit_get_tree_id(commit);
3650 624411d2 2023-07-08 jrick if (pcommit)
3651 624411d2 2023-07-08 jrick obj_id1 = got_object_commit_get_tree_id(pcommit);
3652 624411d2 2023-07-08 jrick fprintf(outfile,
3653 624411d2 2023-07-08 jrick "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3654 624411d2 2023-07-08 jrick fprintf(outfile, "commit - %s\n",
3655 624411d2 2023-07-08 jrick id_str1 ? id_str1 : "/dev/null");
3656 624411d2 2023-07-08 jrick fprintf(outfile, "commit + %s\n", id_str2);
3657 624411d2 2023-07-08 jrick err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
3658 624411d2 2023-07-08 jrick dsa, repo, outfile);
3659 624411d2 2023-07-08 jrick }
3660 624411d2 2023-07-08 jrick done:
3661 624411d2 2023-07-08 jrick free(id_str1);
3662 624411d2 2023-07-08 jrick free(id_str2);
3663 624411d2 2023-07-08 jrick if (pcommit)
3664 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3665 624411d2 2023-07-08 jrick return err;
3666 624411d2 2023-07-08 jrick }
3667 624411d2 2023-07-08 jrick
3668 624411d2 2023-07-08 jrick static char *
3669 624411d2 2023-07-08 jrick get_datestr(time_t *time, char *datebuf)
3670 624411d2 2023-07-08 jrick {
3671 624411d2 2023-07-08 jrick struct tm mytm, *tm;
3672 624411d2 2023-07-08 jrick char *p, *s;
3673 624411d2 2023-07-08 jrick
3674 624411d2 2023-07-08 jrick tm = gmtime_r(time, &mytm);
3675 624411d2 2023-07-08 jrick if (tm == NULL)
3676 624411d2 2023-07-08 jrick return NULL;
3677 624411d2 2023-07-08 jrick s = asctime_r(tm, datebuf);
3678 624411d2 2023-07-08 jrick if (s == NULL)
3679 624411d2 2023-07-08 jrick return NULL;
3680 624411d2 2023-07-08 jrick p = strchr(s, '\n');
3681 624411d2 2023-07-08 jrick if (p)
3682 624411d2 2023-07-08 jrick *p = '\0';
3683 624411d2 2023-07-08 jrick return s;
3684 624411d2 2023-07-08 jrick }
3685 624411d2 2023-07-08 jrick
3686 624411d2 2023-07-08 jrick static const struct got_error *
3687 624411d2 2023-07-08 jrick match_commit(int *have_match, struct got_object_id *id,
3688 624411d2 2023-07-08 jrick struct got_commit_object *commit, regex_t *regex)
3689 624411d2 2023-07-08 jrick {
3690 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3691 624411d2 2023-07-08 jrick regmatch_t regmatch;
3692 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg = NULL;
3693 624411d2 2023-07-08 jrick
3694 624411d2 2023-07-08 jrick *have_match = 0;
3695 624411d2 2023-07-08 jrick
3696 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3697 624411d2 2023-07-08 jrick if (err)
3698 624411d2 2023-07-08 jrick return err;
3699 624411d2 2023-07-08 jrick
3700 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg, commit);
3701 624411d2 2023-07-08 jrick if (err)
3702 624411d2 2023-07-08 jrick goto done;
3703 624411d2 2023-07-08 jrick
3704 624411d2 2023-07-08 jrick if (regexec(regex, got_object_commit_get_author(commit), 1,
3705 624411d2 2023-07-08 jrick &regmatch, 0) == 0 ||
3706 624411d2 2023-07-08 jrick regexec(regex, got_object_commit_get_committer(commit), 1,
3707 624411d2 2023-07-08 jrick &regmatch, 0) == 0 ||
3708 624411d2 2023-07-08 jrick regexec(regex, id_str, 1, &regmatch, 0) == 0 ||
3709 624411d2 2023-07-08 jrick regexec(regex, logmsg, 1, &regmatch, 0) == 0)
3710 624411d2 2023-07-08 jrick *have_match = 1;
3711 624411d2 2023-07-08 jrick done:
3712 624411d2 2023-07-08 jrick free(id_str);
3713 624411d2 2023-07-08 jrick free(logmsg);
3714 624411d2 2023-07-08 jrick return err;
3715 624411d2 2023-07-08 jrick }
3716 624411d2 2023-07-08 jrick
3717 624411d2 2023-07-08 jrick static void
3718 624411d2 2023-07-08 jrick match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3719 624411d2 2023-07-08 jrick regex_t *regex)
3720 624411d2 2023-07-08 jrick {
3721 624411d2 2023-07-08 jrick regmatch_t regmatch;
3722 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
3723 624411d2 2023-07-08 jrick
3724 624411d2 2023-07-08 jrick *have_match = 0;
3725 624411d2 2023-07-08 jrick
3726 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, changed_paths, entry) {
3727 624411d2 2023-07-08 jrick if (regexec(regex, pe->path, 1, &regmatch, 0) == 0) {
3728 624411d2 2023-07-08 jrick *have_match = 1;
3729 624411d2 2023-07-08 jrick break;
3730 624411d2 2023-07-08 jrick }
3731 624411d2 2023-07-08 jrick }
3732 624411d2 2023-07-08 jrick }
3733 624411d2 2023-07-08 jrick
3734 624411d2 2023-07-08 jrick static const struct got_error *
3735 624411d2 2023-07-08 jrick match_patch(int *have_match, struct got_commit_object *commit,
3736 624411d2 2023-07-08 jrick struct got_object_id *id, const char *path, int diff_context,
3737 624411d2 2023-07-08 jrick struct got_repository *repo, regex_t *regex, FILE *f)
3738 624411d2 2023-07-08 jrick {
3739 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3740 624411d2 2023-07-08 jrick char *line = NULL;
3741 624411d2 2023-07-08 jrick size_t linesize = 0;
3742 624411d2 2023-07-08 jrick regmatch_t regmatch;
3743 624411d2 2023-07-08 jrick
3744 624411d2 2023-07-08 jrick *have_match = 0;
3745 624411d2 2023-07-08 jrick
3746 624411d2 2023-07-08 jrick err = got_opentemp_truncate(f);
3747 624411d2 2023-07-08 jrick if (err)
3748 624411d2 2023-07-08 jrick return err;
3749 624411d2 2023-07-08 jrick
3750 624411d2 2023-07-08 jrick err = print_patch(commit, id, path, diff_context, NULL, repo, f);
3751 624411d2 2023-07-08 jrick if (err)
3752 624411d2 2023-07-08 jrick goto done;
3753 624411d2 2023-07-08 jrick
3754 624411d2 2023-07-08 jrick if (fseeko(f, 0L, SEEK_SET) == -1) {
3755 624411d2 2023-07-08 jrick err = got_error_from_errno("fseeko");
3756 624411d2 2023-07-08 jrick goto done;
3757 624411d2 2023-07-08 jrick }
3758 624411d2 2023-07-08 jrick
3759 624411d2 2023-07-08 jrick while (getline(&line, &linesize, f) != -1) {
3760 624411d2 2023-07-08 jrick if (regexec(regex, line, 1, &regmatch, 0) == 0) {
3761 624411d2 2023-07-08 jrick *have_match = 1;
3762 624411d2 2023-07-08 jrick break;
3763 624411d2 2023-07-08 jrick }
3764 624411d2 2023-07-08 jrick }
3765 624411d2 2023-07-08 jrick done:
3766 624411d2 2023-07-08 jrick free(line);
3767 624411d2 2023-07-08 jrick return err;
3768 624411d2 2023-07-08 jrick }
3769 624411d2 2023-07-08 jrick
3770 624411d2 2023-07-08 jrick #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3771 624411d2 2023-07-08 jrick
3772 624411d2 2023-07-08 jrick static const struct got_error*
3773 624411d2 2023-07-08 jrick build_refs_str(char **refs_str, struct got_reflist_head *refs,
3774 624411d2 2023-07-08 jrick struct got_object_id *id, struct got_repository *repo,
3775 624411d2 2023-07-08 jrick int local_only)
3776 624411d2 2023-07-08 jrick {
3777 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
3778 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
3779 624411d2 2023-07-08 jrick char *s;
3780 624411d2 2023-07-08 jrick const char *name;
3781 624411d2 2023-07-08 jrick
3782 624411d2 2023-07-08 jrick *refs_str = NULL;
3783 624411d2 2023-07-08 jrick
3784 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, refs, entry) {
3785 624411d2 2023-07-08 jrick struct got_tag_object *tag = NULL;
3786 624411d2 2023-07-08 jrick struct got_object_id *ref_id;
3787 624411d2 2023-07-08 jrick int cmp;
3788 624411d2 2023-07-08 jrick
3789 624411d2 2023-07-08 jrick name = got_ref_get_name(re->ref);
3790 624411d2 2023-07-08 jrick if (strcmp(name, GOT_REF_HEAD) == 0)
3791 624411d2 2023-07-08 jrick continue;
3792 624411d2 2023-07-08 jrick if (strncmp(name, "refs/", 5) == 0)
3793 624411d2 2023-07-08 jrick name += 5;
3794 624411d2 2023-07-08 jrick if (strncmp(name, "got/", 4) == 0)
3795 624411d2 2023-07-08 jrick continue;
3796 624411d2 2023-07-08 jrick if (strncmp(name, "heads/", 6) == 0)
3797 624411d2 2023-07-08 jrick name += 6;
3798 624411d2 2023-07-08 jrick if (strncmp(name, "remotes/", 8) == 0) {
3799 624411d2 2023-07-08 jrick if (local_only)
3800 624411d2 2023-07-08 jrick continue;
3801 624411d2 2023-07-08 jrick name += 8;
3802 624411d2 2023-07-08 jrick s = strstr(name, "/" GOT_REF_HEAD);
3803 624411d2 2023-07-08 jrick if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0)
3804 624411d2 2023-07-08 jrick continue;
3805 624411d2 2023-07-08 jrick }
3806 624411d2 2023-07-08 jrick err = got_ref_resolve(&ref_id, repo, re->ref);
3807 624411d2 2023-07-08 jrick if (err)
3808 624411d2 2023-07-08 jrick break;
3809 624411d2 2023-07-08 jrick if (strncmp(name, "tags/", 5) == 0) {
3810 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, ref_id);
3811 624411d2 2023-07-08 jrick if (err) {
3812 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_OBJ_TYPE) {
3813 624411d2 2023-07-08 jrick free(ref_id);
3814 624411d2 2023-07-08 jrick break;
3815 624411d2 2023-07-08 jrick }
3816 624411d2 2023-07-08 jrick /* Ref points at something other than a tag. */
3817 624411d2 2023-07-08 jrick err = NULL;
3818 624411d2 2023-07-08 jrick tag = NULL;
3819 624411d2 2023-07-08 jrick }
3820 624411d2 2023-07-08 jrick }
3821 624411d2 2023-07-08 jrick cmp = got_object_id_cmp(tag ?
3822 624411d2 2023-07-08 jrick got_object_tag_get_object_id(tag) : ref_id, id);
3823 624411d2 2023-07-08 jrick free(ref_id);
3824 624411d2 2023-07-08 jrick if (tag)
3825 624411d2 2023-07-08 jrick got_object_tag_close(tag);
3826 624411d2 2023-07-08 jrick if (cmp != 0)
3827 624411d2 2023-07-08 jrick continue;
3828 624411d2 2023-07-08 jrick s = *refs_str;
3829 624411d2 2023-07-08 jrick if (asprintf(refs_str, "%s%s%s", s ? s : "",
3830 624411d2 2023-07-08 jrick s ? ", " : "", name) == -1) {
3831 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
3832 624411d2 2023-07-08 jrick free(s);
3833 624411d2 2023-07-08 jrick *refs_str = NULL;
3834 624411d2 2023-07-08 jrick break;
3835 624411d2 2023-07-08 jrick }
3836 624411d2 2023-07-08 jrick free(s);
3837 624411d2 2023-07-08 jrick }
3838 624411d2 2023-07-08 jrick
3839 624411d2 2023-07-08 jrick return err;
3840 624411d2 2023-07-08 jrick }
3841 624411d2 2023-07-08 jrick
3842 624411d2 2023-07-08 jrick static const struct got_error *
3843 624411d2 2023-07-08 jrick print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id,
3844 624411d2 2023-07-08 jrick struct got_repository *repo, struct got_reflist_object_id_map *refs_idmap)
3845 624411d2 2023-07-08 jrick {
3846 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3847 624411d2 2023-07-08 jrick char *ref_str = NULL, *id_str = NULL, *logmsg0 = NULL;
3848 624411d2 2023-07-08 jrick char *comma, *s, *nl;
3849 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
3850 624411d2 2023-07-08 jrick char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */
3851 624411d2 2023-07-08 jrick struct tm tm;
3852 624411d2 2023-07-08 jrick time_t committer_time;
3853 624411d2 2023-07-08 jrick
3854 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3855 624411d2 2023-07-08 jrick if (refs) {
3856 624411d2 2023-07-08 jrick err = build_refs_str(&ref_str, refs, id, repo, 1);
3857 624411d2 2023-07-08 jrick if (err)
3858 624411d2 2023-07-08 jrick return err;
3859 624411d2 2023-07-08 jrick
3860 624411d2 2023-07-08 jrick /* Display the first matching ref only. */
3861 624411d2 2023-07-08 jrick if (ref_str && (comma = strchr(ref_str, ',')) != NULL)
3862 624411d2 2023-07-08 jrick *comma = '\0';
3863 624411d2 2023-07-08 jrick }
3864 624411d2 2023-07-08 jrick
3865 624411d2 2023-07-08 jrick if (ref_str == NULL) {
3866 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3867 624411d2 2023-07-08 jrick if (err)
3868 624411d2 2023-07-08 jrick return err;
3869 624411d2 2023-07-08 jrick }
3870 624411d2 2023-07-08 jrick
3871 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
3872 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL) {
3873 624411d2 2023-07-08 jrick err = got_error_from_errno("gmtime_r");
3874 624411d2 2023-07-08 jrick goto done;
3875 624411d2 2023-07-08 jrick }
3876 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d ", &tm) == 0) {
3877 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
3878 624411d2 2023-07-08 jrick goto done;
3879 624411d2 2023-07-08 jrick }
3880 624411d2 2023-07-08 jrick
3881 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
3882 624411d2 2023-07-08 jrick if (err)
3883 624411d2 2023-07-08 jrick goto done;
3884 624411d2 2023-07-08 jrick
3885 624411d2 2023-07-08 jrick s = logmsg0;
3886 624411d2 2023-07-08 jrick while (isspace((unsigned char)s[0]))
3887 624411d2 2023-07-08 jrick s++;
3888 624411d2 2023-07-08 jrick
3889 624411d2 2023-07-08 jrick nl = strchr(s, '\n');
3890 624411d2 2023-07-08 jrick if (nl) {
3891 624411d2 2023-07-08 jrick *nl = '\0';
3892 624411d2 2023-07-08 jrick }
3893 624411d2 2023-07-08 jrick
3894 624411d2 2023-07-08 jrick if (ref_str)
3895 624411d2 2023-07-08 jrick printf("%s%-7s %s\n", datebuf, ref_str, s);
3896 624411d2 2023-07-08 jrick else
3897 624411d2 2023-07-08 jrick printf("%s%.7s %s\n", datebuf, id_str, s);
3898 624411d2 2023-07-08 jrick
3899 624411d2 2023-07-08 jrick if (fflush(stdout) != 0 && err == NULL)
3900 624411d2 2023-07-08 jrick err = got_error_from_errno("fflush");
3901 624411d2 2023-07-08 jrick done:
3902 624411d2 2023-07-08 jrick free(id_str);
3903 624411d2 2023-07-08 jrick free(ref_str);
3904 624411d2 2023-07-08 jrick free(logmsg0);
3905 624411d2 2023-07-08 jrick return err;
3906 624411d2 2023-07-08 jrick }
3907 624411d2 2023-07-08 jrick
3908 624411d2 2023-07-08 jrick static const struct got_error *
3909 624411d2 2023-07-08 jrick print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header)
3910 624411d2 2023-07-08 jrick {
3911 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
3912 624411d2 2023-07-08 jrick
3913 624411d2 2023-07-08 jrick if (header != NULL)
3914 624411d2 2023-07-08 jrick printf("%s\n", header);
3915 624411d2 2023-07-08 jrick
3916 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, dsa->paths, entry) {
3917 624411d2 2023-07-08 jrick struct got_diff_changed_path *cp = pe->data;
3918 624411d2 2023-07-08 jrick int pad = dsa->max_path_len - pe->path_len + 1;
3919 624411d2 2023-07-08 jrick
3920 624411d2 2023-07-08 jrick printf(" %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad,
3921 624411d2 2023-07-08 jrick ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm);
3922 624411d2 2023-07-08 jrick }
3923 624411d2 2023-07-08 jrick printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n",
3924 624411d2 2023-07-08 jrick dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins,
3925 624411d2 2023-07-08 jrick dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : "");
3926 624411d2 2023-07-08 jrick
3927 624411d2 2023-07-08 jrick if (fflush(stdout) != 0)
3928 624411d2 2023-07-08 jrick return got_error_from_errno("fflush");
3929 624411d2 2023-07-08 jrick
3930 624411d2 2023-07-08 jrick return NULL;
3931 624411d2 2023-07-08 jrick }
3932 624411d2 2023-07-08 jrick
3933 624411d2 2023-07-08 jrick static const struct got_error *
3934 624411d2 2023-07-08 jrick printfile(FILE *f)
3935 624411d2 2023-07-08 jrick {
3936 624411d2 2023-07-08 jrick char buf[8192];
3937 624411d2 2023-07-08 jrick size_t r;
3938 624411d2 2023-07-08 jrick
3939 624411d2 2023-07-08 jrick if (fseeko(f, 0L, SEEK_SET) == -1)
3940 624411d2 2023-07-08 jrick return got_error_from_errno("fseek");
3941 624411d2 2023-07-08 jrick
3942 624411d2 2023-07-08 jrick for (;;) {
3943 624411d2 2023-07-08 jrick r = fread(buf, 1, sizeof(buf), f);
3944 624411d2 2023-07-08 jrick if (r == 0) {
3945 624411d2 2023-07-08 jrick if (ferror(f))
3946 624411d2 2023-07-08 jrick return got_error_from_errno("fread");
3947 624411d2 2023-07-08 jrick if (feof(f))
3948 624411d2 2023-07-08 jrick break;
3949 624411d2 2023-07-08 jrick }
3950 624411d2 2023-07-08 jrick if (fwrite(buf, 1, r, stdout) != r)
3951 624411d2 2023-07-08 jrick return got_ferror(stdout, GOT_ERR_IO);
3952 624411d2 2023-07-08 jrick }
3953 624411d2 2023-07-08 jrick
3954 624411d2 2023-07-08 jrick return NULL;
3955 624411d2 2023-07-08 jrick }
3956 624411d2 2023-07-08 jrick
3957 624411d2 2023-07-08 jrick static const struct got_error *
3958 624411d2 2023-07-08 jrick print_commit(struct got_commit_object *commit, struct got_object_id *id,
3959 624411d2 2023-07-08 jrick struct got_repository *repo, const char *path,
3960 624411d2 2023-07-08 jrick struct got_pathlist_head *changed_paths,
3961 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context,
3962 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str,
3963 624411d2 2023-07-08 jrick const char *prefix)
3964 624411d2 2023-07-08 jrick {
3965 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3966 624411d2 2023-07-08 jrick FILE *f = NULL;
3967 624411d2 2023-07-08 jrick char *id_str, *datestr, *logmsg0, *logmsg, *line;
3968 624411d2 2023-07-08 jrick char datebuf[26];
3969 624411d2 2023-07-08 jrick time_t committer_time;
3970 624411d2 2023-07-08 jrick const char *author, *committer;
3971 624411d2 2023-07-08 jrick char *refs_str = NULL;
3972 624411d2 2023-07-08 jrick
3973 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3974 624411d2 2023-07-08 jrick if (err)
3975 624411d2 2023-07-08 jrick return err;
3976 624411d2 2023-07-08 jrick
3977 624411d2 2023-07-08 jrick if (custom_refs_str == NULL) {
3978 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
3979 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3980 624411d2 2023-07-08 jrick if (refs) {
3981 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, id, repo, 0);
3982 624411d2 2023-07-08 jrick if (err)
3983 624411d2 2023-07-08 jrick goto done;
3984 624411d2 2023-07-08 jrick }
3985 624411d2 2023-07-08 jrick }
3986 624411d2 2023-07-08 jrick
3987 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
3988 624411d2 2023-07-08 jrick if (custom_refs_str)
3989 624411d2 2023-07-08 jrick printf("%s %s (%s)\n", prefix ? prefix : "commit", id_str,
3990 624411d2 2023-07-08 jrick custom_refs_str);
3991 624411d2 2023-07-08 jrick else
3992 624411d2 2023-07-08 jrick printf("%s %s%s%s%s\n", prefix ? prefix : "commit", id_str,
3993 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
3994 624411d2 2023-07-08 jrick refs_str ? ")" : "");
3995 624411d2 2023-07-08 jrick free(id_str);
3996 624411d2 2023-07-08 jrick id_str = NULL;
3997 624411d2 2023-07-08 jrick free(refs_str);
3998 624411d2 2023-07-08 jrick refs_str = NULL;
3999 624411d2 2023-07-08 jrick printf("from: %s\n", got_object_commit_get_author(commit));
4000 624411d2 2023-07-08 jrick author = got_object_commit_get_author(commit);
4001 624411d2 2023-07-08 jrick committer = got_object_commit_get_committer(commit);
4002 624411d2 2023-07-08 jrick if (strcmp(author, committer) != 0)
4003 624411d2 2023-07-08 jrick printf("via: %s\n", committer);
4004 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
4005 624411d2 2023-07-08 jrick datestr = get_datestr(&committer_time, datebuf);
4006 624411d2 2023-07-08 jrick if (datestr)
4007 624411d2 2023-07-08 jrick printf("date: %s UTC\n", datestr);
4008 624411d2 2023-07-08 jrick if (got_object_commit_get_nparents(commit) > 1) {
4009 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
4010 624411d2 2023-07-08 jrick struct got_object_qid *qid;
4011 624411d2 2023-07-08 jrick int n = 1;
4012 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
4013 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, parent_ids, entry) {
4014 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
4015 624411d2 2023-07-08 jrick if (err)
4016 624411d2 2023-07-08 jrick goto done;
4017 624411d2 2023-07-08 jrick printf("parent %d: %s\n", n++, id_str);
4018 624411d2 2023-07-08 jrick free(id_str);
4019 624411d2 2023-07-08 jrick id_str = NULL;
4020 624411d2 2023-07-08 jrick }
4021 624411d2 2023-07-08 jrick }
4022 624411d2 2023-07-08 jrick
4023 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
4024 624411d2 2023-07-08 jrick if (err)
4025 624411d2 2023-07-08 jrick goto done;
4026 624411d2 2023-07-08 jrick
4027 624411d2 2023-07-08 jrick logmsg = logmsg0;
4028 624411d2 2023-07-08 jrick do {
4029 624411d2 2023-07-08 jrick line = strsep(&logmsg, "\n");
4030 624411d2 2023-07-08 jrick if (line)
4031 624411d2 2023-07-08 jrick printf(" %s\n", line);
4032 624411d2 2023-07-08 jrick } while (line);
4033 624411d2 2023-07-08 jrick free(logmsg0);
4034 624411d2 2023-07-08 jrick
4035 624411d2 2023-07-08 jrick if (changed_paths && diffstat == NULL) {
4036 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
4037 624411d2 2023-07-08 jrick
4038 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, changed_paths, entry) {
4039 624411d2 2023-07-08 jrick struct got_diff_changed_path *cp = pe->data;
4040 624411d2 2023-07-08 jrick
4041 624411d2 2023-07-08 jrick printf(" %c %s\n", cp->status, pe->path);
4042 624411d2 2023-07-08 jrick }
4043 624411d2 2023-07-08 jrick printf("\n");
4044 624411d2 2023-07-08 jrick }
4045 624411d2 2023-07-08 jrick if (show_patch) {
4046 624411d2 2023-07-08 jrick if (diffstat) {
4047 624411d2 2023-07-08 jrick f = got_opentemp();
4048 624411d2 2023-07-08 jrick if (f == NULL) {
4049 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
4050 624411d2 2023-07-08 jrick goto done;
4051 624411d2 2023-07-08 jrick }
4052 624411d2 2023-07-08 jrick }
4053 624411d2 2023-07-08 jrick
4054 624411d2 2023-07-08 jrick err = print_patch(commit, id, path, diff_context, diffstat,
4055 624411d2 2023-07-08 jrick repo, diffstat == NULL ? stdout : f);
4056 624411d2 2023-07-08 jrick if (err)
4057 624411d2 2023-07-08 jrick goto done;
4058 624411d2 2023-07-08 jrick }
4059 624411d2 2023-07-08 jrick if (diffstat) {
4060 624411d2 2023-07-08 jrick err = print_diffstat(diffstat, NULL);
4061 624411d2 2023-07-08 jrick if (err)
4062 624411d2 2023-07-08 jrick goto done;
4063 624411d2 2023-07-08 jrick if (show_patch) {
4064 624411d2 2023-07-08 jrick err = printfile(f);
4065 624411d2 2023-07-08 jrick if (err)
4066 624411d2 2023-07-08 jrick goto done;
4067 624411d2 2023-07-08 jrick }
4068 624411d2 2023-07-08 jrick }
4069 624411d2 2023-07-08 jrick if (show_patch)
4070 624411d2 2023-07-08 jrick printf("\n");
4071 624411d2 2023-07-08 jrick
4072 624411d2 2023-07-08 jrick if (fflush(stdout) != 0 && err == NULL)
4073 624411d2 2023-07-08 jrick err = got_error_from_errno("fflush");
4074 624411d2 2023-07-08 jrick done:
4075 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
4076 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
4077 624411d2 2023-07-08 jrick free(id_str);
4078 624411d2 2023-07-08 jrick free(refs_str);
4079 624411d2 2023-07-08 jrick return err;
4080 624411d2 2023-07-08 jrick }
4081 624411d2 2023-07-08 jrick
4082 624411d2 2023-07-08 jrick static const struct got_error *
4083 624411d2 2023-07-08 jrick print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
4084 624411d2 2023-07-08 jrick struct got_repository *repo, const char *path, int show_changed_paths,
4085 624411d2 2023-07-08 jrick int show_diffstat, int show_patch, const char *search_pattern,
4086 624411d2 2023-07-08 jrick int diff_context, int limit, int log_branches, int reverse_display_order,
4087 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap, int one_line,
4088 624411d2 2023-07-08 jrick FILE *tmpfile)
4089 624411d2 2023-07-08 jrick {
4090 624411d2 2023-07-08 jrick const struct got_error *err;
4091 624411d2 2023-07-08 jrick struct got_commit_graph *graph;
4092 624411d2 2023-07-08 jrick regex_t regex;
4093 624411d2 2023-07-08 jrick int have_match;
4094 624411d2 2023-07-08 jrick struct got_object_id_queue reversed_commits;
4095 624411d2 2023-07-08 jrick struct got_object_qid *qid;
4096 624411d2 2023-07-08 jrick struct got_commit_object *commit;
4097 624411d2 2023-07-08 jrick struct got_pathlist_head changed_paths;
4098 624411d2 2023-07-08 jrick
4099 624411d2 2023-07-08 jrick STAILQ_INIT(&reversed_commits);
4100 624411d2 2023-07-08 jrick TAILQ_INIT(&changed_paths);
4101 624411d2 2023-07-08 jrick
4102 624411d2 2023-07-08 jrick if (search_pattern && regcomp(&regex, search_pattern,
4103 624411d2 2023-07-08 jrick REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
4104 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_REGEX, search_pattern);
4105 624411d2 2023-07-08 jrick
4106 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, path, !log_branches);
4107 624411d2 2023-07-08 jrick if (err)
4108 624411d2 2023-07-08 jrick return err;
4109 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, root_id, repo,
4110 624411d2 2023-07-08 jrick check_cancelled, NULL);
4111 624411d2 2023-07-08 jrick if (err)
4112 624411d2 2023-07-08 jrick goto done;
4113 624411d2 2023-07-08 jrick for (;;) {
4114 624411d2 2023-07-08 jrick struct got_object_id id;
4115 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0,
4116 624411d2 2023-07-08 jrick &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE };
4117 624411d2 2023-07-08 jrick
4118 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
4119 624411d2 2023-07-08 jrick break;
4120 624411d2 2023-07-08 jrick
4121 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&id, graph, repo,
4122 624411d2 2023-07-08 jrick check_cancelled, NULL);
4123 624411d2 2023-07-08 jrick if (err) {
4124 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED)
4125 624411d2 2023-07-08 jrick err = NULL;
4126 624411d2 2023-07-08 jrick break;
4127 624411d2 2023-07-08 jrick }
4128 624411d2 2023-07-08 jrick
4129 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, &id);
4130 624411d2 2023-07-08 jrick if (err)
4131 624411d2 2023-07-08 jrick break;
4132 624411d2 2023-07-08 jrick
4133 624411d2 2023-07-08 jrick if ((show_changed_paths || (show_diffstat && !show_patch))
4134 624411d2 2023-07-08 jrick && !reverse_display_order) {
4135 624411d2 2023-07-08 jrick err = get_changed_paths(&changed_paths, commit, repo,
4136 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL);
4137 624411d2 2023-07-08 jrick if (err)
4138 624411d2 2023-07-08 jrick break;
4139 624411d2 2023-07-08 jrick }
4140 624411d2 2023-07-08 jrick
4141 624411d2 2023-07-08 jrick if (search_pattern) {
4142 624411d2 2023-07-08 jrick err = match_commit(&have_match, &id, commit, &regex);
4143 624411d2 2023-07-08 jrick if (err) {
4144 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4145 624411d2 2023-07-08 jrick break;
4146 624411d2 2023-07-08 jrick }
4147 624411d2 2023-07-08 jrick if (have_match == 0 && show_changed_paths)
4148 624411d2 2023-07-08 jrick match_changed_paths(&have_match,
4149 624411d2 2023-07-08 jrick &changed_paths, &regex);
4150 624411d2 2023-07-08 jrick if (have_match == 0 && show_patch) {
4151 624411d2 2023-07-08 jrick err = match_patch(&have_match, commit, &id,
4152 624411d2 2023-07-08 jrick path, diff_context, repo, &regex, tmpfile);
4153 624411d2 2023-07-08 jrick if (err)
4154 624411d2 2023-07-08 jrick break;
4155 624411d2 2023-07-08 jrick }
4156 624411d2 2023-07-08 jrick if (have_match == 0) {
4157 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4158 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths,
4159 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_ALL);
4160 624411d2 2023-07-08 jrick continue;
4161 624411d2 2023-07-08 jrick }
4162 624411d2 2023-07-08 jrick }
4163 624411d2 2023-07-08 jrick
4164 624411d2 2023-07-08 jrick if (reverse_display_order) {
4165 624411d2 2023-07-08 jrick err = got_object_qid_alloc(&qid, &id);
4166 624411d2 2023-07-08 jrick if (err)
4167 624411d2 2023-07-08 jrick break;
4168 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(&reversed_commits, qid, entry);
4169 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4170 624411d2 2023-07-08 jrick } else {
4171 624411d2 2023-07-08 jrick if (one_line)
4172 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, &id,
4173 624411d2 2023-07-08 jrick repo, refs_idmap);
4174 624411d2 2023-07-08 jrick else
4175 624411d2 2023-07-08 jrick err = print_commit(commit, &id, repo, path,
4176 624411d2 2023-07-08 jrick (show_changed_paths || show_diffstat) ?
4177 624411d2 2023-07-08 jrick &changed_paths : NULL,
4178 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, show_patch,
4179 624411d2 2023-07-08 jrick diff_context, refs_idmap, NULL, NULL);
4180 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4181 624411d2 2023-07-08 jrick if (err)
4182 624411d2 2023-07-08 jrick break;
4183 624411d2 2023-07-08 jrick }
4184 624411d2 2023-07-08 jrick if ((limit && --limit == 0) ||
4185 624411d2 2023-07-08 jrick (end_id && got_object_id_cmp(&id, end_id) == 0))
4186 624411d2 2023-07-08 jrick break;
4187 624411d2 2023-07-08 jrick
4188 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4189 624411d2 2023-07-08 jrick }
4190 624411d2 2023-07-08 jrick if (reverse_display_order) {
4191 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, &reversed_commits, entry) {
4192 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0,
4193 624411d2 2023-07-08 jrick &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE };
4194 624411d2 2023-07-08 jrick
4195 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo,
4196 624411d2 2023-07-08 jrick &qid->id);
4197 624411d2 2023-07-08 jrick if (err)
4198 624411d2 2023-07-08 jrick break;
4199 624411d2 2023-07-08 jrick if (show_changed_paths ||
4200 624411d2 2023-07-08 jrick (show_diffstat && !show_patch)) {
4201 624411d2 2023-07-08 jrick err = get_changed_paths(&changed_paths, commit,
4202 624411d2 2023-07-08 jrick repo, show_diffstat ? &dsa : NULL);
4203 624411d2 2023-07-08 jrick if (err)
4204 624411d2 2023-07-08 jrick break;
4205 624411d2 2023-07-08 jrick }
4206 624411d2 2023-07-08 jrick if (one_line)
4207 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, &qid->id,
4208 624411d2 2023-07-08 jrick repo, refs_idmap);
4209 624411d2 2023-07-08 jrick else
4210 624411d2 2023-07-08 jrick err = print_commit(commit, &qid->id, repo, path,
4211 624411d2 2023-07-08 jrick (show_changed_paths || show_diffstat) ?
4212 624411d2 2023-07-08 jrick &changed_paths : NULL,
4213 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, show_patch,
4214 624411d2 2023-07-08 jrick diff_context, refs_idmap, NULL, NULL);
4215 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4216 624411d2 2023-07-08 jrick if (err)
4217 624411d2 2023-07-08 jrick break;
4218 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4219 624411d2 2023-07-08 jrick }
4220 624411d2 2023-07-08 jrick }
4221 624411d2 2023-07-08 jrick done:
4222 624411d2 2023-07-08 jrick while (!STAILQ_EMPTY(&reversed_commits)) {
4223 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(&reversed_commits);
4224 624411d2 2023-07-08 jrick STAILQ_REMOVE_HEAD(&reversed_commits, entry);
4225 624411d2 2023-07-08 jrick got_object_qid_free(qid);
4226 624411d2 2023-07-08 jrick }
4227 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4228 624411d2 2023-07-08 jrick if (search_pattern)
4229 624411d2 2023-07-08 jrick regfree(&regex);
4230 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
4231 624411d2 2023-07-08 jrick return err;
4232 624411d2 2023-07-08 jrick }
4233 624411d2 2023-07-08 jrick
4234 624411d2 2023-07-08 jrick __dead static void
4235 624411d2 2023-07-08 jrick usage_log(void)
4236 624411d2 2023-07-08 jrick {
4237 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s log [-bdPpRs] [-C number] [-c commit] "
4238 624411d2 2023-07-08 jrick "[-l N] [-r repository-path] [-S search-pattern] [-x commit] "
4239 624411d2 2023-07-08 jrick "[path]\n", getprogname());
4240 624411d2 2023-07-08 jrick exit(1);
4241 624411d2 2023-07-08 jrick }
4242 624411d2 2023-07-08 jrick
4243 624411d2 2023-07-08 jrick static int
4244 624411d2 2023-07-08 jrick get_default_log_limit(void)
4245 624411d2 2023-07-08 jrick {
4246 624411d2 2023-07-08 jrick const char *got_default_log_limit;
4247 624411d2 2023-07-08 jrick long long n;
4248 624411d2 2023-07-08 jrick const char *errstr;
4249 624411d2 2023-07-08 jrick
4250 624411d2 2023-07-08 jrick got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
4251 624411d2 2023-07-08 jrick if (got_default_log_limit == NULL)
4252 624411d2 2023-07-08 jrick return 0;
4253 624411d2 2023-07-08 jrick n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr);
4254 624411d2 2023-07-08 jrick if (errstr != NULL)
4255 624411d2 2023-07-08 jrick return 0;
4256 624411d2 2023-07-08 jrick return n;
4257 624411d2 2023-07-08 jrick }
4258 624411d2 2023-07-08 jrick
4259 624411d2 2023-07-08 jrick static const struct got_error *
4260 624411d2 2023-07-08 jrick cmd_log(int argc, char *argv[])
4261 624411d2 2023-07-08 jrick {
4262 624411d2 2023-07-08 jrick const struct got_error *error;
4263 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
4264 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
4265 624411d2 2023-07-08 jrick struct got_object_id *start_id = NULL, *end_id = NULL;
4266 624411d2 2023-07-08 jrick char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
4267 624411d2 2023-07-08 jrick const char *start_commit = NULL, *end_commit = NULL;
4268 624411d2 2023-07-08 jrick const char *search_pattern = NULL;
4269 624411d2 2023-07-08 jrick int diff_context = -1, ch;
4270 624411d2 2023-07-08 jrick int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
4271 624411d2 2023-07-08 jrick int show_diffstat = 0, reverse_display_order = 0, one_line = 0;
4272 624411d2 2023-07-08 jrick const char *errstr;
4273 624411d2 2023-07-08 jrick struct got_reflist_head refs;
4274 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
4275 624411d2 2023-07-08 jrick FILE *tmpfile = NULL;
4276 624411d2 2023-07-08 jrick int *pack_fds = NULL;
4277 624411d2 2023-07-08 jrick
4278 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
4279 624411d2 2023-07-08 jrick
4280 624411d2 2023-07-08 jrick #ifndef PROFILE
4281 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4282 624411d2 2023-07-08 jrick NULL)
4283 624411d2 2023-07-08 jrick == -1)
4284 624411d2 2023-07-08 jrick err(1, "pledge");
4285 624411d2 2023-07-08 jrick #endif
4286 624411d2 2023-07-08 jrick
4287 624411d2 2023-07-08 jrick limit = get_default_log_limit();
4288 624411d2 2023-07-08 jrick
4289 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "bC:c:dl:PpRr:S:sx:")) != -1) {
4290 624411d2 2023-07-08 jrick switch (ch) {
4291 624411d2 2023-07-08 jrick case 'b':
4292 624411d2 2023-07-08 jrick log_branches = 1;
4293 624411d2 2023-07-08 jrick break;
4294 624411d2 2023-07-08 jrick case 'C':
4295 624411d2 2023-07-08 jrick diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4296 624411d2 2023-07-08 jrick &errstr);
4297 624411d2 2023-07-08 jrick if (errstr != NULL)
4298 624411d2 2023-07-08 jrick errx(1, "number of context lines is %s: %s",
4299 624411d2 2023-07-08 jrick errstr, optarg);
4300 624411d2 2023-07-08 jrick break;
4301 624411d2 2023-07-08 jrick case 'c':
4302 624411d2 2023-07-08 jrick start_commit = optarg;
4303 624411d2 2023-07-08 jrick break;
4304 624411d2 2023-07-08 jrick case 'd':
4305 624411d2 2023-07-08 jrick show_diffstat = 1;
4306 624411d2 2023-07-08 jrick break;
4307 624411d2 2023-07-08 jrick case 'l':
4308 624411d2 2023-07-08 jrick limit = strtonum(optarg, 0, INT_MAX, &errstr);
4309 624411d2 2023-07-08 jrick if (errstr != NULL)
4310 624411d2 2023-07-08 jrick errx(1, "number of commits is %s: %s",
4311 624411d2 2023-07-08 jrick errstr, optarg);
4312 624411d2 2023-07-08 jrick break;
4313 624411d2 2023-07-08 jrick case 'P':
4314 624411d2 2023-07-08 jrick show_changed_paths = 1;
4315 624411d2 2023-07-08 jrick break;
4316 624411d2 2023-07-08 jrick case 'p':
4317 624411d2 2023-07-08 jrick show_patch = 1;
4318 624411d2 2023-07-08 jrick break;
4319 624411d2 2023-07-08 jrick case 'R':
4320 624411d2 2023-07-08 jrick reverse_display_order = 1;
4321 624411d2 2023-07-08 jrick break;
4322 624411d2 2023-07-08 jrick case 'r':
4323 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
4324 624411d2 2023-07-08 jrick if (repo_path == NULL)
4325 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
4326 624411d2 2023-07-08 jrick optarg);
4327 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
4328 624411d2 2023-07-08 jrick break;
4329 624411d2 2023-07-08 jrick case 'S':
4330 624411d2 2023-07-08 jrick search_pattern = optarg;
4331 624411d2 2023-07-08 jrick break;
4332 624411d2 2023-07-08 jrick case 's':
4333 624411d2 2023-07-08 jrick one_line = 1;
4334 624411d2 2023-07-08 jrick break;
4335 624411d2 2023-07-08 jrick case 'x':
4336 624411d2 2023-07-08 jrick end_commit = optarg;
4337 624411d2 2023-07-08 jrick break;
4338 624411d2 2023-07-08 jrick default:
4339 624411d2 2023-07-08 jrick usage_log();
4340 624411d2 2023-07-08 jrick /* NOTREACHED */
4341 624411d2 2023-07-08 jrick }
4342 624411d2 2023-07-08 jrick }
4343 624411d2 2023-07-08 jrick
4344 624411d2 2023-07-08 jrick argc -= optind;
4345 624411d2 2023-07-08 jrick argv += optind;
4346 624411d2 2023-07-08 jrick
4347 624411d2 2023-07-08 jrick if (diff_context == -1)
4348 624411d2 2023-07-08 jrick diff_context = 3;
4349 624411d2 2023-07-08 jrick else if (!show_patch)
4350 624411d2 2023-07-08 jrick errx(1, "-C requires -p");
4351 624411d2 2023-07-08 jrick
4352 624411d2 2023-07-08 jrick if (one_line && (show_patch || show_changed_paths || show_diffstat))
4353 624411d2 2023-07-08 jrick errx(1, "cannot use -s with -d, -p or -P");
4354 624411d2 2023-07-08 jrick
4355 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
4356 624411d2 2023-07-08 jrick if (cwd == NULL) {
4357 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
4358 624411d2 2023-07-08 jrick goto done;
4359 624411d2 2023-07-08 jrick }
4360 624411d2 2023-07-08 jrick
4361 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
4362 624411d2 2023-07-08 jrick if (error != NULL)
4363 624411d2 2023-07-08 jrick goto done;
4364 624411d2 2023-07-08 jrick
4365 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4366 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
4367 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
4368 624411d2 2023-07-08 jrick goto done;
4369 624411d2 2023-07-08 jrick error = NULL;
4370 624411d2 2023-07-08 jrick }
4371 624411d2 2023-07-08 jrick
4372 624411d2 2023-07-08 jrick if (argc == 1) {
4373 624411d2 2023-07-08 jrick if (worktree) {
4374 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&path, worktree,
4375 624411d2 2023-07-08 jrick argv[0]);
4376 624411d2 2023-07-08 jrick if (error)
4377 624411d2 2023-07-08 jrick goto done;
4378 624411d2 2023-07-08 jrick } else {
4379 624411d2 2023-07-08 jrick path = strdup(argv[0]);
4380 624411d2 2023-07-08 jrick if (path == NULL) {
4381 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4382 624411d2 2023-07-08 jrick goto done;
4383 624411d2 2023-07-08 jrick }
4384 624411d2 2023-07-08 jrick }
4385 624411d2 2023-07-08 jrick } else if (argc != 0)
4386 624411d2 2023-07-08 jrick usage_log();
4387 624411d2 2023-07-08 jrick
4388 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4389 624411d2 2023-07-08 jrick repo_path = worktree ?
4390 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
4391 624411d2 2023-07-08 jrick }
4392 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4393 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4394 624411d2 2023-07-08 jrick goto done;
4395 624411d2 2023-07-08 jrick }
4396 624411d2 2023-07-08 jrick
4397 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
4398 624411d2 2023-07-08 jrick if (error != NULL)
4399 624411d2 2023-07-08 jrick goto done;
4400 624411d2 2023-07-08 jrick
4401 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
4402 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
4403 624411d2 2023-07-08 jrick if (error)
4404 624411d2 2023-07-08 jrick goto done;
4405 624411d2 2023-07-08 jrick
4406 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
4407 624411d2 2023-07-08 jrick if (error)
4408 624411d2 2023-07-08 jrick goto done;
4409 624411d2 2023-07-08 jrick
4410 624411d2 2023-07-08 jrick error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
4411 624411d2 2023-07-08 jrick if (error)
4412 624411d2 2023-07-08 jrick goto done;
4413 624411d2 2023-07-08 jrick
4414 624411d2 2023-07-08 jrick if (start_commit == NULL) {
4415 624411d2 2023-07-08 jrick struct got_reference *head_ref;
4416 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
4417 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
4418 624411d2 2023-07-08 jrick worktree ? got_worktree_get_head_ref_name(worktree)
4419 624411d2 2023-07-08 jrick : GOT_REF_HEAD, 0);
4420 624411d2 2023-07-08 jrick if (error != NULL)
4421 624411d2 2023-07-08 jrick goto done;
4422 624411d2 2023-07-08 jrick error = got_ref_resolve(&start_id, repo, head_ref);
4423 624411d2 2023-07-08 jrick got_ref_close(head_ref);
4424 624411d2 2023-07-08 jrick if (error != NULL)
4425 624411d2 2023-07-08 jrick goto done;
4426 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
4427 624411d2 2023-07-08 jrick start_id);
4428 624411d2 2023-07-08 jrick if (error != NULL)
4429 624411d2 2023-07-08 jrick goto done;
4430 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4431 624411d2 2023-07-08 jrick } else {
4432 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&start_id, NULL,
4433 624411d2 2023-07-08 jrick start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4434 624411d2 2023-07-08 jrick if (error != NULL)
4435 624411d2 2023-07-08 jrick goto done;
4436 624411d2 2023-07-08 jrick }
4437 624411d2 2023-07-08 jrick if (end_commit != NULL) {
4438 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&end_id, NULL,
4439 624411d2 2023-07-08 jrick end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4440 624411d2 2023-07-08 jrick if (error != NULL)
4441 624411d2 2023-07-08 jrick goto done;
4442 624411d2 2023-07-08 jrick }
4443 624411d2 2023-07-08 jrick
4444 624411d2 2023-07-08 jrick if (worktree) {
4445 624411d2 2023-07-08 jrick /*
4446 624411d2 2023-07-08 jrick * If a path was specified on the command line it was resolved
4447 624411d2 2023-07-08 jrick * to a path in the work tree above. Prepend the work tree's
4448 624411d2 2023-07-08 jrick * path prefix to obtain the corresponding in-repository path.
4449 624411d2 2023-07-08 jrick */
4450 624411d2 2023-07-08 jrick if (path) {
4451 624411d2 2023-07-08 jrick const char *prefix;
4452 624411d2 2023-07-08 jrick prefix = got_worktree_get_path_prefix(worktree);
4453 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
4454 624411d2 2023-07-08 jrick (path[0] != '\0') ? "/" : "", path) == -1) {
4455 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
4456 624411d2 2023-07-08 jrick goto done;
4457 624411d2 2023-07-08 jrick }
4458 624411d2 2023-07-08 jrick }
4459 624411d2 2023-07-08 jrick } else
4460 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo,
4461 624411d2 2023-07-08 jrick path ? path : "");
4462 624411d2 2023-07-08 jrick if (error != NULL)
4463 624411d2 2023-07-08 jrick goto done;
4464 624411d2 2023-07-08 jrick if (in_repo_path) {
4465 624411d2 2023-07-08 jrick free(path);
4466 624411d2 2023-07-08 jrick path = in_repo_path;
4467 624411d2 2023-07-08 jrick }
4468 624411d2 2023-07-08 jrick
4469 624411d2 2023-07-08 jrick if (worktree) {
4470 624411d2 2023-07-08 jrick /* Release work tree lock. */
4471 624411d2 2023-07-08 jrick got_worktree_close(worktree);
4472 624411d2 2023-07-08 jrick worktree = NULL;
4473 624411d2 2023-07-08 jrick }
4474 624411d2 2023-07-08 jrick
4475 624411d2 2023-07-08 jrick if (search_pattern && show_patch) {
4476 624411d2 2023-07-08 jrick tmpfile = got_opentemp();
4477 624411d2 2023-07-08 jrick if (tmpfile == NULL) {
4478 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4479 624411d2 2023-07-08 jrick goto done;
4480 624411d2 2023-07-08 jrick }
4481 624411d2 2023-07-08 jrick }
4482 624411d2 2023-07-08 jrick
4483 624411d2 2023-07-08 jrick error = print_commits(start_id, end_id, repo, path ? path : "",
4484 624411d2 2023-07-08 jrick show_changed_paths, show_diffstat, show_patch, search_pattern,
4485 624411d2 2023-07-08 jrick diff_context, limit, log_branches, reverse_display_order,
4486 624411d2 2023-07-08 jrick refs_idmap, one_line, tmpfile);
4487 624411d2 2023-07-08 jrick done:
4488 624411d2 2023-07-08 jrick free(path);
4489 624411d2 2023-07-08 jrick free(repo_path);
4490 624411d2 2023-07-08 jrick free(cwd);
4491 624411d2 2023-07-08 jrick if (worktree)
4492 624411d2 2023-07-08 jrick got_worktree_close(worktree);
4493 624411d2 2023-07-08 jrick if (repo) {
4494 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
4495 624411d2 2023-07-08 jrick if (error == NULL)
4496 624411d2 2023-07-08 jrick error = close_err;
4497 624411d2 2023-07-08 jrick }
4498 624411d2 2023-07-08 jrick if (pack_fds) {
4499 624411d2 2023-07-08 jrick const struct got_error *pack_err =
4500 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
4501 624411d2 2023-07-08 jrick if (error == NULL)
4502 624411d2 2023-07-08 jrick error = pack_err;
4503 624411d2 2023-07-08 jrick }
4504 624411d2 2023-07-08 jrick if (refs_idmap)
4505 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
4506 624411d2 2023-07-08 jrick if (tmpfile && fclose(tmpfile) == EOF && error == NULL)
4507 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
4508 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
4509 624411d2 2023-07-08 jrick return error;
4510 624411d2 2023-07-08 jrick }
4511 624411d2 2023-07-08 jrick
4512 624411d2 2023-07-08 jrick __dead static void
4513 624411d2 2023-07-08 jrick usage_diff(void)
4514 624411d2 2023-07-08 jrick {
4515 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] "
4516 624411d2 2023-07-08 jrick "[-r repository-path] [object1 object2 | path ...]\n",
4517 624411d2 2023-07-08 jrick getprogname());
4518 624411d2 2023-07-08 jrick exit(1);
4519 624411d2 2023-07-08 jrick }
4520 624411d2 2023-07-08 jrick
4521 624411d2 2023-07-08 jrick struct print_diff_arg {
4522 624411d2 2023-07-08 jrick struct got_repository *repo;
4523 624411d2 2023-07-08 jrick struct got_worktree *worktree;
4524 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *diffstat;
4525 624411d2 2023-07-08 jrick int diff_context;
4526 624411d2 2023-07-08 jrick const char *id_str;
4527 624411d2 2023-07-08 jrick int header_shown;
4528 624411d2 2023-07-08 jrick int diff_staged;
4529 624411d2 2023-07-08 jrick enum got_diff_algorithm diff_algo;
4530 624411d2 2023-07-08 jrick int ignore_whitespace;
4531 624411d2 2023-07-08 jrick int force_text_diff;
4532 624411d2 2023-07-08 jrick FILE *f1;
4533 624411d2 2023-07-08 jrick FILE *f2;
4534 624411d2 2023-07-08 jrick FILE *outfile;
4535 624411d2 2023-07-08 jrick };
4536 624411d2 2023-07-08 jrick
4537 624411d2 2023-07-08 jrick /*
4538 624411d2 2023-07-08 jrick * Create a file which contains the target path of a symlink so we can feed
4539 624411d2 2023-07-08 jrick * it as content to the diff engine.
4540 624411d2 2023-07-08 jrick */
4541 624411d2 2023-07-08 jrick static const struct got_error *
4542 624411d2 2023-07-08 jrick get_symlink_target_file(int *fd, int dirfd, const char *de_name,
4543 624411d2 2023-07-08 jrick const char *abspath)
4544 624411d2 2023-07-08 jrick {
4545 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
4546 624411d2 2023-07-08 jrick char target_path[PATH_MAX];
4547 624411d2 2023-07-08 jrick ssize_t target_len, outlen;
4548 624411d2 2023-07-08 jrick
4549 624411d2 2023-07-08 jrick *fd = -1;
4550 624411d2 2023-07-08 jrick
4551 624411d2 2023-07-08 jrick if (dirfd != -1) {
4552 624411d2 2023-07-08 jrick target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
4553 624411d2 2023-07-08 jrick if (target_len == -1)
4554 624411d2 2023-07-08 jrick return got_error_from_errno2("readlinkat", abspath);
4555 624411d2 2023-07-08 jrick } else {
4556 624411d2 2023-07-08 jrick target_len = readlink(abspath, target_path, PATH_MAX);
4557 624411d2 2023-07-08 jrick if (target_len == -1)
4558 624411d2 2023-07-08 jrick return got_error_from_errno2("readlink", abspath);
4559 624411d2 2023-07-08 jrick }
4560 624411d2 2023-07-08 jrick
4561 624411d2 2023-07-08 jrick *fd = got_opentempfd();
4562 624411d2 2023-07-08 jrick if (*fd == -1)
4563 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
4564 624411d2 2023-07-08 jrick
4565 624411d2 2023-07-08 jrick outlen = write(*fd, target_path, target_len);
4566 624411d2 2023-07-08 jrick if (outlen == -1) {
4567 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4568 624411d2 2023-07-08 jrick goto done;
4569 624411d2 2023-07-08 jrick }
4570 624411d2 2023-07-08 jrick
4571 624411d2 2023-07-08 jrick if (lseek(*fd, 0, SEEK_SET) == -1) {
4572 624411d2 2023-07-08 jrick err = got_error_from_errno2("lseek", abspath);
4573 624411d2 2023-07-08 jrick goto done;
4574 624411d2 2023-07-08 jrick }
4575 624411d2 2023-07-08 jrick done:
4576 624411d2 2023-07-08 jrick if (err) {
4577 624411d2 2023-07-08 jrick close(*fd);
4578 624411d2 2023-07-08 jrick *fd = -1;
4579 624411d2 2023-07-08 jrick }
4580 624411d2 2023-07-08 jrick return err;
4581 624411d2 2023-07-08 jrick }
4582 624411d2 2023-07-08 jrick
4583 624411d2 2023-07-08 jrick static const struct got_error *
4584 624411d2 2023-07-08 jrick print_diff(void *arg, unsigned char status, unsigned char staged_status,
4585 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
4586 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4587 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
4588 624411d2 2023-07-08 jrick {
4589 624411d2 2023-07-08 jrick struct print_diff_arg *a = arg;
4590 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
4591 624411d2 2023-07-08 jrick struct got_blob_object *blob1 = NULL;
4592 624411d2 2023-07-08 jrick int fd = -1, fd1 = -1, fd2 = -1;
4593 624411d2 2023-07-08 jrick FILE *f2 = NULL;
4594 624411d2 2023-07-08 jrick char *abspath = NULL, *label1 = NULL;
4595 624411d2 2023-07-08 jrick struct stat sb;
4596 624411d2 2023-07-08 jrick off_t size1 = 0;
4597 624411d2 2023-07-08 jrick int f2_exists = 0;
4598 624411d2 2023-07-08 jrick
4599 624411d2 2023-07-08 jrick memset(&sb, 0, sizeof(sb));
4600 624411d2 2023-07-08 jrick
4601 624411d2 2023-07-08 jrick if (a->diff_staged) {
4602 624411d2 2023-07-08 jrick if (staged_status != GOT_STATUS_MODIFY &&
4603 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_ADD &&
4604 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_DELETE)
4605 624411d2 2023-07-08 jrick return NULL;
4606 624411d2 2023-07-08 jrick } else {
4607 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_DELETE)
4608 624411d2 2023-07-08 jrick return NULL;
4609 624411d2 2023-07-08 jrick if (status == GOT_STATUS_NONEXISTENT)
4610 624411d2 2023-07-08 jrick return got_error_set_errno(ENOENT, path);
4611 624411d2 2023-07-08 jrick if (status != GOT_STATUS_MODIFY &&
4612 624411d2 2023-07-08 jrick status != GOT_STATUS_ADD &&
4613 624411d2 2023-07-08 jrick status != GOT_STATUS_DELETE &&
4614 624411d2 2023-07-08 jrick status != GOT_STATUS_CONFLICT)
4615 624411d2 2023-07-08 jrick return NULL;
4616 624411d2 2023-07-08 jrick }
4617 624411d2 2023-07-08 jrick
4618 624411d2 2023-07-08 jrick err = got_opentemp_truncate(a->f1);
4619 624411d2 2023-07-08 jrick if (err)
4620 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentemp_truncate");
4621 624411d2 2023-07-08 jrick err = got_opentemp_truncate(a->f2);
4622 624411d2 2023-07-08 jrick if (err)
4623 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentemp_truncate");
4624 624411d2 2023-07-08 jrick
4625 624411d2 2023-07-08 jrick if (!a->header_shown) {
4626 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "diff %s%s\n",
4627 624411d2 2023-07-08 jrick a->diff_staged ? "-s " : "",
4628 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree)) < 0) {
4629 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4630 624411d2 2023-07-08 jrick goto done;
4631 624411d2 2023-07-08 jrick }
4632 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "commit - %s\n", a->id_str) < 0) {
4633 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4634 624411d2 2023-07-08 jrick goto done;
4635 624411d2 2023-07-08 jrick }
4636 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "path + %s%s\n",
4637 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree),
4638 624411d2 2023-07-08 jrick a->diff_staged ? " (staged changes)" : "") < 0) {
4639 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4640 624411d2 2023-07-08 jrick goto done;
4641 624411d2 2023-07-08 jrick }
4642 624411d2 2023-07-08 jrick a->header_shown = 1;
4643 624411d2 2023-07-08 jrick }
4644 624411d2 2023-07-08 jrick
4645 624411d2 2023-07-08 jrick if (a->diff_staged) {
4646 624411d2 2023-07-08 jrick const char *label1 = NULL, *label2 = NULL;
4647 624411d2 2023-07-08 jrick switch (staged_status) {
4648 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
4649 624411d2 2023-07-08 jrick label1 = path;
4650 624411d2 2023-07-08 jrick label2 = path;
4651 624411d2 2023-07-08 jrick break;
4652 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
4653 624411d2 2023-07-08 jrick label2 = path;
4654 624411d2 2023-07-08 jrick break;
4655 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
4656 624411d2 2023-07-08 jrick label1 = path;
4657 624411d2 2023-07-08 jrick break;
4658 624411d2 2023-07-08 jrick default:
4659 624411d2 2023-07-08 jrick return got_error(GOT_ERR_FILE_STATUS);
4660 624411d2 2023-07-08 jrick }
4661 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
4662 624411d2 2023-07-08 jrick if (fd1 == -1) {
4663 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4664 624411d2 2023-07-08 jrick goto done;
4665 624411d2 2023-07-08 jrick }
4666 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
4667 624411d2 2023-07-08 jrick if (fd2 == -1) {
4668 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4669 624411d2 2023-07-08 jrick goto done;
4670 624411d2 2023-07-08 jrick }
4671 624411d2 2023-07-08 jrick err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2,
4672 624411d2 2023-07-08 jrick fd1, fd2, blob_id, staged_blob_id, label1, label2,
4673 624411d2 2023-07-08 jrick a->diff_algo, a->diff_context, a->ignore_whitespace,
4674 624411d2 2023-07-08 jrick a->force_text_diff, a->diffstat, a->repo, a->outfile);
4675 624411d2 2023-07-08 jrick goto done;
4676 624411d2 2023-07-08 jrick }
4677 624411d2 2023-07-08 jrick
4678 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
4679 624411d2 2023-07-08 jrick if (fd1 == -1) {
4680 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4681 624411d2 2023-07-08 jrick goto done;
4682 624411d2 2023-07-08 jrick }
4683 624411d2 2023-07-08 jrick
4684 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_ADD ||
4685 624411d2 2023-07-08 jrick staged_status == GOT_STATUS_MODIFY) {
4686 624411d2 2023-07-08 jrick char *id_str;
4687 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
4688 624411d2 2023-07-08 jrick 8192, fd1);
4689 624411d2 2023-07-08 jrick if (err)
4690 624411d2 2023-07-08 jrick goto done;
4691 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
4692 624411d2 2023-07-08 jrick if (err)
4693 624411d2 2023-07-08 jrick goto done;
4694 624411d2 2023-07-08 jrick if (asprintf(&label1, "%s (staged)", id_str) == -1) {
4695 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
4696 624411d2 2023-07-08 jrick free(id_str);
4697 624411d2 2023-07-08 jrick goto done;
4698 624411d2 2023-07-08 jrick }
4699 624411d2 2023-07-08 jrick free(id_str);
4700 624411d2 2023-07-08 jrick } else if (status != GOT_STATUS_ADD) {
4701 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192,
4702 624411d2 2023-07-08 jrick fd1);
4703 624411d2 2023-07-08 jrick if (err)
4704 624411d2 2023-07-08 jrick goto done;
4705 624411d2 2023-07-08 jrick }
4706 624411d2 2023-07-08 jrick
4707 624411d2 2023-07-08 jrick if (status != GOT_STATUS_DELETE) {
4708 624411d2 2023-07-08 jrick if (asprintf(&abspath, "%s/%s",
4709 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree), path) == -1) {
4710 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
4711 624411d2 2023-07-08 jrick goto done;
4712 624411d2 2023-07-08 jrick }
4713 624411d2 2023-07-08 jrick
4714 624411d2 2023-07-08 jrick if (dirfd != -1) {
4715 624411d2 2023-07-08 jrick fd = openat(dirfd, de_name,
4716 624411d2 2023-07-08 jrick O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4717 624411d2 2023-07-08 jrick if (fd == -1) {
4718 624411d2 2023-07-08 jrick if (!got_err_open_nofollow_on_symlink()) {
4719 624411d2 2023-07-08 jrick err = got_error_from_errno2("openat",
4720 624411d2 2023-07-08 jrick abspath);
4721 624411d2 2023-07-08 jrick goto done;
4722 624411d2 2023-07-08 jrick }
4723 624411d2 2023-07-08 jrick err = get_symlink_target_file(&fd, dirfd,
4724 624411d2 2023-07-08 jrick de_name, abspath);
4725 624411d2 2023-07-08 jrick if (err)
4726 624411d2 2023-07-08 jrick goto done;
4727 624411d2 2023-07-08 jrick }
4728 624411d2 2023-07-08 jrick } else {
4729 624411d2 2023-07-08 jrick fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4730 624411d2 2023-07-08 jrick if (fd == -1) {
4731 624411d2 2023-07-08 jrick if (!got_err_open_nofollow_on_symlink()) {
4732 624411d2 2023-07-08 jrick err = got_error_from_errno2("open",
4733 624411d2 2023-07-08 jrick abspath);
4734 624411d2 2023-07-08 jrick goto done;
4735 624411d2 2023-07-08 jrick }
4736 624411d2 2023-07-08 jrick err = get_symlink_target_file(&fd, dirfd,
4737 624411d2 2023-07-08 jrick de_name, abspath);
4738 624411d2 2023-07-08 jrick if (err)
4739 624411d2 2023-07-08 jrick goto done;
4740 624411d2 2023-07-08 jrick }
4741 624411d2 2023-07-08 jrick }
4742 624411d2 2023-07-08 jrick if (fstatat(fd, abspath, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
4743 624411d2 2023-07-08 jrick err = got_error_from_errno2("fstatat", abspath);
4744 624411d2 2023-07-08 jrick goto done;
4745 624411d2 2023-07-08 jrick }
4746 624411d2 2023-07-08 jrick f2 = fdopen(fd, "r");
4747 624411d2 2023-07-08 jrick if (f2 == NULL) {
4748 624411d2 2023-07-08 jrick err = got_error_from_errno2("fdopen", abspath);
4749 624411d2 2023-07-08 jrick goto done;
4750 624411d2 2023-07-08 jrick }
4751 624411d2 2023-07-08 jrick fd = -1;
4752 624411d2 2023-07-08 jrick f2_exists = 1;
4753 624411d2 2023-07-08 jrick }
4754 624411d2 2023-07-08 jrick
4755 624411d2 2023-07-08 jrick if (blob1) {
4756 624411d2 2023-07-08 jrick err = got_object_blob_dump_to_file(&size1, NULL, NULL,
4757 624411d2 2023-07-08 jrick a->f1, blob1);
4758 624411d2 2023-07-08 jrick if (err)
4759 624411d2 2023-07-08 jrick goto done;
4760 624411d2 2023-07-08 jrick }
4761 624411d2 2023-07-08 jrick
4762 624411d2 2023-07-08 jrick err = got_diff_blob_file(blob1, a->f1, size1, label1, f2 ? f2 : a->f2,
4763 624411d2 2023-07-08 jrick f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context,
4764 624411d2 2023-07-08 jrick a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile);
4765 624411d2 2023-07-08 jrick done:
4766 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
4767 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4768 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
4769 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4770 624411d2 2023-07-08 jrick if (blob1)
4771 624411d2 2023-07-08 jrick got_object_blob_close(blob1);
4772 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
4773 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4774 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
4775 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
4776 624411d2 2023-07-08 jrick free(abspath);
4777 624411d2 2023-07-08 jrick return err;
4778 624411d2 2023-07-08 jrick }
4779 624411d2 2023-07-08 jrick
4780 624411d2 2023-07-08 jrick static const struct got_error *
4781 624411d2 2023-07-08 jrick cmd_diff(int argc, char *argv[])
4782 624411d2 2023-07-08 jrick {
4783 624411d2 2023-07-08 jrick const struct got_error *error;
4784 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
4785 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
4786 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
4787 624411d2 2023-07-08 jrick const char *commit_args[2] = { NULL, NULL };
4788 624411d2 2023-07-08 jrick int ncommit_args = 0;
4789 624411d2 2023-07-08 jrick struct got_object_id *ids[2] = { NULL, NULL };
4790 624411d2 2023-07-08 jrick char *labels[2] = { NULL, NULL };
4791 624411d2 2023-07-08 jrick int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY;
4792 624411d2 2023-07-08 jrick int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i;
4793 624411d2 2023-07-08 jrick int force_text_diff = 0, force_path = 0, rflag = 0, show_diffstat = 0;
4794 624411d2 2023-07-08 jrick const char *errstr;
4795 624411d2 2023-07-08 jrick struct got_reflist_head refs;
4796 624411d2 2023-07-08 jrick struct got_pathlist_head diffstat_paths, paths;
4797 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL, *outfile = NULL;
4798 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
4799 624411d2 2023-07-08 jrick int *pack_fds = NULL;
4800 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa;
4801 624411d2 2023-07-08 jrick
4802 624411d2 2023-07-08 jrick memset(&dsa, 0, sizeof(dsa));
4803 624411d2 2023-07-08 jrick
4804 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
4805 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
4806 624411d2 2023-07-08 jrick TAILQ_INIT(&diffstat_paths);
4807 624411d2 2023-07-08 jrick
4808 624411d2 2023-07-08 jrick #ifndef PROFILE
4809 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4810 624411d2 2023-07-08 jrick NULL) == -1)
4811 624411d2 2023-07-08 jrick err(1, "pledge");
4812 624411d2 2023-07-08 jrick #endif
4813 624411d2 2023-07-08 jrick
4814 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aC:c:dPr:sw")) != -1) {
4815 624411d2 2023-07-08 jrick switch (ch) {
4816 624411d2 2023-07-08 jrick case 'a':
4817 624411d2 2023-07-08 jrick force_text_diff = 1;
4818 624411d2 2023-07-08 jrick break;
4819 624411d2 2023-07-08 jrick case 'C':
4820 624411d2 2023-07-08 jrick diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4821 624411d2 2023-07-08 jrick &errstr);
4822 624411d2 2023-07-08 jrick if (errstr != NULL)
4823 624411d2 2023-07-08 jrick errx(1, "number of context lines is %s: %s",
4824 624411d2 2023-07-08 jrick errstr, optarg);
4825 624411d2 2023-07-08 jrick break;
4826 624411d2 2023-07-08 jrick case 'c':
4827 624411d2 2023-07-08 jrick if (ncommit_args >= 2)
4828 624411d2 2023-07-08 jrick errx(1, "too many -c options used");
4829 624411d2 2023-07-08 jrick commit_args[ncommit_args++] = optarg;
4830 624411d2 2023-07-08 jrick break;
4831 624411d2 2023-07-08 jrick case 'd':
4832 624411d2 2023-07-08 jrick show_diffstat = 1;
4833 624411d2 2023-07-08 jrick break;
4834 624411d2 2023-07-08 jrick case 'P':
4835 624411d2 2023-07-08 jrick force_path = 1;
4836 624411d2 2023-07-08 jrick break;
4837 624411d2 2023-07-08 jrick case 'r':
4838 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
4839 624411d2 2023-07-08 jrick if (repo_path == NULL)
4840 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
4841 624411d2 2023-07-08 jrick optarg);
4842 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
4843 624411d2 2023-07-08 jrick rflag = 1;
4844 624411d2 2023-07-08 jrick break;
4845 624411d2 2023-07-08 jrick case 's':
4846 624411d2 2023-07-08 jrick diff_staged = 1;
4847 624411d2 2023-07-08 jrick break;
4848 624411d2 2023-07-08 jrick case 'w':
4849 624411d2 2023-07-08 jrick ignore_whitespace = 1;
4850 624411d2 2023-07-08 jrick break;
4851 624411d2 2023-07-08 jrick default:
4852 624411d2 2023-07-08 jrick usage_diff();
4853 624411d2 2023-07-08 jrick /* NOTREACHED */
4854 624411d2 2023-07-08 jrick }
4855 624411d2 2023-07-08 jrick }
4856 624411d2 2023-07-08 jrick
4857 624411d2 2023-07-08 jrick argc -= optind;
4858 624411d2 2023-07-08 jrick argv += optind;
4859 624411d2 2023-07-08 jrick
4860 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
4861 624411d2 2023-07-08 jrick if (cwd == NULL) {
4862 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
4863 624411d2 2023-07-08 jrick goto done;
4864 624411d2 2023-07-08 jrick }
4865 624411d2 2023-07-08 jrick
4866 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
4867 624411d2 2023-07-08 jrick if (error != NULL)
4868 624411d2 2023-07-08 jrick goto done;
4869 624411d2 2023-07-08 jrick
4870 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4871 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
4872 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
4873 624411d2 2023-07-08 jrick goto done;
4874 624411d2 2023-07-08 jrick else
4875 624411d2 2023-07-08 jrick error = NULL;
4876 624411d2 2023-07-08 jrick if (worktree) {
4877 624411d2 2023-07-08 jrick repo_path =
4878 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
4879 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4880 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4881 624411d2 2023-07-08 jrick goto done;
4882 624411d2 2023-07-08 jrick }
4883 624411d2 2023-07-08 jrick } else {
4884 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
4885 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4886 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4887 624411d2 2023-07-08 jrick goto done;
4888 624411d2 2023-07-08 jrick }
4889 624411d2 2023-07-08 jrick }
4890 624411d2 2023-07-08 jrick }
4891 624411d2 2023-07-08 jrick
4892 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
4893 624411d2 2023-07-08 jrick free(repo_path);
4894 624411d2 2023-07-08 jrick if (error != NULL)
4895 624411d2 2023-07-08 jrick goto done;
4896 624411d2 2023-07-08 jrick
4897 624411d2 2023-07-08 jrick if (show_diffstat) {
4898 624411d2 2023-07-08 jrick dsa.paths = &diffstat_paths;
4899 624411d2 2023-07-08 jrick dsa.force_text = force_text_diff;
4900 624411d2 2023-07-08 jrick dsa.ignore_ws = ignore_whitespace;
4901 624411d2 2023-07-08 jrick dsa.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
4902 624411d2 2023-07-08 jrick }
4903 624411d2 2023-07-08 jrick
4904 624411d2 2023-07-08 jrick if (rflag || worktree == NULL || ncommit_args > 0) {
4905 624411d2 2023-07-08 jrick if (force_path) {
4906 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_NOT_IMPL,
4907 624411d2 2023-07-08 jrick "-P option can only be used when diffing "
4908 624411d2 2023-07-08 jrick "a work tree");
4909 624411d2 2023-07-08 jrick goto done;
4910 624411d2 2023-07-08 jrick }
4911 624411d2 2023-07-08 jrick if (diff_staged) {
4912 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_NOT_IMPL,
4913 624411d2 2023-07-08 jrick "-s option can only be used when diffing "
4914 624411d2 2023-07-08 jrick "a work tree");
4915 624411d2 2023-07-08 jrick goto done;
4916 624411d2 2023-07-08 jrick }
4917 624411d2 2023-07-08 jrick }
4918 624411d2 2023-07-08 jrick
4919 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
4920 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
4921 624411d2 2023-07-08 jrick if (error)
4922 624411d2 2023-07-08 jrick goto done;
4923 624411d2 2023-07-08 jrick
4924 624411d2 2023-07-08 jrick if ((!force_path && argc == 2) || ncommit_args > 0) {
4925 624411d2 2023-07-08 jrick int obj_type = (ncommit_args > 0 ?
4926 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY);
4927 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
4928 624411d2 2023-07-08 jrick NULL);
4929 624411d2 2023-07-08 jrick if (error)
4930 624411d2 2023-07-08 jrick goto done;
4931 624411d2 2023-07-08 jrick for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) {
4932 624411d2 2023-07-08 jrick const char *arg;
4933 624411d2 2023-07-08 jrick if (ncommit_args > 0)
4934 624411d2 2023-07-08 jrick arg = commit_args[i];
4935 624411d2 2023-07-08 jrick else
4936 624411d2 2023-07-08 jrick arg = argv[i];
4937 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&ids[i], &labels[i],
4938 624411d2 2023-07-08 jrick arg, obj_type, &refs, repo);
4939 624411d2 2023-07-08 jrick if (error) {
4940 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF &&
4941 624411d2 2023-07-08 jrick error->code != GOT_ERR_NO_OBJ)
4942 624411d2 2023-07-08 jrick goto done;
4943 624411d2 2023-07-08 jrick if (ncommit_args > 0)
4944 624411d2 2023-07-08 jrick goto done;
4945 624411d2 2023-07-08 jrick error = NULL;
4946 624411d2 2023-07-08 jrick break;
4947 624411d2 2023-07-08 jrick }
4948 624411d2 2023-07-08 jrick }
4949 624411d2 2023-07-08 jrick }
4950 624411d2 2023-07-08 jrick
4951 624411d2 2023-07-08 jrick f1 = got_opentemp();
4952 624411d2 2023-07-08 jrick if (f1 == NULL) {
4953 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4954 624411d2 2023-07-08 jrick goto done;
4955 624411d2 2023-07-08 jrick }
4956 624411d2 2023-07-08 jrick
4957 624411d2 2023-07-08 jrick f2 = got_opentemp();
4958 624411d2 2023-07-08 jrick if (f2 == NULL) {
4959 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4960 624411d2 2023-07-08 jrick goto done;
4961 624411d2 2023-07-08 jrick }
4962 624411d2 2023-07-08 jrick
4963 624411d2 2023-07-08 jrick outfile = got_opentemp();
4964 624411d2 2023-07-08 jrick if (outfile == NULL) {
4965 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4966 624411d2 2023-07-08 jrick goto done;
4967 624411d2 2023-07-08 jrick }
4968 624411d2 2023-07-08 jrick
4969 624411d2 2023-07-08 jrick if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) {
4970 624411d2 2023-07-08 jrick struct print_diff_arg arg;
4971 624411d2 2023-07-08 jrick char *id_str;
4972 624411d2 2023-07-08 jrick
4973 624411d2 2023-07-08 jrick if (worktree == NULL) {
4974 624411d2 2023-07-08 jrick if (argc == 2 && ids[0] == NULL) {
4975 624411d2 2023-07-08 jrick error = got_error_path(argv[0], GOT_ERR_NO_OBJ);
4976 624411d2 2023-07-08 jrick goto done;
4977 624411d2 2023-07-08 jrick } else if (argc == 2 && ids[1] == NULL) {
4978 624411d2 2023-07-08 jrick error = got_error_path(argv[1], GOT_ERR_NO_OBJ);
4979 624411d2 2023-07-08 jrick goto done;
4980 624411d2 2023-07-08 jrick } else if (argc > 0) {
4981 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_NOT_WORKTREE,
4982 624411d2 2023-07-08 jrick "%s", "specified paths cannot be resolved");
4983 624411d2 2023-07-08 jrick goto done;
4984 624411d2 2023-07-08 jrick } else {
4985 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_WORKTREE);
4986 624411d2 2023-07-08 jrick goto done;
4987 624411d2 2023-07-08 jrick }
4988 624411d2 2023-07-08 jrick }
4989 624411d2 2023-07-08 jrick
4990 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv,
4991 624411d2 2023-07-08 jrick worktree);
4992 624411d2 2023-07-08 jrick if (error)
4993 624411d2 2023-07-08 jrick goto done;
4994 624411d2 2023-07-08 jrick
4995 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
4996 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
4997 624411d2 2023-07-08 jrick if (error)
4998 624411d2 2023-07-08 jrick goto done;
4999 624411d2 2023-07-08 jrick arg.repo = repo;
5000 624411d2 2023-07-08 jrick arg.worktree = worktree;
5001 624411d2 2023-07-08 jrick arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
5002 624411d2 2023-07-08 jrick arg.diff_context = diff_context;
5003 624411d2 2023-07-08 jrick arg.id_str = id_str;
5004 624411d2 2023-07-08 jrick arg.header_shown = 0;
5005 624411d2 2023-07-08 jrick arg.diff_staged = diff_staged;
5006 624411d2 2023-07-08 jrick arg.ignore_whitespace = ignore_whitespace;
5007 624411d2 2023-07-08 jrick arg.force_text_diff = force_text_diff;
5008 624411d2 2023-07-08 jrick arg.diffstat = show_diffstat ? &dsa : NULL;
5009 624411d2 2023-07-08 jrick arg.f1 = f1;
5010 624411d2 2023-07-08 jrick arg.f2 = f2;
5011 624411d2 2023-07-08 jrick arg.outfile = outfile;
5012 624411d2 2023-07-08 jrick
5013 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, 0,
5014 624411d2 2023-07-08 jrick print_diff, &arg, check_cancelled, NULL);
5015 624411d2 2023-07-08 jrick free(id_str);
5016 624411d2 2023-07-08 jrick if (error)
5017 624411d2 2023-07-08 jrick goto done;
5018 624411d2 2023-07-08 jrick
5019 624411d2 2023-07-08 jrick if (show_diffstat && dsa.nfiles > 0) {
5020 624411d2 2023-07-08 jrick char *header;
5021 624411d2 2023-07-08 jrick
5022 624411d2 2023-07-08 jrick if (asprintf(&header, "diffstat %s%s",
5023 624411d2 2023-07-08 jrick diff_staged ? "-s " : "",
5024 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree)) == -1) {
5025 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5026 624411d2 2023-07-08 jrick goto done;
5027 624411d2 2023-07-08 jrick }
5028 624411d2 2023-07-08 jrick
5029 624411d2 2023-07-08 jrick error = print_diffstat(&dsa, header);
5030 624411d2 2023-07-08 jrick free(header);
5031 624411d2 2023-07-08 jrick if (error)
5032 624411d2 2023-07-08 jrick goto done;
5033 624411d2 2023-07-08 jrick }
5034 624411d2 2023-07-08 jrick
5035 624411d2 2023-07-08 jrick error = printfile(outfile);
5036 624411d2 2023-07-08 jrick goto done;
5037 624411d2 2023-07-08 jrick }
5038 624411d2 2023-07-08 jrick
5039 624411d2 2023-07-08 jrick if (ncommit_args == 1) {
5040 624411d2 2023-07-08 jrick struct got_commit_object *commit;
5041 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, ids[0]);
5042 624411d2 2023-07-08 jrick if (error)
5043 624411d2 2023-07-08 jrick goto done;
5044 624411d2 2023-07-08 jrick
5045 624411d2 2023-07-08 jrick labels[1] = labels[0];
5046 624411d2 2023-07-08 jrick ids[1] = ids[0];
5047 624411d2 2023-07-08 jrick if (got_object_commit_get_nparents(commit) > 0) {
5048 624411d2 2023-07-08 jrick const struct got_object_id_queue *pids;
5049 624411d2 2023-07-08 jrick struct got_object_qid *pid;
5050 624411d2 2023-07-08 jrick pids = got_object_commit_get_parent_ids(commit);
5051 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(pids);
5052 624411d2 2023-07-08 jrick ids[0] = got_object_id_dup(&pid->id);
5053 624411d2 2023-07-08 jrick if (ids[0] == NULL) {
5054 624411d2 2023-07-08 jrick error = got_error_from_errno(
5055 624411d2 2023-07-08 jrick "got_object_id_dup");
5056 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5057 624411d2 2023-07-08 jrick goto done;
5058 624411d2 2023-07-08 jrick }
5059 624411d2 2023-07-08 jrick error = got_object_id_str(&labels[0], ids[0]);
5060 624411d2 2023-07-08 jrick if (error) {
5061 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5062 624411d2 2023-07-08 jrick goto done;
5063 624411d2 2023-07-08 jrick }
5064 624411d2 2023-07-08 jrick } else {
5065 624411d2 2023-07-08 jrick ids[0] = NULL;
5066 624411d2 2023-07-08 jrick labels[0] = strdup("/dev/null");
5067 624411d2 2023-07-08 jrick if (labels[0] == NULL) {
5068 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5069 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5070 624411d2 2023-07-08 jrick goto done;
5071 624411d2 2023-07-08 jrick }
5072 624411d2 2023-07-08 jrick }
5073 624411d2 2023-07-08 jrick
5074 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5075 624411d2 2023-07-08 jrick }
5076 624411d2 2023-07-08 jrick
5077 624411d2 2023-07-08 jrick if (ncommit_args == 0 && argc > 2) {
5078 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
5079 624411d2 2023-07-08 jrick "path arguments cannot be used when diffing two objects");
5080 624411d2 2023-07-08 jrick goto done;
5081 624411d2 2023-07-08 jrick }
5082 624411d2 2023-07-08 jrick
5083 624411d2 2023-07-08 jrick if (ids[0]) {
5084 624411d2 2023-07-08 jrick error = got_object_get_type(&type1, repo, ids[0]);
5085 624411d2 2023-07-08 jrick if (error)
5086 624411d2 2023-07-08 jrick goto done;
5087 624411d2 2023-07-08 jrick }
5088 624411d2 2023-07-08 jrick
5089 624411d2 2023-07-08 jrick error = got_object_get_type(&type2, repo, ids[1]);
5090 624411d2 2023-07-08 jrick if (error)
5091 624411d2 2023-07-08 jrick goto done;
5092 624411d2 2023-07-08 jrick if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) {
5093 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
5094 624411d2 2023-07-08 jrick goto done;
5095 624411d2 2023-07-08 jrick }
5096 624411d2 2023-07-08 jrick if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) {
5097 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_OBJ_TYPE,
5098 624411d2 2023-07-08 jrick "path arguments cannot be used when diffing blobs");
5099 624411d2 2023-07-08 jrick goto done;
5100 624411d2 2023-07-08 jrick }
5101 624411d2 2023-07-08 jrick
5102 624411d2 2023-07-08 jrick for (i = 0; ncommit_args > 0 && i < argc; i++) {
5103 624411d2 2023-07-08 jrick char *in_repo_path;
5104 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
5105 624411d2 2023-07-08 jrick if (worktree) {
5106 624411d2 2023-07-08 jrick const char *prefix;
5107 624411d2 2023-07-08 jrick char *p;
5108 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree,
5109 624411d2 2023-07-08 jrick argv[i]);
5110 624411d2 2023-07-08 jrick if (error)
5111 624411d2 2023-07-08 jrick goto done;
5112 624411d2 2023-07-08 jrick prefix = got_worktree_get_path_prefix(worktree);
5113 624411d2 2023-07-08 jrick while (prefix[0] == '/')
5114 624411d2 2023-07-08 jrick prefix++;
5115 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5116 624411d2 2023-07-08 jrick (p[0] != '\0' && prefix[0] != '\0') ? "/" : "",
5117 624411d2 2023-07-08 jrick p) == -1) {
5118 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5119 624411d2 2023-07-08 jrick free(p);
5120 624411d2 2023-07-08 jrick goto done;
5121 624411d2 2023-07-08 jrick }
5122 624411d2 2023-07-08 jrick free(p);
5123 624411d2 2023-07-08 jrick } else {
5124 624411d2 2023-07-08 jrick char *mapped_path, *s;
5125 624411d2 2023-07-08 jrick error = got_repo_map_path(&mapped_path, repo, argv[i]);
5126 624411d2 2023-07-08 jrick if (error)
5127 624411d2 2023-07-08 jrick goto done;
5128 624411d2 2023-07-08 jrick s = mapped_path;
5129 624411d2 2023-07-08 jrick while (s[0] == '/')
5130 624411d2 2023-07-08 jrick s++;
5131 624411d2 2023-07-08 jrick in_repo_path = strdup(s);
5132 624411d2 2023-07-08 jrick if (in_repo_path == NULL) {
5133 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5134 624411d2 2023-07-08 jrick free(mapped_path);
5135 624411d2 2023-07-08 jrick goto done;
5136 624411d2 2023-07-08 jrick }
5137 624411d2 2023-07-08 jrick free(mapped_path);
5138 624411d2 2023-07-08 jrick
5139 624411d2 2023-07-08 jrick }
5140 624411d2 2023-07-08 jrick error = got_pathlist_insert(&new, &paths, in_repo_path, NULL);
5141 624411d2 2023-07-08 jrick if (error || new == NULL /* duplicate */)
5142 624411d2 2023-07-08 jrick free(in_repo_path);
5143 624411d2 2023-07-08 jrick if (error)
5144 624411d2 2023-07-08 jrick goto done;
5145 624411d2 2023-07-08 jrick }
5146 624411d2 2023-07-08 jrick
5147 624411d2 2023-07-08 jrick if (worktree) {
5148 624411d2 2023-07-08 jrick /* Release work tree lock. */
5149 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5150 624411d2 2023-07-08 jrick worktree = NULL;
5151 624411d2 2023-07-08 jrick }
5152 624411d2 2023-07-08 jrick
5153 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
5154 624411d2 2023-07-08 jrick if (fd1 == -1) {
5155 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5156 624411d2 2023-07-08 jrick goto done;
5157 624411d2 2023-07-08 jrick }
5158 624411d2 2023-07-08 jrick
5159 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
5160 624411d2 2023-07-08 jrick if (fd2 == -1) {
5161 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5162 624411d2 2023-07-08 jrick goto done;
5163 624411d2 2023-07-08 jrick }
5164 624411d2 2023-07-08 jrick
5165 624411d2 2023-07-08 jrick switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) {
5166 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
5167 624411d2 2023-07-08 jrick error = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
5168 624411d2 2023-07-08 jrick fd1, fd2, ids[0], ids[1], NULL, NULL,
5169 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5170 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5171 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5172 624411d2 2023-07-08 jrick break;
5173 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
5174 624411d2 2023-07-08 jrick error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2,
5175 624411d2 2023-07-08 jrick ids[0], ids[1], &paths, "", "",
5176 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5177 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5178 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5179 624411d2 2023-07-08 jrick break;
5180 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
5181 624411d2 2023-07-08 jrick fprintf(outfile, "diff %s %s\n", labels[0], labels[1]);
5182 624411d2 2023-07-08 jrick error = got_diff_objects_as_commits(NULL, NULL, f1, f2,
5183 624411d2 2023-07-08 jrick fd1, fd2, ids[0], ids[1], &paths,
5184 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5185 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5186 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5187 624411d2 2023-07-08 jrick break;
5188 624411d2 2023-07-08 jrick default:
5189 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
5190 624411d2 2023-07-08 jrick }
5191 624411d2 2023-07-08 jrick if (error)
5192 624411d2 2023-07-08 jrick goto done;
5193 624411d2 2023-07-08 jrick
5194 624411d2 2023-07-08 jrick if (show_diffstat && dsa.nfiles > 0) {
5195 624411d2 2023-07-08 jrick char *header = NULL;
5196 624411d2 2023-07-08 jrick
5197 624411d2 2023-07-08 jrick if (asprintf(&header, "diffstat %s %s",
5198 624411d2 2023-07-08 jrick labels[0], labels[1]) == -1) {
5199 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5200 624411d2 2023-07-08 jrick goto done;
5201 624411d2 2023-07-08 jrick }
5202 624411d2 2023-07-08 jrick
5203 624411d2 2023-07-08 jrick error = print_diffstat(&dsa, header);
5204 624411d2 2023-07-08 jrick free(header);
5205 624411d2 2023-07-08 jrick if (error)
5206 624411d2 2023-07-08 jrick goto done;
5207 624411d2 2023-07-08 jrick }
5208 624411d2 2023-07-08 jrick
5209 624411d2 2023-07-08 jrick error = printfile(outfile);
5210 624411d2 2023-07-08 jrick
5211 624411d2 2023-07-08 jrick done:
5212 624411d2 2023-07-08 jrick free(labels[0]);
5213 624411d2 2023-07-08 jrick free(labels[1]);
5214 624411d2 2023-07-08 jrick free(ids[0]);
5215 624411d2 2023-07-08 jrick free(ids[1]);
5216 624411d2 2023-07-08 jrick if (worktree)
5217 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5218 624411d2 2023-07-08 jrick if (repo) {
5219 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5220 624411d2 2023-07-08 jrick if (error == NULL)
5221 624411d2 2023-07-08 jrick error = close_err;
5222 624411d2 2023-07-08 jrick }
5223 624411d2 2023-07-08 jrick if (pack_fds) {
5224 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5225 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5226 624411d2 2023-07-08 jrick if (error == NULL)
5227 624411d2 2023-07-08 jrick error = pack_err;
5228 624411d2 2023-07-08 jrick }
5229 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
5230 624411d2 2023-07-08 jrick got_pathlist_free(&diffstat_paths, GOT_PATHLIST_FREE_ALL);
5231 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5232 624411d2 2023-07-08 jrick if (outfile && fclose(outfile) == EOF && error == NULL)
5233 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5234 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && error == NULL)
5235 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5236 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && error == NULL)
5237 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5238 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && error == NULL)
5239 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5240 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && error == NULL)
5241 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5242 624411d2 2023-07-08 jrick return error;
5243 624411d2 2023-07-08 jrick }
5244 624411d2 2023-07-08 jrick
5245 624411d2 2023-07-08 jrick __dead static void
5246 624411d2 2023-07-08 jrick usage_blame(void)
5247 624411d2 2023-07-08 jrick {
5248 624411d2 2023-07-08 jrick fprintf(stderr,
5249 624411d2 2023-07-08 jrick "usage: %s blame [-c commit] [-r repository-path] path\n",
5250 624411d2 2023-07-08 jrick getprogname());
5251 624411d2 2023-07-08 jrick exit(1);
5252 624411d2 2023-07-08 jrick }
5253 624411d2 2023-07-08 jrick
5254 624411d2 2023-07-08 jrick struct blame_line {
5255 624411d2 2023-07-08 jrick int annotated;
5256 624411d2 2023-07-08 jrick char *id_str;
5257 624411d2 2023-07-08 jrick char *committer;
5258 624411d2 2023-07-08 jrick char datebuf[11]; /* YYYY-MM-DD + NUL */
5259 624411d2 2023-07-08 jrick };
5260 624411d2 2023-07-08 jrick
5261 624411d2 2023-07-08 jrick struct blame_cb_args {
5262 624411d2 2023-07-08 jrick struct blame_line *lines;
5263 624411d2 2023-07-08 jrick int nlines;
5264 624411d2 2023-07-08 jrick int nlines_prec;
5265 624411d2 2023-07-08 jrick int lineno_cur;
5266 624411d2 2023-07-08 jrick off_t *line_offsets;
5267 624411d2 2023-07-08 jrick FILE *f;
5268 624411d2 2023-07-08 jrick struct got_repository *repo;
5269 624411d2 2023-07-08 jrick };
5270 624411d2 2023-07-08 jrick
5271 624411d2 2023-07-08 jrick static const struct got_error *
5272 624411d2 2023-07-08 jrick blame_cb(void *arg, int nlines, int lineno,
5273 624411d2 2023-07-08 jrick struct got_commit_object *commit, struct got_object_id *id)
5274 624411d2 2023-07-08 jrick {
5275 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5276 624411d2 2023-07-08 jrick struct blame_cb_args *a = arg;
5277 624411d2 2023-07-08 jrick struct blame_line *bline;
5278 624411d2 2023-07-08 jrick char *line = NULL;
5279 624411d2 2023-07-08 jrick size_t linesize = 0;
5280 624411d2 2023-07-08 jrick off_t offset;
5281 624411d2 2023-07-08 jrick struct tm tm;
5282 624411d2 2023-07-08 jrick time_t committer_time;
5283 624411d2 2023-07-08 jrick
5284 624411d2 2023-07-08 jrick if (nlines != a->nlines ||
5285 624411d2 2023-07-08 jrick (lineno != -1 && lineno < 1) || lineno > a->nlines)
5286 624411d2 2023-07-08 jrick return got_error(GOT_ERR_RANGE);
5287 624411d2 2023-07-08 jrick
5288 624411d2 2023-07-08 jrick if (sigint_received)
5289 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ITER_COMPLETED);
5290 624411d2 2023-07-08 jrick
5291 624411d2 2023-07-08 jrick if (lineno == -1)
5292 624411d2 2023-07-08 jrick return NULL; /* no change in this commit */
5293 624411d2 2023-07-08 jrick
5294 624411d2 2023-07-08 jrick /* Annotate this line. */
5295 624411d2 2023-07-08 jrick bline = &a->lines[lineno - 1];
5296 624411d2 2023-07-08 jrick if (bline->annotated)
5297 624411d2 2023-07-08 jrick return NULL;
5298 624411d2 2023-07-08 jrick err = got_object_id_str(&bline->id_str, id);
5299 624411d2 2023-07-08 jrick if (err)
5300 624411d2 2023-07-08 jrick return err;
5301 624411d2 2023-07-08 jrick
5302 624411d2 2023-07-08 jrick bline->committer = strdup(got_object_commit_get_committer(commit));
5303 624411d2 2023-07-08 jrick if (bline->committer == NULL) {
5304 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
5305 624411d2 2023-07-08 jrick goto done;
5306 624411d2 2023-07-08 jrick }
5307 624411d2 2023-07-08 jrick
5308 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
5309 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL)
5310 624411d2 2023-07-08 jrick return got_error_from_errno("gmtime_r");
5311 624411d2 2023-07-08 jrick if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
5312 624411d2 2023-07-08 jrick &tm) == 0) {
5313 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
5314 624411d2 2023-07-08 jrick goto done;
5315 624411d2 2023-07-08 jrick }
5316 624411d2 2023-07-08 jrick bline->annotated = 1;
5317 624411d2 2023-07-08 jrick
5318 624411d2 2023-07-08 jrick /* Print lines annotated so far. */
5319 624411d2 2023-07-08 jrick bline = &a->lines[a->lineno_cur - 1];
5320 624411d2 2023-07-08 jrick if (!bline->annotated)
5321 624411d2 2023-07-08 jrick goto done;
5322 624411d2 2023-07-08 jrick
5323 624411d2 2023-07-08 jrick offset = a->line_offsets[a->lineno_cur - 1];
5324 624411d2 2023-07-08 jrick if (fseeko(a->f, offset, SEEK_SET) == -1) {
5325 624411d2 2023-07-08 jrick err = got_error_from_errno("fseeko");
5326 624411d2 2023-07-08 jrick goto done;
5327 624411d2 2023-07-08 jrick }
5328 624411d2 2023-07-08 jrick
5329 624411d2 2023-07-08 jrick while (a->lineno_cur <= a->nlines && bline->annotated) {
5330 624411d2 2023-07-08 jrick char *smallerthan, *at, *nl, *committer;
5331 624411d2 2023-07-08 jrick size_t len;
5332 624411d2 2023-07-08 jrick
5333 624411d2 2023-07-08 jrick if (getline(&line, &linesize, a->f) == -1) {
5334 624411d2 2023-07-08 jrick if (ferror(a->f))
5335 624411d2 2023-07-08 jrick err = got_error_from_errno("getline");
5336 624411d2 2023-07-08 jrick break;
5337 624411d2 2023-07-08 jrick }
5338 624411d2 2023-07-08 jrick
5339 624411d2 2023-07-08 jrick committer = bline->committer;
5340 624411d2 2023-07-08 jrick smallerthan = strchr(committer, '<');
5341 624411d2 2023-07-08 jrick if (smallerthan && smallerthan[1] != '\0')
5342 624411d2 2023-07-08 jrick committer = smallerthan + 1;
5343 624411d2 2023-07-08 jrick at = strchr(committer, '@');
5344 624411d2 2023-07-08 jrick if (at)
5345 624411d2 2023-07-08 jrick *at = '\0';
5346 624411d2 2023-07-08 jrick len = strlen(committer);
5347 624411d2 2023-07-08 jrick if (len >= 9)
5348 624411d2 2023-07-08 jrick committer[8] = '\0';
5349 624411d2 2023-07-08 jrick
5350 624411d2 2023-07-08 jrick nl = strchr(line, '\n');
5351 624411d2 2023-07-08 jrick if (nl)
5352 624411d2 2023-07-08 jrick *nl = '\0';
5353 624411d2 2023-07-08 jrick printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
5354 624411d2 2023-07-08 jrick bline->id_str, bline->datebuf, committer, line);
5355 624411d2 2023-07-08 jrick
5356 624411d2 2023-07-08 jrick a->lineno_cur++;
5357 624411d2 2023-07-08 jrick bline = &a->lines[a->lineno_cur - 1];
5358 624411d2 2023-07-08 jrick }
5359 624411d2 2023-07-08 jrick done:
5360 624411d2 2023-07-08 jrick free(line);
5361 624411d2 2023-07-08 jrick return err;
5362 624411d2 2023-07-08 jrick }
5363 624411d2 2023-07-08 jrick
5364 624411d2 2023-07-08 jrick static const struct got_error *
5365 624411d2 2023-07-08 jrick cmd_blame(int argc, char *argv[])
5366 624411d2 2023-07-08 jrick {
5367 624411d2 2023-07-08 jrick const struct got_error *error;
5368 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5369 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5370 624411d2 2023-07-08 jrick char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5371 624411d2 2023-07-08 jrick char *link_target = NULL;
5372 624411d2 2023-07-08 jrick struct got_object_id *obj_id = NULL;
5373 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
5374 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
5375 624411d2 2023-07-08 jrick struct got_blob_object *blob = NULL;
5376 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
5377 624411d2 2023-07-08 jrick struct blame_cb_args bca;
5378 624411d2 2023-07-08 jrick int ch, obj_type, i, fd1 = -1, fd2 = -1, fd3 = -1;
5379 624411d2 2023-07-08 jrick off_t filesize;
5380 624411d2 2023-07-08 jrick int *pack_fds = NULL;
5381 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
5382 624411d2 2023-07-08 jrick
5383 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
5384 624411d2 2023-07-08 jrick if (fd1 == -1)
5385 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
5386 624411d2 2023-07-08 jrick
5387 624411d2 2023-07-08 jrick memset(&bca, 0, sizeof(bca));
5388 624411d2 2023-07-08 jrick
5389 624411d2 2023-07-08 jrick #ifndef PROFILE
5390 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5391 624411d2 2023-07-08 jrick NULL) == -1)
5392 624411d2 2023-07-08 jrick err(1, "pledge");
5393 624411d2 2023-07-08 jrick #endif
5394 624411d2 2023-07-08 jrick
5395 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:r:")) != -1) {
5396 624411d2 2023-07-08 jrick switch (ch) {
5397 624411d2 2023-07-08 jrick case 'c':
5398 624411d2 2023-07-08 jrick commit_id_str = optarg;
5399 624411d2 2023-07-08 jrick break;
5400 624411d2 2023-07-08 jrick case 'r':
5401 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
5402 624411d2 2023-07-08 jrick if (repo_path == NULL)
5403 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
5404 624411d2 2023-07-08 jrick optarg);
5405 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
5406 624411d2 2023-07-08 jrick break;
5407 624411d2 2023-07-08 jrick default:
5408 624411d2 2023-07-08 jrick usage_blame();
5409 624411d2 2023-07-08 jrick /* NOTREACHED */
5410 624411d2 2023-07-08 jrick }
5411 624411d2 2023-07-08 jrick }
5412 624411d2 2023-07-08 jrick
5413 624411d2 2023-07-08 jrick argc -= optind;
5414 624411d2 2023-07-08 jrick argv += optind;
5415 624411d2 2023-07-08 jrick
5416 624411d2 2023-07-08 jrick if (argc == 1)
5417 624411d2 2023-07-08 jrick path = argv[0];
5418 624411d2 2023-07-08 jrick else
5419 624411d2 2023-07-08 jrick usage_blame();
5420 624411d2 2023-07-08 jrick
5421 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
5422 624411d2 2023-07-08 jrick if (cwd == NULL) {
5423 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
5424 624411d2 2023-07-08 jrick goto done;
5425 624411d2 2023-07-08 jrick }
5426 624411d2 2023-07-08 jrick
5427 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
5428 624411d2 2023-07-08 jrick if (error != NULL)
5429 624411d2 2023-07-08 jrick goto done;
5430 624411d2 2023-07-08 jrick
5431 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5432 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
5433 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
5434 624411d2 2023-07-08 jrick goto done;
5435 624411d2 2023-07-08 jrick else
5436 624411d2 2023-07-08 jrick error = NULL;
5437 624411d2 2023-07-08 jrick if (worktree) {
5438 624411d2 2023-07-08 jrick repo_path =
5439 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
5440 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5441 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5442 624411d2 2023-07-08 jrick if (error)
5443 624411d2 2023-07-08 jrick goto done;
5444 624411d2 2023-07-08 jrick }
5445 624411d2 2023-07-08 jrick } else {
5446 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
5447 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5448 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5449 624411d2 2023-07-08 jrick goto done;
5450 624411d2 2023-07-08 jrick }
5451 624411d2 2023-07-08 jrick }
5452 624411d2 2023-07-08 jrick }
5453 624411d2 2023-07-08 jrick
5454 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
5455 624411d2 2023-07-08 jrick if (error != NULL)
5456 624411d2 2023-07-08 jrick goto done;
5457 624411d2 2023-07-08 jrick
5458 624411d2 2023-07-08 jrick if (worktree) {
5459 624411d2 2023-07-08 jrick const char *prefix = got_worktree_get_path_prefix(worktree);
5460 624411d2 2023-07-08 jrick char *p;
5461 624411d2 2023-07-08 jrick
5462 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree, path);
5463 624411d2 2023-07-08 jrick if (error)
5464 624411d2 2023-07-08 jrick goto done;
5465 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5466 624411d2 2023-07-08 jrick (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5467 624411d2 2023-07-08 jrick p) == -1) {
5468 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5469 624411d2 2023-07-08 jrick free(p);
5470 624411d2 2023-07-08 jrick goto done;
5471 624411d2 2023-07-08 jrick }
5472 624411d2 2023-07-08 jrick free(p);
5473 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5474 624411d2 2023-07-08 jrick } else {
5475 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5476 624411d2 2023-07-08 jrick if (error)
5477 624411d2 2023-07-08 jrick goto done;
5478 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo, path);
5479 624411d2 2023-07-08 jrick }
5480 624411d2 2023-07-08 jrick if (error)
5481 624411d2 2023-07-08 jrick goto done;
5482 624411d2 2023-07-08 jrick
5483 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
5484 624411d2 2023-07-08 jrick struct got_reference *head_ref;
5485 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, worktree ?
5486 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0);
5487 624411d2 2023-07-08 jrick if (error != NULL)
5488 624411d2 2023-07-08 jrick goto done;
5489 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
5490 624411d2 2023-07-08 jrick got_ref_close(head_ref);
5491 624411d2 2023-07-08 jrick if (error != NULL)
5492 624411d2 2023-07-08 jrick goto done;
5493 624411d2 2023-07-08 jrick } else {
5494 624411d2 2023-07-08 jrick struct got_reflist_head refs;
5495 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
5496 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5497 624411d2 2023-07-08 jrick NULL);
5498 624411d2 2023-07-08 jrick if (error)
5499 624411d2 2023-07-08 jrick goto done;
5500 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
5501 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5502 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5503 624411d2 2023-07-08 jrick if (error)
5504 624411d2 2023-07-08 jrick goto done;
5505 624411d2 2023-07-08 jrick }
5506 624411d2 2023-07-08 jrick
5507 624411d2 2023-07-08 jrick if (worktree) {
5508 624411d2 2023-07-08 jrick /* Release work tree lock. */
5509 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5510 624411d2 2023-07-08 jrick worktree = NULL;
5511 624411d2 2023-07-08 jrick }
5512 624411d2 2023-07-08 jrick
5513 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
5514 624411d2 2023-07-08 jrick if (error)
5515 624411d2 2023-07-08 jrick goto done;
5516 624411d2 2023-07-08 jrick
5517 624411d2 2023-07-08 jrick error = got_object_resolve_symlinks(&link_target, in_repo_path,
5518 624411d2 2023-07-08 jrick commit, repo);
5519 624411d2 2023-07-08 jrick if (error)
5520 624411d2 2023-07-08 jrick goto done;
5521 624411d2 2023-07-08 jrick
5522 624411d2 2023-07-08 jrick error = got_object_id_by_path(&obj_id, repo, commit,
5523 624411d2 2023-07-08 jrick link_target ? link_target : in_repo_path);
5524 624411d2 2023-07-08 jrick if (error)
5525 624411d2 2023-07-08 jrick goto done;
5526 624411d2 2023-07-08 jrick
5527 624411d2 2023-07-08 jrick error = got_object_get_type(&obj_type, repo, obj_id);
5528 624411d2 2023-07-08 jrick if (error)
5529 624411d2 2023-07-08 jrick goto done;
5530 624411d2 2023-07-08 jrick
5531 624411d2 2023-07-08 jrick if (obj_type != GOT_OBJ_TYPE_BLOB) {
5532 624411d2 2023-07-08 jrick error = got_error_path(link_target ? link_target : in_repo_path,
5533 624411d2 2023-07-08 jrick GOT_ERR_OBJ_TYPE);
5534 624411d2 2023-07-08 jrick goto done;
5535 624411d2 2023-07-08 jrick }
5536 624411d2 2023-07-08 jrick
5537 624411d2 2023-07-08 jrick error = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1);
5538 624411d2 2023-07-08 jrick if (error)
5539 624411d2 2023-07-08 jrick goto done;
5540 624411d2 2023-07-08 jrick bca.f = got_opentemp();
5541 624411d2 2023-07-08 jrick if (bca.f == NULL) {
5542 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5543 624411d2 2023-07-08 jrick goto done;
5544 624411d2 2023-07-08 jrick }
5545 624411d2 2023-07-08 jrick error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
5546 624411d2 2023-07-08 jrick &bca.line_offsets, bca.f, blob);
5547 624411d2 2023-07-08 jrick if (error || bca.nlines == 0)
5548 624411d2 2023-07-08 jrick goto done;
5549 624411d2 2023-07-08 jrick
5550 624411d2 2023-07-08 jrick /* Don't include \n at EOF in the blame line count. */
5551 624411d2 2023-07-08 jrick if (bca.line_offsets[bca.nlines - 1] == filesize)
5552 624411d2 2023-07-08 jrick bca.nlines--;
5553 624411d2 2023-07-08 jrick
5554 624411d2 2023-07-08 jrick bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
5555 624411d2 2023-07-08 jrick if (bca.lines == NULL) {
5556 624411d2 2023-07-08 jrick error = got_error_from_errno("calloc");
5557 624411d2 2023-07-08 jrick goto done;
5558 624411d2 2023-07-08 jrick }
5559 624411d2 2023-07-08 jrick bca.lineno_cur = 1;
5560 624411d2 2023-07-08 jrick bca.nlines_prec = 0;
5561 624411d2 2023-07-08 jrick i = bca.nlines;
5562 624411d2 2023-07-08 jrick while (i > 0) {
5563 624411d2 2023-07-08 jrick i /= 10;
5564 624411d2 2023-07-08 jrick bca.nlines_prec++;
5565 624411d2 2023-07-08 jrick }
5566 624411d2 2023-07-08 jrick bca.repo = repo;
5567 624411d2 2023-07-08 jrick
5568 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
5569 624411d2 2023-07-08 jrick if (fd2 == -1) {
5570 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5571 624411d2 2023-07-08 jrick goto done;
5572 624411d2 2023-07-08 jrick }
5573 624411d2 2023-07-08 jrick fd3 = got_opentempfd();
5574 624411d2 2023-07-08 jrick if (fd3 == -1) {
5575 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5576 624411d2 2023-07-08 jrick goto done;
5577 624411d2 2023-07-08 jrick }
5578 624411d2 2023-07-08 jrick f1 = got_opentemp();
5579 624411d2 2023-07-08 jrick if (f1 == NULL) {
5580 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5581 624411d2 2023-07-08 jrick goto done;
5582 624411d2 2023-07-08 jrick }
5583 624411d2 2023-07-08 jrick f2 = got_opentemp();
5584 624411d2 2023-07-08 jrick if (f2 == NULL) {
5585 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5586 624411d2 2023-07-08 jrick goto done;
5587 624411d2 2023-07-08 jrick }
5588 624411d2 2023-07-08 jrick error = got_blame(link_target ? link_target : in_repo_path, commit_id,
5589 624411d2 2023-07-08 jrick repo, GOT_DIFF_ALGORITHM_PATIENCE, blame_cb, &bca,
5590 624411d2 2023-07-08 jrick check_cancelled, NULL, fd2, fd3, f1, f2);
5591 624411d2 2023-07-08 jrick done:
5592 624411d2 2023-07-08 jrick free(in_repo_path);
5593 624411d2 2023-07-08 jrick free(link_target);
5594 624411d2 2023-07-08 jrick free(repo_path);
5595 624411d2 2023-07-08 jrick free(cwd);
5596 624411d2 2023-07-08 jrick free(commit_id);
5597 624411d2 2023-07-08 jrick free(obj_id);
5598 624411d2 2023-07-08 jrick if (commit)
5599 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5600 624411d2 2023-07-08 jrick
5601 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && error == NULL)
5602 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5603 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && error == NULL)
5604 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5605 624411d2 2023-07-08 jrick if (fd3 != -1 && close(fd3) == -1 && error == NULL)
5606 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5607 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && error == NULL)
5608 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5609 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && error == NULL)
5610 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5611 624411d2 2023-07-08 jrick
5612 624411d2 2023-07-08 jrick if (blob)
5613 624411d2 2023-07-08 jrick got_object_blob_close(blob);
5614 624411d2 2023-07-08 jrick if (worktree)
5615 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5616 624411d2 2023-07-08 jrick if (repo) {
5617 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5618 624411d2 2023-07-08 jrick if (error == NULL)
5619 624411d2 2023-07-08 jrick error = close_err;
5620 624411d2 2023-07-08 jrick }
5621 624411d2 2023-07-08 jrick if (pack_fds) {
5622 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5623 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5624 624411d2 2023-07-08 jrick if (error == NULL)
5625 624411d2 2023-07-08 jrick error = pack_err;
5626 624411d2 2023-07-08 jrick }
5627 624411d2 2023-07-08 jrick if (bca.lines) {
5628 624411d2 2023-07-08 jrick for (i = 0; i < bca.nlines; i++) {
5629 624411d2 2023-07-08 jrick struct blame_line *bline = &bca.lines[i];
5630 624411d2 2023-07-08 jrick free(bline->id_str);
5631 624411d2 2023-07-08 jrick free(bline->committer);
5632 624411d2 2023-07-08 jrick }
5633 624411d2 2023-07-08 jrick free(bca.lines);
5634 624411d2 2023-07-08 jrick }
5635 624411d2 2023-07-08 jrick free(bca.line_offsets);
5636 624411d2 2023-07-08 jrick if (bca.f && fclose(bca.f) == EOF && error == NULL)
5637 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5638 624411d2 2023-07-08 jrick return error;
5639 624411d2 2023-07-08 jrick }
5640 624411d2 2023-07-08 jrick
5641 624411d2 2023-07-08 jrick __dead static void
5642 624411d2 2023-07-08 jrick usage_tree(void)
5643 624411d2 2023-07-08 jrick {
5644 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
5645 624411d2 2023-07-08 jrick "[path]\n", getprogname());
5646 624411d2 2023-07-08 jrick exit(1);
5647 624411d2 2023-07-08 jrick }
5648 624411d2 2023-07-08 jrick
5649 624411d2 2023-07-08 jrick static const struct got_error *
5650 624411d2 2023-07-08 jrick print_entry(struct got_tree_entry *te, const char *id, const char *path,
5651 624411d2 2023-07-08 jrick const char *root_path, struct got_repository *repo)
5652 624411d2 2023-07-08 jrick {
5653 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5654 624411d2 2023-07-08 jrick int is_root_path = (strcmp(path, root_path) == 0);
5655 624411d2 2023-07-08 jrick const char *modestr = "";
5656 624411d2 2023-07-08 jrick mode_t mode = got_tree_entry_get_mode(te);
5657 624411d2 2023-07-08 jrick char *link_target = NULL;
5658 624411d2 2023-07-08 jrick
5659 624411d2 2023-07-08 jrick path += strlen(root_path);
5660 624411d2 2023-07-08 jrick while (path[0] == '/')
5661 624411d2 2023-07-08 jrick path++;
5662 624411d2 2023-07-08 jrick
5663 624411d2 2023-07-08 jrick if (got_object_tree_entry_is_submodule(te))
5664 624411d2 2023-07-08 jrick modestr = "$";
5665 624411d2 2023-07-08 jrick else if (S_ISLNK(mode)) {
5666 624411d2 2023-07-08 jrick int i;
5667 624411d2 2023-07-08 jrick
5668 624411d2 2023-07-08 jrick err = got_tree_entry_get_symlink_target(&link_target, te, repo);
5669 624411d2 2023-07-08 jrick if (err)
5670 624411d2 2023-07-08 jrick return err;
5671 624411d2 2023-07-08 jrick for (i = 0; link_target[i] != '\0'; i++) {
5672 624411d2 2023-07-08 jrick if (!isprint((unsigned char)link_target[i]))
5673 624411d2 2023-07-08 jrick link_target[i] = '?';
5674 624411d2 2023-07-08 jrick }
5675 624411d2 2023-07-08 jrick
5676 624411d2 2023-07-08 jrick modestr = "@";
5677 624411d2 2023-07-08 jrick }
5678 624411d2 2023-07-08 jrick else if (S_ISDIR(mode))
5679 624411d2 2023-07-08 jrick modestr = "/";
5680 624411d2 2023-07-08 jrick else if (mode & S_IXUSR)
5681 624411d2 2023-07-08 jrick modestr = "*";
5682 624411d2 2023-07-08 jrick
5683 624411d2 2023-07-08 jrick printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
5684 624411d2 2023-07-08 jrick is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
5685 624411d2 2023-07-08 jrick link_target ? " -> ": "", link_target ? link_target : "");
5686 624411d2 2023-07-08 jrick
5687 624411d2 2023-07-08 jrick free(link_target);
5688 624411d2 2023-07-08 jrick return NULL;
5689 624411d2 2023-07-08 jrick }
5690 624411d2 2023-07-08 jrick
5691 624411d2 2023-07-08 jrick static const struct got_error *
5692 624411d2 2023-07-08 jrick print_tree(const char *path, struct got_commit_object *commit,
5693 624411d2 2023-07-08 jrick int show_ids, int recurse, const char *root_path,
5694 624411d2 2023-07-08 jrick struct got_repository *repo)
5695 624411d2 2023-07-08 jrick {
5696 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5697 624411d2 2023-07-08 jrick struct got_object_id *tree_id = NULL;
5698 624411d2 2023-07-08 jrick struct got_tree_object *tree = NULL;
5699 624411d2 2023-07-08 jrick int nentries, i;
5700 624411d2 2023-07-08 jrick
5701 624411d2 2023-07-08 jrick err = got_object_id_by_path(&tree_id, repo, commit, path);
5702 624411d2 2023-07-08 jrick if (err)
5703 624411d2 2023-07-08 jrick goto done;
5704 624411d2 2023-07-08 jrick
5705 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo, tree_id);
5706 624411d2 2023-07-08 jrick if (err)
5707 624411d2 2023-07-08 jrick goto done;
5708 624411d2 2023-07-08 jrick nentries = got_object_tree_get_nentries(tree);
5709 624411d2 2023-07-08 jrick for (i = 0; i < nentries; i++) {
5710 624411d2 2023-07-08 jrick struct got_tree_entry *te;
5711 624411d2 2023-07-08 jrick char *id = NULL;
5712 624411d2 2023-07-08 jrick
5713 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
5714 624411d2 2023-07-08 jrick break;
5715 624411d2 2023-07-08 jrick
5716 624411d2 2023-07-08 jrick te = got_object_tree_get_entry(tree, i);
5717 624411d2 2023-07-08 jrick if (show_ids) {
5718 624411d2 2023-07-08 jrick char *id_str;
5719 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str,
5720 624411d2 2023-07-08 jrick got_tree_entry_get_id(te));
5721 624411d2 2023-07-08 jrick if (err)
5722 624411d2 2023-07-08 jrick goto done;
5723 624411d2 2023-07-08 jrick if (asprintf(&id, "%s ", id_str) == -1) {
5724 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
5725 624411d2 2023-07-08 jrick free(id_str);
5726 624411d2 2023-07-08 jrick goto done;
5727 624411d2 2023-07-08 jrick }
5728 624411d2 2023-07-08 jrick free(id_str);
5729 624411d2 2023-07-08 jrick }
5730 624411d2 2023-07-08 jrick err = print_entry(te, id, path, root_path, repo);
5731 624411d2 2023-07-08 jrick free(id);
5732 624411d2 2023-07-08 jrick if (err)
5733 624411d2 2023-07-08 jrick goto done;
5734 624411d2 2023-07-08 jrick
5735 624411d2 2023-07-08 jrick if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
5736 624411d2 2023-07-08 jrick char *child_path;
5737 624411d2 2023-07-08 jrick if (asprintf(&child_path, "%s%s%s", path,
5738 624411d2 2023-07-08 jrick path[0] == '/' && path[1] == '\0' ? "" : "/",
5739 624411d2 2023-07-08 jrick got_tree_entry_get_name(te)) == -1) {
5740 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
5741 624411d2 2023-07-08 jrick goto done;
5742 624411d2 2023-07-08 jrick }
5743 624411d2 2023-07-08 jrick err = print_tree(child_path, commit, show_ids, 1,
5744 624411d2 2023-07-08 jrick root_path, repo);
5745 624411d2 2023-07-08 jrick free(child_path);
5746 624411d2 2023-07-08 jrick if (err)
5747 624411d2 2023-07-08 jrick goto done;
5748 624411d2 2023-07-08 jrick }
5749 624411d2 2023-07-08 jrick }
5750 624411d2 2023-07-08 jrick done:
5751 624411d2 2023-07-08 jrick if (tree)
5752 624411d2 2023-07-08 jrick got_object_tree_close(tree);
5753 624411d2 2023-07-08 jrick free(tree_id);
5754 624411d2 2023-07-08 jrick return err;
5755 624411d2 2023-07-08 jrick }
5756 624411d2 2023-07-08 jrick
5757 624411d2 2023-07-08 jrick static const struct got_error *
5758 624411d2 2023-07-08 jrick cmd_tree(int argc, char *argv[])
5759 624411d2 2023-07-08 jrick {
5760 624411d2 2023-07-08 jrick const struct got_error *error;
5761 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5762 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5763 624411d2 2023-07-08 jrick const char *path, *refname = NULL;
5764 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5765 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
5766 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
5767 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
5768 624411d2 2023-07-08 jrick int show_ids = 0, recurse = 0;
5769 624411d2 2023-07-08 jrick int ch;
5770 624411d2 2023-07-08 jrick int *pack_fds = NULL;
5771 624411d2 2023-07-08 jrick
5772 624411d2 2023-07-08 jrick #ifndef PROFILE
5773 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5774 624411d2 2023-07-08 jrick NULL) == -1)
5775 624411d2 2023-07-08 jrick err(1, "pledge");
5776 624411d2 2023-07-08 jrick #endif
5777 624411d2 2023-07-08 jrick
5778 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:iRr:")) != -1) {
5779 624411d2 2023-07-08 jrick switch (ch) {
5780 624411d2 2023-07-08 jrick case 'c':
5781 624411d2 2023-07-08 jrick commit_id_str = optarg;
5782 624411d2 2023-07-08 jrick break;
5783 624411d2 2023-07-08 jrick case 'i':
5784 624411d2 2023-07-08 jrick show_ids = 1;
5785 624411d2 2023-07-08 jrick break;
5786 624411d2 2023-07-08 jrick case 'R':
5787 624411d2 2023-07-08 jrick recurse = 1;
5788 624411d2 2023-07-08 jrick break;
5789 624411d2 2023-07-08 jrick case 'r':
5790 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
5791 624411d2 2023-07-08 jrick if (repo_path == NULL)
5792 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
5793 624411d2 2023-07-08 jrick optarg);
5794 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
5795 624411d2 2023-07-08 jrick break;
5796 624411d2 2023-07-08 jrick default:
5797 624411d2 2023-07-08 jrick usage_tree();
5798 624411d2 2023-07-08 jrick /* NOTREACHED */
5799 624411d2 2023-07-08 jrick }
5800 624411d2 2023-07-08 jrick }
5801 624411d2 2023-07-08 jrick
5802 624411d2 2023-07-08 jrick argc -= optind;
5803 624411d2 2023-07-08 jrick argv += optind;
5804 624411d2 2023-07-08 jrick
5805 624411d2 2023-07-08 jrick if (argc == 1)
5806 624411d2 2023-07-08 jrick path = argv[0];
5807 624411d2 2023-07-08 jrick else if (argc > 1)
5808 624411d2 2023-07-08 jrick usage_tree();
5809 624411d2 2023-07-08 jrick else
5810 624411d2 2023-07-08 jrick path = NULL;
5811 624411d2 2023-07-08 jrick
5812 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
5813 624411d2 2023-07-08 jrick if (cwd == NULL) {
5814 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
5815 624411d2 2023-07-08 jrick goto done;
5816 624411d2 2023-07-08 jrick }
5817 624411d2 2023-07-08 jrick
5818 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
5819 624411d2 2023-07-08 jrick if (error != NULL)
5820 624411d2 2023-07-08 jrick goto done;
5821 624411d2 2023-07-08 jrick
5822 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5823 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
5824 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
5825 624411d2 2023-07-08 jrick goto done;
5826 624411d2 2023-07-08 jrick else
5827 624411d2 2023-07-08 jrick error = NULL;
5828 624411d2 2023-07-08 jrick if (worktree) {
5829 624411d2 2023-07-08 jrick repo_path =
5830 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
5831 624411d2 2023-07-08 jrick if (repo_path == NULL)
5832 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5833 624411d2 2023-07-08 jrick if (error)
5834 624411d2 2023-07-08 jrick goto done;
5835 624411d2 2023-07-08 jrick } else {
5836 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
5837 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5838 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5839 624411d2 2023-07-08 jrick goto done;
5840 624411d2 2023-07-08 jrick }
5841 624411d2 2023-07-08 jrick }
5842 624411d2 2023-07-08 jrick }
5843 624411d2 2023-07-08 jrick
5844 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
5845 624411d2 2023-07-08 jrick if (error != NULL)
5846 624411d2 2023-07-08 jrick goto done;
5847 624411d2 2023-07-08 jrick
5848 624411d2 2023-07-08 jrick if (worktree) {
5849 624411d2 2023-07-08 jrick const char *prefix = got_worktree_get_path_prefix(worktree);
5850 624411d2 2023-07-08 jrick char *p;
5851 624411d2 2023-07-08 jrick
5852 624411d2 2023-07-08 jrick if (path == NULL || got_path_is_root_dir(path))
5853 624411d2 2023-07-08 jrick path = "";
5854 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree, path);
5855 624411d2 2023-07-08 jrick if (error)
5856 624411d2 2023-07-08 jrick goto done;
5857 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5858 624411d2 2023-07-08 jrick (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5859 624411d2 2023-07-08 jrick p) == -1) {
5860 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5861 624411d2 2023-07-08 jrick free(p);
5862 624411d2 2023-07-08 jrick goto done;
5863 624411d2 2023-07-08 jrick }
5864 624411d2 2023-07-08 jrick free(p);
5865 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5866 624411d2 2023-07-08 jrick if (error)
5867 624411d2 2023-07-08 jrick goto done;
5868 624411d2 2023-07-08 jrick } else {
5869 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5870 624411d2 2023-07-08 jrick if (error)
5871 624411d2 2023-07-08 jrick goto done;
5872 624411d2 2023-07-08 jrick if (path == NULL)
5873 624411d2 2023-07-08 jrick path = "/";
5874 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo, path);
5875 624411d2 2023-07-08 jrick if (error != NULL)
5876 624411d2 2023-07-08 jrick goto done;
5877 624411d2 2023-07-08 jrick }
5878 624411d2 2023-07-08 jrick
5879 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
5880 624411d2 2023-07-08 jrick struct got_reference *head_ref;
5881 624411d2 2023-07-08 jrick if (worktree)
5882 624411d2 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
5883 624411d2 2023-07-08 jrick else
5884 624411d2 2023-07-08 jrick refname = GOT_REF_HEAD;
5885 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, refname, 0);
5886 624411d2 2023-07-08 jrick if (error != NULL)
5887 624411d2 2023-07-08 jrick goto done;
5888 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
5889 624411d2 2023-07-08 jrick got_ref_close(head_ref);
5890 624411d2 2023-07-08 jrick if (error != NULL)
5891 624411d2 2023-07-08 jrick goto done;
5892 624411d2 2023-07-08 jrick } else {
5893 624411d2 2023-07-08 jrick struct got_reflist_head refs;
5894 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
5895 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5896 624411d2 2023-07-08 jrick NULL);
5897 624411d2 2023-07-08 jrick if (error)
5898 624411d2 2023-07-08 jrick goto done;
5899 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
5900 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5901 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5902 624411d2 2023-07-08 jrick if (error)
5903 624411d2 2023-07-08 jrick goto done;
5904 624411d2 2023-07-08 jrick }
5905 624411d2 2023-07-08 jrick
5906 624411d2 2023-07-08 jrick if (worktree) {
5907 624411d2 2023-07-08 jrick /* Release work tree lock. */
5908 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5909 624411d2 2023-07-08 jrick worktree = NULL;
5910 624411d2 2023-07-08 jrick }
5911 624411d2 2023-07-08 jrick
5912 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
5913 624411d2 2023-07-08 jrick if (error)
5914 624411d2 2023-07-08 jrick goto done;
5915 624411d2 2023-07-08 jrick
5916 624411d2 2023-07-08 jrick error = print_tree(in_repo_path, commit, show_ids, recurse,
5917 624411d2 2023-07-08 jrick in_repo_path, repo);
5918 624411d2 2023-07-08 jrick done:
5919 624411d2 2023-07-08 jrick free(in_repo_path);
5920 624411d2 2023-07-08 jrick free(repo_path);
5921 624411d2 2023-07-08 jrick free(cwd);
5922 624411d2 2023-07-08 jrick free(commit_id);
5923 624411d2 2023-07-08 jrick if (commit)
5924 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5925 624411d2 2023-07-08 jrick if (worktree)
5926 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5927 624411d2 2023-07-08 jrick if (repo) {
5928 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5929 624411d2 2023-07-08 jrick if (error == NULL)
5930 624411d2 2023-07-08 jrick error = close_err;
5931 624411d2 2023-07-08 jrick }
5932 624411d2 2023-07-08 jrick if (pack_fds) {
5933 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5934 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5935 624411d2 2023-07-08 jrick if (error == NULL)
5936 624411d2 2023-07-08 jrick error = pack_err;
5937 624411d2 2023-07-08 jrick }
5938 624411d2 2023-07-08 jrick return error;
5939 624411d2 2023-07-08 jrick }
5940 624411d2 2023-07-08 jrick
5941 624411d2 2023-07-08 jrick __dead static void
5942 624411d2 2023-07-08 jrick usage_status(void)
5943 624411d2 2023-07-08 jrick {
5944 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s status [-I] [-S status-codes] "
5945 624411d2 2023-07-08 jrick "[-s status-codes] [path ...]\n", getprogname());
5946 624411d2 2023-07-08 jrick exit(1);
5947 624411d2 2023-07-08 jrick }
5948 624411d2 2023-07-08 jrick
5949 624411d2 2023-07-08 jrick struct got_status_arg {
5950 624411d2 2023-07-08 jrick char *status_codes;
5951 624411d2 2023-07-08 jrick int suppress;
5952 624411d2 2023-07-08 jrick };
5953 624411d2 2023-07-08 jrick
5954 624411d2 2023-07-08 jrick static const struct got_error *
5955 624411d2 2023-07-08 jrick print_status(void *arg, unsigned char status, unsigned char staged_status,
5956 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
5957 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5958 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
5959 624411d2 2023-07-08 jrick {
5960 624411d2 2023-07-08 jrick struct got_status_arg *st = arg;
5961 624411d2 2023-07-08 jrick
5962 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
5963 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
5964 624411d2 2023-07-08 jrick if (st != NULL && st->status_codes) {
5965 624411d2 2023-07-08 jrick size_t ncodes = strlen(st->status_codes);
5966 624411d2 2023-07-08 jrick int i, j = 0;
5967 624411d2 2023-07-08 jrick
5968 624411d2 2023-07-08 jrick for (i = 0; i < ncodes ; i++) {
5969 624411d2 2023-07-08 jrick if (st->suppress) {
5970 624411d2 2023-07-08 jrick if (status == st->status_codes[i] ||
5971 624411d2 2023-07-08 jrick staged_status == st->status_codes[i]) {
5972 624411d2 2023-07-08 jrick j++;
5973 624411d2 2023-07-08 jrick continue;
5974 624411d2 2023-07-08 jrick }
5975 624411d2 2023-07-08 jrick } else {
5976 624411d2 2023-07-08 jrick if (status == st->status_codes[i] ||
5977 624411d2 2023-07-08 jrick staged_status == st->status_codes[i])
5978 624411d2 2023-07-08 jrick break;
5979 624411d2 2023-07-08 jrick }
5980 624411d2 2023-07-08 jrick }
5981 624411d2 2023-07-08 jrick
5982 624411d2 2023-07-08 jrick if (st->suppress && j == 0)
5983 624411d2 2023-07-08 jrick goto print;
5984 624411d2 2023-07-08 jrick
5985 624411d2 2023-07-08 jrick if (i == ncodes)
5986 624411d2 2023-07-08 jrick return NULL;
5987 624411d2 2023-07-08 jrick }
5988 624411d2 2023-07-08 jrick print:
5989 624411d2 2023-07-08 jrick printf("%c%c %s\n", status, staged_status, path);
5990 624411d2 2023-07-08 jrick return NULL;
5991 624411d2 2023-07-08 jrick }
5992 624411d2 2023-07-08 jrick
5993 624411d2 2023-07-08 jrick static const struct got_error *
5994 624411d2 2023-07-08 jrick cmd_status(int argc, char *argv[])
5995 624411d2 2023-07-08 jrick {
5996 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
5997 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5998 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5999 624411d2 2023-07-08 jrick struct got_status_arg st;
6000 624411d2 2023-07-08 jrick char *cwd = NULL;
6001 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
6002 624411d2 2023-07-08 jrick int ch, i, no_ignores = 0;
6003 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6004 624411d2 2023-07-08 jrick
6005 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
6006 624411d2 2023-07-08 jrick
6007 624411d2 2023-07-08 jrick memset(&st, 0, sizeof(st));
6008 624411d2 2023-07-08 jrick st.status_codes = NULL;
6009 624411d2 2023-07-08 jrick st.suppress = 0;
6010 624411d2 2023-07-08 jrick
6011 624411d2 2023-07-08 jrick #ifndef PROFILE
6012 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6013 624411d2 2023-07-08 jrick NULL) == -1)
6014 624411d2 2023-07-08 jrick err(1, "pledge");
6015 624411d2 2023-07-08 jrick #endif
6016 624411d2 2023-07-08 jrick
6017 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "IS:s:")) != -1) {
6018 624411d2 2023-07-08 jrick switch (ch) {
6019 624411d2 2023-07-08 jrick case 'I':
6020 624411d2 2023-07-08 jrick no_ignores = 1;
6021 624411d2 2023-07-08 jrick break;
6022 624411d2 2023-07-08 jrick case 'S':
6023 624411d2 2023-07-08 jrick if (st.status_codes != NULL && st.suppress == 0)
6024 624411d2 2023-07-08 jrick option_conflict('S', 's');
6025 624411d2 2023-07-08 jrick st.suppress = 1;
6026 624411d2 2023-07-08 jrick /* fallthrough */
6027 624411d2 2023-07-08 jrick case 's':
6028 624411d2 2023-07-08 jrick for (i = 0; optarg[i] != '\0'; i++) {
6029 624411d2 2023-07-08 jrick switch (optarg[i]) {
6030 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
6031 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
6032 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
6033 624411d2 2023-07-08 jrick case GOT_STATUS_CONFLICT:
6034 624411d2 2023-07-08 jrick case GOT_STATUS_MISSING:
6035 624411d2 2023-07-08 jrick case GOT_STATUS_OBSTRUCTED:
6036 624411d2 2023-07-08 jrick case GOT_STATUS_UNVERSIONED:
6037 624411d2 2023-07-08 jrick case GOT_STATUS_MODE_CHANGE:
6038 624411d2 2023-07-08 jrick case GOT_STATUS_NONEXISTENT:
6039 624411d2 2023-07-08 jrick break;
6040 624411d2 2023-07-08 jrick default:
6041 624411d2 2023-07-08 jrick errx(1, "invalid status code '%c'",
6042 624411d2 2023-07-08 jrick optarg[i]);
6043 624411d2 2023-07-08 jrick }
6044 624411d2 2023-07-08 jrick }
6045 624411d2 2023-07-08 jrick if (ch == 's' && st.suppress)
6046 624411d2 2023-07-08 jrick option_conflict('s', 'S');
6047 624411d2 2023-07-08 jrick st.status_codes = optarg;
6048 624411d2 2023-07-08 jrick break;
6049 624411d2 2023-07-08 jrick default:
6050 624411d2 2023-07-08 jrick usage_status();
6051 624411d2 2023-07-08 jrick /* NOTREACHED */
6052 624411d2 2023-07-08 jrick }
6053 624411d2 2023-07-08 jrick }
6054 624411d2 2023-07-08 jrick
6055 624411d2 2023-07-08 jrick argc -= optind;
6056 624411d2 2023-07-08 jrick argv += optind;
6057 624411d2 2023-07-08 jrick
6058 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6059 624411d2 2023-07-08 jrick if (cwd == NULL) {
6060 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6061 624411d2 2023-07-08 jrick goto done;
6062 624411d2 2023-07-08 jrick }
6063 624411d2 2023-07-08 jrick
6064 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6065 624411d2 2023-07-08 jrick if (error != NULL)
6066 624411d2 2023-07-08 jrick goto done;
6067 624411d2 2023-07-08 jrick
6068 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6069 624411d2 2023-07-08 jrick if (error) {
6070 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
6071 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "status", cwd);
6072 624411d2 2023-07-08 jrick goto done;
6073 624411d2 2023-07-08 jrick }
6074 624411d2 2023-07-08 jrick
6075 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6076 624411d2 2023-07-08 jrick NULL, pack_fds);
6077 624411d2 2023-07-08 jrick if (error != NULL)
6078 624411d2 2023-07-08 jrick goto done;
6079 624411d2 2023-07-08 jrick
6080 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
6081 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
6082 624411d2 2023-07-08 jrick if (error)
6083 624411d2 2023-07-08 jrick goto done;
6084 624411d2 2023-07-08 jrick
6085 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6086 624411d2 2023-07-08 jrick if (error)
6087 624411d2 2023-07-08 jrick goto done;
6088 624411d2 2023-07-08 jrick
6089 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, no_ignores,
6090 624411d2 2023-07-08 jrick print_status, &st, check_cancelled, NULL);
6091 624411d2 2023-07-08 jrick done:
6092 624411d2 2023-07-08 jrick if (pack_fds) {
6093 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6094 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6095 624411d2 2023-07-08 jrick if (error == NULL)
6096 624411d2 2023-07-08 jrick error = pack_err;
6097 624411d2 2023-07-08 jrick }
6098 624411d2 2023-07-08 jrick if (repo) {
6099 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6100 624411d2 2023-07-08 jrick if (error == NULL)
6101 624411d2 2023-07-08 jrick error = close_err;
6102 624411d2 2023-07-08 jrick }
6103 624411d2 2023-07-08 jrick
6104 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
6105 624411d2 2023-07-08 jrick free(cwd);
6106 624411d2 2023-07-08 jrick return error;
6107 624411d2 2023-07-08 jrick }
6108 624411d2 2023-07-08 jrick
6109 624411d2 2023-07-08 jrick __dead static void
6110 624411d2 2023-07-08 jrick usage_ref(void)
6111 624411d2 2023-07-08 jrick {
6112 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s ref [-dlt] [-c object] [-r repository-path] "
6113 624411d2 2023-07-08 jrick "[-s reference] [name]\n", getprogname());
6114 624411d2 2023-07-08 jrick exit(1);
6115 624411d2 2023-07-08 jrick }
6116 624411d2 2023-07-08 jrick
6117 624411d2 2023-07-08 jrick static const struct got_error *
6118 624411d2 2023-07-08 jrick list_refs(struct got_repository *repo, const char *refname, int sort_by_time)
6119 624411d2 2023-07-08 jrick {
6120 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6121 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6122 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6123 624411d2 2023-07-08 jrick
6124 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6125 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, refname, sort_by_time ?
6126 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6127 624411d2 2023-07-08 jrick repo);
6128 624411d2 2023-07-08 jrick if (err)
6129 624411d2 2023-07-08 jrick return err;
6130 624411d2 2023-07-08 jrick
6131 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
6132 624411d2 2023-07-08 jrick char *refstr;
6133 624411d2 2023-07-08 jrick refstr = got_ref_to_str(re->ref);
6134 624411d2 2023-07-08 jrick if (refstr == NULL) {
6135 624411d2 2023-07-08 jrick err = got_error_from_errno("got_ref_to_str");
6136 624411d2 2023-07-08 jrick break;
6137 624411d2 2023-07-08 jrick }
6138 624411d2 2023-07-08 jrick printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
6139 624411d2 2023-07-08 jrick free(refstr);
6140 624411d2 2023-07-08 jrick }
6141 624411d2 2023-07-08 jrick
6142 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6143 624411d2 2023-07-08 jrick return err;
6144 624411d2 2023-07-08 jrick }
6145 624411d2 2023-07-08 jrick
6146 624411d2 2023-07-08 jrick static const struct got_error *
6147 624411d2 2023-07-08 jrick delete_ref_by_name(struct got_repository *repo, const char *refname)
6148 624411d2 2023-07-08 jrick {
6149 624411d2 2023-07-08 jrick const struct got_error *err;
6150 624411d2 2023-07-08 jrick struct got_reference *ref;
6151 624411d2 2023-07-08 jrick
6152 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6153 624411d2 2023-07-08 jrick if (err)
6154 624411d2 2023-07-08 jrick return err;
6155 624411d2 2023-07-08 jrick
6156 624411d2 2023-07-08 jrick err = delete_ref(repo, ref);
6157 624411d2 2023-07-08 jrick got_ref_close(ref);
6158 624411d2 2023-07-08 jrick return err;
6159 624411d2 2023-07-08 jrick }
6160 624411d2 2023-07-08 jrick
6161 624411d2 2023-07-08 jrick static const struct got_error *
6162 624411d2 2023-07-08 jrick add_ref(struct got_repository *repo, const char *refname, const char *target)
6163 624411d2 2023-07-08 jrick {
6164 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6165 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
6166 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6167 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6168 624411d2 2023-07-08 jrick
6169 624411d2 2023-07-08 jrick /*
6170 624411d2 2023-07-08 jrick * Don't let the user create a reference name with a leading '-'.
6171 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6172 624411d2 2023-07-08 jrick * an unintended typo.
6173 624411d2 2023-07-08 jrick */
6174 624411d2 2023-07-08 jrick if (refname[0] == '-')
6175 624411d2 2023-07-08 jrick return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
6176 624411d2 2023-07-08 jrick
6177 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6178 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
6179 624411d2 2023-07-08 jrick if (err)
6180 624411d2 2023-07-08 jrick goto done;
6181 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, target, GOT_OBJ_TYPE_ANY,
6182 624411d2 2023-07-08 jrick &refs, repo);
6183 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6184 624411d2 2023-07-08 jrick if (err)
6185 624411d2 2023-07-08 jrick goto done;
6186 624411d2 2023-07-08 jrick
6187 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, id);
6188 624411d2 2023-07-08 jrick if (err)
6189 624411d2 2023-07-08 jrick goto done;
6190 624411d2 2023-07-08 jrick
6191 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6192 624411d2 2023-07-08 jrick done:
6193 624411d2 2023-07-08 jrick if (ref)
6194 624411d2 2023-07-08 jrick got_ref_close(ref);
6195 624411d2 2023-07-08 jrick free(id);
6196 624411d2 2023-07-08 jrick return err;
6197 624411d2 2023-07-08 jrick }
6198 624411d2 2023-07-08 jrick
6199 624411d2 2023-07-08 jrick static const struct got_error *
6200 624411d2 2023-07-08 jrick add_symref(struct got_repository *repo, const char *refname, const char *target)
6201 624411d2 2023-07-08 jrick {
6202 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6203 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6204 624411d2 2023-07-08 jrick struct got_reference *target_ref = NULL;
6205 624411d2 2023-07-08 jrick
6206 624411d2 2023-07-08 jrick /*
6207 624411d2 2023-07-08 jrick * Don't let the user create a reference name with a leading '-'.
6208 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6209 624411d2 2023-07-08 jrick * an unintended typo.
6210 624411d2 2023-07-08 jrick */
6211 624411d2 2023-07-08 jrick if (refname[0] == '-')
6212 624411d2 2023-07-08 jrick return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
6213 624411d2 2023-07-08 jrick
6214 624411d2 2023-07-08 jrick err = got_ref_open(&target_ref, repo, target, 0);
6215 624411d2 2023-07-08 jrick if (err)
6216 624411d2 2023-07-08 jrick return err;
6217 624411d2 2023-07-08 jrick
6218 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&ref, refname, target_ref);
6219 624411d2 2023-07-08 jrick if (err)
6220 624411d2 2023-07-08 jrick goto done;
6221 624411d2 2023-07-08 jrick
6222 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6223 624411d2 2023-07-08 jrick done:
6224 624411d2 2023-07-08 jrick if (target_ref)
6225 624411d2 2023-07-08 jrick got_ref_close(target_ref);
6226 624411d2 2023-07-08 jrick if (ref)
6227 624411d2 2023-07-08 jrick got_ref_close(ref);
6228 624411d2 2023-07-08 jrick return err;
6229 624411d2 2023-07-08 jrick }
6230 624411d2 2023-07-08 jrick
6231 624411d2 2023-07-08 jrick static const struct got_error *
6232 624411d2 2023-07-08 jrick cmd_ref(int argc, char *argv[])
6233 624411d2 2023-07-08 jrick {
6234 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
6235 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
6236 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
6237 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
6238 624411d2 2023-07-08 jrick int ch, do_list = 0, do_delete = 0, sort_by_time = 0;
6239 624411d2 2023-07-08 jrick const char *obj_arg = NULL, *symref_target= NULL;
6240 624411d2 2023-07-08 jrick char *refname = NULL;
6241 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6242 624411d2 2023-07-08 jrick
6243 624411d2 2023-07-08 jrick #ifndef PROFILE
6244 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6245 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
6246 624411d2 2023-07-08 jrick err(1, "pledge");
6247 624411d2 2023-07-08 jrick #endif
6248 624411d2 2023-07-08 jrick
6249 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:dlr:s:t")) != -1) {
6250 624411d2 2023-07-08 jrick switch (ch) {
6251 624411d2 2023-07-08 jrick case 'c':
6252 624411d2 2023-07-08 jrick obj_arg = optarg;
6253 624411d2 2023-07-08 jrick break;
6254 624411d2 2023-07-08 jrick case 'd':
6255 624411d2 2023-07-08 jrick do_delete = 1;
6256 624411d2 2023-07-08 jrick break;
6257 624411d2 2023-07-08 jrick case 'l':
6258 624411d2 2023-07-08 jrick do_list = 1;
6259 624411d2 2023-07-08 jrick break;
6260 624411d2 2023-07-08 jrick case 'r':
6261 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
6262 624411d2 2023-07-08 jrick if (repo_path == NULL)
6263 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
6264 624411d2 2023-07-08 jrick optarg);
6265 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
6266 624411d2 2023-07-08 jrick break;
6267 624411d2 2023-07-08 jrick case 's':
6268 624411d2 2023-07-08 jrick symref_target = optarg;
6269 624411d2 2023-07-08 jrick break;
6270 624411d2 2023-07-08 jrick case 't':
6271 624411d2 2023-07-08 jrick sort_by_time = 1;
6272 624411d2 2023-07-08 jrick break;
6273 624411d2 2023-07-08 jrick default:
6274 624411d2 2023-07-08 jrick usage_ref();
6275 624411d2 2023-07-08 jrick /* NOTREACHED */
6276 624411d2 2023-07-08 jrick }
6277 624411d2 2023-07-08 jrick }
6278 624411d2 2023-07-08 jrick
6279 624411d2 2023-07-08 jrick if (obj_arg && do_list)
6280 624411d2 2023-07-08 jrick option_conflict('c', 'l');
6281 624411d2 2023-07-08 jrick if (obj_arg && do_delete)
6282 624411d2 2023-07-08 jrick option_conflict('c', 'd');
6283 624411d2 2023-07-08 jrick if (obj_arg && symref_target)
6284 624411d2 2023-07-08 jrick option_conflict('c', 's');
6285 624411d2 2023-07-08 jrick if (symref_target && do_delete)
6286 624411d2 2023-07-08 jrick option_conflict('s', 'd');
6287 624411d2 2023-07-08 jrick if (symref_target && do_list)
6288 624411d2 2023-07-08 jrick option_conflict('s', 'l');
6289 624411d2 2023-07-08 jrick if (do_delete && do_list)
6290 624411d2 2023-07-08 jrick option_conflict('d', 'l');
6291 624411d2 2023-07-08 jrick if (sort_by_time && !do_list)
6292 624411d2 2023-07-08 jrick errx(1, "-t option requires -l option");
6293 624411d2 2023-07-08 jrick
6294 624411d2 2023-07-08 jrick argc -= optind;
6295 624411d2 2023-07-08 jrick argv += optind;
6296 624411d2 2023-07-08 jrick
6297 624411d2 2023-07-08 jrick if (do_list) {
6298 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
6299 624411d2 2023-07-08 jrick usage_ref();
6300 624411d2 2023-07-08 jrick if (argc == 1) {
6301 624411d2 2023-07-08 jrick refname = strdup(argv[0]);
6302 624411d2 2023-07-08 jrick if (refname == NULL) {
6303 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6304 624411d2 2023-07-08 jrick goto done;
6305 624411d2 2023-07-08 jrick }
6306 624411d2 2023-07-08 jrick }
6307 624411d2 2023-07-08 jrick } else {
6308 624411d2 2023-07-08 jrick if (argc != 1)
6309 624411d2 2023-07-08 jrick usage_ref();
6310 624411d2 2023-07-08 jrick refname = strdup(argv[0]);
6311 624411d2 2023-07-08 jrick if (refname == NULL) {
6312 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6313 624411d2 2023-07-08 jrick goto done;
6314 624411d2 2023-07-08 jrick }
6315 624411d2 2023-07-08 jrick }
6316 624411d2 2023-07-08 jrick
6317 624411d2 2023-07-08 jrick if (refname)
6318 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(refname);
6319 624411d2 2023-07-08 jrick
6320 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6321 624411d2 2023-07-08 jrick if (cwd == NULL) {
6322 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6323 624411d2 2023-07-08 jrick goto done;
6324 624411d2 2023-07-08 jrick }
6325 624411d2 2023-07-08 jrick
6326 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6327 624411d2 2023-07-08 jrick if (error != NULL)
6328 624411d2 2023-07-08 jrick goto done;
6329 624411d2 2023-07-08 jrick
6330 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6331 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6332 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
6333 624411d2 2023-07-08 jrick goto done;
6334 624411d2 2023-07-08 jrick else
6335 624411d2 2023-07-08 jrick error = NULL;
6336 624411d2 2023-07-08 jrick if (worktree) {
6337 624411d2 2023-07-08 jrick repo_path =
6338 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
6339 624411d2 2023-07-08 jrick if (repo_path == NULL)
6340 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6341 624411d2 2023-07-08 jrick if (error)
6342 624411d2 2023-07-08 jrick goto done;
6343 624411d2 2023-07-08 jrick } else {
6344 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
6345 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6346 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6347 624411d2 2023-07-08 jrick goto done;
6348 624411d2 2023-07-08 jrick }
6349 624411d2 2023-07-08 jrick }
6350 624411d2 2023-07-08 jrick }
6351 624411d2 2023-07-08 jrick
6352 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
6353 624411d2 2023-07-08 jrick if (error != NULL)
6354 624411d2 2023-07-08 jrick goto done;
6355 624411d2 2023-07-08 jrick
6356 624411d2 2023-07-08 jrick #ifndef PROFILE
6357 624411d2 2023-07-08 jrick if (do_list) {
6358 624411d2 2023-07-08 jrick /* Remove "cpath" promise. */
6359 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6360 624411d2 2023-07-08 jrick NULL) == -1)
6361 624411d2 2023-07-08 jrick err(1, "pledge");
6362 624411d2 2023-07-08 jrick }
6363 624411d2 2023-07-08 jrick #endif
6364 624411d2 2023-07-08 jrick
6365 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), do_list,
6366 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
6367 624411d2 2023-07-08 jrick if (error)
6368 624411d2 2023-07-08 jrick goto done;
6369 624411d2 2023-07-08 jrick
6370 624411d2 2023-07-08 jrick if (do_list)
6371 624411d2 2023-07-08 jrick error = list_refs(repo, refname, sort_by_time);
6372 624411d2 2023-07-08 jrick else if (do_delete)
6373 624411d2 2023-07-08 jrick error = delete_ref_by_name(repo, refname);
6374 624411d2 2023-07-08 jrick else if (symref_target)
6375 624411d2 2023-07-08 jrick error = add_symref(repo, refname, symref_target);
6376 624411d2 2023-07-08 jrick else {
6377 624411d2 2023-07-08 jrick if (obj_arg == NULL)
6378 624411d2 2023-07-08 jrick usage_ref();
6379 624411d2 2023-07-08 jrick error = add_ref(repo, refname, obj_arg);
6380 624411d2 2023-07-08 jrick }
6381 624411d2 2023-07-08 jrick done:
6382 624411d2 2023-07-08 jrick free(refname);
6383 624411d2 2023-07-08 jrick if (repo) {
6384 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6385 624411d2 2023-07-08 jrick if (error == NULL)
6386 624411d2 2023-07-08 jrick error = close_err;
6387 624411d2 2023-07-08 jrick }
6388 624411d2 2023-07-08 jrick if (worktree)
6389 624411d2 2023-07-08 jrick got_worktree_close(worktree);
6390 624411d2 2023-07-08 jrick if (pack_fds) {
6391 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6392 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6393 624411d2 2023-07-08 jrick if (error == NULL)
6394 624411d2 2023-07-08 jrick error = pack_err;
6395 624411d2 2023-07-08 jrick }
6396 624411d2 2023-07-08 jrick free(cwd);
6397 624411d2 2023-07-08 jrick free(repo_path);
6398 624411d2 2023-07-08 jrick return error;
6399 624411d2 2023-07-08 jrick }
6400 624411d2 2023-07-08 jrick
6401 624411d2 2023-07-08 jrick __dead static void
6402 624411d2 2023-07-08 jrick usage_branch(void)
6403 624411d2 2023-07-08 jrick {
6404 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s branch [-lnt] [-c commit] [-d name] "
6405 624411d2 2023-07-08 jrick "[-r repository-path] [name]\n", getprogname());
6406 624411d2 2023-07-08 jrick exit(1);
6407 624411d2 2023-07-08 jrick }
6408 624411d2 2023-07-08 jrick
6409 624411d2 2023-07-08 jrick static const struct got_error *
6410 624411d2 2023-07-08 jrick list_branch(struct got_repository *repo, struct got_worktree *worktree,
6411 624411d2 2023-07-08 jrick struct got_reference *ref)
6412 624411d2 2023-07-08 jrick {
6413 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6414 624411d2 2023-07-08 jrick const char *refname, *marker = " ";
6415 624411d2 2023-07-08 jrick char *refstr;
6416 624411d2 2023-07-08 jrick
6417 624411d2 2023-07-08 jrick refname = got_ref_get_name(ref);
6418 624411d2 2023-07-08 jrick if (worktree && strcmp(refname,
6419 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree)) == 0) {
6420 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
6421 624411d2 2023-07-08 jrick
6422 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
6423 624411d2 2023-07-08 jrick if (err)
6424 624411d2 2023-07-08 jrick return err;
6425 624411d2 2023-07-08 jrick if (got_object_id_cmp(id,
6426 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree)) == 0)
6427 624411d2 2023-07-08 jrick marker = "* ";
6428 624411d2 2023-07-08 jrick else
6429 624411d2 2023-07-08 jrick marker = "~ ";
6430 624411d2 2023-07-08 jrick free(id);
6431 624411d2 2023-07-08 jrick }
6432 624411d2 2023-07-08 jrick
6433 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
6434 624411d2 2023-07-08 jrick refname += 11;
6435 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/got/worktree/", 18) == 0)
6436 624411d2 2023-07-08 jrick refname += 18;
6437 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/remotes/", 13) == 0)
6438 624411d2 2023-07-08 jrick refname += 13;
6439 624411d2 2023-07-08 jrick
6440 624411d2 2023-07-08 jrick refstr = got_ref_to_str(ref);
6441 624411d2 2023-07-08 jrick if (refstr == NULL)
6442 624411d2 2023-07-08 jrick return got_error_from_errno("got_ref_to_str");
6443 624411d2 2023-07-08 jrick
6444 624411d2 2023-07-08 jrick printf("%s%s: %s\n", marker, refname, refstr);
6445 624411d2 2023-07-08 jrick free(refstr);
6446 624411d2 2023-07-08 jrick return NULL;
6447 624411d2 2023-07-08 jrick }
6448 624411d2 2023-07-08 jrick
6449 624411d2 2023-07-08 jrick static const struct got_error *
6450 624411d2 2023-07-08 jrick show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
6451 624411d2 2023-07-08 jrick {
6452 624411d2 2023-07-08 jrick const char *refname;
6453 624411d2 2023-07-08 jrick
6454 624411d2 2023-07-08 jrick if (worktree == NULL)
6455 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NOT_WORKTREE);
6456 624411d2 2023-07-08 jrick
6457 624411d2 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
6458 624411d2 2023-07-08 jrick
6459 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
6460 624411d2 2023-07-08 jrick refname += 11;
6461 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/got/worktree/", 18) == 0)
6462 624411d2 2023-07-08 jrick refname += 18;
6463 624411d2 2023-07-08 jrick
6464 624411d2 2023-07-08 jrick printf("%s\n", refname);
6465 624411d2 2023-07-08 jrick
6466 624411d2 2023-07-08 jrick return NULL;
6467 624411d2 2023-07-08 jrick }
6468 624411d2 2023-07-08 jrick
6469 624411d2 2023-07-08 jrick static const struct got_error *
6470 624411d2 2023-07-08 jrick list_branches(struct got_repository *repo, struct got_worktree *worktree,
6471 624411d2 2023-07-08 jrick int sort_by_time)
6472 624411d2 2023-07-08 jrick {
6473 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6474 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6475 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6476 624411d2 2023-07-08 jrick struct got_reference *temp_ref = NULL;
6477 624411d2 2023-07-08 jrick int rebase_in_progress, histedit_in_progress;
6478 624411d2 2023-07-08 jrick
6479 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6480 624411d2 2023-07-08 jrick
6481 624411d2 2023-07-08 jrick if (worktree) {
6482 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&rebase_in_progress,
6483 624411d2 2023-07-08 jrick worktree);
6484 624411d2 2023-07-08 jrick if (err)
6485 624411d2 2023-07-08 jrick return err;
6486 624411d2 2023-07-08 jrick
6487 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&histedit_in_progress,
6488 624411d2 2023-07-08 jrick worktree);
6489 624411d2 2023-07-08 jrick if (err)
6490 624411d2 2023-07-08 jrick return err;
6491 624411d2 2023-07-08 jrick
6492 624411d2 2023-07-08 jrick if (rebase_in_progress || histedit_in_progress) {
6493 624411d2 2023-07-08 jrick err = got_ref_open(&temp_ref, repo,
6494 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
6495 624411d2 2023-07-08 jrick if (err)
6496 624411d2 2023-07-08 jrick return err;
6497 624411d2 2023-07-08 jrick list_branch(repo, worktree, temp_ref);
6498 624411d2 2023-07-08 jrick got_ref_close(temp_ref);
6499 624411d2 2023-07-08 jrick }
6500 624411d2 2023-07-08 jrick }
6501 624411d2 2023-07-08 jrick
6502 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/heads", sort_by_time ?
6503 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6504 624411d2 2023-07-08 jrick repo);
6505 624411d2 2023-07-08 jrick if (err)
6506 624411d2 2023-07-08 jrick return err;
6507 624411d2 2023-07-08 jrick
6508 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
6509 624411d2 2023-07-08 jrick list_branch(repo, worktree, re->ref);
6510 624411d2 2023-07-08 jrick
6511 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6512 624411d2 2023-07-08 jrick
6513 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/remotes", sort_by_time ?
6514 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6515 624411d2 2023-07-08 jrick repo);
6516 624411d2 2023-07-08 jrick if (err)
6517 624411d2 2023-07-08 jrick return err;
6518 624411d2 2023-07-08 jrick
6519 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
6520 624411d2 2023-07-08 jrick list_branch(repo, worktree, re->ref);
6521 624411d2 2023-07-08 jrick
6522 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6523 624411d2 2023-07-08 jrick
6524 624411d2 2023-07-08 jrick return NULL;
6525 624411d2 2023-07-08 jrick }
6526 624411d2 2023-07-08 jrick
6527 624411d2 2023-07-08 jrick static const struct got_error *
6528 624411d2 2023-07-08 jrick delete_branch(struct got_repository *repo, struct got_worktree *worktree,
6529 624411d2 2023-07-08 jrick const char *branch_name)
6530 624411d2 2023-07-08 jrick {
6531 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6532 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6533 624411d2 2023-07-08 jrick char *refname, *remote_refname = NULL;
6534 624411d2 2023-07-08 jrick
6535 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/", 5) == 0)
6536 624411d2 2023-07-08 jrick branch_name += 5;
6537 624411d2 2023-07-08 jrick if (strncmp(branch_name, "heads/", 6) == 0)
6538 624411d2 2023-07-08 jrick branch_name += 6;
6539 624411d2 2023-07-08 jrick else if (strncmp(branch_name, "remotes/", 8) == 0)
6540 624411d2 2023-07-08 jrick branch_name += 8;
6541 624411d2 2023-07-08 jrick
6542 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
6543 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
6544 624411d2 2023-07-08 jrick
6545 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s",
6546 624411d2 2023-07-08 jrick branch_name) == -1) {
6547 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6548 624411d2 2023-07-08 jrick goto done;
6549 624411d2 2023-07-08 jrick }
6550 624411d2 2023-07-08 jrick
6551 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6552 624411d2 2023-07-08 jrick if (err) {
6553 624411d2 2023-07-08 jrick const struct got_error *err2;
6554 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
6555 624411d2 2023-07-08 jrick goto done;
6556 624411d2 2023-07-08 jrick /*
6557 624411d2 2023-07-08 jrick * Keep 'err' intact such that if neither branch exists
6558 624411d2 2023-07-08 jrick * we report "refs/heads" rather than "refs/remotes" in
6559 624411d2 2023-07-08 jrick * our error message.
6560 624411d2 2023-07-08 jrick */
6561 624411d2 2023-07-08 jrick err2 = got_ref_open(&ref, repo, remote_refname, 0);
6562 624411d2 2023-07-08 jrick if (err2)
6563 624411d2 2023-07-08 jrick goto done;
6564 624411d2 2023-07-08 jrick err = NULL;
6565 624411d2 2023-07-08 jrick }
6566 624411d2 2023-07-08 jrick
6567 624411d2 2023-07-08 jrick if (worktree &&
6568 624411d2 2023-07-08 jrick strcmp(got_worktree_get_head_ref_name(worktree),
6569 624411d2 2023-07-08 jrick got_ref_get_name(ref)) == 0) {
6570 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_SAME_BRANCH,
6571 624411d2 2023-07-08 jrick "will not delete this work tree's current branch");
6572 624411d2 2023-07-08 jrick goto done;
6573 624411d2 2023-07-08 jrick }
6574 624411d2 2023-07-08 jrick
6575 624411d2 2023-07-08 jrick err = delete_ref(repo, ref);
6576 624411d2 2023-07-08 jrick done:
6577 624411d2 2023-07-08 jrick if (ref)
6578 624411d2 2023-07-08 jrick got_ref_close(ref);
6579 624411d2 2023-07-08 jrick free(refname);
6580 624411d2 2023-07-08 jrick free(remote_refname);
6581 624411d2 2023-07-08 jrick return err;
6582 624411d2 2023-07-08 jrick }
6583 624411d2 2023-07-08 jrick
6584 624411d2 2023-07-08 jrick static const struct got_error *
6585 624411d2 2023-07-08 jrick add_branch(struct got_repository *repo, const char *branch_name,
6586 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id)
6587 624411d2 2023-07-08 jrick {
6588 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6589 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6590 624411d2 2023-07-08 jrick char *refname = NULL;
6591 624411d2 2023-07-08 jrick
6592 624411d2 2023-07-08 jrick /*
6593 624411d2 2023-07-08 jrick * Don't let the user create a branch name with a leading '-'.
6594 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6595 624411d2 2023-07-08 jrick * an unintended typo.
6596 624411d2 2023-07-08 jrick */
6597 624411d2 2023-07-08 jrick if (branch_name[0] == '-')
6598 624411d2 2023-07-08 jrick return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
6599 624411d2 2023-07-08 jrick
6600 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/heads/", 11) == 0)
6601 624411d2 2023-07-08 jrick branch_name += 11;
6602 624411d2 2023-07-08 jrick
6603 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
6604 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6605 624411d2 2023-07-08 jrick goto done;
6606 624411d2 2023-07-08 jrick }
6607 624411d2 2023-07-08 jrick
6608 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6609 624411d2 2023-07-08 jrick if (err == NULL) {
6610 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_BRANCH_EXISTS);
6611 624411d2 2023-07-08 jrick goto done;
6612 624411d2 2023-07-08 jrick } else if (err->code != GOT_ERR_NOT_REF)
6613 624411d2 2023-07-08 jrick goto done;
6614 624411d2 2023-07-08 jrick
6615 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, base_commit_id);
6616 624411d2 2023-07-08 jrick if (err)
6617 624411d2 2023-07-08 jrick goto done;
6618 624411d2 2023-07-08 jrick
6619 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6620 624411d2 2023-07-08 jrick done:
6621 624411d2 2023-07-08 jrick if (ref)
6622 624411d2 2023-07-08 jrick got_ref_close(ref);
6623 624411d2 2023-07-08 jrick free(refname);
6624 624411d2 2023-07-08 jrick return err;
6625 624411d2 2023-07-08 jrick }
6626 624411d2 2023-07-08 jrick
6627 624411d2 2023-07-08 jrick static const struct got_error *
6628 624411d2 2023-07-08 jrick cmd_branch(int argc, char *argv[])
6629 624411d2 2023-07-08 jrick {
6630 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
6631 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
6632 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
6633 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
6634 624411d2 2023-07-08 jrick int ch, do_list = 0, do_show = 0, do_update = 1, sort_by_time = 0;
6635 624411d2 2023-07-08 jrick const char *delref = NULL, *commit_id_arg = NULL;
6636 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6637 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
6638 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
6639 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
6640 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6641 624411d2 2023-07-08 jrick
6642 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
6643 624411d2 2023-07-08 jrick
6644 624411d2 2023-07-08 jrick #ifndef PROFILE
6645 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6646 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
6647 624411d2 2023-07-08 jrick err(1, "pledge");
6648 624411d2 2023-07-08 jrick #endif
6649 624411d2 2023-07-08 jrick
6650 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:d:lnr:t")) != -1) {
6651 624411d2 2023-07-08 jrick switch (ch) {
6652 624411d2 2023-07-08 jrick case 'c':
6653 624411d2 2023-07-08 jrick commit_id_arg = optarg;
6654 624411d2 2023-07-08 jrick break;
6655 624411d2 2023-07-08 jrick case 'd':
6656 624411d2 2023-07-08 jrick delref = optarg;
6657 624411d2 2023-07-08 jrick break;
6658 624411d2 2023-07-08 jrick case 'l':
6659 624411d2 2023-07-08 jrick do_list = 1;
6660 624411d2 2023-07-08 jrick break;
6661 624411d2 2023-07-08 jrick case 'n':
6662 624411d2 2023-07-08 jrick do_update = 0;
6663 624411d2 2023-07-08 jrick break;
6664 624411d2 2023-07-08 jrick case 'r':
6665 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
6666 624411d2 2023-07-08 jrick if (repo_path == NULL)
6667 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
6668 624411d2 2023-07-08 jrick optarg);
6669 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
6670 624411d2 2023-07-08 jrick break;
6671 624411d2 2023-07-08 jrick case 't':
6672 624411d2 2023-07-08 jrick sort_by_time = 1;
6673 624411d2 2023-07-08 jrick break;
6674 624411d2 2023-07-08 jrick default:
6675 624411d2 2023-07-08 jrick usage_branch();
6676 624411d2 2023-07-08 jrick /* NOTREACHED */
6677 624411d2 2023-07-08 jrick }
6678 624411d2 2023-07-08 jrick }
6679 624411d2 2023-07-08 jrick
6680 624411d2 2023-07-08 jrick if (do_list && delref)
6681 624411d2 2023-07-08 jrick option_conflict('l', 'd');
6682 624411d2 2023-07-08 jrick if (sort_by_time && !do_list)
6683 624411d2 2023-07-08 jrick errx(1, "-t option requires -l option");
6684 624411d2 2023-07-08 jrick
6685 624411d2 2023-07-08 jrick argc -= optind;
6686 624411d2 2023-07-08 jrick argv += optind;
6687 624411d2 2023-07-08 jrick
6688 624411d2 2023-07-08 jrick if (!do_list && !delref && argc == 0)
6689 624411d2 2023-07-08 jrick do_show = 1;
6690 624411d2 2023-07-08 jrick
6691 624411d2 2023-07-08 jrick if ((do_list || delref || do_show) && commit_id_arg != NULL)
6692 624411d2 2023-07-08 jrick errx(1, "-c option can only be used when creating a branch");
6693 624411d2 2023-07-08 jrick
6694 624411d2 2023-07-08 jrick if (do_list || delref) {
6695 624411d2 2023-07-08 jrick if (argc > 0)
6696 624411d2 2023-07-08 jrick usage_branch();
6697 624411d2 2023-07-08 jrick } else if (!do_show && argc != 1)
6698 624411d2 2023-07-08 jrick usage_branch();
6699 624411d2 2023-07-08 jrick
6700 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6701 624411d2 2023-07-08 jrick if (cwd == NULL) {
6702 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6703 624411d2 2023-07-08 jrick goto done;
6704 624411d2 2023-07-08 jrick }
6705 624411d2 2023-07-08 jrick
6706 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6707 624411d2 2023-07-08 jrick if (error != NULL)
6708 624411d2 2023-07-08 jrick goto done;
6709 624411d2 2023-07-08 jrick
6710 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6711 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6712 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
6713 624411d2 2023-07-08 jrick goto done;
6714 624411d2 2023-07-08 jrick else
6715 624411d2 2023-07-08 jrick error = NULL;
6716 624411d2 2023-07-08 jrick if (worktree) {
6717 624411d2 2023-07-08 jrick repo_path =
6718 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
6719 624411d2 2023-07-08 jrick if (repo_path == NULL)
6720 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6721 624411d2 2023-07-08 jrick if (error)
6722 624411d2 2023-07-08 jrick goto done;
6723 624411d2 2023-07-08 jrick } else {
6724 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
6725 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6726 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6727 624411d2 2023-07-08 jrick goto done;
6728 624411d2 2023-07-08 jrick }
6729 624411d2 2023-07-08 jrick }
6730 624411d2 2023-07-08 jrick }
6731 624411d2 2023-07-08 jrick
6732 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
6733 624411d2 2023-07-08 jrick if (error != NULL)
6734 624411d2 2023-07-08 jrick goto done;
6735 624411d2 2023-07-08 jrick
6736 624411d2 2023-07-08 jrick #ifndef PROFILE
6737 624411d2 2023-07-08 jrick if (do_list || do_show) {
6738 624411d2 2023-07-08 jrick /* Remove "cpath" promise. */
6739 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6740 624411d2 2023-07-08 jrick NULL) == -1)
6741 624411d2 2023-07-08 jrick err(1, "pledge");
6742 624411d2 2023-07-08 jrick }
6743 624411d2 2023-07-08 jrick #endif
6744 624411d2 2023-07-08 jrick
6745 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), do_list,
6746 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
6747 624411d2 2023-07-08 jrick if (error)
6748 624411d2 2023-07-08 jrick goto done;
6749 624411d2 2023-07-08 jrick
6750 624411d2 2023-07-08 jrick if (do_show)
6751 624411d2 2023-07-08 jrick error = show_current_branch(repo, worktree);
6752 624411d2 2023-07-08 jrick else if (do_list)
6753 624411d2 2023-07-08 jrick error = list_branches(repo, worktree, sort_by_time);
6754 624411d2 2023-07-08 jrick else if (delref)
6755 624411d2 2023-07-08 jrick error = delete_branch(repo, worktree, delref);
6756 624411d2 2023-07-08 jrick else {
6757 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6758 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6759 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
6760 624411d2 2023-07-08 jrick NULL);
6761 624411d2 2023-07-08 jrick if (error)
6762 624411d2 2023-07-08 jrick goto done;
6763 624411d2 2023-07-08 jrick if (commit_id_arg == NULL)
6764 624411d2 2023-07-08 jrick commit_id_arg = worktree ?
6765 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree) :
6766 624411d2 2023-07-08 jrick GOT_REF_HEAD;
6767 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
6768 624411d2 2023-07-08 jrick commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo);
6769 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6770 624411d2 2023-07-08 jrick if (error)
6771 624411d2 2023-07-08 jrick goto done;
6772 624411d2 2023-07-08 jrick error = add_branch(repo, argv[0], commit_id);
6773 624411d2 2023-07-08 jrick if (error)
6774 624411d2 2023-07-08 jrick goto done;
6775 624411d2 2023-07-08 jrick if (worktree && do_update) {
6776 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
6777 624411d2 2023-07-08 jrick char *branch_refname = NULL;
6778 624411d2 2023-07-08 jrick
6779 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
6780 624411d2 2023-07-08 jrick if (error)
6781 624411d2 2023-07-08 jrick goto done;
6782 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, 0, NULL,
6783 624411d2 2023-07-08 jrick worktree);
6784 624411d2 2023-07-08 jrick if (error)
6785 624411d2 2023-07-08 jrick goto done;
6786 624411d2 2023-07-08 jrick if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
6787 624411d2 2023-07-08 jrick == -1) {
6788 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
6789 624411d2 2023-07-08 jrick goto done;
6790 624411d2 2023-07-08 jrick }
6791 624411d2 2023-07-08 jrick error = got_ref_open(&ref, repo, branch_refname, 0);
6792 624411d2 2023-07-08 jrick free(branch_refname);
6793 624411d2 2023-07-08 jrick if (error)
6794 624411d2 2023-07-08 jrick goto done;
6795 624411d2 2023-07-08 jrick error = switch_head_ref(ref, commit_id, worktree,
6796 624411d2 2023-07-08 jrick repo);
6797 624411d2 2023-07-08 jrick if (error)
6798 624411d2 2023-07-08 jrick goto done;
6799 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
6800 624411d2 2023-07-08 jrick commit_id);
6801 624411d2 2023-07-08 jrick if (error)
6802 624411d2 2023-07-08 jrick goto done;
6803 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
6804 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths,
6805 624411d2 2023-07-08 jrick repo, update_progress, &upa, check_cancelled,
6806 624411d2 2023-07-08 jrick NULL);
6807 624411d2 2023-07-08 jrick if (error)
6808 624411d2 2023-07-08 jrick goto done;
6809 624411d2 2023-07-08 jrick if (upa.did_something) {
6810 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
6811 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
6812 624411d2 2023-07-08 jrick commit_id_str);
6813 624411d2 2023-07-08 jrick }
6814 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
6815 624411d2 2023-07-08 jrick }
6816 624411d2 2023-07-08 jrick }
6817 624411d2 2023-07-08 jrick done:
6818 624411d2 2023-07-08 jrick if (ref)
6819 624411d2 2023-07-08 jrick got_ref_close(ref);
6820 624411d2 2023-07-08 jrick if (repo) {
6821 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6822 624411d2 2023-07-08 jrick if (error == NULL)
6823 624411d2 2023-07-08 jrick error = close_err;
6824 624411d2 2023-07-08 jrick }
6825 624411d2 2023-07-08 jrick if (worktree)
6826 624411d2 2023-07-08 jrick got_worktree_close(worktree);
6827 624411d2 2023-07-08 jrick if (pack_fds) {
6828 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6829 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6830 624411d2 2023-07-08 jrick if (error == NULL)
6831 624411d2 2023-07-08 jrick error = pack_err;
6832 624411d2 2023-07-08 jrick }
6833 624411d2 2023-07-08 jrick free(cwd);
6834 624411d2 2023-07-08 jrick free(repo_path);
6835 624411d2 2023-07-08 jrick free(commit_id);
6836 624411d2 2023-07-08 jrick free(commit_id_str);
6837 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
6838 624411d2 2023-07-08 jrick return error;
6839 624411d2 2023-07-08 jrick }
6840 624411d2 2023-07-08 jrick
6841 624411d2 2023-07-08 jrick
6842 624411d2 2023-07-08 jrick __dead static void
6843 624411d2 2023-07-08 jrick usage_tag(void)
6844 624411d2 2023-07-08 jrick {
6845 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] "
6846 624411d2 2023-07-08 jrick "[-r repository-path] [-s signer-id] name\n", getprogname());
6847 624411d2 2023-07-08 jrick exit(1);
6848 624411d2 2023-07-08 jrick }
6849 624411d2 2023-07-08 jrick
6850 624411d2 2023-07-08 jrick #if 0
6851 624411d2 2023-07-08 jrick static const struct got_error *
6852 624411d2 2023-07-08 jrick sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
6853 624411d2 2023-07-08 jrick {
6854 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6855 624411d2 2023-07-08 jrick struct got_reflist_entry *re, *se, *new;
6856 624411d2 2023-07-08 jrick struct got_object_id *re_id, *se_id;
6857 624411d2 2023-07-08 jrick struct got_tag_object *re_tag, *se_tag;
6858 624411d2 2023-07-08 jrick time_t re_time, se_time;
6859 624411d2 2023-07-08 jrick
6860 624411d2 2023-07-08 jrick STAILQ_FOREACH(re, tags, entry) {
6861 624411d2 2023-07-08 jrick se = STAILQ_FIRST(sorted);
6862 624411d2 2023-07-08 jrick if (se == NULL) {
6863 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&new, re);
6864 624411d2 2023-07-08 jrick if (err)
6865 624411d2 2023-07-08 jrick return err;
6866 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(sorted, new, entry);
6867 624411d2 2023-07-08 jrick continue;
6868 624411d2 2023-07-08 jrick } else {
6869 624411d2 2023-07-08 jrick err = got_ref_resolve(&re_id, repo, re->ref);
6870 624411d2 2023-07-08 jrick if (err)
6871 624411d2 2023-07-08 jrick break;
6872 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&re_tag, repo, re_id);
6873 624411d2 2023-07-08 jrick free(re_id);
6874 624411d2 2023-07-08 jrick if (err)
6875 624411d2 2023-07-08 jrick break;
6876 624411d2 2023-07-08 jrick re_time = got_object_tag_get_tagger_time(re_tag);
6877 624411d2 2023-07-08 jrick got_object_tag_close(re_tag);
6878 624411d2 2023-07-08 jrick }
6879 624411d2 2023-07-08 jrick
6880 624411d2 2023-07-08 jrick while (se) {
6881 624411d2 2023-07-08 jrick err = got_ref_resolve(&se_id, repo, re->ref);
6882 624411d2 2023-07-08 jrick if (err)
6883 624411d2 2023-07-08 jrick break;
6884 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&se_tag, repo, se_id);
6885 624411d2 2023-07-08 jrick free(se_id);
6886 624411d2 2023-07-08 jrick if (err)
6887 624411d2 2023-07-08 jrick break;
6888 624411d2 2023-07-08 jrick se_time = got_object_tag_get_tagger_time(se_tag);
6889 624411d2 2023-07-08 jrick got_object_tag_close(se_tag);
6890 624411d2 2023-07-08 jrick
6891 624411d2 2023-07-08 jrick if (se_time > re_time) {
6892 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&new, re);
6893 624411d2 2023-07-08 jrick if (err)
6894 624411d2 2023-07-08 jrick return err;
6895 624411d2 2023-07-08 jrick STAILQ_INSERT_AFTER(sorted, se, new, entry);
6896 624411d2 2023-07-08 jrick break;
6897 624411d2 2023-07-08 jrick }
6898 624411d2 2023-07-08 jrick se = STAILQ_NEXT(se, entry);
6899 624411d2 2023-07-08 jrick continue;
6900 624411d2 2023-07-08 jrick }
6901 624411d2 2023-07-08 jrick }
6902 624411d2 2023-07-08 jrick done:
6903 624411d2 2023-07-08 jrick return err;
6904 624411d2 2023-07-08 jrick }
6905 624411d2 2023-07-08 jrick #endif
6906 624411d2 2023-07-08 jrick
6907 624411d2 2023-07-08 jrick static const struct got_error *
6908 624411d2 2023-07-08 jrick get_tag_refname(char **refname, const char *tag_name)
6909 624411d2 2023-07-08 jrick {
6910 624411d2 2023-07-08 jrick const struct got_error *err;
6911 624411d2 2023-07-08 jrick
6912 624411d2 2023-07-08 jrick if (strncmp("refs/tags/", tag_name, 10) == 0) {
6913 624411d2 2023-07-08 jrick *refname = strdup(tag_name);
6914 624411d2 2023-07-08 jrick if (*refname == NULL)
6915 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
6916 624411d2 2023-07-08 jrick } else if (asprintf(refname, "refs/tags/%s", tag_name) == -1) {
6917 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6918 624411d2 2023-07-08 jrick *refname = NULL;
6919 624411d2 2023-07-08 jrick return err;
6920 624411d2 2023-07-08 jrick }
6921 624411d2 2023-07-08 jrick
6922 624411d2 2023-07-08 jrick return NULL;
6923 624411d2 2023-07-08 jrick }
6924 624411d2 2023-07-08 jrick
6925 624411d2 2023-07-08 jrick static const struct got_error *
6926 624411d2 2023-07-08 jrick list_tags(struct got_repository *repo, const char *tag_name, int verify_tags,
6927 624411d2 2023-07-08 jrick const char *allowed_signers, const char *revoked_signers, int verbosity)
6928 624411d2 2023-07-08 jrick {
6929 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6930 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6931 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6932 624411d2 2023-07-08 jrick char *wanted_refname = NULL;
6933 624411d2 2023-07-08 jrick int bad_sigs = 0;
6934 624411d2 2023-07-08 jrick
6935 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6936 624411d2 2023-07-08 jrick
6937 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
6938 624411d2 2023-07-08 jrick if (err)
6939 624411d2 2023-07-08 jrick return err;
6940 624411d2 2023-07-08 jrick
6941 624411d2 2023-07-08 jrick if (tag_name) {
6942 624411d2 2023-07-08 jrick struct got_reference *ref;
6943 624411d2 2023-07-08 jrick err = get_tag_refname(&wanted_refname, tag_name);
6944 624411d2 2023-07-08 jrick if (err)
6945 624411d2 2023-07-08 jrick goto done;
6946 624411d2 2023-07-08 jrick /* Wanted tag reference should exist. */
6947 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, wanted_refname, 0);
6948 624411d2 2023-07-08 jrick if (err)
6949 624411d2 2023-07-08 jrick goto done;
6950 624411d2 2023-07-08 jrick got_ref_close(ref);
6951 624411d2 2023-07-08 jrick }
6952 624411d2 2023-07-08 jrick
6953 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
6954 624411d2 2023-07-08 jrick const char *refname;
6955 624411d2 2023-07-08 jrick char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
6956 624411d2 2023-07-08 jrick char datebuf[26];
6957 624411d2 2023-07-08 jrick const char *tagger, *ssh_sig = NULL;
6958 624411d2 2023-07-08 jrick char *sig_msg = NULL;
6959 624411d2 2023-07-08 jrick time_t tagger_time;
6960 624411d2 2023-07-08 jrick struct got_object_id *id;
6961 624411d2 2023-07-08 jrick struct got_tag_object *tag;
6962 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
6963 624411d2 2023-07-08 jrick
6964 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
6965 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/tags/", 10) != 0 ||
6966 624411d2 2023-07-08 jrick (wanted_refname && strcmp(refname, wanted_refname) != 0))
6967 624411d2 2023-07-08 jrick continue;
6968 624411d2 2023-07-08 jrick refname += 10;
6969 624411d2 2023-07-08 jrick refstr = got_ref_to_str(re->ref);
6970 624411d2 2023-07-08 jrick if (refstr == NULL) {
6971 624411d2 2023-07-08 jrick err = got_error_from_errno("got_ref_to_str");
6972 624411d2 2023-07-08 jrick break;
6973 624411d2 2023-07-08 jrick }
6974 624411d2 2023-07-08 jrick
6975 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, re->ref);
6976 624411d2 2023-07-08 jrick if (err)
6977 624411d2 2023-07-08 jrick break;
6978 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, id);
6979 624411d2 2023-07-08 jrick if (err) {
6980 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_OBJ_TYPE) {
6981 624411d2 2023-07-08 jrick free(id);
6982 624411d2 2023-07-08 jrick break;
6983 624411d2 2023-07-08 jrick }
6984 624411d2 2023-07-08 jrick /* "lightweight" tag */
6985 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
6986 624411d2 2023-07-08 jrick if (err) {
6987 624411d2 2023-07-08 jrick free(id);
6988 624411d2 2023-07-08 jrick break;
6989 624411d2 2023-07-08 jrick }
6990 624411d2 2023-07-08 jrick tagger = got_object_commit_get_committer(commit);
6991 624411d2 2023-07-08 jrick tagger_time =
6992 624411d2 2023-07-08 jrick got_object_commit_get_committer_time(commit);
6993 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
6994 624411d2 2023-07-08 jrick free(id);
6995 624411d2 2023-07-08 jrick if (err)
6996 624411d2 2023-07-08 jrick break;
6997 624411d2 2023-07-08 jrick } else {
6998 624411d2 2023-07-08 jrick free(id);
6999 624411d2 2023-07-08 jrick tagger = got_object_tag_get_tagger(tag);
7000 624411d2 2023-07-08 jrick tagger_time = got_object_tag_get_tagger_time(tag);
7001 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str,
7002 624411d2 2023-07-08 jrick got_object_tag_get_object_id(tag));
7003 624411d2 2023-07-08 jrick if (err)
7004 624411d2 2023-07-08 jrick break;
7005 624411d2 2023-07-08 jrick }
7006 624411d2 2023-07-08 jrick
7007 624411d2 2023-07-08 jrick if (tag && verify_tags) {
7008 624411d2 2023-07-08 jrick ssh_sig = got_sigs_get_tagmsg_ssh_signature(
7009 624411d2 2023-07-08 jrick got_object_tag_get_message(tag));
7010 624411d2 2023-07-08 jrick if (ssh_sig && allowed_signers == NULL) {
7011 624411d2 2023-07-08 jrick err = got_error_msg(
7012 624411d2 2023-07-08 jrick GOT_ERR_VERIFY_TAG_SIGNATURE,
7013 624411d2 2023-07-08 jrick "SSH signature verification requires "
7014 624411d2 2023-07-08 jrick "setting allowed_signers in "
7015 624411d2 2023-07-08 jrick "got.conf(5)");
7016 624411d2 2023-07-08 jrick break;
7017 624411d2 2023-07-08 jrick }
7018 624411d2 2023-07-08 jrick }
7019 624411d2 2023-07-08 jrick
7020 624411d2 2023-07-08 jrick printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr);
7021 624411d2 2023-07-08 jrick free(refstr);
7022 624411d2 2023-07-08 jrick printf("from: %s\n", tagger);
7023 624411d2 2023-07-08 jrick datestr = get_datestr(&tagger_time, datebuf);
7024 624411d2 2023-07-08 jrick if (datestr)
7025 624411d2 2023-07-08 jrick printf("date: %s UTC\n", datestr);
7026 624411d2 2023-07-08 jrick if (commit)
7027 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str);
7028 624411d2 2023-07-08 jrick else {
7029 624411d2 2023-07-08 jrick switch (got_object_tag_get_object_type(tag)) {
7030 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
7031 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB,
7032 624411d2 2023-07-08 jrick id_str);
7033 624411d2 2023-07-08 jrick break;
7034 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
7035 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_TREE,
7036 624411d2 2023-07-08 jrick id_str);
7037 624411d2 2023-07-08 jrick break;
7038 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
7039 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT,
7040 624411d2 2023-07-08 jrick id_str);
7041 624411d2 2023-07-08 jrick break;
7042 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
7043 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_TAG,
7044 624411d2 2023-07-08 jrick id_str);
7045 624411d2 2023-07-08 jrick break;
7046 624411d2 2023-07-08 jrick default:
7047 624411d2 2023-07-08 jrick break;
7048 624411d2 2023-07-08 jrick }
7049 624411d2 2023-07-08 jrick }
7050 624411d2 2023-07-08 jrick free(id_str);
7051 624411d2 2023-07-08 jrick
7052 624411d2 2023-07-08 jrick if (ssh_sig) {
7053 624411d2 2023-07-08 jrick err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig,
7054 624411d2 2023-07-08 jrick allowed_signers, revoked_signers, verbosity);
7055 624411d2 2023-07-08 jrick if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE)
7056 624411d2 2023-07-08 jrick bad_sigs = 1;
7057 624411d2 2023-07-08 jrick else if (err)
7058 624411d2 2023-07-08 jrick break;
7059 624411d2 2023-07-08 jrick printf("signature: %s", sig_msg);
7060 624411d2 2023-07-08 jrick free(sig_msg);
7061 624411d2 2023-07-08 jrick sig_msg = NULL;
7062 624411d2 2023-07-08 jrick }
7063 624411d2 2023-07-08 jrick
7064 624411d2 2023-07-08 jrick if (commit) {
7065 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&tagmsg0, commit);
7066 624411d2 2023-07-08 jrick if (err)
7067 624411d2 2023-07-08 jrick break;
7068 624411d2 2023-07-08 jrick got_object_commit_close(commit);
7069 624411d2 2023-07-08 jrick } else {
7070 624411d2 2023-07-08 jrick tagmsg0 = strdup(got_object_tag_get_message(tag));
7071 624411d2 2023-07-08 jrick got_object_tag_close(tag);
7072 624411d2 2023-07-08 jrick if (tagmsg0 == NULL) {
7073 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
7074 624411d2 2023-07-08 jrick break;
7075 624411d2 2023-07-08 jrick }
7076 624411d2 2023-07-08 jrick }
7077 624411d2 2023-07-08 jrick
7078 624411d2 2023-07-08 jrick tagmsg = tagmsg0;
7079 624411d2 2023-07-08 jrick do {
7080 624411d2 2023-07-08 jrick line = strsep(&tagmsg, "\n");
7081 624411d2 2023-07-08 jrick if (line)
7082 624411d2 2023-07-08 jrick printf(" %s\n", line);
7083 624411d2 2023-07-08 jrick } while (line);
7084 624411d2 2023-07-08 jrick free(tagmsg0);
7085 624411d2 2023-07-08 jrick }
7086 624411d2 2023-07-08 jrick done:
7087 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
7088 624411d2 2023-07-08 jrick free(wanted_refname);
7089 624411d2 2023-07-08 jrick
7090 624411d2 2023-07-08 jrick if (err == NULL && bad_sigs)
7091 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_BAD_TAG_SIGNATURE);
7092 624411d2 2023-07-08 jrick return err;
7093 624411d2 2023-07-08 jrick }
7094 624411d2 2023-07-08 jrick
7095 624411d2 2023-07-08 jrick static const struct got_error *
7096 624411d2 2023-07-08 jrick get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
7097 624411d2 2023-07-08 jrick const char *tag_name, const char *repo_path)
7098 624411d2 2023-07-08 jrick {
7099 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7100 624411d2 2023-07-08 jrick char *template = NULL, *initial_content = NULL;
7101 624411d2 2023-07-08 jrick char *editor = NULL;
7102 624411d2 2023-07-08 jrick int initial_content_len;
7103 624411d2 2023-07-08 jrick int fd = -1;
7104 624411d2 2023-07-08 jrick
7105 624411d2 2023-07-08 jrick if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) {
7106 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
7107 624411d2 2023-07-08 jrick goto done;
7108 624411d2 2023-07-08 jrick }
7109 624411d2 2023-07-08 jrick
7110 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
7111 624411d2 2023-07-08 jrick "\n# tagging commit %s as %s\n",
7112 624411d2 2023-07-08 jrick commit_id_str, tag_name);
7113 624411d2 2023-07-08 jrick if (initial_content_len == -1) {
7114 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
7115 624411d2 2023-07-08 jrick goto done;
7116 624411d2 2023-07-08 jrick }
7117 624411d2 2023-07-08 jrick
7118 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(tagmsg_path, &fd, template, "");
7119 624411d2 2023-07-08 jrick if (err)
7120 624411d2 2023-07-08 jrick goto done;
7121 624411d2 2023-07-08 jrick
7122 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
7123 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", *tagmsg_path);
7124 624411d2 2023-07-08 jrick goto done;
7125 624411d2 2023-07-08 jrick }
7126 624411d2 2023-07-08 jrick if (close(fd) == -1) {
7127 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *tagmsg_path);
7128 624411d2 2023-07-08 jrick goto done;
7129 624411d2 2023-07-08 jrick }
7130 624411d2 2023-07-08 jrick fd = -1;
7131 624411d2 2023-07-08 jrick
7132 624411d2 2023-07-08 jrick err = get_editor(&editor);
7133 624411d2 2023-07-08 jrick if (err)
7134 624411d2 2023-07-08 jrick goto done;
7135 624411d2 2023-07-08 jrick err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content,
7136 624411d2 2023-07-08 jrick initial_content_len, 1);
7137 624411d2 2023-07-08 jrick done:
7138 624411d2 2023-07-08 jrick free(initial_content);
7139 624411d2 2023-07-08 jrick free(template);
7140 624411d2 2023-07-08 jrick free(editor);
7141 624411d2 2023-07-08 jrick
7142 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
7143 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *tagmsg_path);
7144 624411d2 2023-07-08 jrick
7145 624411d2 2023-07-08 jrick if (err) {
7146 624411d2 2023-07-08 jrick free(*tagmsg);
7147 624411d2 2023-07-08 jrick *tagmsg = NULL;
7148 624411d2 2023-07-08 jrick }
7149 624411d2 2023-07-08 jrick return err;
7150 624411d2 2023-07-08 jrick }
7151 624411d2 2023-07-08 jrick
7152 624411d2 2023-07-08 jrick static const struct got_error *
7153 624411d2 2023-07-08 jrick add_tag(struct got_repository *repo, const char *tagger,
7154 624411d2 2023-07-08 jrick const char *tag_name, const char *commit_arg, const char *tagmsg_arg,
7155 624411d2 2023-07-08 jrick const char *signer_id, int verbosity)
7156 624411d2 2023-07-08 jrick {
7157 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7158 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *tag_id = NULL;
7159 624411d2 2023-07-08 jrick char *label = NULL, *commit_id_str = NULL;
7160 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
7161 624411d2 2023-07-08 jrick char *refname = NULL, *tagmsg = NULL;
7162 624411d2 2023-07-08 jrick char *tagmsg_path = NULL, *tag_id_str = NULL;
7163 624411d2 2023-07-08 jrick int preserve_tagmsg = 0;
7164 624411d2 2023-07-08 jrick struct got_reflist_head refs;
7165 624411d2 2023-07-08 jrick
7166 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
7167 624411d2 2023-07-08 jrick
7168 624411d2 2023-07-08 jrick /*
7169 624411d2 2023-07-08 jrick * Don't let the user create a tag name with a leading '-'.
7170 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
7171 624411d2 2023-07-08 jrick * an unintended typo.
7172 624411d2 2023-07-08 jrick */
7173 624411d2 2023-07-08 jrick if (tag_name[0] == '-')
7174 624411d2 2023-07-08 jrick return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS);
7175 624411d2 2023-07-08 jrick
7176 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
7177 624411d2 2023-07-08 jrick if (err)
7178 624411d2 2023-07-08 jrick goto done;
7179 624411d2 2023-07-08 jrick
7180 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&commit_id, &label, commit_arg,
7181 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, &refs, repo);
7182 624411d2 2023-07-08 jrick if (err)
7183 624411d2 2023-07-08 jrick goto done;
7184 624411d2 2023-07-08 jrick
7185 624411d2 2023-07-08 jrick err = got_object_id_str(&commit_id_str, commit_id);
7186 624411d2 2023-07-08 jrick if (err)
7187 624411d2 2023-07-08 jrick goto done;
7188 624411d2 2023-07-08 jrick
7189 624411d2 2023-07-08 jrick err = get_tag_refname(&refname, tag_name);
7190 624411d2 2023-07-08 jrick if (err)
7191 624411d2 2023-07-08 jrick goto done;
7192 624411d2 2023-07-08 jrick if (strncmp("refs/tags/", tag_name, 10) == 0)
7193 624411d2 2023-07-08 jrick tag_name += 10;
7194 624411d2 2023-07-08 jrick
7195 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
7196 624411d2 2023-07-08 jrick if (err == NULL) {
7197 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_TAG_EXISTS);
7198 624411d2 2023-07-08 jrick goto done;
7199 624411d2 2023-07-08 jrick } else if (err->code != GOT_ERR_NOT_REF)
7200 624411d2 2023-07-08 jrick goto done;
7201 624411d2 2023-07-08 jrick
7202 624411d2 2023-07-08 jrick if (tagmsg_arg == NULL) {
7203 624411d2 2023-07-08 jrick err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
7204 624411d2 2023-07-08 jrick tag_name, got_repo_get_path(repo));
7205 624411d2 2023-07-08 jrick if (err) {
7206 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_MSG_EMPTY &&
7207 624411d2 2023-07-08 jrick tagmsg_path != NULL)
7208 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7209 624411d2 2023-07-08 jrick goto done;
7210 624411d2 2023-07-08 jrick }
7211 624411d2 2023-07-08 jrick /* Editor is done; we can now apply unveil(2) */
7212 624411d2 2023-07-08 jrick err = got_sigs_apply_unveil();
7213 624411d2 2023-07-08 jrick if (err)
7214 624411d2 2023-07-08 jrick goto done;
7215 624411d2 2023-07-08 jrick err = apply_unveil(got_repo_get_path(repo), 0, NULL);
7216 624411d2 2023-07-08 jrick if (err)
7217 624411d2 2023-07-08 jrick goto done;
7218 624411d2 2023-07-08 jrick }
7219 624411d2 2023-07-08 jrick
7220 624411d2 2023-07-08 jrick err = got_object_tag_create(&tag_id, tag_name, commit_id,
7221 624411d2 2023-07-08 jrick tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, signer_id, repo,
7222 624411d2 2023-07-08 jrick verbosity);
7223 624411d2 2023-07-08 jrick if (err) {
7224 624411d2 2023-07-08 jrick if (tagmsg_path)
7225 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7226 624411d2 2023-07-08 jrick goto done;
7227 624411d2 2023-07-08 jrick }
7228 624411d2 2023-07-08 jrick
7229 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, tag_id);
7230 624411d2 2023-07-08 jrick if (err) {
7231 624411d2 2023-07-08 jrick if (tagmsg_path)
7232 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7233 624411d2 2023-07-08 jrick goto done;
7234 624411d2 2023-07-08 jrick }
7235 624411d2 2023-07-08 jrick
7236 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
7237 624411d2 2023-07-08 jrick if (err) {
7238 624411d2 2023-07-08 jrick if (tagmsg_path)
7239 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7240 624411d2 2023-07-08 jrick goto done;
7241 624411d2 2023-07-08 jrick }
7242 624411d2 2023-07-08 jrick
7243 624411d2 2023-07-08 jrick err = got_object_id_str(&tag_id_str, tag_id);
7244 624411d2 2023-07-08 jrick if (err) {
7245 624411d2 2023-07-08 jrick if (tagmsg_path)
7246 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7247 624411d2 2023-07-08 jrick goto done;
7248 624411d2 2023-07-08 jrick }
7249 624411d2 2023-07-08 jrick printf("Created tag %s\n", tag_id_str);
7250 624411d2 2023-07-08 jrick done:
7251 624411d2 2023-07-08 jrick if (preserve_tagmsg) {
7252 624411d2 2023-07-08 jrick fprintf(stderr, "%s: tag message preserved in %s\n",
7253 624411d2 2023-07-08 jrick getprogname(), tagmsg_path);
7254 624411d2 2023-07-08 jrick } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL)
7255 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", tagmsg_path);
7256 624411d2 2023-07-08 jrick free(tag_id_str);
7257 624411d2 2023-07-08 jrick if (ref)
7258 624411d2 2023-07-08 jrick got_ref_close(ref);
7259 624411d2 2023-07-08 jrick free(commit_id);
7260 624411d2 2023-07-08 jrick free(commit_id_str);
7261 624411d2 2023-07-08 jrick free(refname);
7262 624411d2 2023-07-08 jrick free(tagmsg);
7263 624411d2 2023-07-08 jrick free(tagmsg_path);
7264 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
7265 624411d2 2023-07-08 jrick return err;
7266 624411d2 2023-07-08 jrick }
7267 624411d2 2023-07-08 jrick
7268 624411d2 2023-07-08 jrick static const struct got_error *
7269 624411d2 2023-07-08 jrick cmd_tag(int argc, char *argv[])
7270 624411d2 2023-07-08 jrick {
7271 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7272 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7273 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7274 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
7275 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *tagger = NULL;
7276 624411d2 2023-07-08 jrick char *allowed_signers = NULL, *revoked_signers = NULL;
7277 624411d2 2023-07-08 jrick const char *signer_id = NULL;
7278 624411d2 2023-07-08 jrick const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL;
7279 624411d2 2023-07-08 jrick int ch, do_list = 0, verify_tags = 0, verbosity = 0;
7280 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7281 624411d2 2023-07-08 jrick
7282 624411d2 2023-07-08 jrick #ifndef PROFILE
7283 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7284 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
7285 624411d2 2023-07-08 jrick err(1, "pledge");
7286 624411d2 2023-07-08 jrick #endif
7287 624411d2 2023-07-08 jrick
7288 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:lm:r:s:Vv")) != -1) {
7289 624411d2 2023-07-08 jrick switch (ch) {
7290 624411d2 2023-07-08 jrick case 'c':
7291 624411d2 2023-07-08 jrick commit_id_arg = optarg;
7292 624411d2 2023-07-08 jrick break;
7293 624411d2 2023-07-08 jrick case 'l':
7294 624411d2 2023-07-08 jrick do_list = 1;
7295 624411d2 2023-07-08 jrick break;
7296 624411d2 2023-07-08 jrick case 'm':
7297 624411d2 2023-07-08 jrick tagmsg = optarg;
7298 624411d2 2023-07-08 jrick break;
7299 624411d2 2023-07-08 jrick case 'r':
7300 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
7301 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7302 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
7303 624411d2 2023-07-08 jrick optarg);
7304 624411d2 2023-07-08 jrick goto done;
7305 624411d2 2023-07-08 jrick }
7306 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
7307 624411d2 2023-07-08 jrick break;
7308 624411d2 2023-07-08 jrick case 's':
7309 624411d2 2023-07-08 jrick signer_id = optarg;
7310 624411d2 2023-07-08 jrick break;
7311 624411d2 2023-07-08 jrick case 'V':
7312 624411d2 2023-07-08 jrick verify_tags = 1;
7313 624411d2 2023-07-08 jrick break;
7314 624411d2 2023-07-08 jrick case 'v':
7315 624411d2 2023-07-08 jrick if (verbosity < 0)
7316 624411d2 2023-07-08 jrick verbosity = 0;
7317 624411d2 2023-07-08 jrick else if (verbosity < 3)
7318 624411d2 2023-07-08 jrick verbosity++;
7319 624411d2 2023-07-08 jrick break;
7320 624411d2 2023-07-08 jrick default:
7321 624411d2 2023-07-08 jrick usage_tag();
7322 624411d2 2023-07-08 jrick /* NOTREACHED */
7323 624411d2 2023-07-08 jrick }
7324 624411d2 2023-07-08 jrick }
7325 624411d2 2023-07-08 jrick
7326 624411d2 2023-07-08 jrick argc -= optind;
7327 624411d2 2023-07-08 jrick argv += optind;
7328 624411d2 2023-07-08 jrick
7329 624411d2 2023-07-08 jrick if (do_list || verify_tags) {
7330 624411d2 2023-07-08 jrick if (commit_id_arg != NULL)
7331 624411d2 2023-07-08 jrick errx(1,
7332 624411d2 2023-07-08 jrick "-c option can only be used when creating a tag");
7333 624411d2 2023-07-08 jrick if (tagmsg) {
7334 624411d2 2023-07-08 jrick if (do_list)
7335 624411d2 2023-07-08 jrick option_conflict('l', 'm');
7336 624411d2 2023-07-08 jrick else
7337 624411d2 2023-07-08 jrick option_conflict('V', 'm');
7338 624411d2 2023-07-08 jrick }
7339 624411d2 2023-07-08 jrick if (signer_id) {
7340 624411d2 2023-07-08 jrick if (do_list)
7341 624411d2 2023-07-08 jrick option_conflict('l', 's');
7342 624411d2 2023-07-08 jrick else
7343 624411d2 2023-07-08 jrick option_conflict('V', 's');
7344 624411d2 2023-07-08 jrick }
7345 624411d2 2023-07-08 jrick if (argc > 1)
7346 624411d2 2023-07-08 jrick usage_tag();
7347 624411d2 2023-07-08 jrick } else if (argc != 1)
7348 624411d2 2023-07-08 jrick usage_tag();
7349 624411d2 2023-07-08 jrick
7350 624411d2 2023-07-08 jrick if (argc == 1)
7351 624411d2 2023-07-08 jrick tag_name = argv[0];
7352 624411d2 2023-07-08 jrick
7353 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7354 624411d2 2023-07-08 jrick if (cwd == NULL) {
7355 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7356 624411d2 2023-07-08 jrick goto done;
7357 624411d2 2023-07-08 jrick }
7358 624411d2 2023-07-08 jrick
7359 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7360 624411d2 2023-07-08 jrick if (error != NULL)
7361 624411d2 2023-07-08 jrick goto done;
7362 624411d2 2023-07-08 jrick
7363 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7364 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7365 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
7366 624411d2 2023-07-08 jrick goto done;
7367 624411d2 2023-07-08 jrick else
7368 624411d2 2023-07-08 jrick error = NULL;
7369 624411d2 2023-07-08 jrick if (worktree) {
7370 624411d2 2023-07-08 jrick repo_path =
7371 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
7372 624411d2 2023-07-08 jrick if (repo_path == NULL)
7373 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
7374 624411d2 2023-07-08 jrick if (error)
7375 624411d2 2023-07-08 jrick goto done;
7376 624411d2 2023-07-08 jrick } else {
7377 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
7378 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7379 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
7380 624411d2 2023-07-08 jrick goto done;
7381 624411d2 2023-07-08 jrick }
7382 624411d2 2023-07-08 jrick }
7383 624411d2 2023-07-08 jrick }
7384 624411d2 2023-07-08 jrick
7385 624411d2 2023-07-08 jrick if (do_list || verify_tags) {
7386 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
7387 624411d2 2023-07-08 jrick if (error != NULL)
7388 624411d2 2023-07-08 jrick goto done;
7389 624411d2 2023-07-08 jrick error = get_allowed_signers(&allowed_signers, repo, worktree);
7390 624411d2 2023-07-08 jrick if (error)
7391 624411d2 2023-07-08 jrick goto done;
7392 624411d2 2023-07-08 jrick error = get_revoked_signers(&revoked_signers, repo, worktree);
7393 624411d2 2023-07-08 jrick if (error)
7394 624411d2 2023-07-08 jrick goto done;
7395 624411d2 2023-07-08 jrick if (worktree) {
7396 624411d2 2023-07-08 jrick /* Release work tree lock. */
7397 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7398 624411d2 2023-07-08 jrick worktree = NULL;
7399 624411d2 2023-07-08 jrick }
7400 624411d2 2023-07-08 jrick
7401 624411d2 2023-07-08 jrick /*
7402 624411d2 2023-07-08 jrick * Remove "cpath" promise unless needed for signature tmpfile
7403 624411d2 2023-07-08 jrick * creation.
7404 624411d2 2023-07-08 jrick */
7405 624411d2 2023-07-08 jrick if (verify_tags)
7406 624411d2 2023-07-08 jrick got_sigs_apply_unveil();
7407 624411d2 2023-07-08 jrick else {
7408 624411d2 2023-07-08 jrick #ifndef PROFILE
7409 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd "
7410 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
7411 624411d2 2023-07-08 jrick err(1, "pledge");
7412 624411d2 2023-07-08 jrick #endif
7413 624411d2 2023-07-08 jrick }
7414 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
7415 624411d2 2023-07-08 jrick if (error)
7416 624411d2 2023-07-08 jrick goto done;
7417 624411d2 2023-07-08 jrick error = list_tags(repo, tag_name, verify_tags, allowed_signers,
7418 624411d2 2023-07-08 jrick revoked_signers, verbosity);
7419 624411d2 2023-07-08 jrick } else {
7420 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
7421 624411d2 2023-07-08 jrick if (error)
7422 624411d2 2023-07-08 jrick goto done;
7423 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, gitconfig_path,
7424 624411d2 2023-07-08 jrick pack_fds);
7425 624411d2 2023-07-08 jrick if (error != NULL)
7426 624411d2 2023-07-08 jrick goto done;
7427 624411d2 2023-07-08 jrick
7428 624411d2 2023-07-08 jrick error = get_author(&tagger, repo, worktree);
7429 624411d2 2023-07-08 jrick if (error)
7430 624411d2 2023-07-08 jrick goto done;
7431 624411d2 2023-07-08 jrick if (signer_id == NULL)
7432 624411d2 2023-07-08 jrick signer_id = get_signer_id(repo, worktree);
7433 624411d2 2023-07-08 jrick
7434 624411d2 2023-07-08 jrick if (tagmsg) {
7435 624411d2 2023-07-08 jrick if (signer_id) {
7436 624411d2 2023-07-08 jrick error = got_sigs_apply_unveil();
7437 624411d2 2023-07-08 jrick if (error)
7438 624411d2 2023-07-08 jrick goto done;
7439 624411d2 2023-07-08 jrick }
7440 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
7441 624411d2 2023-07-08 jrick if (error)
7442 624411d2 2023-07-08 jrick goto done;
7443 624411d2 2023-07-08 jrick }
7444 624411d2 2023-07-08 jrick
7445 624411d2 2023-07-08 jrick if (commit_id_arg == NULL) {
7446 624411d2 2023-07-08 jrick struct got_reference *head_ref;
7447 624411d2 2023-07-08 jrick struct got_object_id *commit_id;
7448 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
7449 624411d2 2023-07-08 jrick worktree ? got_worktree_get_head_ref_name(worktree)
7450 624411d2 2023-07-08 jrick : GOT_REF_HEAD, 0);
7451 624411d2 2023-07-08 jrick if (error)
7452 624411d2 2023-07-08 jrick goto done;
7453 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
7454 624411d2 2023-07-08 jrick got_ref_close(head_ref);
7455 624411d2 2023-07-08 jrick if (error)
7456 624411d2 2023-07-08 jrick goto done;
7457 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
7458 624411d2 2023-07-08 jrick free(commit_id);
7459 624411d2 2023-07-08 jrick if (error)
7460 624411d2 2023-07-08 jrick goto done;
7461 624411d2 2023-07-08 jrick }
7462 624411d2 2023-07-08 jrick
7463 624411d2 2023-07-08 jrick if (worktree) {
7464 624411d2 2023-07-08 jrick /* Release work tree lock. */
7465 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7466 624411d2 2023-07-08 jrick worktree = NULL;
7467 624411d2 2023-07-08 jrick }
7468 624411d2 2023-07-08 jrick
7469 624411d2 2023-07-08 jrick error = add_tag(repo, tagger, tag_name,
7470 624411d2 2023-07-08 jrick commit_id_str ? commit_id_str : commit_id_arg, tagmsg,
7471 624411d2 2023-07-08 jrick signer_id, verbosity);
7472 624411d2 2023-07-08 jrick }
7473 624411d2 2023-07-08 jrick done:
7474 624411d2 2023-07-08 jrick if (repo) {
7475 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7476 624411d2 2023-07-08 jrick if (error == NULL)
7477 624411d2 2023-07-08 jrick error = close_err;
7478 624411d2 2023-07-08 jrick }
7479 624411d2 2023-07-08 jrick if (worktree)
7480 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7481 624411d2 2023-07-08 jrick if (pack_fds) {
7482 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7483 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7484 624411d2 2023-07-08 jrick if (error == NULL)
7485 624411d2 2023-07-08 jrick error = pack_err;
7486 624411d2 2023-07-08 jrick }
7487 624411d2 2023-07-08 jrick free(cwd);
7488 624411d2 2023-07-08 jrick free(repo_path);
7489 624411d2 2023-07-08 jrick free(gitconfig_path);
7490 624411d2 2023-07-08 jrick free(commit_id_str);
7491 624411d2 2023-07-08 jrick free(tagger);
7492 624411d2 2023-07-08 jrick free(allowed_signers);
7493 624411d2 2023-07-08 jrick free(revoked_signers);
7494 624411d2 2023-07-08 jrick return error;
7495 624411d2 2023-07-08 jrick }
7496 624411d2 2023-07-08 jrick
7497 624411d2 2023-07-08 jrick __dead static void
7498 624411d2 2023-07-08 jrick usage_add(void)
7499 624411d2 2023-07-08 jrick {
7500 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname());
7501 624411d2 2023-07-08 jrick exit(1);
7502 624411d2 2023-07-08 jrick }
7503 624411d2 2023-07-08 jrick
7504 624411d2 2023-07-08 jrick static const struct got_error *
7505 624411d2 2023-07-08 jrick add_progress(void *arg, unsigned char status, const char *path)
7506 624411d2 2023-07-08 jrick {
7507 624411d2 2023-07-08 jrick while (path[0] == '/')
7508 624411d2 2023-07-08 jrick path++;
7509 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
7510 624411d2 2023-07-08 jrick return NULL;
7511 624411d2 2023-07-08 jrick }
7512 624411d2 2023-07-08 jrick
7513 624411d2 2023-07-08 jrick static const struct got_error *
7514 624411d2 2023-07-08 jrick cmd_add(int argc, char *argv[])
7515 624411d2 2023-07-08 jrick {
7516 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7517 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7518 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7519 624411d2 2023-07-08 jrick char *cwd = NULL;
7520 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
7521 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
7522 624411d2 2023-07-08 jrick int ch, can_recurse = 0, no_ignores = 0;
7523 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7524 624411d2 2023-07-08 jrick
7525 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
7526 624411d2 2023-07-08 jrick
7527 624411d2 2023-07-08 jrick #ifndef PROFILE
7528 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7529 624411d2 2023-07-08 jrick NULL) == -1)
7530 624411d2 2023-07-08 jrick err(1, "pledge");
7531 624411d2 2023-07-08 jrick #endif
7532 624411d2 2023-07-08 jrick
7533 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "IR")) != -1) {
7534 624411d2 2023-07-08 jrick switch (ch) {
7535 624411d2 2023-07-08 jrick case 'I':
7536 624411d2 2023-07-08 jrick no_ignores = 1;
7537 624411d2 2023-07-08 jrick break;
7538 624411d2 2023-07-08 jrick case 'R':
7539 624411d2 2023-07-08 jrick can_recurse = 1;
7540 624411d2 2023-07-08 jrick break;
7541 624411d2 2023-07-08 jrick default:
7542 624411d2 2023-07-08 jrick usage_add();
7543 624411d2 2023-07-08 jrick /* NOTREACHED */
7544 624411d2 2023-07-08 jrick }
7545 624411d2 2023-07-08 jrick }
7546 624411d2 2023-07-08 jrick
7547 624411d2 2023-07-08 jrick argc -= optind;
7548 624411d2 2023-07-08 jrick argv += optind;
7549 624411d2 2023-07-08 jrick
7550 624411d2 2023-07-08 jrick if (argc < 1)
7551 624411d2 2023-07-08 jrick usage_add();
7552 624411d2 2023-07-08 jrick
7553 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7554 624411d2 2023-07-08 jrick if (cwd == NULL) {
7555 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7556 624411d2 2023-07-08 jrick goto done;
7557 624411d2 2023-07-08 jrick }
7558 624411d2 2023-07-08 jrick
7559 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7560 624411d2 2023-07-08 jrick if (error != NULL)
7561 624411d2 2023-07-08 jrick goto done;
7562 624411d2 2023-07-08 jrick
7563 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7564 624411d2 2023-07-08 jrick if (error) {
7565 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
7566 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "add", cwd);
7567 624411d2 2023-07-08 jrick goto done;
7568 624411d2 2023-07-08 jrick }
7569 624411d2 2023-07-08 jrick
7570 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7571 624411d2 2023-07-08 jrick NULL, pack_fds);
7572 624411d2 2023-07-08 jrick if (error != NULL)
7573 624411d2 2023-07-08 jrick goto done;
7574 624411d2 2023-07-08 jrick
7575 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
7576 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
7577 624411d2 2023-07-08 jrick if (error)
7578 624411d2 2023-07-08 jrick goto done;
7579 624411d2 2023-07-08 jrick
7580 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7581 624411d2 2023-07-08 jrick if (error)
7582 624411d2 2023-07-08 jrick goto done;
7583 624411d2 2023-07-08 jrick
7584 624411d2 2023-07-08 jrick if (!can_recurse) {
7585 624411d2 2023-07-08 jrick char *ondisk_path;
7586 624411d2 2023-07-08 jrick struct stat sb;
7587 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
7588 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
7589 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
7590 624411d2 2023-07-08 jrick pe->path) == -1) {
7591 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
7592 624411d2 2023-07-08 jrick goto done;
7593 624411d2 2023-07-08 jrick }
7594 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
7595 624411d2 2023-07-08 jrick if (errno == ENOENT) {
7596 624411d2 2023-07-08 jrick free(ondisk_path);
7597 624411d2 2023-07-08 jrick continue;
7598 624411d2 2023-07-08 jrick }
7599 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
7600 624411d2 2023-07-08 jrick ondisk_path);
7601 624411d2 2023-07-08 jrick free(ondisk_path);
7602 624411d2 2023-07-08 jrick goto done;
7603 624411d2 2023-07-08 jrick }
7604 624411d2 2023-07-08 jrick free(ondisk_path);
7605 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
7606 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
7607 624411d2 2023-07-08 jrick "adding directories requires -R option");
7608 624411d2 2023-07-08 jrick goto done;
7609 624411d2 2023-07-08 jrick }
7610 624411d2 2023-07-08 jrick }
7611 624411d2 2023-07-08 jrick }
7612 624411d2 2023-07-08 jrick
7613 624411d2 2023-07-08 jrick error = got_worktree_schedule_add(worktree, &paths, add_progress,
7614 624411d2 2023-07-08 jrick NULL, repo, no_ignores);
7615 624411d2 2023-07-08 jrick done:
7616 624411d2 2023-07-08 jrick if (repo) {
7617 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7618 624411d2 2023-07-08 jrick if (error == NULL)
7619 624411d2 2023-07-08 jrick error = close_err;
7620 624411d2 2023-07-08 jrick }
7621 624411d2 2023-07-08 jrick if (worktree)
7622 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7623 624411d2 2023-07-08 jrick if (pack_fds) {
7624 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7625 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7626 624411d2 2023-07-08 jrick if (error == NULL)
7627 624411d2 2023-07-08 jrick error = pack_err;
7628 624411d2 2023-07-08 jrick }
7629 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
7630 624411d2 2023-07-08 jrick free(cwd);
7631 624411d2 2023-07-08 jrick return error;
7632 624411d2 2023-07-08 jrick }
7633 624411d2 2023-07-08 jrick
7634 624411d2 2023-07-08 jrick __dead static void
7635 624411d2 2023-07-08 jrick usage_remove(void)
7636 624411d2 2023-07-08 jrick {
7637 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
7638 624411d2 2023-07-08 jrick getprogname());
7639 624411d2 2023-07-08 jrick exit(1);
7640 624411d2 2023-07-08 jrick }
7641 624411d2 2023-07-08 jrick
7642 624411d2 2023-07-08 jrick static const struct got_error *
7643 624411d2 2023-07-08 jrick print_remove_status(void *arg, unsigned char status,
7644 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path)
7645 624411d2 2023-07-08 jrick {
7646 624411d2 2023-07-08 jrick while (path[0] == '/')
7647 624411d2 2023-07-08 jrick path++;
7648 624411d2 2023-07-08 jrick if (status == GOT_STATUS_NONEXISTENT)
7649 624411d2 2023-07-08 jrick return NULL;
7650 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
7651 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
7652 624411d2 2023-07-08 jrick printf("%c%c %s\n", status, staged_status, path);
7653 624411d2 2023-07-08 jrick return NULL;
7654 624411d2 2023-07-08 jrick }
7655 624411d2 2023-07-08 jrick
7656 624411d2 2023-07-08 jrick static const struct got_error *
7657 624411d2 2023-07-08 jrick cmd_remove(int argc, char *argv[])
7658 624411d2 2023-07-08 jrick {
7659 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7660 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7661 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7662 624411d2 2023-07-08 jrick const char *status_codes = NULL;
7663 624411d2 2023-07-08 jrick char *cwd = NULL;
7664 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
7665 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
7666 624411d2 2023-07-08 jrick int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i;
7667 624411d2 2023-07-08 jrick int ignore_missing_paths = 0;
7668 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7669 624411d2 2023-07-08 jrick
7670 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
7671 624411d2 2023-07-08 jrick
7672 624411d2 2023-07-08 jrick #ifndef PROFILE
7673 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7674 624411d2 2023-07-08 jrick NULL) == -1)
7675 624411d2 2023-07-08 jrick err(1, "pledge");
7676 624411d2 2023-07-08 jrick #endif
7677 624411d2 2023-07-08 jrick
7678 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "fkRs:")) != -1) {
7679 624411d2 2023-07-08 jrick switch (ch) {
7680 624411d2 2023-07-08 jrick case 'f':
7681 624411d2 2023-07-08 jrick delete_local_mods = 1;
7682 624411d2 2023-07-08 jrick ignore_missing_paths = 1;
7683 624411d2 2023-07-08 jrick break;
7684 624411d2 2023-07-08 jrick case 'k':
7685 624411d2 2023-07-08 jrick keep_on_disk = 1;
7686 624411d2 2023-07-08 jrick break;
7687 624411d2 2023-07-08 jrick case 'R':
7688 624411d2 2023-07-08 jrick can_recurse = 1;
7689 624411d2 2023-07-08 jrick break;
7690 624411d2 2023-07-08 jrick case 's':
7691 624411d2 2023-07-08 jrick for (i = 0; optarg[i] != '\0'; i++) {
7692 624411d2 2023-07-08 jrick switch (optarg[i]) {
7693 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
7694 624411d2 2023-07-08 jrick delete_local_mods = 1;
7695 624411d2 2023-07-08 jrick break;
7696 624411d2 2023-07-08 jrick case GOT_STATUS_MISSING:
7697 624411d2 2023-07-08 jrick ignore_missing_paths = 1;
7698 624411d2 2023-07-08 jrick break;
7699 624411d2 2023-07-08 jrick default:
7700 624411d2 2023-07-08 jrick errx(1, "invalid status code '%c'",
7701 624411d2 2023-07-08 jrick optarg[i]);
7702 624411d2 2023-07-08 jrick }
7703 624411d2 2023-07-08 jrick }
7704 624411d2 2023-07-08 jrick status_codes = optarg;
7705 624411d2 2023-07-08 jrick break;
7706 624411d2 2023-07-08 jrick default:
7707 624411d2 2023-07-08 jrick usage_remove();
7708 624411d2 2023-07-08 jrick /* NOTREACHED */
7709 624411d2 2023-07-08 jrick }
7710 624411d2 2023-07-08 jrick }
7711 624411d2 2023-07-08 jrick
7712 624411d2 2023-07-08 jrick argc -= optind;
7713 624411d2 2023-07-08 jrick argv += optind;
7714 624411d2 2023-07-08 jrick
7715 624411d2 2023-07-08 jrick if (argc < 1)
7716 624411d2 2023-07-08 jrick usage_remove();
7717 624411d2 2023-07-08 jrick
7718 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7719 624411d2 2023-07-08 jrick if (cwd == NULL) {
7720 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7721 624411d2 2023-07-08 jrick goto done;
7722 624411d2 2023-07-08 jrick }
7723 624411d2 2023-07-08 jrick
7724 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7725 624411d2 2023-07-08 jrick if (error != NULL)
7726 624411d2 2023-07-08 jrick goto done;
7727 624411d2 2023-07-08 jrick
7728 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7729 624411d2 2023-07-08 jrick if (error) {
7730 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
7731 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "remove", cwd);
7732 624411d2 2023-07-08 jrick goto done;
7733 624411d2 2023-07-08 jrick }
7734 624411d2 2023-07-08 jrick
7735 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7736 624411d2 2023-07-08 jrick NULL, pack_fds);
7737 624411d2 2023-07-08 jrick if (error)
7738 624411d2 2023-07-08 jrick goto done;
7739 624411d2 2023-07-08 jrick
7740 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
7741 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
7742 624411d2 2023-07-08 jrick if (error)
7743 624411d2 2023-07-08 jrick goto done;
7744 624411d2 2023-07-08 jrick
7745 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7746 624411d2 2023-07-08 jrick if (error)
7747 624411d2 2023-07-08 jrick goto done;
7748 624411d2 2023-07-08 jrick
7749 624411d2 2023-07-08 jrick if (!can_recurse) {
7750 624411d2 2023-07-08 jrick char *ondisk_path;
7751 624411d2 2023-07-08 jrick struct stat sb;
7752 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
7753 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
7754 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
7755 624411d2 2023-07-08 jrick pe->path) == -1) {
7756 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
7757 624411d2 2023-07-08 jrick goto done;
7758 624411d2 2023-07-08 jrick }
7759 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
7760 624411d2 2023-07-08 jrick if (errno == ENOENT) {
7761 624411d2 2023-07-08 jrick free(ondisk_path);
7762 624411d2 2023-07-08 jrick continue;
7763 624411d2 2023-07-08 jrick }
7764 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
7765 624411d2 2023-07-08 jrick ondisk_path);
7766 624411d2 2023-07-08 jrick free(ondisk_path);
7767 624411d2 2023-07-08 jrick goto done;
7768 624411d2 2023-07-08 jrick }
7769 624411d2 2023-07-08 jrick free(ondisk_path);
7770 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
7771 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
7772 624411d2 2023-07-08 jrick "removing directories requires -R option");
7773 624411d2 2023-07-08 jrick goto done;
7774 624411d2 2023-07-08 jrick }
7775 624411d2 2023-07-08 jrick }
7776 624411d2 2023-07-08 jrick }
7777 624411d2 2023-07-08 jrick
7778 624411d2 2023-07-08 jrick error = got_worktree_schedule_delete(worktree, &paths,
7779 624411d2 2023-07-08 jrick delete_local_mods, status_codes, print_remove_status, NULL,
7780 624411d2 2023-07-08 jrick repo, keep_on_disk, ignore_missing_paths);
7781 624411d2 2023-07-08 jrick done:
7782 624411d2 2023-07-08 jrick if (repo) {
7783 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7784 624411d2 2023-07-08 jrick if (error == NULL)
7785 624411d2 2023-07-08 jrick error = close_err;
7786 624411d2 2023-07-08 jrick }
7787 624411d2 2023-07-08 jrick if (worktree)
7788 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7789 624411d2 2023-07-08 jrick if (pack_fds) {
7790 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7791 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7792 624411d2 2023-07-08 jrick if (error == NULL)
7793 624411d2 2023-07-08 jrick error = pack_err;
7794 624411d2 2023-07-08 jrick }
7795 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
7796 624411d2 2023-07-08 jrick free(cwd);
7797 624411d2 2023-07-08 jrick return error;
7798 624411d2 2023-07-08 jrick }
7799 624411d2 2023-07-08 jrick
7800 624411d2 2023-07-08 jrick __dead static void
7801 624411d2 2023-07-08 jrick usage_patch(void)
7802 624411d2 2023-07-08 jrick {
7803 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
7804 624411d2 2023-07-08 jrick "[patchfile]\n", getprogname());
7805 624411d2 2023-07-08 jrick exit(1);
7806 624411d2 2023-07-08 jrick }
7807 624411d2 2023-07-08 jrick
7808 624411d2 2023-07-08 jrick static const struct got_error *
7809 624411d2 2023-07-08 jrick patch_from_stdin(int *patchfd)
7810 624411d2 2023-07-08 jrick {
7811 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7812 624411d2 2023-07-08 jrick ssize_t r;
7813 624411d2 2023-07-08 jrick char buf[BUFSIZ];
7814 624411d2 2023-07-08 jrick sig_t sighup, sigint, sigquit;
7815 624411d2 2023-07-08 jrick
7816 624411d2 2023-07-08 jrick *patchfd = got_opentempfd();
7817 624411d2 2023-07-08 jrick if (*patchfd == -1)
7818 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
7819 624411d2 2023-07-08 jrick
7820 624411d2 2023-07-08 jrick sighup = signal(SIGHUP, SIG_DFL);
7821 624411d2 2023-07-08 jrick sigint = signal(SIGINT, SIG_DFL);
7822 624411d2 2023-07-08 jrick sigquit = signal(SIGQUIT, SIG_DFL);
7823 624411d2 2023-07-08 jrick
7824 624411d2 2023-07-08 jrick for (;;) {
7825 624411d2 2023-07-08 jrick r = read(0, buf, sizeof(buf));
7826 624411d2 2023-07-08 jrick if (r == -1) {
7827 624411d2 2023-07-08 jrick err = got_error_from_errno("read");
7828 624411d2 2023-07-08 jrick break;
7829 624411d2 2023-07-08 jrick }
7830 624411d2 2023-07-08 jrick if (r == 0)
7831 624411d2 2023-07-08 jrick break;
7832 624411d2 2023-07-08 jrick if (write(*patchfd, buf, r) == -1) {
7833 624411d2 2023-07-08 jrick err = got_error_from_errno("write");
7834 624411d2 2023-07-08 jrick break;
7835 624411d2 2023-07-08 jrick }
7836 624411d2 2023-07-08 jrick }
7837 624411d2 2023-07-08 jrick
7838 624411d2 2023-07-08 jrick signal(SIGHUP, sighup);
7839 624411d2 2023-07-08 jrick signal(SIGINT, sigint);
7840 624411d2 2023-07-08 jrick signal(SIGQUIT, sigquit);
7841 624411d2 2023-07-08 jrick
7842 624411d2 2023-07-08 jrick if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1)
7843 624411d2 2023-07-08 jrick err = got_error_from_errno("lseek");
7844 624411d2 2023-07-08 jrick
7845 624411d2 2023-07-08 jrick if (err != NULL) {
7846 624411d2 2023-07-08 jrick close(*patchfd);
7847 624411d2 2023-07-08 jrick *patchfd = -1;
7848 624411d2 2023-07-08 jrick }
7849 624411d2 2023-07-08 jrick
7850 624411d2 2023-07-08 jrick return err;
7851 624411d2 2023-07-08 jrick }
7852 624411d2 2023-07-08 jrick
7853 624411d2 2023-07-08 jrick struct got_patch_progress_arg {
7854 624411d2 2023-07-08 jrick int did_something;
7855 624411d2 2023-07-08 jrick int conflicts;
7856 624411d2 2023-07-08 jrick int rejects;
7857 624411d2 2023-07-08 jrick };
7858 624411d2 2023-07-08 jrick
7859 624411d2 2023-07-08 jrick static const struct got_error *
7860 624411d2 2023-07-08 jrick patch_progress(void *arg, const char *old, const char *new,
7861 624411d2 2023-07-08 jrick unsigned char status, const struct got_error *error, int old_from,
7862 624411d2 2023-07-08 jrick int old_lines, int new_from, int new_lines, int offset,
7863 624411d2 2023-07-08 jrick int ws_mangled, const struct got_error *hunk_err)
7864 624411d2 2023-07-08 jrick {
7865 624411d2 2023-07-08 jrick const char *path = new == NULL ? old : new;
7866 624411d2 2023-07-08 jrick struct got_patch_progress_arg *a = arg;
7867 624411d2 2023-07-08 jrick
7868 624411d2 2023-07-08 jrick while (*path == '/')
7869 624411d2 2023-07-08 jrick path++;
7870 624411d2 2023-07-08 jrick
7871 624411d2 2023-07-08 jrick if (status != GOT_STATUS_NO_CHANGE &&
7872 624411d2 2023-07-08 jrick status != 0 /* per-hunk progress */) {
7873 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
7874 624411d2 2023-07-08 jrick a->did_something = 1;
7875 624411d2 2023-07-08 jrick }
7876 624411d2 2023-07-08 jrick
7877 624411d2 2023-07-08 jrick if (hunk_err == NULL) {
7878 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_UPDATE)
7879 624411d2 2023-07-08 jrick a->rejects++;
7880 624411d2 2023-07-08 jrick else if (status == GOT_STATUS_CONFLICT)
7881 624411d2 2023-07-08 jrick a->conflicts++;
7882 624411d2 2023-07-08 jrick }
7883 624411d2 2023-07-08 jrick
7884 624411d2 2023-07-08 jrick if (error != NULL)
7885 624411d2 2023-07-08 jrick fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
7886 624411d2 2023-07-08 jrick
7887 624411d2 2023-07-08 jrick if (offset != 0 || hunk_err != NULL || ws_mangled) {
7888 624411d2 2023-07-08 jrick printf("@@ -%d,%d +%d,%d @@ ", old_from,
7889 624411d2 2023-07-08 jrick old_lines, new_from, new_lines);
7890 624411d2 2023-07-08 jrick if (hunk_err != NULL)
7891 624411d2 2023-07-08 jrick printf("%s\n", hunk_err->msg);
7892 624411d2 2023-07-08 jrick else if (offset != 0)
7893 624411d2 2023-07-08 jrick printf("applied with offset %d\n", offset);
7894 624411d2 2023-07-08 jrick else
7895 624411d2 2023-07-08 jrick printf("hunk contains mangled whitespace\n");
7896 624411d2 2023-07-08 jrick }
7897 624411d2 2023-07-08 jrick
7898 624411d2 2023-07-08 jrick return NULL;
7899 624411d2 2023-07-08 jrick }
7900 624411d2 2023-07-08 jrick
7901 624411d2 2023-07-08 jrick static void
7902 624411d2 2023-07-08 jrick print_patch_progress_stats(struct got_patch_progress_arg *ppa)
7903 624411d2 2023-07-08 jrick {
7904 624411d2 2023-07-08 jrick if (!ppa->did_something)
7905 624411d2 2023-07-08 jrick return;
7906 624411d2 2023-07-08 jrick
7907 624411d2 2023-07-08 jrick if (ppa->conflicts > 0)
7908 624411d2 2023-07-08 jrick printf("Files with merge conflicts: %d\n", ppa->conflicts);
7909 624411d2 2023-07-08 jrick
7910 624411d2 2023-07-08 jrick if (ppa->rejects > 0) {
7911 624411d2 2023-07-08 jrick printf("Files where patch failed to apply: %d\n",
7912 624411d2 2023-07-08 jrick ppa->rejects);
7913 624411d2 2023-07-08 jrick }
7914 624411d2 2023-07-08 jrick }
7915 624411d2 2023-07-08 jrick
7916 624411d2 2023-07-08 jrick static const struct got_error *
7917 624411d2 2023-07-08 jrick cmd_patch(int argc, char *argv[])
7918 624411d2 2023-07-08 jrick {
7919 624411d2 2023-07-08 jrick const struct got_error *error = NULL, *close_error = NULL;
7920 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7921 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7922 624411d2 2023-07-08 jrick struct got_reflist_head refs;
7923 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
7924 624411d2 2023-07-08 jrick const char *commit_id_str = NULL;
7925 624411d2 2023-07-08 jrick struct stat sb;
7926 624411d2 2023-07-08 jrick const char *errstr;
7927 624411d2 2023-07-08 jrick char *cwd = NULL;
7928 624411d2 2023-07-08 jrick int ch, nop = 0, strip = -1, reverse = 0;
7929 624411d2 2023-07-08 jrick int patchfd;
7930 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7931 624411d2 2023-07-08 jrick struct got_patch_progress_arg ppa;
7932 624411d2 2023-07-08 jrick
7933 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
7934 624411d2 2023-07-08 jrick
7935 624411d2 2023-07-08 jrick #ifndef PROFILE
7936 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock "
7937 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
7938 624411d2 2023-07-08 jrick err(1, "pledge");
7939 624411d2 2023-07-08 jrick #endif
7940 624411d2 2023-07-08 jrick
7941 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:np:R")) != -1) {
7942 624411d2 2023-07-08 jrick switch (ch) {
7943 624411d2 2023-07-08 jrick case 'c':
7944 624411d2 2023-07-08 jrick commit_id_str = optarg;
7945 624411d2 2023-07-08 jrick break;
7946 624411d2 2023-07-08 jrick case 'n':
7947 624411d2 2023-07-08 jrick nop = 1;
7948 624411d2 2023-07-08 jrick break;
7949 624411d2 2023-07-08 jrick case 'p':
7950 624411d2 2023-07-08 jrick strip = strtonum(optarg, 0, INT_MAX, &errstr);
7951 624411d2 2023-07-08 jrick if (errstr != NULL)
7952 624411d2 2023-07-08 jrick errx(1, "pathname strip count is %s: %s",
7953 624411d2 2023-07-08 jrick errstr, optarg);
7954 624411d2 2023-07-08 jrick break;
7955 624411d2 2023-07-08 jrick case 'R':
7956 624411d2 2023-07-08 jrick reverse = 1;
7957 624411d2 2023-07-08 jrick break;
7958 624411d2 2023-07-08 jrick default:
7959 624411d2 2023-07-08 jrick usage_patch();
7960 624411d2 2023-07-08 jrick /* NOTREACHED */
7961 624411d2 2023-07-08 jrick }
7962 624411d2 2023-07-08 jrick }
7963 624411d2 2023-07-08 jrick
7964 624411d2 2023-07-08 jrick argc -= optind;
7965 624411d2 2023-07-08 jrick argv += optind;
7966 624411d2 2023-07-08 jrick
7967 624411d2 2023-07-08 jrick if (argc == 0) {
7968 624411d2 2023-07-08 jrick error = patch_from_stdin(&patchfd);
7969 624411d2 2023-07-08 jrick if (error)
7970 624411d2 2023-07-08 jrick return error;
7971 624411d2 2023-07-08 jrick } else if (argc == 1) {
7972 624411d2 2023-07-08 jrick patchfd = open(argv[0], O_RDONLY);
7973 624411d2 2023-07-08 jrick if (patchfd == -1) {
7974 624411d2 2023-07-08 jrick error = got_error_from_errno2("open", argv[0]);
7975 624411d2 2023-07-08 jrick return error;
7976 624411d2 2023-07-08 jrick }
7977 624411d2 2023-07-08 jrick if (fstat(patchfd, &sb) == -1) {
7978 624411d2 2023-07-08 jrick error = got_error_from_errno2("fstat", argv[0]);
7979 624411d2 2023-07-08 jrick goto done;
7980 624411d2 2023-07-08 jrick }
7981 624411d2 2023-07-08 jrick if (!S_ISREG(sb.st_mode)) {
7982 624411d2 2023-07-08 jrick error = got_error_path(argv[0], GOT_ERR_BAD_FILETYPE);
7983 624411d2 2023-07-08 jrick goto done;
7984 624411d2 2023-07-08 jrick }
7985 624411d2 2023-07-08 jrick } else
7986 624411d2 2023-07-08 jrick usage_patch();
7987 624411d2 2023-07-08 jrick
7988 624411d2 2023-07-08 jrick if ((cwd = getcwd(NULL, 0)) == NULL) {
7989 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7990 624411d2 2023-07-08 jrick goto done;
7991 624411d2 2023-07-08 jrick }
7992 624411d2 2023-07-08 jrick
7993 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7994 624411d2 2023-07-08 jrick if (error != NULL)
7995 624411d2 2023-07-08 jrick goto done;
7996 624411d2 2023-07-08 jrick
7997 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7998 624411d2 2023-07-08 jrick if (error != NULL)
7999 624411d2 2023-07-08 jrick goto done;
8000 624411d2 2023-07-08 jrick
8001 624411d2 2023-07-08 jrick const char *repo_path = got_worktree_get_repo_path(worktree);
8002 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
8003 624411d2 2023-07-08 jrick if (error != NULL)
8004 624411d2 2023-07-08 jrick goto done;
8005 624411d2 2023-07-08 jrick
8006 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
8007 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
8008 624411d2 2023-07-08 jrick if (error != NULL)
8009 624411d2 2023-07-08 jrick goto done;
8010 624411d2 2023-07-08 jrick
8011 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
8012 624411d2 2023-07-08 jrick if (error)
8013 624411d2 2023-07-08 jrick goto done;
8014 624411d2 2023-07-08 jrick
8015 624411d2 2023-07-08 jrick if (commit_id_str != NULL) {
8016 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
8017 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
8018 624411d2 2023-07-08 jrick if (error)
8019 624411d2 2023-07-08 jrick goto done;
8020 624411d2 2023-07-08 jrick }
8021 624411d2 2023-07-08 jrick
8022 624411d2 2023-07-08 jrick memset(&ppa, 0, sizeof(ppa));
8023 624411d2 2023-07-08 jrick error = got_patch(patchfd, worktree, repo, nop, strip, reverse,
8024 624411d2 2023-07-08 jrick commit_id, patch_progress, &ppa, check_cancelled, NULL);
8025 624411d2 2023-07-08 jrick print_patch_progress_stats(&ppa);
8026 624411d2 2023-07-08 jrick done:
8027 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8028 624411d2 2023-07-08 jrick free(commit_id);
8029 624411d2 2023-07-08 jrick if (repo) {
8030 624411d2 2023-07-08 jrick close_error = got_repo_close(repo);
8031 624411d2 2023-07-08 jrick if (error == NULL)
8032 624411d2 2023-07-08 jrick error = close_error;
8033 624411d2 2023-07-08 jrick }
8034 624411d2 2023-07-08 jrick if (worktree != NULL) {
8035 624411d2 2023-07-08 jrick close_error = got_worktree_close(worktree);
8036 624411d2 2023-07-08 jrick if (error == NULL)
8037 624411d2 2023-07-08 jrick error = close_error;
8038 624411d2 2023-07-08 jrick }
8039 624411d2 2023-07-08 jrick if (pack_fds) {
8040 624411d2 2023-07-08 jrick const struct got_error *pack_err =
8041 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
8042 624411d2 2023-07-08 jrick if (error == NULL)
8043 624411d2 2023-07-08 jrick error = pack_err;
8044 624411d2 2023-07-08 jrick }
8045 624411d2 2023-07-08 jrick free(cwd);
8046 624411d2 2023-07-08 jrick return error;
8047 624411d2 2023-07-08 jrick }
8048 624411d2 2023-07-08 jrick
8049 624411d2 2023-07-08 jrick __dead static void
8050 624411d2 2023-07-08 jrick usage_revert(void)
8051 624411d2 2023-07-08 jrick {
8052 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n",
8053 624411d2 2023-07-08 jrick getprogname());
8054 624411d2 2023-07-08 jrick exit(1);
8055 624411d2 2023-07-08 jrick }
8056 624411d2 2023-07-08 jrick
8057 624411d2 2023-07-08 jrick static const struct got_error *
8058 624411d2 2023-07-08 jrick revert_progress(void *arg, unsigned char status, const char *path)
8059 624411d2 2023-07-08 jrick {
8060 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
8061 624411d2 2023-07-08 jrick return NULL;
8062 624411d2 2023-07-08 jrick
8063 624411d2 2023-07-08 jrick while (path[0] == '/')
8064 624411d2 2023-07-08 jrick path++;
8065 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
8066 624411d2 2023-07-08 jrick return NULL;
8067 624411d2 2023-07-08 jrick }
8068 624411d2 2023-07-08 jrick
8069 624411d2 2023-07-08 jrick struct choose_patch_arg {
8070 624411d2 2023-07-08 jrick FILE *patch_script_file;
8071 624411d2 2023-07-08 jrick const char *action;
8072 624411d2 2023-07-08 jrick };
8073 624411d2 2023-07-08 jrick
8074 624411d2 2023-07-08 jrick static const struct got_error *
8075 624411d2 2023-07-08 jrick show_change(unsigned char status, const char *path, FILE *patch_file, int n,
8076 624411d2 2023-07-08 jrick int nchanges, const char *action)
8077 624411d2 2023-07-08 jrick {
8078 624411d2 2023-07-08 jrick const struct got_error *err;
8079 624411d2 2023-07-08 jrick char *line = NULL;
8080 624411d2 2023-07-08 jrick size_t linesize = 0;
8081 624411d2 2023-07-08 jrick ssize_t linelen;
8082 624411d2 2023-07-08 jrick
8083 624411d2 2023-07-08 jrick switch (status) {
8084 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
8085 624411d2 2023-07-08 jrick printf("A %s\n%s this addition? [y/n] ", path, action);
8086 624411d2 2023-07-08 jrick break;
8087 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
8088 624411d2 2023-07-08 jrick printf("D %s\n%s this deletion? [y/n] ", path, action);
8089 624411d2 2023-07-08 jrick break;
8090 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
8091 624411d2 2023-07-08 jrick if (fseek(patch_file, 0L, SEEK_SET) == -1)
8092 624411d2 2023-07-08 jrick return got_error_from_errno("fseek");
8093 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
8094 624411d2 2023-07-08 jrick while ((linelen = getline(&line, &linesize, patch_file)) != -1)
8095 624411d2 2023-07-08 jrick printf("%s", line);
8096 624411d2 2023-07-08 jrick if (linelen == -1 && ferror(patch_file)) {
8097 624411d2 2023-07-08 jrick err = got_error_from_errno("getline");
8098 624411d2 2023-07-08 jrick free(line);
8099 624411d2 2023-07-08 jrick return err;
8100 624411d2 2023-07-08 jrick }
8101 624411d2 2023-07-08 jrick free(line);
8102 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
8103 624411d2 2023-07-08 jrick printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
8104 624411d2 2023-07-08 jrick path, n, nchanges, action);
8105 624411d2 2023-07-08 jrick break;
8106 624411d2 2023-07-08 jrick default:
8107 624411d2 2023-07-08 jrick return got_error_path(path, GOT_ERR_FILE_STATUS);
8108 624411d2 2023-07-08 jrick }
8109 624411d2 2023-07-08 jrick
8110 624411d2 2023-07-08 jrick fflush(stdout);
8111 624411d2 2023-07-08 jrick return NULL;
8112 624411d2 2023-07-08 jrick }
8113 624411d2 2023-07-08 jrick
8114 624411d2 2023-07-08 jrick static const struct got_error *
8115 624411d2 2023-07-08 jrick choose_patch(int *choice, void *arg, unsigned char status, const char *path,
8116 624411d2 2023-07-08 jrick FILE *patch_file, int n, int nchanges)
8117 624411d2 2023-07-08 jrick {
8118 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8119 624411d2 2023-07-08 jrick char *line = NULL;
8120 624411d2 2023-07-08 jrick size_t linesize = 0;
8121 624411d2 2023-07-08 jrick ssize_t linelen;
8122 624411d2 2023-07-08 jrick int resp = ' ';
8123 624411d2 2023-07-08 jrick struct choose_patch_arg *a = arg;
8124 624411d2 2023-07-08 jrick
8125 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NONE;
8126 624411d2 2023-07-08 jrick
8127 624411d2 2023-07-08 jrick if (a->patch_script_file) {
8128 624411d2 2023-07-08 jrick char *nl;
8129 624411d2 2023-07-08 jrick err = show_change(status, path, patch_file, n, nchanges,
8130 624411d2 2023-07-08 jrick a->action);
8131 624411d2 2023-07-08 jrick if (err)
8132 624411d2 2023-07-08 jrick return err;
8133 624411d2 2023-07-08 jrick linelen = getline(&line, &linesize, a->patch_script_file);
8134 624411d2 2023-07-08 jrick if (linelen == -1) {
8135 624411d2 2023-07-08 jrick if (ferror(a->patch_script_file))
8136 624411d2 2023-07-08 jrick return got_error_from_errno("getline");
8137 624411d2 2023-07-08 jrick return NULL;
8138 624411d2 2023-07-08 jrick }
8139 624411d2 2023-07-08 jrick nl = strchr(line, '\n');
8140 624411d2 2023-07-08 jrick if (nl)
8141 624411d2 2023-07-08 jrick *nl = '\0';
8142 624411d2 2023-07-08 jrick if (strcmp(line, "y") == 0) {
8143 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_YES;
8144 624411d2 2023-07-08 jrick printf("y\n");
8145 624411d2 2023-07-08 jrick } else if (strcmp(line, "n") == 0) {
8146 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NO;
8147 624411d2 2023-07-08 jrick printf("n\n");
8148 624411d2 2023-07-08 jrick } else if (strcmp(line, "q") == 0 &&
8149 624411d2 2023-07-08 jrick status == GOT_STATUS_MODIFY) {
8150 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_QUIT;
8151 624411d2 2023-07-08 jrick printf("q\n");
8152 624411d2 2023-07-08 jrick } else
8153 624411d2 2023-07-08 jrick printf("invalid response '%s'\n", line);
8154 624411d2 2023-07-08 jrick free(line);
8155 624411d2 2023-07-08 jrick return NULL;
8156 624411d2 2023-07-08 jrick }
8157 624411d2 2023-07-08 jrick
8158 624411d2 2023-07-08 jrick while (resp != 'y' && resp != 'n' && resp != 'q') {
8159 624411d2 2023-07-08 jrick err = show_change(status, path, patch_file, n, nchanges,
8160 624411d2 2023-07-08 jrick a->action);
8161 624411d2 2023-07-08 jrick if (err)
8162 624411d2 2023-07-08 jrick return err;
8163 624411d2 2023-07-08 jrick resp = getchar();
8164 624411d2 2023-07-08 jrick if (resp == '\n')
8165 624411d2 2023-07-08 jrick resp = getchar();
8166 624411d2 2023-07-08 jrick if (status == GOT_STATUS_MODIFY) {
8167 624411d2 2023-07-08 jrick if (resp != 'y' && resp != 'n' && resp != 'q') {
8168 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
8169 624411d2 2023-07-08 jrick resp = ' ';
8170 624411d2 2023-07-08 jrick }
8171 624411d2 2023-07-08 jrick } else if (resp != 'y' && resp != 'n') {
8172 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
8173 624411d2 2023-07-08 jrick resp = ' ';
8174 624411d2 2023-07-08 jrick }
8175 624411d2 2023-07-08 jrick }
8176 624411d2 2023-07-08 jrick
8177 624411d2 2023-07-08 jrick if (resp == 'y')
8178 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_YES;
8179 624411d2 2023-07-08 jrick else if (resp == 'n')
8180 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NO;
8181 624411d2 2023-07-08 jrick else if (resp == 'q' && status == GOT_STATUS_MODIFY)
8182 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_QUIT;
8183 624411d2 2023-07-08 jrick
8184 624411d2 2023-07-08 jrick return NULL;
8185 624411d2 2023-07-08 jrick }
8186 624411d2 2023-07-08 jrick
8187 624411d2 2023-07-08 jrick struct wt_commitable_path_arg {
8188 624411d2 2023-07-08 jrick struct got_pathlist_head *commit_paths;
8189 624411d2 2023-07-08 jrick int *has_changes;
8190 624411d2 2023-07-08 jrick };
8191 624411d2 2023-07-08 jrick
8192 624411d2 2023-07-08 jrick /*
8193 624411d2 2023-07-08 jrick * Shortcut work tree status callback to determine if the set of paths scanned
8194 624411d2 2023-07-08 jrick * has at least one versioned path that is being modified and, if not NULL, is
8195 624411d2 2023-07-08 jrick * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as
8196 624411d2 2023-07-08 jrick * soon as a path is passed with a status that satisfies this criteria.
8197 624411d2 2023-07-08 jrick */
8198 624411d2 2023-07-08 jrick static const struct got_error *
8199 624411d2 2023-07-08 jrick worktree_has_commitable_path(void *arg, unsigned char status,
8200 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path,
8201 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8202 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int dirfd, const char *de_name)
8203 624411d2 2023-07-08 jrick {
8204 624411d2 2023-07-08 jrick struct wt_commitable_path_arg *a = arg;
8205 624411d2 2023-07-08 jrick
8206 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
8207 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
8208 624411d2 2023-07-08 jrick
8209 624411d2 2023-07-08 jrick if (!(status == GOT_STATUS_NO_CHANGE ||
8210 624411d2 2023-07-08 jrick status == GOT_STATUS_UNVERSIONED) ||
8211 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_NO_CHANGE) {
8212 624411d2 2023-07-08 jrick if (a->commit_paths != NULL) {
8213 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8214 624411d2 2023-07-08 jrick
8215 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, a->commit_paths, entry) {
8216 624411d2 2023-07-08 jrick if (strncmp(path, pe->path,
8217 624411d2 2023-07-08 jrick pe->path_len) == 0) {
8218 624411d2 2023-07-08 jrick *a->has_changes = 1;
8219 624411d2 2023-07-08 jrick break;
8220 624411d2 2023-07-08 jrick }
8221 624411d2 2023-07-08 jrick }
8222 624411d2 2023-07-08 jrick } else
8223 624411d2 2023-07-08 jrick *a->has_changes = 1;
8224 624411d2 2023-07-08 jrick
8225 624411d2 2023-07-08 jrick if (*a->has_changes)
8226 624411d2 2023-07-08 jrick return got_error(GOT_ERR_FILE_MODIFIED);
8227 624411d2 2023-07-08 jrick }
8228 624411d2 2023-07-08 jrick
8229 624411d2 2023-07-08 jrick return NULL;
8230 624411d2 2023-07-08 jrick }
8231 624411d2 2023-07-08 jrick
8232 624411d2 2023-07-08 jrick /*
8233 624411d2 2023-07-08 jrick * Check that the changeset of the commit identified by id is
8234 624411d2 2023-07-08 jrick * comprised of at least one modified path that is being committed.
8235 624411d2 2023-07-08 jrick */
8236 624411d2 2023-07-08 jrick static const struct got_error *
8237 624411d2 2023-07-08 jrick commit_path_changed_in_worktree(struct wt_commitable_path_arg *wcpa,
8238 624411d2 2023-07-08 jrick struct got_object_id *id, struct got_worktree *worktree,
8239 624411d2 2023-07-08 jrick struct got_repository *repo)
8240 624411d2 2023-07-08 jrick {
8241 624411d2 2023-07-08 jrick const struct got_error *err;
8242 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8243 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL, *pcommit = NULL;
8244 624411d2 2023-07-08 jrick struct got_tree_object *tree = NULL, *ptree = NULL;
8245 624411d2 2023-07-08 jrick struct got_object_qid *pid;
8246 624411d2 2023-07-08 jrick
8247 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8248 624411d2 2023-07-08 jrick
8249 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
8250 624411d2 2023-07-08 jrick if (err)
8251 624411d2 2023-07-08 jrick goto done;
8252 624411d2 2023-07-08 jrick
8253 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo,
8254 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(commit));
8255 624411d2 2023-07-08 jrick if (err)
8256 624411d2 2023-07-08 jrick goto done;
8257 624411d2 2023-07-08 jrick
8258 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8259 624411d2 2023-07-08 jrick if (pid != NULL) {
8260 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo, &pid->id);
8261 624411d2 2023-07-08 jrick if (err)
8262 624411d2 2023-07-08 jrick goto done;
8263 624411d2 2023-07-08 jrick
8264 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&ptree, repo,
8265 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(pcommit));
8266 624411d2 2023-07-08 jrick if (err)
8267 624411d2 2023-07-08 jrick goto done;
8268 624411d2 2023-07-08 jrick }
8269 624411d2 2023-07-08 jrick
8270 624411d2 2023-07-08 jrick err = got_diff_tree(ptree, tree, NULL, NULL, -1, -1, "", "", repo,
8271 624411d2 2023-07-08 jrick got_diff_tree_collect_changed_paths, &paths, 0);
8272 624411d2 2023-07-08 jrick if (err)
8273 624411d2 2023-07-08 jrick goto done;
8274 624411d2 2023-07-08 jrick
8275 624411d2 2023-07-08 jrick err = got_worktree_status(worktree, &paths, repo, 0,
8276 624411d2 2023-07-08 jrick worktree_has_commitable_path, wcpa, check_cancelled, NULL);
8277 624411d2 2023-07-08 jrick if (err && err->code == GOT_ERR_FILE_MODIFIED) {
8278 624411d2 2023-07-08 jrick /*
8279 624411d2 2023-07-08 jrick * At least one changed path in the referenced commit is
8280 624411d2 2023-07-08 jrick * modified in the work tree, that's all we need to know!
8281 624411d2 2023-07-08 jrick */
8282 624411d2 2023-07-08 jrick err = NULL;
8283 624411d2 2023-07-08 jrick }
8284 624411d2 2023-07-08 jrick
8285 624411d2 2023-07-08 jrick done:
8286 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
8287 624411d2 2023-07-08 jrick if (commit)
8288 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8289 624411d2 2023-07-08 jrick if (pcommit)
8290 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
8291 624411d2 2023-07-08 jrick if (tree)
8292 624411d2 2023-07-08 jrick got_object_tree_close(tree);
8293 624411d2 2023-07-08 jrick if (ptree)
8294 624411d2 2023-07-08 jrick got_object_tree_close(ptree);
8295 624411d2 2023-07-08 jrick return err;
8296 624411d2 2023-07-08 jrick }
8297 624411d2 2023-07-08 jrick
8298 624411d2 2023-07-08 jrick /*
8299 624411d2 2023-07-08 jrick * Remove any "logmsg" reference comprised entirely of paths that have
8300 624411d2 2023-07-08 jrick * been reverted in this work tree. If any path in the logmsg ref changeset
8301 624411d2 2023-07-08 jrick * remains in a changed state in the worktree, do not remove the reference.
8302 624411d2 2023-07-08 jrick */
8303 624411d2 2023-07-08 jrick static const struct got_error *
8304 624411d2 2023-07-08 jrick rm_logmsg_ref(struct got_worktree *worktree, struct got_repository *repo)
8305 624411d2 2023-07-08 jrick {
8306 624411d2 2023-07-08 jrick const struct got_error *err;
8307 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8308 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
8309 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
8310 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
8311 624411d2 2023-07-08 jrick struct wt_commitable_path_arg wcpa;
8312 624411d2 2023-07-08 jrick char *uuidstr = NULL;
8313 624411d2 2023-07-08 jrick
8314 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8315 624411d2 2023-07-08 jrick
8316 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
8317 624411d2 2023-07-08 jrick if (err)
8318 624411d2 2023-07-08 jrick goto done;
8319 624411d2 2023-07-08 jrick
8320 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
8321 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
8322 624411d2 2023-07-08 jrick if (err)
8323 624411d2 2023-07-08 jrick goto done;
8324 624411d2 2023-07-08 jrick
8325 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
8326 624411d2 2023-07-08 jrick const char *refname;
8327 624411d2 2023-07-08 jrick int has_changes = 0;
8328 624411d2 2023-07-08 jrick
8329 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
8330 624411d2 2023-07-08 jrick
8331 624411d2 2023-07-08 jrick if (!strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
8332 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN))
8333 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
8334 624411d2 2023-07-08 jrick else if (!strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
8335 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN))
8336 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
8337 624411d2 2023-07-08 jrick else
8338 624411d2 2023-07-08 jrick continue;
8339 624411d2 2023-07-08 jrick
8340 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0)
8341 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
8342 624411d2 2023-07-08 jrick else
8343 624411d2 2023-07-08 jrick continue;
8344 624411d2 2023-07-08 jrick
8345 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&commit_id, NULL, refname,
8346 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
8347 624411d2 2023-07-08 jrick if (err)
8348 624411d2 2023-07-08 jrick goto done;
8349 624411d2 2023-07-08 jrick
8350 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
8351 624411d2 2023-07-08 jrick if (err)
8352 624411d2 2023-07-08 jrick goto done;
8353 624411d2 2023-07-08 jrick
8354 624411d2 2023-07-08 jrick wcpa.commit_paths = NULL;
8355 624411d2 2023-07-08 jrick wcpa.has_changes = &has_changes;
8356 624411d2 2023-07-08 jrick
8357 624411d2 2023-07-08 jrick err = commit_path_changed_in_worktree(&wcpa, commit_id,
8358 624411d2 2023-07-08 jrick worktree, repo);
8359 624411d2 2023-07-08 jrick if (err)
8360 624411d2 2023-07-08 jrick goto done;
8361 624411d2 2023-07-08 jrick
8362 624411d2 2023-07-08 jrick if (!has_changes) {
8363 624411d2 2023-07-08 jrick err = got_ref_delete(re->ref, repo);
8364 624411d2 2023-07-08 jrick if (err)
8365 624411d2 2023-07-08 jrick goto done;
8366 624411d2 2023-07-08 jrick }
8367 624411d2 2023-07-08 jrick
8368 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8369 624411d2 2023-07-08 jrick commit = NULL;
8370 624411d2 2023-07-08 jrick free(commit_id);
8371 624411d2 2023-07-08 jrick commit_id = NULL;
8372 624411d2 2023-07-08 jrick }
8373 624411d2 2023-07-08 jrick
8374 624411d2 2023-07-08 jrick done:
8375 624411d2 2023-07-08 jrick free(uuidstr);
8376 624411d2 2023-07-08 jrick free(commit_id);
8377 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8378 624411d2 2023-07-08 jrick if (commit)
8379 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8380 624411d2 2023-07-08 jrick return err;
8381 624411d2 2023-07-08 jrick }
8382 624411d2 2023-07-08 jrick
8383 624411d2 2023-07-08 jrick static const struct got_error *
8384 624411d2 2023-07-08 jrick cmd_revert(int argc, char *argv[])
8385 624411d2 2023-07-08 jrick {
8386 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
8387 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
8388 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
8389 624411d2 2023-07-08 jrick char *cwd = NULL, *path = NULL;
8390 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8391 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8392 624411d2 2023-07-08 jrick int ch, can_recurse = 0, pflag = 0;
8393 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
8394 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
8395 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
8396 624411d2 2023-07-08 jrick int *pack_fds = NULL;
8397 624411d2 2023-07-08 jrick
8398 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8399 624411d2 2023-07-08 jrick
8400 624411d2 2023-07-08 jrick #ifndef PROFILE
8401 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8402 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
8403 624411d2 2023-07-08 jrick err(1, "pledge");
8404 624411d2 2023-07-08 jrick #endif
8405 624411d2 2023-07-08 jrick
8406 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:pR")) != -1) {
8407 624411d2 2023-07-08 jrick switch (ch) {
8408 624411d2 2023-07-08 jrick case 'F':
8409 624411d2 2023-07-08 jrick patch_script_path = optarg;
8410 624411d2 2023-07-08 jrick break;
8411 624411d2 2023-07-08 jrick case 'p':
8412 624411d2 2023-07-08 jrick pflag = 1;
8413 624411d2 2023-07-08 jrick break;
8414 624411d2 2023-07-08 jrick case 'R':
8415 624411d2 2023-07-08 jrick can_recurse = 1;
8416 624411d2 2023-07-08 jrick break;
8417 624411d2 2023-07-08 jrick default:
8418 624411d2 2023-07-08 jrick usage_revert();
8419 624411d2 2023-07-08 jrick /* NOTREACHED */
8420 624411d2 2023-07-08 jrick }
8421 624411d2 2023-07-08 jrick }
8422 624411d2 2023-07-08 jrick
8423 624411d2 2023-07-08 jrick argc -= optind;
8424 624411d2 2023-07-08 jrick argv += optind;
8425 624411d2 2023-07-08 jrick
8426 624411d2 2023-07-08 jrick if (argc < 1)
8427 624411d2 2023-07-08 jrick usage_revert();
8428 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
8429 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
8430 624411d2 2023-07-08 jrick
8431 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
8432 624411d2 2023-07-08 jrick if (cwd == NULL) {
8433 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
8434 624411d2 2023-07-08 jrick goto done;
8435 624411d2 2023-07-08 jrick }
8436 624411d2 2023-07-08 jrick
8437 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
8438 624411d2 2023-07-08 jrick if (error != NULL)
8439 624411d2 2023-07-08 jrick goto done;
8440 624411d2 2023-07-08 jrick
8441 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
8442 624411d2 2023-07-08 jrick if (error) {
8443 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
8444 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "revert", cwd);
8445 624411d2 2023-07-08 jrick goto done;
8446 624411d2 2023-07-08 jrick }
8447 624411d2 2023-07-08 jrick
8448 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8449 624411d2 2023-07-08 jrick NULL, pack_fds);
8450 624411d2 2023-07-08 jrick if (error != NULL)
8451 624411d2 2023-07-08 jrick goto done;
8452 624411d2 2023-07-08 jrick
8453 624411d2 2023-07-08 jrick if (patch_script_path) {
8454 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
8455 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
8456 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
8457 624411d2 2023-07-08 jrick patch_script_path);
8458 624411d2 2023-07-08 jrick goto done;
8459 624411d2 2023-07-08 jrick }
8460 624411d2 2023-07-08 jrick }
8461 624411d2 2023-07-08 jrick
8462 624411d2 2023-07-08 jrick /*
8463 624411d2 2023-07-08 jrick * XXX "c" perm needed on repo dir to delete merge references.
8464 624411d2 2023-07-08 jrick */
8465 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
8466 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
8467 624411d2 2023-07-08 jrick if (error)
8468 624411d2 2023-07-08 jrick goto done;
8469 624411d2 2023-07-08 jrick
8470 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
8471 624411d2 2023-07-08 jrick if (error)
8472 624411d2 2023-07-08 jrick goto done;
8473 624411d2 2023-07-08 jrick
8474 624411d2 2023-07-08 jrick if (!can_recurse) {
8475 624411d2 2023-07-08 jrick char *ondisk_path;
8476 624411d2 2023-07-08 jrick struct stat sb;
8477 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
8478 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
8479 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
8480 624411d2 2023-07-08 jrick pe->path) == -1) {
8481 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
8482 624411d2 2023-07-08 jrick goto done;
8483 624411d2 2023-07-08 jrick }
8484 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
8485 624411d2 2023-07-08 jrick if (errno == ENOENT) {
8486 624411d2 2023-07-08 jrick free(ondisk_path);
8487 624411d2 2023-07-08 jrick continue;
8488 624411d2 2023-07-08 jrick }
8489 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
8490 624411d2 2023-07-08 jrick ondisk_path);
8491 624411d2 2023-07-08 jrick free(ondisk_path);
8492 624411d2 2023-07-08 jrick goto done;
8493 624411d2 2023-07-08 jrick }
8494 624411d2 2023-07-08 jrick free(ondisk_path);
8495 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
8496 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
8497 624411d2 2023-07-08 jrick "reverting directories requires -R option");
8498 624411d2 2023-07-08 jrick goto done;
8499 624411d2 2023-07-08 jrick }
8500 624411d2 2023-07-08 jrick }
8501 624411d2 2023-07-08 jrick }
8502 624411d2 2023-07-08 jrick
8503 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
8504 624411d2 2023-07-08 jrick cpa.action = "revert";
8505 624411d2 2023-07-08 jrick error = got_worktree_revert(worktree, &paths, revert_progress, NULL,
8506 624411d2 2023-07-08 jrick pflag ? choose_patch : NULL, &cpa, repo);
8507 624411d2 2023-07-08 jrick
8508 624411d2 2023-07-08 jrick error = rm_logmsg_ref(worktree, repo);
8509 624411d2 2023-07-08 jrick done:
8510 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
8511 624411d2 2023-07-08 jrick error == NULL)
8512 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
8513 624411d2 2023-07-08 jrick if (repo) {
8514 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
8515 624411d2 2023-07-08 jrick if (error == NULL)
8516 624411d2 2023-07-08 jrick error = close_err;
8517 624411d2 2023-07-08 jrick }
8518 624411d2 2023-07-08 jrick if (worktree)
8519 624411d2 2023-07-08 jrick got_worktree_close(worktree);
8520 624411d2 2023-07-08 jrick if (pack_fds) {
8521 624411d2 2023-07-08 jrick const struct got_error *pack_err =
8522 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
8523 624411d2 2023-07-08 jrick if (error == NULL)
8524 624411d2 2023-07-08 jrick error = pack_err;
8525 624411d2 2023-07-08 jrick }
8526 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
8527 624411d2 2023-07-08 jrick free(path);
8528 624411d2 2023-07-08 jrick free(cwd);
8529 624411d2 2023-07-08 jrick return error;
8530 624411d2 2023-07-08 jrick }
8531 624411d2 2023-07-08 jrick
8532 624411d2 2023-07-08 jrick __dead static void
8533 624411d2 2023-07-08 jrick usage_commit(void)
8534 624411d2 2023-07-08 jrick {
8535 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s commit [-CNnS] [-A author] [-F path] "
8536 624411d2 2023-07-08 jrick "[-m message] [path ...]\n", getprogname());
8537 624411d2 2023-07-08 jrick exit(1);
8538 624411d2 2023-07-08 jrick }
8539 624411d2 2023-07-08 jrick
8540 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg {
8541 624411d2 2023-07-08 jrick const char *cmdline_log;
8542 624411d2 2023-07-08 jrick const char *prepared_log;
8543 624411d2 2023-07-08 jrick const char *merged_log;
8544 624411d2 2023-07-08 jrick int non_interactive;
8545 624411d2 2023-07-08 jrick const char *editor;
8546 624411d2 2023-07-08 jrick const char *worktree_path;
8547 624411d2 2023-07-08 jrick const char *repo_path;
8548 3d1b16d1 2023-07-08 jrick const char *dial_proto;
8549 624411d2 2023-07-08 jrick char *logmsg_path;
8550 624411d2 2023-07-08 jrick };
8551 624411d2 2023-07-08 jrick
8552 624411d2 2023-07-08 jrick static const struct got_error *
8553 624411d2 2023-07-08 jrick read_prepared_logmsg(char **logmsg, const char *path)
8554 624411d2 2023-07-08 jrick {
8555 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8556 624411d2 2023-07-08 jrick FILE *f = NULL;
8557 624411d2 2023-07-08 jrick struct stat sb;
8558 624411d2 2023-07-08 jrick size_t r;
8559 624411d2 2023-07-08 jrick
8560 624411d2 2023-07-08 jrick *logmsg = NULL;
8561 624411d2 2023-07-08 jrick memset(&sb, 0, sizeof(sb));
8562 624411d2 2023-07-08 jrick
8563 624411d2 2023-07-08 jrick f = fopen(path, "re");
8564 624411d2 2023-07-08 jrick if (f == NULL)
8565 624411d2 2023-07-08 jrick return got_error_from_errno2("fopen", path);
8566 624411d2 2023-07-08 jrick
8567 624411d2 2023-07-08 jrick if (fstat(fileno(f), &sb) == -1) {
8568 624411d2 2023-07-08 jrick err = got_error_from_errno2("fstat", path);
8569 624411d2 2023-07-08 jrick goto done;
8570 624411d2 2023-07-08 jrick }
8571 624411d2 2023-07-08 jrick if (sb.st_size == 0) {
8572 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
8573 624411d2 2023-07-08 jrick goto done;
8574 624411d2 2023-07-08 jrick }
8575 624411d2 2023-07-08 jrick
8576 624411d2 2023-07-08 jrick *logmsg = malloc(sb.st_size + 1);
8577 624411d2 2023-07-08 jrick if (*logmsg == NULL) {
8578 624411d2 2023-07-08 jrick err = got_error_from_errno("malloc");
8579 624411d2 2023-07-08 jrick goto done;
8580 624411d2 2023-07-08 jrick }
8581 624411d2 2023-07-08 jrick
8582 624411d2 2023-07-08 jrick r = fread(*logmsg, 1, sb.st_size, f);
8583 624411d2 2023-07-08 jrick if (r != sb.st_size) {
8584 624411d2 2023-07-08 jrick if (ferror(f))
8585 624411d2 2023-07-08 jrick err = got_error_from_errno2("fread", path);
8586 624411d2 2023-07-08 jrick else
8587 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_IO);
8588 624411d2 2023-07-08 jrick goto done;
8589 624411d2 2023-07-08 jrick }
8590 624411d2 2023-07-08 jrick (*logmsg)[sb.st_size] = '\0';
8591 624411d2 2023-07-08 jrick done:
8592 624411d2 2023-07-08 jrick if (fclose(f) == EOF && err == NULL)
8593 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", path);
8594 624411d2 2023-07-08 jrick if (err) {
8595 624411d2 2023-07-08 jrick free(*logmsg);
8596 624411d2 2023-07-08 jrick *logmsg = NULL;
8597 624411d2 2023-07-08 jrick }
8598 624411d2 2023-07-08 jrick return err;
8599 624411d2 2023-07-08 jrick }
8600 624411d2 2023-07-08 jrick
8601 624411d2 2023-07-08 jrick static const struct got_error *
8602 624411d2 2023-07-08 jrick collect_commit_logmsg(struct got_pathlist_head *commitable_paths,
8603 624411d2 2023-07-08 jrick const char *diff_path, char **logmsg, void *arg)
8604 624411d2 2023-07-08 jrick {
8605 624411d2 2023-07-08 jrick char *initial_content = NULL;
8606 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8607 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8608 624411d2 2023-07-08 jrick char *template = NULL;
8609 624411d2 2023-07-08 jrick char *prepared_msg = NULL, *merged_msg = NULL;
8610 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg *a = arg;
8611 624411d2 2023-07-08 jrick int initial_content_len;
8612 624411d2 2023-07-08 jrick int fd = -1;
8613 624411d2 2023-07-08 jrick size_t len;
8614 624411d2 2023-07-08 jrick
8615 624411d2 2023-07-08 jrick /* if a message was specified on the command line, just use it */
8616 624411d2 2023-07-08 jrick if (a->cmdline_log != NULL && *a->cmdline_log != '\0') {
8617 624411d2 2023-07-08 jrick len = strlen(a->cmdline_log) + 1;
8618 624411d2 2023-07-08 jrick *logmsg = malloc(len + 1);
8619 624411d2 2023-07-08 jrick if (*logmsg == NULL)
8620 624411d2 2023-07-08 jrick return got_error_from_errno("malloc");
8621 624411d2 2023-07-08 jrick strlcpy(*logmsg, a->cmdline_log, len);
8622 624411d2 2023-07-08 jrick return NULL;
8623 624411d2 2023-07-08 jrick } else if (a->prepared_log != NULL && a->non_interactive)
8624 624411d2 2023-07-08 jrick return read_prepared_logmsg(logmsg, a->prepared_log);
8625 624411d2 2023-07-08 jrick
8626 624411d2 2023-07-08 jrick if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
8627 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
8628 624411d2 2023-07-08 jrick
8629 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(&a->logmsg_path, &fd, template, "");
8630 624411d2 2023-07-08 jrick if (err)
8631 624411d2 2023-07-08 jrick goto done;
8632 624411d2 2023-07-08 jrick
8633 624411d2 2023-07-08 jrick if (a->prepared_log) {
8634 624411d2 2023-07-08 jrick err = read_prepared_logmsg(&prepared_msg, a->prepared_log);
8635 624411d2 2023-07-08 jrick if (err)
8636 624411d2 2023-07-08 jrick goto done;
8637 624411d2 2023-07-08 jrick } else if (a->merged_log) {
8638 624411d2 2023-07-08 jrick err = read_prepared_logmsg(&merged_msg, a->merged_log);
8639 624411d2 2023-07-08 jrick if (err)
8640 624411d2 2023-07-08 jrick goto done;
8641 624411d2 2023-07-08 jrick }
8642 624411d2 2023-07-08 jrick
8643 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
8644 3d1b16d1 2023-07-08 jrick "%s%s\n# changes to be committed:\n",
8645 624411d2 2023-07-08 jrick prepared_msg ? prepared_msg : "",
8646 3d1b16d1 2023-07-08 jrick merged_msg ? merged_msg : "");
8647 624411d2 2023-07-08 jrick if (initial_content_len == -1) {
8648 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
8649 624411d2 2023-07-08 jrick goto done;
8650 624411d2 2023-07-08 jrick }
8651 624411d2 2023-07-08 jrick
8652 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
8653 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", a->logmsg_path);
8654 624411d2 2023-07-08 jrick goto done;
8655 624411d2 2023-07-08 jrick }
8656 624411d2 2023-07-08 jrick
8657 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, commitable_paths, entry) {
8658 624411d2 2023-07-08 jrick struct got_commitable *ct = pe->data;
8659 624411d2 2023-07-08 jrick dprintf(fd, "# %c %s\n",
8660 624411d2 2023-07-08 jrick got_commitable_get_status(ct),
8661 624411d2 2023-07-08 jrick got_commitable_get_path(ct));
8662 624411d2 2023-07-08 jrick }
8663 624411d2 2023-07-08 jrick
8664 624411d2 2023-07-08 jrick if (diff_path) {
8665 624411d2 2023-07-08 jrick dprintf(fd, "# detailed changes can be viewed in %s\n",
8666 624411d2 2023-07-08 jrick diff_path);
8667 624411d2 2023-07-08 jrick }
8668 624411d2 2023-07-08 jrick
8669 624411d2 2023-07-08 jrick if (close(fd) == -1) {
8670 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", a->logmsg_path);
8671 624411d2 2023-07-08 jrick goto done;
8672 624411d2 2023-07-08 jrick }
8673 624411d2 2023-07-08 jrick fd = -1;
8674 624411d2 2023-07-08 jrick
8675 624411d2 2023-07-08 jrick err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content,
8676 624411d2 2023-07-08 jrick initial_content_len, a->prepared_log ? 0 : 1);
8677 624411d2 2023-07-08 jrick done:
8678 624411d2 2023-07-08 jrick free(initial_content);
8679 624411d2 2023-07-08 jrick free(template);
8680 624411d2 2023-07-08 jrick free(prepared_msg);
8681 624411d2 2023-07-08 jrick free(merged_msg);
8682 624411d2 2023-07-08 jrick
8683 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
8684 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", a->logmsg_path);
8685 624411d2 2023-07-08 jrick
8686 624411d2 2023-07-08 jrick /* Editor is done; we can now apply unveil(2) */
8687 624411d2 2023-07-08 jrick if (err == NULL)
8688 3d1b16d1 2023-07-08 jrick err = got_dial_apply_unveil(a->dial_proto);
8689 3d1b16d1 2023-07-08 jrick if (err == NULL)
8690 624411d2 2023-07-08 jrick err = apply_unveil(a->repo_path, 0, a->worktree_path);
8691 624411d2 2023-07-08 jrick if (err) {
8692 624411d2 2023-07-08 jrick free(*logmsg);
8693 624411d2 2023-07-08 jrick *logmsg = NULL;
8694 624411d2 2023-07-08 jrick }
8695 624411d2 2023-07-08 jrick return err;
8696 624411d2 2023-07-08 jrick }
8697 624411d2 2023-07-08 jrick
8698 624411d2 2023-07-08 jrick static const struct got_error *
8699 624411d2 2023-07-08 jrick cat_logmsg(FILE *f, struct got_commit_object *commit, const char *idstr,
8700 624411d2 2023-07-08 jrick const char *type, int has_content)
8701 624411d2 2023-07-08 jrick {
8702 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8703 624411d2 2023-07-08 jrick char *logmsg = NULL;
8704 624411d2 2023-07-08 jrick
8705 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg, commit);
8706 624411d2 2023-07-08 jrick if (err)
8707 624411d2 2023-07-08 jrick return err;
8708 624411d2 2023-07-08 jrick
8709 624411d2 2023-07-08 jrick if (fprintf(f, "%s# log message of %s commit %s:%s",
8710 624411d2 2023-07-08 jrick has_content ? "\n" : "", type, idstr, logmsg) < 0)
8711 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
8712 624411d2 2023-07-08 jrick
8713 624411d2 2023-07-08 jrick free(logmsg);
8714 624411d2 2023-07-08 jrick return err;
8715 624411d2 2023-07-08 jrick }
8716 624411d2 2023-07-08 jrick
8717 624411d2 2023-07-08 jrick /*
8718 624411d2 2023-07-08 jrick * Lookup "logmsg" references of backed-out and cherrypicked commits
8719 624411d2 2023-07-08 jrick * belonging to the current work tree. If found, and the worktree has
8720 624411d2 2023-07-08 jrick * at least one modified file that was changed in the referenced commit,
8721 624411d2 2023-07-08 jrick * add its log message to a new temporary file at *logmsg_path.
8722 624411d2 2023-07-08 jrick * Add all refs found to matched_refs to be scheduled for removal on
8723 624411d2 2023-07-08 jrick * successful commit.
8724 624411d2 2023-07-08 jrick */
8725 624411d2 2023-07-08 jrick static const struct got_error *
8726 624411d2 2023-07-08 jrick lookup_logmsg_ref(char **logmsg_path, struct got_pathlist_head *paths,
8727 624411d2 2023-07-08 jrick struct got_reflist_head *matched_refs, struct got_worktree *worktree,
8728 624411d2 2023-07-08 jrick struct got_repository *repo)
8729 624411d2 2023-07-08 jrick {
8730 624411d2 2023-07-08 jrick const struct got_error *err;
8731 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
8732 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
8733 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8734 624411d2 2023-07-08 jrick struct got_reflist_entry *re, *re_match;
8735 624411d2 2023-07-08 jrick FILE *f = NULL;
8736 624411d2 2023-07-08 jrick char *uuidstr = NULL;
8737 624411d2 2023-07-08 jrick int added_logmsg = 0;
8738 624411d2 2023-07-08 jrick
8739 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8740 624411d2 2023-07-08 jrick
8741 624411d2 2023-07-08 jrick *logmsg_path = NULL;
8742 624411d2 2023-07-08 jrick
8743 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
8744 624411d2 2023-07-08 jrick if (err)
8745 624411d2 2023-07-08 jrick goto done;
8746 624411d2 2023-07-08 jrick
8747 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
8748 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
8749 624411d2 2023-07-08 jrick if (err)
8750 624411d2 2023-07-08 jrick goto done;
8751 624411d2 2023-07-08 jrick
8752 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
8753 624411d2 2023-07-08 jrick const char *refname, *type;
8754 624411d2 2023-07-08 jrick struct wt_commitable_path_arg wcpa;
8755 624411d2 2023-07-08 jrick int add_logmsg = 0;
8756 624411d2 2023-07-08 jrick
8757 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
8758 624411d2 2023-07-08 jrick
8759 624411d2 2023-07-08 jrick if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
8760 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) {
8761 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
8762 624411d2 2023-07-08 jrick type = "cherrypicked";
8763 624411d2 2023-07-08 jrick } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
8764 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) {
8765 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
8766 624411d2 2023-07-08 jrick type = "backed-out";
8767 624411d2 2023-07-08 jrick } else
8768 624411d2 2023-07-08 jrick continue;
8769 624411d2 2023-07-08 jrick
8770 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0)
8771 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
8772 624411d2 2023-07-08 jrick else
8773 624411d2 2023-07-08 jrick continue;
8774 624411d2 2023-07-08 jrick
8775 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, refname,
8776 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
8777 624411d2 2023-07-08 jrick if (err)
8778 624411d2 2023-07-08 jrick goto done;
8779 624411d2 2023-07-08 jrick
8780 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
8781 624411d2 2023-07-08 jrick if (err)
8782 624411d2 2023-07-08 jrick goto done;
8783 624411d2 2023-07-08 jrick
8784 624411d2 2023-07-08 jrick wcpa.commit_paths = paths;
8785 624411d2 2023-07-08 jrick wcpa.has_changes = &add_logmsg;
8786 624411d2 2023-07-08 jrick
8787 624411d2 2023-07-08 jrick err = commit_path_changed_in_worktree(&wcpa, id,
8788 624411d2 2023-07-08 jrick worktree, repo);
8789 624411d2 2023-07-08 jrick if (err)
8790 624411d2 2023-07-08 jrick goto done;
8791 624411d2 2023-07-08 jrick
8792 624411d2 2023-07-08 jrick if (add_logmsg) {
8793 624411d2 2023-07-08 jrick if (f == NULL) {
8794 624411d2 2023-07-08 jrick err = got_opentemp_named(logmsg_path, &f,
8795 624411d2 2023-07-08 jrick "got-commit-logmsg", "");
8796 624411d2 2023-07-08 jrick if (err)
8797 624411d2 2023-07-08 jrick goto done;
8798 624411d2 2023-07-08 jrick }
8799 624411d2 2023-07-08 jrick err = cat_logmsg(f, commit, refname, type,
8800 624411d2 2023-07-08 jrick added_logmsg);
8801 624411d2 2023-07-08 jrick if (err)
8802 624411d2 2023-07-08 jrick goto done;
8803 624411d2 2023-07-08 jrick if (!added_logmsg)
8804 624411d2 2023-07-08 jrick ++added_logmsg;
8805 624411d2 2023-07-08 jrick
8806 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&re_match, re);
8807 624411d2 2023-07-08 jrick if (err)
8808 624411d2 2023-07-08 jrick goto done;
8809 624411d2 2023-07-08 jrick TAILQ_INSERT_HEAD(matched_refs, re_match, entry);
8810 624411d2 2023-07-08 jrick }
8811 624411d2 2023-07-08 jrick
8812 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8813 624411d2 2023-07-08 jrick commit = NULL;
8814 624411d2 2023-07-08 jrick free(id);
8815 624411d2 2023-07-08 jrick id = NULL;
8816 624411d2 2023-07-08 jrick }
8817 624411d2 2023-07-08 jrick
8818 624411d2 2023-07-08 jrick done:
8819 624411d2 2023-07-08 jrick free(id);
8820 624411d2 2023-07-08 jrick free(uuidstr);
8821 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8822 624411d2 2023-07-08 jrick if (commit)
8823 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8824 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
8825 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
8826 624411d2 2023-07-08 jrick if (!added_logmsg) {
8827 624411d2 2023-07-08 jrick if (*logmsg_path && unlink(*logmsg_path) != 0 && err == NULL)
8828 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", *logmsg_path);
8829 624411d2 2023-07-08 jrick *logmsg_path = NULL;
8830 624411d2 2023-07-08 jrick }
8831 624411d2 2023-07-08 jrick return err;
8832 624411d2 2023-07-08 jrick }
8833 624411d2 2023-07-08 jrick
8834 624411d2 2023-07-08 jrick static const struct got_error *
8835 624411d2 2023-07-08 jrick cmd_commit(int argc, char *argv[])
8836 624411d2 2023-07-08 jrick {
8837 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
8838 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
8839 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
8840 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL;
8841 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
8842 624411d2 2023-07-08 jrick const char *logmsg = NULL;
8843 624411d2 2023-07-08 jrick char *prepared_logmsg = NULL, *merged_logmsg = NULL;
8844 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg cl_arg;
8845 624411d2 2023-07-08 jrick const char *author = NULL;
8846 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *editor = NULL, *committer = NULL;
8847 624411d2 2023-07-08 jrick int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
8848 624411d2 2023-07-08 jrick int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0;
8849 624411d2 2023-07-08 jrick int show_diff = 1, commit_conflicts = 0;
8850 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8851 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8852 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
8853 624411d2 2023-07-08 jrick int *pack_fds = NULL;
8854 3d1b16d1 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
8855 3d1b16d1 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
8856 3d1b16d1 2023-07-08 jrick int nremotes;
8857 3d1b16d1 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
8858 3d1b16d1 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
8859 3d1b16d1 2023-07-08 jrick const char *remote_name;
8860 3d1b16d1 2023-07-08 jrick int verbosity = 0;
8861 3d1b16d1 2023-07-08 jrick int i;
8862 624411d2 2023-07-08 jrick
8863 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8864 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8865 624411d2 2023-07-08 jrick cl_arg.logmsg_path = NULL;
8866 624411d2 2023-07-08 jrick
8867 624411d2 2023-07-08 jrick #ifndef PROFILE
8868 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8869 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
8870 624411d2 2023-07-08 jrick err(1, "pledge");
8871 624411d2 2023-07-08 jrick #endif
8872 624411d2 2023-07-08 jrick
8873 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "A:CF:m:NnS")) != -1) {
8874 624411d2 2023-07-08 jrick switch (ch) {
8875 624411d2 2023-07-08 jrick case 'A':
8876 624411d2 2023-07-08 jrick author = optarg;
8877 624411d2 2023-07-08 jrick error = valid_author(author);
8878 624411d2 2023-07-08 jrick if (error)
8879 624411d2 2023-07-08 jrick return error;
8880 624411d2 2023-07-08 jrick break;
8881 624411d2 2023-07-08 jrick case 'C':
8882 624411d2 2023-07-08 jrick commit_conflicts = 1;
8883 624411d2 2023-07-08 jrick break;
8884 624411d2 2023-07-08 jrick case 'F':
8885 624411d2 2023-07-08 jrick if (logmsg != NULL)
8886 624411d2 2023-07-08 jrick option_conflict('F', 'm');
8887 624411d2 2023-07-08 jrick prepared_logmsg = realpath(optarg, NULL);
8888 624411d2 2023-07-08 jrick if (prepared_logmsg == NULL)
8889 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
8890 624411d2 2023-07-08 jrick optarg);
8891 624411d2 2023-07-08 jrick break;
8892 624411d2 2023-07-08 jrick case 'm':
8893 624411d2 2023-07-08 jrick if (prepared_logmsg)
8894 624411d2 2023-07-08 jrick option_conflict('m', 'F');
8895 624411d2 2023-07-08 jrick logmsg = optarg;
8896 624411d2 2023-07-08 jrick break;
8897 624411d2 2023-07-08 jrick case 'N':
8898 624411d2 2023-07-08 jrick non_interactive = 1;
8899 624411d2 2023-07-08 jrick break;
8900 624411d2 2023-07-08 jrick case 'n':
8901 624411d2 2023-07-08 jrick show_diff = 0;
8902 624411d2 2023-07-08 jrick break;
8903 624411d2 2023-07-08 jrick case 'S':
8904 624411d2 2023-07-08 jrick allow_bad_symlinks = 1;
8905 624411d2 2023-07-08 jrick break;
8906 624411d2 2023-07-08 jrick default:
8907 624411d2 2023-07-08 jrick usage_commit();
8908 624411d2 2023-07-08 jrick /* NOTREACHED */
8909 624411d2 2023-07-08 jrick }
8910 624411d2 2023-07-08 jrick }
8911 624411d2 2023-07-08 jrick
8912 624411d2 2023-07-08 jrick argc -= optind;
8913 624411d2 2023-07-08 jrick argv += optind;
8914 624411d2 2023-07-08 jrick
8915 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
8916 624411d2 2023-07-08 jrick if (cwd == NULL) {
8917 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
8918 624411d2 2023-07-08 jrick goto done;
8919 624411d2 2023-07-08 jrick }
8920 624411d2 2023-07-08 jrick
8921 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
8922 624411d2 2023-07-08 jrick if (error != NULL)
8923 624411d2 2023-07-08 jrick goto done;
8924 624411d2 2023-07-08 jrick
8925 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
8926 624411d2 2023-07-08 jrick if (error) {
8927 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
8928 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "commit", cwd);
8929 624411d2 2023-07-08 jrick goto done;
8930 624411d2 2023-07-08 jrick }
8931 624411d2 2023-07-08 jrick
8932 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
8933 624411d2 2023-07-08 jrick if (error)
8934 624411d2 2023-07-08 jrick goto done;
8935 624411d2 2023-07-08 jrick if (rebase_in_progress) {
8936 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASING);
8937 624411d2 2023-07-08 jrick goto done;
8938 624411d2 2023-07-08 jrick }
8939 624411d2 2023-07-08 jrick
8940 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&histedit_in_progress,
8941 624411d2 2023-07-08 jrick worktree);
8942 624411d2 2023-07-08 jrick if (error)
8943 624411d2 2023-07-08 jrick goto done;
8944 624411d2 2023-07-08 jrick
8945 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
8946 624411d2 2023-07-08 jrick if (error)
8947 624411d2 2023-07-08 jrick goto done;
8948 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8949 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
8950 624411d2 2023-07-08 jrick if (error != NULL)
8951 624411d2 2023-07-08 jrick goto done;
8952 624411d2 2023-07-08 jrick
8953 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo);
8954 624411d2 2023-07-08 jrick if (error)
8955 624411d2 2023-07-08 jrick goto done;
8956 624411d2 2023-07-08 jrick if (merge_in_progress) {
8957 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
8958 624411d2 2023-07-08 jrick goto done;
8959 624411d2 2023-07-08 jrick }
8960 624411d2 2023-07-08 jrick
8961 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
8962 624411d2 2023-07-08 jrick if (error)
8963 624411d2 2023-07-08 jrick goto done;
8964 624411d2 2023-07-08 jrick
8965 624411d2 2023-07-08 jrick if (author == NULL)
8966 624411d2 2023-07-08 jrick author = committer;
8967 3d1b16d1 2023-07-08 jrick
8968 3d1b16d1 2023-07-08 jrick remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
8969 3d1b16d1 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
8970 3d1b16d1 2023-07-08 jrick if (worktree_conf) {
8971 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
8972 3d1b16d1 2023-07-08 jrick worktree_conf);
8973 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8974 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8975 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
8976 3d1b16d1 2023-07-08 jrick break;
8977 3d1b16d1 2023-07-08 jrick }
8978 3d1b16d1 2023-07-08 jrick }
8979 3d1b16d1 2023-07-08 jrick }
8980 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
8981 3d1b16d1 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
8982 3d1b16d1 2023-07-08 jrick if (repo_conf) {
8983 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
8984 3d1b16d1 2023-07-08 jrick repo_conf);
8985 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8986 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8987 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
8988 3d1b16d1 2023-07-08 jrick break;
8989 3d1b16d1 2023-07-08 jrick }
8990 3d1b16d1 2023-07-08 jrick }
8991 3d1b16d1 2023-07-08 jrick }
8992 3d1b16d1 2023-07-08 jrick }
8993 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
8994 3d1b16d1 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
8995 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8996 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8997 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
8998 3d1b16d1 2023-07-08 jrick break;
8999 3d1b16d1 2023-07-08 jrick }
9000 3d1b16d1 2023-07-08 jrick }
9001 3d1b16d1 2023-07-08 jrick }
9002 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
9003 3d1b16d1 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
9004 3d1b16d1 2023-07-08 jrick goto done;
9005 3d1b16d1 2023-07-08 jrick }
9006 3d1b16d1 2023-07-08 jrick
9007 3d1b16d1 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
9008 3d1b16d1 2023-07-08 jrick &repo_name, remote->fetch_url);
9009 3d1b16d1 2023-07-08 jrick if (error)
9010 3d1b16d1 2023-07-08 jrick goto done;
9011 3d1b16d1 2023-07-08 jrick
9012 3d1b16d1 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
9013 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
9014 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9015 3d1b16d1 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
9016 3d1b16d1 2023-07-08 jrick err(1, "pledge");
9017 3d1b16d1 2023-07-08 jrick #endif
9018 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
9019 3d1b16d1 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
9020 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
9021 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9022 3d1b16d1 2023-07-08 jrick "sendfd unveil", NULL) == -1)
9023 3d1b16d1 2023-07-08 jrick err(1, "pledge");
9024 3d1b16d1 2023-07-08 jrick #endif
9025 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
9026 3d1b16d1 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
9027 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
9028 3d1b16d1 2023-07-08 jrick goto done;
9029 3d1b16d1 2023-07-08 jrick } else {
9030 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
9031 3d1b16d1 2023-07-08 jrick goto done;
9032 3d1b16d1 2023-07-08 jrick }
9033 624411d2 2023-07-08 jrick
9034 3d1b16d1 2023-07-08 jrick
9035 3d1b16d1 2023-07-08 jrick /*if (verbosity >= 0) {
9036 3d1b16d1 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
9037 3d1b16d1 2023-07-08 jrick remote->name, proto, host,
9038 3d1b16d1 2023-07-08 jrick port ? ":" : "", port ? port : "",
9039 3d1b16d1 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
9040 3d1b16d1 2023-07-08 jrick }*/
9041 3d1b16d1 2023-07-08 jrick
9042 624411d2 2023-07-08 jrick /*
9043 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have
9044 3d1b16d1 2023-07-08 jrick * to apply unveil after the log message has been written during
9045 3d1b16d1 2023-07-08 jrick * the callback.
9046 624411d2 2023-07-08 jrick */
9047 624411d2 2023-07-08 jrick if (logmsg == NULL || strlen(logmsg) == 0)
9048 624411d2 2023-07-08 jrick error = get_editor(&editor);
9049 3d1b16d1 2023-07-08 jrick else {
9050 3d1b16d1 2023-07-08 jrick error = got_dial_apply_unveil(proto);
9051 3d1b16d1 2023-07-08 jrick if (error)
9052 3d1b16d1 2023-07-08 jrick goto done;
9053 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
9054 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
9055 3d1b16d1 2023-07-08 jrick }
9056 624411d2 2023-07-08 jrick if (error)
9057 624411d2 2023-07-08 jrick goto done;
9058 624411d2 2023-07-08 jrick
9059 624411d2 2023-07-08 jrick if (prepared_logmsg == NULL) {
9060 624411d2 2023-07-08 jrick error = lookup_logmsg_ref(&merged_logmsg,
9061 624411d2 2023-07-08 jrick argc > 0 ? &paths : NULL, &refs, worktree, repo);
9062 624411d2 2023-07-08 jrick if (error)
9063 624411d2 2023-07-08 jrick goto done;
9064 624411d2 2023-07-08 jrick }
9065 624411d2 2023-07-08 jrick
9066 3d1b16d1 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
9067 3d1b16d1 2023-07-08 jrick if (error)
9068 3d1b16d1 2023-07-08 jrick goto done;
9069 3d1b16d1 2023-07-08 jrick
9070 624411d2 2023-07-08 jrick cl_arg.editor = editor;
9071 624411d2 2023-07-08 jrick cl_arg.cmdline_log = logmsg;
9072 624411d2 2023-07-08 jrick cl_arg.prepared_log = prepared_logmsg;
9073 624411d2 2023-07-08 jrick cl_arg.merged_log = merged_logmsg;
9074 624411d2 2023-07-08 jrick cl_arg.non_interactive = non_interactive;
9075 624411d2 2023-07-08 jrick cl_arg.worktree_path = got_worktree_get_root_path(worktree);
9076 3d1b16d1 2023-07-08 jrick cl_arg.repo_path = got_repo_get_path(repo);
9077 3d1b16d1 2023-07-08 jrick cl_arg.dial_proto = proto;
9078 3d1b16d1 2023-07-08 jrick error = got_worktree_cvg_commit(&id, worktree, &paths, author,
9079 3d1b16d1 2023-07-08 jrick committer, allow_bad_symlinks, show_diff, commit_conflicts,
9080 3d1b16d1 2023-07-08 jrick collect_commit_logmsg, &cl_arg, print_status, NULL, proto, host,
9081 3d1b16d1 2023-07-08 jrick port, server_path, verbosity, remote, check_cancelled, repo);
9082 624411d2 2023-07-08 jrick if (error) {
9083 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
9084 624411d2 2023-07-08 jrick cl_arg.logmsg_path != NULL)
9085 624411d2 2023-07-08 jrick preserve_logmsg = 1;
9086 624411d2 2023-07-08 jrick goto done;
9087 624411d2 2023-07-08 jrick }
9088 624411d2 2023-07-08 jrick
9089 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, id);
9090 624411d2 2023-07-08 jrick if (error)
9091 624411d2 2023-07-08 jrick goto done;
9092 624411d2 2023-07-08 jrick printf("Created commit %s\n", id_str);
9093 624411d2 2023-07-08 jrick
9094 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
9095 624411d2 2023-07-08 jrick error = got_ref_delete(re->ref, repo);
9096 624411d2 2023-07-08 jrick if (error)
9097 624411d2 2023-07-08 jrick goto done;
9098 624411d2 2023-07-08 jrick }
9099 624411d2 2023-07-08 jrick
9100 624411d2 2023-07-08 jrick done:
9101 624411d2 2023-07-08 jrick if (preserve_logmsg) {
9102 624411d2 2023-07-08 jrick fprintf(stderr, "%s: log message preserved in %s\n",
9103 624411d2 2023-07-08 jrick getprogname(), cl_arg.logmsg_path);
9104 624411d2 2023-07-08 jrick } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
9105 624411d2 2023-07-08 jrick error == NULL)
9106 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
9107 624411d2 2023-07-08 jrick free(cl_arg.logmsg_path);
9108 624411d2 2023-07-08 jrick if (merged_logmsg && unlink(merged_logmsg) == -1 && error == NULL)
9109 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", merged_logmsg);
9110 624411d2 2023-07-08 jrick free(merged_logmsg);
9111 624411d2 2023-07-08 jrick if (repo) {
9112 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
9113 624411d2 2023-07-08 jrick if (error == NULL)
9114 624411d2 2023-07-08 jrick error = close_err;
9115 624411d2 2023-07-08 jrick }
9116 624411d2 2023-07-08 jrick if (worktree)
9117 624411d2 2023-07-08 jrick got_worktree_close(worktree);
9118 624411d2 2023-07-08 jrick if (pack_fds) {
9119 624411d2 2023-07-08 jrick const struct got_error *pack_err =
9120 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
9121 624411d2 2023-07-08 jrick if (error == NULL)
9122 624411d2 2023-07-08 jrick error = pack_err;
9123 624411d2 2023-07-08 jrick }
9124 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
9125 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
9126 624411d2 2023-07-08 jrick free(cwd);
9127 624411d2 2023-07-08 jrick free(id_str);
9128 624411d2 2023-07-08 jrick free(gitconfig_path);
9129 624411d2 2023-07-08 jrick free(editor);
9130 624411d2 2023-07-08 jrick free(committer);
9131 624411d2 2023-07-08 jrick free(prepared_logmsg);
9132 624411d2 2023-07-08 jrick return error;
9133 624411d2 2023-07-08 jrick }
9134 624411d2 2023-07-08 jrick
9135 624411d2 2023-07-08 jrick __dead static void
9136 624411d2 2023-07-08 jrick usage_send(void)
9137 624411d2 2023-07-08 jrick {
9138 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s send [-afqTv] [-b branch] [-d branch] "
9139 624411d2 2023-07-08 jrick "[-r repository-path] [-t tag] [remote-repository]\n",
9140 624411d2 2023-07-08 jrick getprogname());
9141 624411d2 2023-07-08 jrick exit(1);
9142 624411d2 2023-07-08 jrick }
9143 624411d2 2023-07-08 jrick
9144 624411d2 2023-07-08 jrick static void
9145 624411d2 2023-07-08 jrick print_load_info(int print_colored, int print_found, int print_trees,
9146 624411d2 2023-07-08 jrick int ncolored, int nfound, int ntrees)
9147 624411d2 2023-07-08 jrick {
9148 624411d2 2023-07-08 jrick if (print_colored) {
9149 624411d2 2023-07-08 jrick printf("%d commit%s colored", ncolored,
9150 624411d2 2023-07-08 jrick ncolored == 1 ? "" : "s");
9151 624411d2 2023-07-08 jrick }
9152 624411d2 2023-07-08 jrick if (print_found) {
9153 624411d2 2023-07-08 jrick printf("%s%d object%s found",
9154 624411d2 2023-07-08 jrick ncolored > 0 ? "; " : "",
9155 624411d2 2023-07-08 jrick nfound, nfound == 1 ? "" : "s");
9156 624411d2 2023-07-08 jrick }
9157 624411d2 2023-07-08 jrick if (print_trees) {
9158 624411d2 2023-07-08 jrick printf("; %d tree%s scanned", ntrees,
9159 624411d2 2023-07-08 jrick ntrees == 1 ? "" : "s");
9160 624411d2 2023-07-08 jrick }
9161 624411d2 2023-07-08 jrick }
9162 624411d2 2023-07-08 jrick
9163 624411d2 2023-07-08 jrick struct got_send_progress_arg {
9164 624411d2 2023-07-08 jrick char last_scaled_packsize[FMT_SCALED_STRSIZE];
9165 624411d2 2023-07-08 jrick int verbosity;
9166 624411d2 2023-07-08 jrick int last_ncolored;
9167 624411d2 2023-07-08 jrick int last_nfound;
9168 624411d2 2023-07-08 jrick int last_ntrees;
9169 624411d2 2023-07-08 jrick int loading_done;
9170 624411d2 2023-07-08 jrick int last_ncommits;
9171 624411d2 2023-07-08 jrick int last_nobj_total;
9172 624411d2 2023-07-08 jrick int last_p_deltify;
9173 624411d2 2023-07-08 jrick int last_p_written;
9174 624411d2 2023-07-08 jrick int last_p_sent;
9175 624411d2 2023-07-08 jrick int printed_something;
9176 624411d2 2023-07-08 jrick int sent_something;
9177 624411d2 2023-07-08 jrick struct got_pathlist_head *delete_branches;
9178 624411d2 2023-07-08 jrick };
9179 624411d2 2023-07-08 jrick
9180 624411d2 2023-07-08 jrick static const struct got_error *
9181 624411d2 2023-07-08 jrick send_progress(void *arg, int ncolored, int nfound, int ntrees,
9182 624411d2 2023-07-08 jrick off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify,
9183 624411d2 2023-07-08 jrick int nobj_written, off_t bytes_sent, const char *refname,
9184 624411d2 2023-07-08 jrick const char *errmsg, int success)
9185 624411d2 2023-07-08 jrick {
9186 624411d2 2023-07-08 jrick struct got_send_progress_arg *a = arg;
9187 624411d2 2023-07-08 jrick char scaled_packsize[FMT_SCALED_STRSIZE];
9188 624411d2 2023-07-08 jrick char scaled_sent[FMT_SCALED_STRSIZE];
9189 624411d2 2023-07-08 jrick int p_deltify = 0, p_written = 0, p_sent = 0;
9190 624411d2 2023-07-08 jrick int print_colored = 0, print_found = 0, print_trees = 0;
9191 624411d2 2023-07-08 jrick int print_searching = 0, print_total = 0;
9192 624411d2 2023-07-08 jrick int print_deltify = 0, print_written = 0, print_sent = 0;
9193 624411d2 2023-07-08 jrick
9194 624411d2 2023-07-08 jrick if (a->verbosity < 0)
9195 624411d2 2023-07-08 jrick return NULL;
9196 624411d2 2023-07-08 jrick
9197 624411d2 2023-07-08 jrick if (refname) {
9198 624411d2 2023-07-08 jrick const char *status = success ? "accepted" : "rejected";
9199 624411d2 2023-07-08 jrick
9200 624411d2 2023-07-08 jrick if (success) {
9201 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
9202 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, a->delete_branches, entry) {
9203 624411d2 2023-07-08 jrick const char *branchname = pe->path;
9204 624411d2 2023-07-08 jrick if (got_path_cmp(branchname, refname,
9205 624411d2 2023-07-08 jrick strlen(branchname), strlen(refname)) == 0) {
9206 624411d2 2023-07-08 jrick status = "deleted";
9207 624411d2 2023-07-08 jrick a->sent_something = 1;
9208 624411d2 2023-07-08 jrick break;
9209 624411d2 2023-07-08 jrick }
9210 624411d2 2023-07-08 jrick }
9211 624411d2 2023-07-08 jrick }
9212 624411d2 2023-07-08 jrick
9213 624411d2 2023-07-08 jrick if (a->printed_something)
9214 624411d2 2023-07-08 jrick putchar('\n');
9215 624411d2 2023-07-08 jrick printf("Server has %s %s", status, refname);
9216 624411d2 2023-07-08 jrick if (errmsg)
9217 624411d2 2023-07-08 jrick printf(": %s", errmsg);
9218 624411d2 2023-07-08 jrick a->printed_something = 1;
9219 624411d2 2023-07-08 jrick return NULL;
9220 624411d2 2023-07-08 jrick }
9221 624411d2 2023-07-08 jrick
9222 624411d2 2023-07-08 jrick if (a->last_ncolored != ncolored) {
9223 624411d2 2023-07-08 jrick print_colored = 1;
9224 624411d2 2023-07-08 jrick a->last_ncolored = ncolored;
9225 624411d2 2023-07-08 jrick }
9226 624411d2 2023-07-08 jrick
9227 624411d2 2023-07-08 jrick if (a->last_nfound != nfound) {
9228 624411d2 2023-07-08 jrick print_colored = 1;
9229 624411d2 2023-07-08 jrick print_found = 1;
9230 624411d2 2023-07-08 jrick a->last_nfound = nfound;
9231 624411d2 2023-07-08 jrick }
9232 624411d2 2023-07-08 jrick
9233 624411d2 2023-07-08 jrick if (a->last_ntrees != ntrees) {
9234 624411d2 2023-07-08 jrick print_colored = 1;
9235 624411d2 2023-07-08 jrick print_found = 1;
9236 624411d2 2023-07-08 jrick print_trees = 1;
9237 624411d2 2023-07-08 jrick a->last_ntrees = ntrees;
9238 624411d2 2023-07-08 jrick }
9239 624411d2 2023-07-08 jrick
9240 624411d2 2023-07-08 jrick if ((print_colored || print_found || print_trees) &&
9241 624411d2 2023-07-08 jrick !a->loading_done) {
9242 624411d2 2023-07-08 jrick printf("\r");
9243 624411d2 2023-07-08 jrick print_load_info(print_colored, print_found, print_trees,
9244 624411d2 2023-07-08 jrick ncolored, nfound, ntrees);
9245 624411d2 2023-07-08 jrick a->printed_something = 1;
9246 624411d2 2023-07-08 jrick fflush(stdout);
9247 624411d2 2023-07-08 jrick return NULL;
9248 624411d2 2023-07-08 jrick } else if (!a->loading_done) {
9249 624411d2 2023-07-08 jrick printf("\r");
9250 624411d2 2023-07-08 jrick print_load_info(1, 1, 1, ncolored, nfound, ntrees);
9251 624411d2 2023-07-08 jrick printf("\n");
9252 624411d2 2023-07-08 jrick a->loading_done = 1;
9253 624411d2 2023-07-08 jrick }
9254 624411d2 2023-07-08 jrick
9255 624411d2 2023-07-08 jrick if (fmt_scaled(packfile_size, scaled_packsize) == -1)
9256 624411d2 2023-07-08 jrick return got_error_from_errno("fmt_scaled");
9257 624411d2 2023-07-08 jrick if (fmt_scaled(bytes_sent, scaled_sent) == -1)
9258 624411d2 2023-07-08 jrick return got_error_from_errno("fmt_scaled");
9259 624411d2 2023-07-08 jrick
9260 624411d2 2023-07-08 jrick if (a->last_ncommits != ncommits) {
9261 624411d2 2023-07-08 jrick print_searching = 1;
9262 624411d2 2023-07-08 jrick a->last_ncommits = ncommits;
9263 624411d2 2023-07-08 jrick }
9264 624411d2 2023-07-08 jrick
9265 624411d2 2023-07-08 jrick if (a->last_nobj_total != nobj_total) {
9266 624411d2 2023-07-08 jrick print_searching = 1;
9267 624411d2 2023-07-08 jrick print_total = 1;
9268 624411d2 2023-07-08 jrick a->last_nobj_total = nobj_total;
9269 624411d2 2023-07-08 jrick }
9270 624411d2 2023-07-08 jrick
9271 624411d2 2023-07-08 jrick if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' ||
9272 624411d2 2023-07-08 jrick strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) {
9273 624411d2 2023-07-08 jrick if (strlcpy(a->last_scaled_packsize, scaled_packsize,
9274 624411d2 2023-07-08 jrick FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
9275 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
9276 624411d2 2023-07-08 jrick }
9277 624411d2 2023-07-08 jrick
9278 624411d2 2023-07-08 jrick if (nobj_deltify > 0 || nobj_written > 0) {
9279 624411d2 2023-07-08 jrick if (nobj_deltify > 0) {
9280 624411d2 2023-07-08 jrick p_deltify = (nobj_deltify * 100) / nobj_total;
9281 624411d2 2023-07-08 jrick if (p_deltify != a->last_p_deltify) {
9282 624411d2 2023-07-08 jrick a->last_p_deltify = p_deltify;
9283 624411d2 2023-07-08 jrick print_searching = 1;
9284 624411d2 2023-07-08 jrick print_total = 1;
9285 624411d2 2023-07-08 jrick print_deltify = 1;
9286 624411d2 2023-07-08 jrick }
9287 624411d2 2023-07-08 jrick }
9288 624411d2 2023-07-08 jrick if (nobj_written > 0) {
9289 624411d2 2023-07-08 jrick p_written = (nobj_written * 100) / nobj_total;
9290 624411d2 2023-07-08 jrick if (p_written != a->last_p_written) {
9291 624411d2 2023-07-08 jrick a->last_p_written = p_written;
9292 624411d2 2023-07-08 jrick print_searching = 1;
9293 624411d2 2023-07-08 jrick print_total = 1;
9294 624411d2 2023-07-08 jrick print_deltify = 1;
9295 624411d2 2023-07-08 jrick print_written = 1;
9296 624411d2 2023-07-08 jrick }
9297 624411d2 2023-07-08 jrick }
9298 624411d2 2023-07-08 jrick }
9299 624411d2 2023-07-08 jrick
9300 624411d2 2023-07-08 jrick if (bytes_sent > 0) {
9301 624411d2 2023-07-08 jrick p_sent = (bytes_sent * 100) / packfile_size;
9302 624411d2 2023-07-08 jrick if (p_sent != a->last_p_sent) {
9303 624411d2 2023-07-08 jrick a->last_p_sent = p_sent;
9304 624411d2 2023-07-08 jrick print_searching = 1;
9305 624411d2 2023-07-08 jrick print_total = 1;
9306 624411d2 2023-07-08 jrick print_deltify = 1;
9307 624411d2 2023-07-08 jrick print_written = 1;
9308 624411d2 2023-07-08 jrick print_sent = 1;
9309 624411d2 2023-07-08 jrick }
9310 624411d2 2023-07-08 jrick a->sent_something = 1;
9311 624411d2 2023-07-08 jrick }
9312 624411d2 2023-07-08 jrick
9313 624411d2 2023-07-08 jrick if (print_searching || print_total || print_deltify || print_written ||
9314 624411d2 2023-07-08 jrick print_sent)
9315 624411d2 2023-07-08 jrick printf("\r");
9316 624411d2 2023-07-08 jrick if (print_searching)
9317 624411d2 2023-07-08 jrick printf("packing %d reference%s", ncommits,
9318 624411d2 2023-07-08 jrick ncommits == 1 ? "" : "s");
9319 624411d2 2023-07-08 jrick if (print_total)
9320 624411d2 2023-07-08 jrick printf("; %d object%s", nobj_total,
9321 624411d2 2023-07-08 jrick nobj_total == 1 ? "" : "s");
9322 624411d2 2023-07-08 jrick if (print_deltify)
9323 624411d2 2023-07-08 jrick printf("; deltify: %d%%", p_deltify);
9324 624411d2 2023-07-08 jrick if (print_sent)
9325 624411d2 2023-07-08 jrick printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
9326 624411d2 2023-07-08 jrick scaled_packsize, p_sent);
9327 624411d2 2023-07-08 jrick else if (print_written)
9328 624411d2 2023-07-08 jrick printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
9329 624411d2 2023-07-08 jrick scaled_packsize, p_written);
9330 624411d2 2023-07-08 jrick if (print_searching || print_total || print_deltify ||
9331 624411d2 2023-07-08 jrick print_written || print_sent) {
9332 624411d2 2023-07-08 jrick a->printed_something = 1;
9333 624411d2 2023-07-08 jrick fflush(stdout);
9334 624411d2 2023-07-08 jrick }
9335 624411d2 2023-07-08 jrick return NULL;
9336 624411d2 2023-07-08 jrick }
9337 624411d2 2023-07-08 jrick
9338 624411d2 2023-07-08 jrick static const struct got_error *
9339 624411d2 2023-07-08 jrick cmd_send(int argc, char *argv[])
9340 624411d2 2023-07-08 jrick {
9341 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
9342 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
9343 624411d2 2023-07-08 jrick const char *remote_name;
9344 624411d2 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
9345 624411d2 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
9346 624411d2 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
9347 624411d2 2023-07-08 jrick int nremotes, nbranches = 0, ndelete_branches = 0;
9348 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
9349 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
9350 624411d2 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
9351 624411d2 2023-07-08 jrick struct got_pathlist_head branches;
9352 624411d2 2023-07-08 jrick struct got_pathlist_head tags;
9353 624411d2 2023-07-08 jrick struct got_reflist_head all_branches;
9354 624411d2 2023-07-08 jrick struct got_reflist_head all_tags;
9355 624411d2 2023-07-08 jrick struct got_pathlist_head delete_args;
9356 624411d2 2023-07-08 jrick struct got_pathlist_head delete_branches;
9357 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
9358 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
9359 624411d2 2023-07-08 jrick int i, ch, sendfd = -1, sendstatus;
9360 624411d2 2023-07-08 jrick pid_t sendpid = -1;
9361 624411d2 2023-07-08 jrick struct got_send_progress_arg spa;
9362 624411d2 2023-07-08 jrick int verbosity = 0, overwrite_refs = 0;
9363 624411d2 2023-07-08 jrick int send_all_branches = 0, send_all_tags = 0;
9364 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
9365 624411d2 2023-07-08 jrick int *pack_fds = NULL;
9366 624411d2 2023-07-08 jrick
9367 624411d2 2023-07-08 jrick TAILQ_INIT(&branches);
9368 624411d2 2023-07-08 jrick TAILQ_INIT(&tags);
9369 624411d2 2023-07-08 jrick TAILQ_INIT(&all_branches);
9370 624411d2 2023-07-08 jrick TAILQ_INIT(&all_tags);
9371 624411d2 2023-07-08 jrick TAILQ_INIT(&delete_args);
9372 624411d2 2023-07-08 jrick TAILQ_INIT(&delete_branches);
9373 624411d2 2023-07-08 jrick
9374 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "ab:d:fqr:Tt:v")) != -1) {
9375 624411d2 2023-07-08 jrick switch (ch) {
9376 624411d2 2023-07-08 jrick case 'a':
9377 624411d2 2023-07-08 jrick send_all_branches = 1;
9378 624411d2 2023-07-08 jrick break;
9379 624411d2 2023-07-08 jrick case 'b':
9380 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches, optarg, NULL);
9381 624411d2 2023-07-08 jrick if (error)
9382 624411d2 2023-07-08 jrick return error;
9383 624411d2 2023-07-08 jrick nbranches++;
9384 624411d2 2023-07-08 jrick break;
9385 624411d2 2023-07-08 jrick case 'd':
9386 624411d2 2023-07-08 jrick error = got_pathlist_append(&delete_args, optarg, NULL);
9387 624411d2 2023-07-08 jrick if (error)
9388 624411d2 2023-07-08 jrick return error;
9389 624411d2 2023-07-08 jrick break;
9390 624411d2 2023-07-08 jrick case 'f':
9391 624411d2 2023-07-08 jrick overwrite_refs = 1;
9392 624411d2 2023-07-08 jrick break;
9393 624411d2 2023-07-08 jrick case 'q':
9394 624411d2 2023-07-08 jrick verbosity = -1;
9395 624411d2 2023-07-08 jrick break;
9396 624411d2 2023-07-08 jrick case 'r':
9397 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
9398 624411d2 2023-07-08 jrick if (repo_path == NULL)
9399 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
9400 624411d2 2023-07-08 jrick optarg);
9401 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
9402 624411d2 2023-07-08 jrick break;
9403 624411d2 2023-07-08 jrick case 'T':
9404 624411d2 2023-07-08 jrick send_all_tags = 1;
9405 624411d2 2023-07-08 jrick break;
9406 624411d2 2023-07-08 jrick case 't':
9407 624411d2 2023-07-08 jrick error = got_pathlist_append(&tags, optarg, NULL);
9408 624411d2 2023-07-08 jrick if (error)
9409 624411d2 2023-07-08 jrick return error;
9410 624411d2 2023-07-08 jrick break;
9411 624411d2 2023-07-08 jrick case 'v':
9412 624411d2 2023-07-08 jrick if (verbosity < 0)
9413 624411d2 2023-07-08 jrick verbosity = 0;
9414 624411d2 2023-07-08 jrick else if (verbosity < 3)
9415 624411d2 2023-07-08 jrick verbosity++;
9416 624411d2 2023-07-08 jrick break;
9417 624411d2 2023-07-08 jrick default:
9418 624411d2 2023-07-08 jrick usage_send();
9419 624411d2 2023-07-08 jrick /* NOTREACHED */
9420 624411d2 2023-07-08 jrick }
9421 624411d2 2023-07-08 jrick }
9422 624411d2 2023-07-08 jrick argc -= optind;
9423 624411d2 2023-07-08 jrick argv += optind;
9424 624411d2 2023-07-08 jrick
9425 624411d2 2023-07-08 jrick if (send_all_branches && !TAILQ_EMPTY(&branches))
9426 624411d2 2023-07-08 jrick option_conflict('a', 'b');
9427 624411d2 2023-07-08 jrick if (send_all_tags && !TAILQ_EMPTY(&tags))
9428 624411d2 2023-07-08 jrick option_conflict('T', 't');
9429 624411d2 2023-07-08 jrick
9430 624411d2 2023-07-08 jrick
9431 624411d2 2023-07-08 jrick if (argc == 0)
9432 624411d2 2023-07-08 jrick remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
9433 624411d2 2023-07-08 jrick else if (argc == 1)
9434 624411d2 2023-07-08 jrick remote_name = argv[0];
9435 624411d2 2023-07-08 jrick else
9436 624411d2 2023-07-08 jrick usage_send();
9437 624411d2 2023-07-08 jrick
9438 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
9439 624411d2 2023-07-08 jrick if (cwd == NULL) {
9440 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
9441 624411d2 2023-07-08 jrick goto done;
9442 624411d2 2023-07-08 jrick }
9443 624411d2 2023-07-08 jrick
9444 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
9445 624411d2 2023-07-08 jrick if (error != NULL)
9446 624411d2 2023-07-08 jrick goto done;
9447 624411d2 2023-07-08 jrick
9448 624411d2 2023-07-08 jrick if (repo_path == NULL) {
9449 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
9450 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
9451 624411d2 2023-07-08 jrick goto done;
9452 624411d2 2023-07-08 jrick else
9453 624411d2 2023-07-08 jrick error = NULL;
9454 624411d2 2023-07-08 jrick if (worktree) {
9455 624411d2 2023-07-08 jrick repo_path =
9456 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
9457 624411d2 2023-07-08 jrick if (repo_path == NULL)
9458 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9459 624411d2 2023-07-08 jrick if (error)
9460 624411d2 2023-07-08 jrick goto done;
9461 624411d2 2023-07-08 jrick } else {
9462 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
9463 624411d2 2023-07-08 jrick if (repo_path == NULL) {
9464 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9465 624411d2 2023-07-08 jrick goto done;
9466 624411d2 2023-07-08 jrick }
9467 624411d2 2023-07-08 jrick }
9468 624411d2 2023-07-08 jrick }
9469 624411d2 2023-07-08 jrick
9470 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
9471 624411d2 2023-07-08 jrick if (error)
9472 624411d2 2023-07-08 jrick goto done;
9473 624411d2 2023-07-08 jrick
9474 624411d2 2023-07-08 jrick if (worktree) {
9475 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
9476 624411d2 2023-07-08 jrick if (worktree_conf) {
9477 624411d2 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
9478 624411d2 2023-07-08 jrick worktree_conf);
9479 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9480 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9481 624411d2 2023-07-08 jrick remote = &remotes[i];
9482 624411d2 2023-07-08 jrick break;
9483 624411d2 2023-07-08 jrick }
9484 624411d2 2023-07-08 jrick }
9485 624411d2 2023-07-08 jrick }
9486 624411d2 2023-07-08 jrick }
9487 624411d2 2023-07-08 jrick if (remote == NULL) {
9488 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
9489 624411d2 2023-07-08 jrick if (repo_conf) {
9490 624411d2 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
9491 624411d2 2023-07-08 jrick repo_conf);
9492 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9493 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9494 624411d2 2023-07-08 jrick remote = &remotes[i];
9495 624411d2 2023-07-08 jrick break;
9496 624411d2 2023-07-08 jrick }
9497 624411d2 2023-07-08 jrick }
9498 624411d2 2023-07-08 jrick }
9499 624411d2 2023-07-08 jrick }
9500 624411d2 2023-07-08 jrick if (remote == NULL) {
9501 624411d2 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
9502 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9503 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9504 624411d2 2023-07-08 jrick remote = &remotes[i];
9505 624411d2 2023-07-08 jrick break;
9506 624411d2 2023-07-08 jrick }
9507 624411d2 2023-07-08 jrick }
9508 624411d2 2023-07-08 jrick }
9509 624411d2 2023-07-08 jrick if (remote == NULL) {
9510 624411d2 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
9511 624411d2 2023-07-08 jrick goto done;
9512 624411d2 2023-07-08 jrick }
9513 624411d2 2023-07-08 jrick
9514 624411d2 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
9515 624411d2 2023-07-08 jrick &repo_name, remote->send_url);
9516 624411d2 2023-07-08 jrick if (error)
9517 624411d2 2023-07-08 jrick goto done;
9518 624411d2 2023-07-08 jrick
9519 624411d2 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
9520 624411d2 2023-07-08 jrick #ifndef PROFILE
9521 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9522 624411d2 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
9523 624411d2 2023-07-08 jrick err(1, "pledge");
9524 624411d2 2023-07-08 jrick #endif
9525 624411d2 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
9526 624411d2 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
9527 624411d2 2023-07-08 jrick #ifndef PROFILE
9528 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9529 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
9530 624411d2 2023-07-08 jrick err(1, "pledge");
9531 624411d2 2023-07-08 jrick #endif
9532 624411d2 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
9533 624411d2 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
9534 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
9535 624411d2 2023-07-08 jrick goto done;
9536 624411d2 2023-07-08 jrick } else {
9537 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
9538 624411d2 2023-07-08 jrick goto done;
9539 624411d2 2023-07-08 jrick }
9540 624411d2 2023-07-08 jrick
9541 624411d2 2023-07-08 jrick error = got_dial_apply_unveil(proto);
9542 624411d2 2023-07-08 jrick if (error)
9543 624411d2 2023-07-08 jrick goto done;
9544 624411d2 2023-07-08 jrick
9545 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
9546 624411d2 2023-07-08 jrick if (error)
9547 624411d2 2023-07-08 jrick goto done;
9548 624411d2 2023-07-08 jrick
9549 624411d2 2023-07-08 jrick if (send_all_branches) {
9550 624411d2 2023-07-08 jrick error = got_ref_list(&all_branches, repo, "refs/heads",
9551 624411d2 2023-07-08 jrick got_ref_cmp_by_name, NULL);
9552 624411d2 2023-07-08 jrick if (error)
9553 624411d2 2023-07-08 jrick goto done;
9554 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &all_branches, entry) {
9555 624411d2 2023-07-08 jrick const char *branchname = got_ref_get_name(re->ref);
9556 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches,
9557 624411d2 2023-07-08 jrick branchname, NULL);
9558 624411d2 2023-07-08 jrick if (error)
9559 624411d2 2023-07-08 jrick goto done;
9560 624411d2 2023-07-08 jrick nbranches++;
9561 624411d2 2023-07-08 jrick }
9562 624411d2 2023-07-08 jrick } else if (nbranches == 0) {
9563 624411d2 2023-07-08 jrick for (i = 0; i < remote->nsend_branches; i++) {
9564 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches,
9565 624411d2 2023-07-08 jrick remote->send_branches[i], NULL);
9566 624411d2 2023-07-08 jrick if (error)
9567 624411d2 2023-07-08 jrick goto done;
9568 624411d2 2023-07-08 jrick }
9569 624411d2 2023-07-08 jrick }
9570 624411d2 2023-07-08 jrick
9571 624411d2 2023-07-08 jrick if (send_all_tags) {
9572 624411d2 2023-07-08 jrick error = got_ref_list(&all_tags, repo, "refs/tags",
9573 624411d2 2023-07-08 jrick got_ref_cmp_by_name, NULL);
9574 624411d2 2023-07-08 jrick if (error)
9575 624411d2 2023-07-08 jrick goto done;
9576 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &all_tags, entry) {
9577 624411d2 2023-07-08 jrick const char *tagname = got_ref_get_name(re->ref);
9578 624411d2 2023-07-08 jrick error = got_pathlist_append(&tags,
9579 624411d2 2023-07-08 jrick tagname, NULL);
9580 624411d2 2023-07-08 jrick if (error)
9581 624411d2 2023-07-08 jrick goto done;
9582 624411d2 2023-07-08 jrick }
9583 624411d2 2023-07-08 jrick }
9584 624411d2 2023-07-08 jrick
9585 624411d2 2023-07-08 jrick /*
9586 624411d2 2023-07-08 jrick * To prevent accidents only branches in refs/heads/ can be deleted
9587 624411d2 2023-07-08 jrick * with 'got send -d'.
9588 624411d2 2023-07-08 jrick * Deleting anything else requires local repository access or Git.
9589 624411d2 2023-07-08 jrick */
9590 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &delete_args, entry) {
9591 624411d2 2023-07-08 jrick const char *branchname = pe->path;
9592 624411d2 2023-07-08 jrick char *s;
9593 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
9594 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0) {
9595 624411d2 2023-07-08 jrick s = strdup(branchname);
9596 624411d2 2023-07-08 jrick if (s == NULL) {
9597 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9598 624411d2 2023-07-08 jrick goto done;
9599 624411d2 2023-07-08 jrick }
9600 624411d2 2023-07-08 jrick } else {
9601 624411d2 2023-07-08 jrick if (asprintf(&s, "refs/heads/%s", branchname) == -1) {
9602 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
9603 624411d2 2023-07-08 jrick goto done;
9604 624411d2 2023-07-08 jrick }
9605 624411d2 2023-07-08 jrick }
9606 624411d2 2023-07-08 jrick error = got_pathlist_insert(&new, &delete_branches, s, NULL);
9607 624411d2 2023-07-08 jrick if (error || new == NULL /* duplicate */)
9608 624411d2 2023-07-08 jrick free(s);
9609 624411d2 2023-07-08 jrick if (error)
9610 624411d2 2023-07-08 jrick goto done;
9611 624411d2 2023-07-08 jrick ndelete_branches++;
9612 624411d2 2023-07-08 jrick }
9613 624411d2 2023-07-08 jrick
9614 624411d2 2023-07-08 jrick if (nbranches == 0 && ndelete_branches == 0) {
9615 624411d2 2023-07-08 jrick struct got_reference *head_ref;
9616 624411d2 2023-07-08 jrick if (worktree)
9617 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
9618 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
9619 624411d2 2023-07-08 jrick else
9620 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
9621 624411d2 2023-07-08 jrick if (error)
9622 624411d2 2023-07-08 jrick goto done;
9623 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(head_ref)) {
9624 624411d2 2023-07-08 jrick error = got_ref_resolve_symbolic(&ref, repo, head_ref);
9625 624411d2 2023-07-08 jrick got_ref_close(head_ref);
9626 624411d2 2023-07-08 jrick if (error)
9627 624411d2 2023-07-08 jrick goto done;
9628 624411d2 2023-07-08 jrick } else
9629 624411d2 2023-07-08 jrick ref = head_ref;
9630 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches, got_ref_get_name(ref),
9631 624411d2 2023-07-08 jrick NULL);
9632 624411d2 2023-07-08 jrick if (error)
9633 624411d2 2023-07-08 jrick goto done;
9634 624411d2 2023-07-08 jrick nbranches++;
9635 624411d2 2023-07-08 jrick }
9636 624411d2 2023-07-08 jrick
9637 624411d2 2023-07-08 jrick if (verbosity >= 0) {
9638 624411d2 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
9639 624411d2 2023-07-08 jrick remote->name, proto, host,
9640 624411d2 2023-07-08 jrick port ? ":" : "", port ? port : "",
9641 624411d2 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
9642 624411d2 2023-07-08 jrick }
9643 624411d2 2023-07-08 jrick
9644 624411d2 2023-07-08 jrick error = got_send_connect(&sendpid, &sendfd, proto, host, port,
9645 624411d2 2023-07-08 jrick server_path, verbosity);
9646 624411d2 2023-07-08 jrick if (error)
9647 624411d2 2023-07-08 jrick goto done;
9648 624411d2 2023-07-08 jrick
9649 624411d2 2023-07-08 jrick memset(&spa, 0, sizeof(spa));
9650 624411d2 2023-07-08 jrick spa.last_scaled_packsize[0] = '\0';
9651 624411d2 2023-07-08 jrick spa.last_p_deltify = -1;
9652 624411d2 2023-07-08 jrick spa.last_p_written = -1;
9653 624411d2 2023-07-08 jrick spa.verbosity = verbosity;
9654 624411d2 2023-07-08 jrick spa.delete_branches = &delete_branches;
9655 624411d2 2023-07-08 jrick error = got_send_pack(remote_name, &branches, &tags, &delete_branches,
9656 624411d2 2023-07-08 jrick verbosity, overwrite_refs, sendfd, repo, send_progress, &spa,
9657 624411d2 2023-07-08 jrick check_cancelled, NULL);
9658 624411d2 2023-07-08 jrick if (spa.printed_something)
9659 624411d2 2023-07-08 jrick putchar('\n');
9660 624411d2 2023-07-08 jrick if (error)
9661 624411d2 2023-07-08 jrick goto done;
9662 624411d2 2023-07-08 jrick if (!spa.sent_something && verbosity >= 0)
9663 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
9664 624411d2 2023-07-08 jrick done:
9665 624411d2 2023-07-08 jrick if (sendpid > 0) {
9666 624411d2 2023-07-08 jrick if (kill(sendpid, SIGTERM) == -1)
9667 624411d2 2023-07-08 jrick error = got_error_from_errno("kill");
9668 624411d2 2023-07-08 jrick if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL)
9669 624411d2 2023-07-08 jrick error = got_error_from_errno("waitpid");
9670 624411d2 2023-07-08 jrick }
9671 624411d2 2023-07-08 jrick if (sendfd != -1 && close(sendfd) == -1 && error == NULL)
9672 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
9673 624411d2 2023-07-08 jrick if (repo) {
9674 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
9675 624411d2 2023-07-08 jrick if (error == NULL)
9676 624411d2 2023-07-08 jrick error = close_err;
9677 624411d2 2023-07-08 jrick }
9678 624411d2 2023-07-08 jrick if (worktree)
9679 624411d2 2023-07-08 jrick got_worktree_close(worktree);
9680 624411d2 2023-07-08 jrick if (pack_fds) {
9681 624411d2 2023-07-08 jrick const struct got_error *pack_err =
9682 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
9683 624411d2 2023-07-08 jrick if (error == NULL)
9684 624411d2 2023-07-08 jrick error = pack_err;
9685 624411d2 2023-07-08 jrick }
9686 624411d2 2023-07-08 jrick if (ref)
9687 624411d2 2023-07-08 jrick got_ref_close(ref);
9688 624411d2 2023-07-08 jrick got_pathlist_free(&branches, GOT_PATHLIST_FREE_NONE);
9689 624411d2 2023-07-08 jrick got_pathlist_free(&tags, GOT_PATHLIST_FREE_NONE);
9690 624411d2 2023-07-08 jrick got_ref_list_free(&all_branches);
9691 624411d2 2023-07-08 jrick got_ref_list_free(&all_tags);
9692 624411d2 2023-07-08 jrick got_pathlist_free(&delete_args, GOT_PATHLIST_FREE_NONE);
9693 624411d2 2023-07-08 jrick got_pathlist_free(&delete_branches, GOT_PATHLIST_FREE_PATH);
9694 624411d2 2023-07-08 jrick free(cwd);
9695 624411d2 2023-07-08 jrick free(repo_path);
9696 624411d2 2023-07-08 jrick free(proto);
9697 624411d2 2023-07-08 jrick free(host);
9698 624411d2 2023-07-08 jrick free(port);
9699 624411d2 2023-07-08 jrick free(server_path);
9700 624411d2 2023-07-08 jrick free(repo_name);
9701 624411d2 2023-07-08 jrick return error;
9702 624411d2 2023-07-08 jrick }
9703 624411d2 2023-07-08 jrick
9704 624411d2 2023-07-08 jrick /*
9705 624411d2 2023-07-08 jrick * Print and if delete is set delete all ref_prefix references.
9706 624411d2 2023-07-08 jrick * If wanted_ref is not NULL, only print or delete this reference.
9707 624411d2 2023-07-08 jrick */
9708 624411d2 2023-07-08 jrick static const struct got_error *
9709 624411d2 2023-07-08 jrick process_logmsg_refs(const char *ref_prefix, size_t prefix_len,
9710 624411d2 2023-07-08 jrick const char *wanted_ref, int delete, struct got_worktree *worktree,
9711 624411d2 2023-07-08 jrick struct got_repository *repo)
9712 624411d2 2023-07-08 jrick {
9713 624411d2 2023-07-08 jrick const struct got_error *err;
9714 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
9715 624411d2 2023-07-08 jrick struct got_reflist_head refs;
9716 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
9717 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
9718 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
9719 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
9720 624411d2 2023-07-08 jrick const char *header_prefix;
9721 624411d2 2023-07-08 jrick char *uuidstr = NULL;
9722 624411d2 2023-07-08 jrick int found = 0;
9723 624411d2 2023-07-08 jrick
9724 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
9725 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
9726 624411d2 2023-07-08 jrick
9727 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo);
9728 624411d2 2023-07-08 jrick if (err)
9729 624411d2 2023-07-08 jrick goto done;
9730 624411d2 2023-07-08 jrick
9731 624411d2 2023-07-08 jrick err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
9732 624411d2 2023-07-08 jrick if (err)
9733 624411d2 2023-07-08 jrick goto done;
9734 624411d2 2023-07-08 jrick
9735 624411d2 2023-07-08 jrick if (worktree != NULL) {
9736 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
9737 624411d2 2023-07-08 jrick if (err)
9738 624411d2 2023-07-08 jrick goto done;
9739 624411d2 2023-07-08 jrick }
9740 624411d2 2023-07-08 jrick
9741 624411d2 2023-07-08 jrick if (wanted_ref) {
9742 624411d2 2023-07-08 jrick if (strncmp(wanted_ref, "refs/heads/", 11) == 0)
9743 624411d2 2023-07-08 jrick wanted_ref += 11;
9744 624411d2 2023-07-08 jrick }
9745 624411d2 2023-07-08 jrick
9746 624411d2 2023-07-08 jrick if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0)
9747 624411d2 2023-07-08 jrick header_prefix = "backout";
9748 624411d2 2023-07-08 jrick else
9749 624411d2 2023-07-08 jrick header_prefix = "cherrypick";
9750 624411d2 2023-07-08 jrick
9751 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
9752 624411d2 2023-07-08 jrick const char *refname, *wt;
9753 624411d2 2023-07-08 jrick
9754 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
9755 624411d2 2023-07-08 jrick
9756 624411d2 2023-07-08 jrick err = check_cancelled(NULL);
9757 624411d2 2023-07-08 jrick if (err)
9758 624411d2 2023-07-08 jrick goto done;
9759 624411d2 2023-07-08 jrick
9760 624411d2 2023-07-08 jrick if (strncmp(refname, ref_prefix, prefix_len) == 0)
9761 624411d2 2023-07-08 jrick refname += prefix_len + 1; /* skip '-' delimiter */
9762 624411d2 2023-07-08 jrick else
9763 624411d2 2023-07-08 jrick continue;
9764 624411d2 2023-07-08 jrick
9765 624411d2 2023-07-08 jrick wt = refname;
9766 624411d2 2023-07-08 jrick
9767 624411d2 2023-07-08 jrick if (worktree == NULL || strncmp(refname, uuidstr,
9768 624411d2 2023-07-08 jrick GOT_WORKTREE_UUID_STRLEN) == 0)
9769 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
9770 624411d2 2023-07-08 jrick else
9771 624411d2 2023-07-08 jrick continue;
9772 624411d2 2023-07-08 jrick
9773 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, refname,
9774 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
9775 624411d2 2023-07-08 jrick if (err)
9776 624411d2 2023-07-08 jrick goto done;
9777 624411d2 2023-07-08 jrick
9778 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
9779 624411d2 2023-07-08 jrick if (err)
9780 624411d2 2023-07-08 jrick goto done;
9781 624411d2 2023-07-08 jrick
9782 624411d2 2023-07-08 jrick if (wanted_ref)
9783 624411d2 2023-07-08 jrick found = strncmp(wanted_ref, refname,
9784 624411d2 2023-07-08 jrick strlen(wanted_ref)) == 0;
9785 624411d2 2023-07-08 jrick if (wanted_ref && !found) {
9786 624411d2 2023-07-08 jrick struct got_reflist_head *ci_refs;
9787 624411d2 2023-07-08 jrick
9788 624411d2 2023-07-08 jrick ci_refs = got_reflist_object_id_map_lookup(refs_idmap,
9789 624411d2 2023-07-08 jrick id);
9790 624411d2 2023-07-08 jrick
9791 624411d2 2023-07-08 jrick if (ci_refs) {
9792 624411d2 2023-07-08 jrick char *refs_str = NULL;
9793 624411d2 2023-07-08 jrick char const *r = NULL;
9794 624411d2 2023-07-08 jrick
9795 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, ci_refs, id,
9796 624411d2 2023-07-08 jrick repo, 1);
9797 624411d2 2023-07-08 jrick if (err)
9798 624411d2 2023-07-08 jrick goto done;
9799 624411d2 2023-07-08 jrick
9800 624411d2 2023-07-08 jrick r = refs_str;
9801 624411d2 2023-07-08 jrick while (r) {
9802 624411d2 2023-07-08 jrick if (strncmp(r, wanted_ref,
9803 624411d2 2023-07-08 jrick strlen(wanted_ref)) == 0) {
9804 624411d2 2023-07-08 jrick found = 1;
9805 624411d2 2023-07-08 jrick break;
9806 624411d2 2023-07-08 jrick }
9807 624411d2 2023-07-08 jrick r = strchr(r, ' ');
9808 624411d2 2023-07-08 jrick if (r)
9809 624411d2 2023-07-08 jrick ++r;
9810 624411d2 2023-07-08 jrick }
9811 624411d2 2023-07-08 jrick free(refs_str);
9812 624411d2 2023-07-08 jrick }
9813 624411d2 2023-07-08 jrick }
9814 624411d2 2023-07-08 jrick
9815 624411d2 2023-07-08 jrick if (wanted_ref == NULL || found) {
9816 624411d2 2023-07-08 jrick if (delete) {
9817 624411d2 2023-07-08 jrick err = got_ref_delete(re->ref, repo);
9818 624411d2 2023-07-08 jrick if (err)
9819 624411d2 2023-07-08 jrick goto done;
9820 624411d2 2023-07-08 jrick printf("Deleted: ");
9821 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, id, repo,
9822 624411d2 2023-07-08 jrick refs_idmap);
9823 624411d2 2023-07-08 jrick } else {
9824 624411d2 2023-07-08 jrick /*
9825 624411d2 2023-07-08 jrick * Print paths modified by commit to help
9826 624411d2 2023-07-08 jrick * associate commits with worktree changes.
9827 624411d2 2023-07-08 jrick */
9828 624411d2 2023-07-08 jrick err = get_changed_paths(&paths, commit,
9829 624411d2 2023-07-08 jrick repo, NULL);
9830 624411d2 2023-07-08 jrick if (err)
9831 624411d2 2023-07-08 jrick goto done;
9832 624411d2 2023-07-08 jrick
9833 624411d2 2023-07-08 jrick err = print_commit(commit, id, repo, NULL,
9834 624411d2 2023-07-08 jrick &paths, NULL, 0, 0, refs_idmap, NULL,
9835 624411d2 2023-07-08 jrick header_prefix);
9836 624411d2 2023-07-08 jrick got_pathlist_free(&paths,
9837 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_ALL);
9838 624411d2 2023-07-08 jrick
9839 624411d2 2023-07-08 jrick if (worktree == NULL)
9840 624411d2 2023-07-08 jrick printf("work tree: %.*s\n\n",
9841 624411d2 2023-07-08 jrick GOT_WORKTREE_UUID_STRLEN, wt);
9842 624411d2 2023-07-08 jrick }
9843 624411d2 2023-07-08 jrick if (err || found)
9844 624411d2 2023-07-08 jrick goto done;
9845 624411d2 2023-07-08 jrick }
9846 624411d2 2023-07-08 jrick
9847 624411d2 2023-07-08 jrick got_object_commit_close(commit);
9848 624411d2 2023-07-08 jrick commit = NULL;
9849 624411d2 2023-07-08 jrick free(id);
9850 624411d2 2023-07-08 jrick id = NULL;
9851 624411d2 2023-07-08 jrick }
9852 624411d2 2023-07-08 jrick
9853 624411d2 2023-07-08 jrick if (wanted_ref != NULL && !found)
9854 624411d2 2023-07-08 jrick err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref);
9855 624411d2 2023-07-08 jrick
9856 624411d2 2023-07-08 jrick done:
9857 624411d2 2023-07-08 jrick free(id);
9858 624411d2 2023-07-08 jrick free(uuidstr);
9859 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
9860 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
9861 624411d2 2023-07-08 jrick if (refs_idmap)
9862 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
9863 624411d2 2023-07-08 jrick if (commit)
9864 624411d2 2023-07-08 jrick got_object_commit_close(commit);
9865 624411d2 2023-07-08 jrick return err;
9866 624411d2 2023-07-08 jrick }
9867 624411d2 2023-07-08 jrick
9868 624411d2 2023-07-08 jrick /*
9869 624411d2 2023-07-08 jrick * Create new temp "logmsg" ref of the backed-out or cherrypicked commit
9870 624411d2 2023-07-08 jrick * identified by id for log messages to prepopulate the editor on commit.
9871 624411d2 2023-07-08 jrick */
9872 624411d2 2023-07-08 jrick static const struct got_error *
9873 624411d2 2023-07-08 jrick logmsg_ref(struct got_object_id *id, const char *prefix,
9874 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
9875 624411d2 2023-07-08 jrick {
9876 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
9877 624411d2 2023-07-08 jrick char *idstr, *ref = NULL, *refname = NULL;
9878 624411d2 2023-07-08 jrick int histedit_in_progress;
9879 624411d2 2023-07-08 jrick int rebase_in_progress, merge_in_progress;
9880 624411d2 2023-07-08 jrick
9881 624411d2 2023-07-08 jrick /*
9882 624411d2 2023-07-08 jrick * Silenty refuse to create merge reference if any histedit, merge,
9883 624411d2 2023-07-08 jrick * or rebase operation is in progress.
9884 624411d2 2023-07-08 jrick */
9885 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&histedit_in_progress,
9886 624411d2 2023-07-08 jrick worktree);
9887 624411d2 2023-07-08 jrick if (err)
9888 624411d2 2023-07-08 jrick return err;
9889 624411d2 2023-07-08 jrick if (histedit_in_progress)
9890 624411d2 2023-07-08 jrick return NULL;
9891 624411d2 2023-07-08 jrick
9892 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
9893 624411d2 2023-07-08 jrick if (err)
9894 624411d2 2023-07-08 jrick return err;
9895 624411d2 2023-07-08 jrick if (rebase_in_progress)
9896 624411d2 2023-07-08 jrick return NULL;
9897 624411d2 2023-07-08 jrick
9898 624411d2 2023-07-08 jrick err = got_worktree_merge_in_progress(&merge_in_progress, worktree,
9899 624411d2 2023-07-08 jrick repo);
9900 624411d2 2023-07-08 jrick if (err)
9901 624411d2 2023-07-08 jrick return err;
9902 624411d2 2023-07-08 jrick if (merge_in_progress)
9903 624411d2 2023-07-08 jrick return NULL;
9904 624411d2 2023-07-08 jrick
9905 624411d2 2023-07-08 jrick err = got_object_id_str(&idstr, id);
9906 624411d2 2023-07-08 jrick if (err)
9907 624411d2 2023-07-08 jrick return err;
9908 624411d2 2023-07-08 jrick
9909 624411d2 2023-07-08 jrick err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix);
9910 624411d2 2023-07-08 jrick if (err)
9911 624411d2 2023-07-08 jrick goto done;
9912 624411d2 2023-07-08 jrick
9913 624411d2 2023-07-08 jrick if (asprintf(&ref, "%s-%s", refname, idstr) == -1) {
9914 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
9915 624411d2 2023-07-08 jrick goto done;
9916 624411d2 2023-07-08 jrick }
9917 624411d2 2023-07-08 jrick
9918 624411d2 2023-07-08 jrick err = create_ref(ref, got_worktree_get_base_commit_id(worktree),
9919 624411d2 2023-07-08 jrick -1, repo);
9920 624411d2 2023-07-08 jrick done:
9921 624411d2 2023-07-08 jrick free(ref);
9922 624411d2 2023-07-08 jrick free(idstr);
9923 624411d2 2023-07-08 jrick free(refname);
9924 624411d2 2023-07-08 jrick return err;
9925 624411d2 2023-07-08 jrick }
9926 624411d2 2023-07-08 jrick
9927 624411d2 2023-07-08 jrick __dead static void
9928 624411d2 2023-07-08 jrick usage_cherrypick(void)
9929 624411d2 2023-07-08 jrick {
9930 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
9931 624411d2 2023-07-08 jrick getprogname());
9932 624411d2 2023-07-08 jrick exit(1);
9933 624411d2 2023-07-08 jrick }
9934 624411d2 2023-07-08 jrick
9935 624411d2 2023-07-08 jrick static const struct got_error *
9936 624411d2 2023-07-08 jrick cmd_cherrypick(int argc, char *argv[])
9937 624411d2 2023-07-08 jrick {
9938 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
9939 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
9940 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
9941 624411d2 2023-07-08 jrick char *cwd = NULL, *commit_id_str = NULL;
9942 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
9943 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
9944 624411d2 2023-07-08 jrick struct got_object_qid *pid;
9945 624411d2 2023-07-08 jrick int ch, list_refs = 0, remove_refs = 0;
9946 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
9947 624411d2 2023-07-08 jrick int *pack_fds = NULL;
9948 624411d2 2023-07-08 jrick
9949 624411d2 2023-07-08 jrick #ifndef PROFILE
9950 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9951 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
9952 624411d2 2023-07-08 jrick err(1, "pledge");
9953 624411d2 2023-07-08 jrick #endif
9954 624411d2 2023-07-08 jrick
9955 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "lX")) != -1) {
9956 624411d2 2023-07-08 jrick switch (ch) {
9957 624411d2 2023-07-08 jrick case 'l':
9958 624411d2 2023-07-08 jrick list_refs = 1;
9959 624411d2 2023-07-08 jrick break;
9960 624411d2 2023-07-08 jrick case 'X':
9961 624411d2 2023-07-08 jrick remove_refs = 1;
9962 624411d2 2023-07-08 jrick break;
9963 624411d2 2023-07-08 jrick default:
9964 624411d2 2023-07-08 jrick usage_cherrypick();
9965 624411d2 2023-07-08 jrick /* NOTREACHED */
9966 624411d2 2023-07-08 jrick }
9967 624411d2 2023-07-08 jrick }
9968 624411d2 2023-07-08 jrick
9969 624411d2 2023-07-08 jrick argc -= optind;
9970 624411d2 2023-07-08 jrick argv += optind;
9971 624411d2 2023-07-08 jrick
9972 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
9973 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
9974 624411d2 2023-07-08 jrick usage_cherrypick();
9975 624411d2 2023-07-08 jrick } else if (argc != 1)
9976 624411d2 2023-07-08 jrick usage_cherrypick();
9977 624411d2 2023-07-08 jrick if (list_refs && remove_refs)
9978 624411d2 2023-07-08 jrick option_conflict('l', 'X');
9979 624411d2 2023-07-08 jrick
9980 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
9981 624411d2 2023-07-08 jrick if (cwd == NULL) {
9982 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
9983 624411d2 2023-07-08 jrick goto done;
9984 624411d2 2023-07-08 jrick }
9985 624411d2 2023-07-08 jrick
9986 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
9987 624411d2 2023-07-08 jrick if (error != NULL)
9988 624411d2 2023-07-08 jrick goto done;
9989 624411d2 2023-07-08 jrick
9990 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
9991 624411d2 2023-07-08 jrick if (error) {
9992 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
9993 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
9994 624411d2 2023-07-08 jrick goto done;
9995 624411d2 2023-07-08 jrick } else {
9996 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
9997 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
9998 624411d2 2023-07-08 jrick "cherrypick", cwd);
9999 624411d2 2023-07-08 jrick goto done;
10000 624411d2 2023-07-08 jrick }
10001 624411d2 2023-07-08 jrick }
10002 624411d2 2023-07-08 jrick
10003 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10004 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10005 624411d2 2023-07-08 jrick NULL, pack_fds);
10006 624411d2 2023-07-08 jrick if (error != NULL)
10007 624411d2 2023-07-08 jrick goto done;
10008 624411d2 2023-07-08 jrick
10009 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10010 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10011 624411d2 2023-07-08 jrick if (error)
10012 624411d2 2023-07-08 jrick goto done;
10013 624411d2 2023-07-08 jrick
10014 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10015 624411d2 2023-07-08 jrick error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
10016 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN,
10017 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
10018 624411d2 2023-07-08 jrick goto done;
10019 624411d2 2023-07-08 jrick }
10020 624411d2 2023-07-08 jrick
10021 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL, argv[0],
10022 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
10023 624411d2 2023-07-08 jrick if (error)
10024 624411d2 2023-07-08 jrick goto done;
10025 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
10026 624411d2 2023-07-08 jrick if (error)
10027 624411d2 2023-07-08 jrick goto done;
10028 624411d2 2023-07-08 jrick
10029 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10030 624411d2 2023-07-08 jrick if (error)
10031 624411d2 2023-07-08 jrick goto done;
10032 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
10033 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10034 624411d2 2023-07-08 jrick error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL,
10035 624411d2 2023-07-08 jrick commit_id, repo, update_progress, &upa, check_cancelled,
10036 624411d2 2023-07-08 jrick NULL);
10037 624411d2 2023-07-08 jrick if (error != NULL)
10038 624411d2 2023-07-08 jrick goto done;
10039 624411d2 2023-07-08 jrick
10040 624411d2 2023-07-08 jrick if (upa.did_something) {
10041 624411d2 2023-07-08 jrick error = logmsg_ref(commit_id,
10042 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo);
10043 624411d2 2023-07-08 jrick if (error)
10044 624411d2 2023-07-08 jrick goto done;
10045 624411d2 2023-07-08 jrick printf("Merged commit %s\n", commit_id_str);
10046 624411d2 2023-07-08 jrick }
10047 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
10048 624411d2 2023-07-08 jrick done:
10049 624411d2 2023-07-08 jrick free(cwd);
10050 624411d2 2023-07-08 jrick if (commit)
10051 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10052 624411d2 2023-07-08 jrick free(commit_id_str);
10053 624411d2 2023-07-08 jrick if (worktree)
10054 624411d2 2023-07-08 jrick got_worktree_close(worktree);
10055 624411d2 2023-07-08 jrick if (repo) {
10056 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
10057 624411d2 2023-07-08 jrick if (error == NULL)
10058 624411d2 2023-07-08 jrick error = close_err;
10059 624411d2 2023-07-08 jrick }
10060 624411d2 2023-07-08 jrick if (pack_fds) {
10061 624411d2 2023-07-08 jrick const struct got_error *pack_err =
10062 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
10063 624411d2 2023-07-08 jrick if (error == NULL)
10064 624411d2 2023-07-08 jrick error = pack_err;
10065 624411d2 2023-07-08 jrick }
10066 624411d2 2023-07-08 jrick
10067 624411d2 2023-07-08 jrick return error;
10068 624411d2 2023-07-08 jrick }
10069 624411d2 2023-07-08 jrick
10070 624411d2 2023-07-08 jrick __dead static void
10071 624411d2 2023-07-08 jrick usage_backout(void)
10072 624411d2 2023-07-08 jrick {
10073 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
10074 624411d2 2023-07-08 jrick exit(1);
10075 624411d2 2023-07-08 jrick }
10076 624411d2 2023-07-08 jrick
10077 624411d2 2023-07-08 jrick static const struct got_error *
10078 624411d2 2023-07-08 jrick cmd_backout(int argc, char *argv[])
10079 624411d2 2023-07-08 jrick {
10080 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
10081 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
10082 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
10083 624411d2 2023-07-08 jrick char *cwd = NULL, *commit_id_str = NULL;
10084 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
10085 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10086 624411d2 2023-07-08 jrick struct got_object_qid *pid;
10087 624411d2 2023-07-08 jrick int ch, list_refs = 0, remove_refs = 0;
10088 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
10089 624411d2 2023-07-08 jrick int *pack_fds = NULL;
10090 624411d2 2023-07-08 jrick
10091 624411d2 2023-07-08 jrick #ifndef PROFILE
10092 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10093 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
10094 624411d2 2023-07-08 jrick err(1, "pledge");
10095 624411d2 2023-07-08 jrick #endif
10096 624411d2 2023-07-08 jrick
10097 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "lX")) != -1) {
10098 624411d2 2023-07-08 jrick switch (ch) {
10099 624411d2 2023-07-08 jrick case 'l':
10100 624411d2 2023-07-08 jrick list_refs = 1;
10101 624411d2 2023-07-08 jrick break;
10102 624411d2 2023-07-08 jrick case 'X':
10103 624411d2 2023-07-08 jrick remove_refs = 1;
10104 624411d2 2023-07-08 jrick break;
10105 624411d2 2023-07-08 jrick default:
10106 624411d2 2023-07-08 jrick usage_backout();
10107 624411d2 2023-07-08 jrick /* NOTREACHED */
10108 624411d2 2023-07-08 jrick }
10109 624411d2 2023-07-08 jrick }
10110 624411d2 2023-07-08 jrick
10111 624411d2 2023-07-08 jrick argc -= optind;
10112 624411d2 2023-07-08 jrick argv += optind;
10113 624411d2 2023-07-08 jrick
10114 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10115 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10116 624411d2 2023-07-08 jrick usage_backout();
10117 624411d2 2023-07-08 jrick } else if (argc != 1)
10118 624411d2 2023-07-08 jrick usage_backout();
10119 624411d2 2023-07-08 jrick if (list_refs && remove_refs)
10120 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10121 624411d2 2023-07-08 jrick
10122 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
10123 624411d2 2023-07-08 jrick if (cwd == NULL) {
10124 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
10125 624411d2 2023-07-08 jrick goto done;
10126 624411d2 2023-07-08 jrick }
10127 624411d2 2023-07-08 jrick
10128 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
10129 624411d2 2023-07-08 jrick if (error != NULL)
10130 624411d2 2023-07-08 jrick goto done;
10131 624411d2 2023-07-08 jrick
10132 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
10133 624411d2 2023-07-08 jrick if (error) {
10134 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10135 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
10136 624411d2 2023-07-08 jrick goto done;
10137 624411d2 2023-07-08 jrick } else {
10138 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
10139 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
10140 624411d2 2023-07-08 jrick "backout", cwd);
10141 624411d2 2023-07-08 jrick goto done;
10142 624411d2 2023-07-08 jrick }
10143 624411d2 2023-07-08 jrick }
10144 624411d2 2023-07-08 jrick
10145 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10146 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10147 624411d2 2023-07-08 jrick NULL, pack_fds);
10148 624411d2 2023-07-08 jrick if (error != NULL)
10149 624411d2 2023-07-08 jrick goto done;
10150 624411d2 2023-07-08 jrick
10151 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10152 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10153 624411d2 2023-07-08 jrick if (error)
10154 624411d2 2023-07-08 jrick goto done;
10155 624411d2 2023-07-08 jrick
10156 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10157 624411d2 2023-07-08 jrick error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX,
10158 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN,
10159 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
10160 624411d2 2023-07-08 jrick goto done;
10161 624411d2 2023-07-08 jrick }
10162 624411d2 2023-07-08 jrick
10163 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL, argv[0],
10164 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
10165 624411d2 2023-07-08 jrick if (error)
10166 624411d2 2023-07-08 jrick goto done;
10167 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
10168 624411d2 2023-07-08 jrick if (error)
10169 624411d2 2023-07-08 jrick goto done;
10170 624411d2 2023-07-08 jrick
10171 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10172 624411d2 2023-07-08 jrick if (error)
10173 624411d2 2023-07-08 jrick goto done;
10174 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
10175 624411d2 2023-07-08 jrick if (pid == NULL) {
10176 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_ROOT_COMMIT);
10177 624411d2 2023-07-08 jrick goto done;
10178 624411d2 2023-07-08 jrick }
10179 624411d2 2023-07-08 jrick
10180 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10181 624411d2 2023-07-08 jrick error = got_worktree_merge_files(worktree, commit_id, &pid->id,
10182 624411d2 2023-07-08 jrick repo, update_progress, &upa, check_cancelled, NULL);
10183 624411d2 2023-07-08 jrick if (error != NULL)
10184 624411d2 2023-07-08 jrick goto done;
10185 624411d2 2023-07-08 jrick
10186 624411d2 2023-07-08 jrick if (upa.did_something) {
10187 624411d2 2023-07-08 jrick error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX,
10188 624411d2 2023-07-08 jrick worktree, repo);
10189 624411d2 2023-07-08 jrick if (error)
10190 624411d2 2023-07-08 jrick goto done;
10191 624411d2 2023-07-08 jrick printf("Backed out commit %s\n", commit_id_str);
10192 624411d2 2023-07-08 jrick }
10193 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
10194 624411d2 2023-07-08 jrick done:
10195 624411d2 2023-07-08 jrick free(cwd);
10196 624411d2 2023-07-08 jrick if (commit)
10197 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10198 624411d2 2023-07-08 jrick free(commit_id_str);
10199 624411d2 2023-07-08 jrick if (worktree)
10200 624411d2 2023-07-08 jrick got_worktree_close(worktree);
10201 624411d2 2023-07-08 jrick if (repo) {
10202 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
10203 624411d2 2023-07-08 jrick if (error == NULL)
10204 624411d2 2023-07-08 jrick error = close_err;
10205 624411d2 2023-07-08 jrick }
10206 624411d2 2023-07-08 jrick if (pack_fds) {
10207 624411d2 2023-07-08 jrick const struct got_error *pack_err =
10208 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
10209 624411d2 2023-07-08 jrick if (error == NULL)
10210 624411d2 2023-07-08 jrick error = pack_err;
10211 624411d2 2023-07-08 jrick }
10212 624411d2 2023-07-08 jrick return error;
10213 624411d2 2023-07-08 jrick }
10214 624411d2 2023-07-08 jrick
10215 624411d2 2023-07-08 jrick __dead static void
10216 624411d2 2023-07-08 jrick usage_rebase(void)
10217 624411d2 2023-07-08 jrick {
10218 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
10219 624411d2 2023-07-08 jrick exit(1);
10220 624411d2 2023-07-08 jrick }
10221 624411d2 2023-07-08 jrick
10222 624411d2 2023-07-08 jrick static void
10223 624411d2 2023-07-08 jrick trim_logmsg(char *logmsg, int limit)
10224 624411d2 2023-07-08 jrick {
10225 624411d2 2023-07-08 jrick char *nl;
10226 624411d2 2023-07-08 jrick size_t len;
10227 624411d2 2023-07-08 jrick
10228 624411d2 2023-07-08 jrick len = strlen(logmsg);
10229 624411d2 2023-07-08 jrick if (len > limit)
10230 624411d2 2023-07-08 jrick len = limit;
10231 624411d2 2023-07-08 jrick logmsg[len] = '\0';
10232 624411d2 2023-07-08 jrick nl = strchr(logmsg, '\n');
10233 624411d2 2023-07-08 jrick if (nl)
10234 624411d2 2023-07-08 jrick *nl = '\0';
10235 624411d2 2023-07-08 jrick }
10236 624411d2 2023-07-08 jrick
10237 624411d2 2023-07-08 jrick static const struct got_error *
10238 624411d2 2023-07-08 jrick get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
10239 624411d2 2023-07-08 jrick {
10240 624411d2 2023-07-08 jrick const struct got_error *err;
10241 624411d2 2023-07-08 jrick char *logmsg0 = NULL;
10242 624411d2 2023-07-08 jrick const char *s;
10243 624411d2 2023-07-08 jrick
10244 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
10245 624411d2 2023-07-08 jrick if (err)
10246 624411d2 2023-07-08 jrick return err;
10247 624411d2 2023-07-08 jrick
10248 624411d2 2023-07-08 jrick s = logmsg0;
10249 624411d2 2023-07-08 jrick while (isspace((unsigned char)s[0]))
10250 624411d2 2023-07-08 jrick s++;
10251 624411d2 2023-07-08 jrick
10252 624411d2 2023-07-08 jrick *logmsg = strdup(s);
10253 624411d2 2023-07-08 jrick if (*logmsg == NULL) {
10254 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
10255 624411d2 2023-07-08 jrick goto done;
10256 624411d2 2023-07-08 jrick }
10257 624411d2 2023-07-08 jrick
10258 624411d2 2023-07-08 jrick trim_logmsg(*logmsg, limit);
10259 624411d2 2023-07-08 jrick done:
10260 624411d2 2023-07-08 jrick free(logmsg0);
10261 624411d2 2023-07-08 jrick return err;
10262 624411d2 2023-07-08 jrick }
10263 624411d2 2023-07-08 jrick
10264 624411d2 2023-07-08 jrick static const struct got_error *
10265 624411d2 2023-07-08 jrick show_rebase_merge_conflict(struct got_object_id *id,
10266 624411d2 2023-07-08 jrick struct got_repository *repo)
10267 624411d2 2023-07-08 jrick {
10268 624411d2 2023-07-08 jrick const struct got_error *err;
10269 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10270 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg = NULL;
10271 624411d2 2023-07-08 jrick
10272 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
10273 624411d2 2023-07-08 jrick if (err)
10274 624411d2 2023-07-08 jrick return err;
10275 624411d2 2023-07-08 jrick
10276 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
10277 624411d2 2023-07-08 jrick if (err)
10278 624411d2 2023-07-08 jrick goto done;
10279 624411d2 2023-07-08 jrick
10280 624411d2 2023-07-08 jrick id_str[12] = '\0';
10281 624411d2 2023-07-08 jrick
10282 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
10283 624411d2 2023-07-08 jrick if (err)
10284 624411d2 2023-07-08 jrick goto done;
10285 624411d2 2023-07-08 jrick
10286 624411d2 2023-07-08 jrick printf("%s -> merge conflict: %s\n", id_str, logmsg);
10287 624411d2 2023-07-08 jrick done:
10288 624411d2 2023-07-08 jrick free(id_str);
10289 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10290 624411d2 2023-07-08 jrick free(logmsg);
10291 624411d2 2023-07-08 jrick return err;
10292 624411d2 2023-07-08 jrick }
10293 624411d2 2023-07-08 jrick
10294 624411d2 2023-07-08 jrick static const struct got_error *
10295 624411d2 2023-07-08 jrick show_rebase_progress(struct got_commit_object *commit,
10296 624411d2 2023-07-08 jrick struct got_object_id *old_id, struct got_object_id *new_id)
10297 624411d2 2023-07-08 jrick {
10298 624411d2 2023-07-08 jrick const struct got_error *err;
10299 624411d2 2023-07-08 jrick char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
10300 624411d2 2023-07-08 jrick
10301 624411d2 2023-07-08 jrick err = got_object_id_str(&old_id_str, old_id);
10302 624411d2 2023-07-08 jrick if (err)
10303 624411d2 2023-07-08 jrick goto done;
10304 624411d2 2023-07-08 jrick
10305 624411d2 2023-07-08 jrick if (new_id) {
10306 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
10307 624411d2 2023-07-08 jrick if (err)
10308 624411d2 2023-07-08 jrick goto done;
10309 624411d2 2023-07-08 jrick }
10310 624411d2 2023-07-08 jrick
10311 624411d2 2023-07-08 jrick old_id_str[12] = '\0';
10312 624411d2 2023-07-08 jrick if (new_id_str)
10313 624411d2 2023-07-08 jrick new_id_str[12] = '\0';
10314 624411d2 2023-07-08 jrick
10315 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
10316 624411d2 2023-07-08 jrick if (err)
10317 624411d2 2023-07-08 jrick goto done;
10318 624411d2 2023-07-08 jrick
10319 624411d2 2023-07-08 jrick printf("%s -> %s: %s\n", old_id_str,
10320 624411d2 2023-07-08 jrick new_id_str ? new_id_str : "no-op change", logmsg);
10321 624411d2 2023-07-08 jrick done:
10322 624411d2 2023-07-08 jrick free(old_id_str);
10323 624411d2 2023-07-08 jrick free(new_id_str);
10324 624411d2 2023-07-08 jrick free(logmsg);
10325 624411d2 2023-07-08 jrick return err;
10326 624411d2 2023-07-08 jrick }
10327 624411d2 2023-07-08 jrick
10328 624411d2 2023-07-08 jrick static const struct got_error *
10329 624411d2 2023-07-08 jrick rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
10330 624411d2 2023-07-08 jrick struct got_reference *branch, struct got_reference *tmp_branch,
10331 624411d2 2023-07-08 jrick struct got_repository *repo, int create_backup)
10332 624411d2 2023-07-08 jrick {
10333 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n", got_ref_get_name(branch));
10334 624411d2 2023-07-08 jrick return got_worktree_rebase_complete(worktree, fileindex,
10335 624411d2 2023-07-08 jrick tmp_branch, branch, repo, create_backup);
10336 624411d2 2023-07-08 jrick }
10337 624411d2 2023-07-08 jrick
10338 624411d2 2023-07-08 jrick static const struct got_error *
10339 624411d2 2023-07-08 jrick rebase_commit(struct got_pathlist_head *merged_paths,
10340 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_fileindex *fileindex,
10341 624411d2 2023-07-08 jrick struct got_reference *tmp_branch, const char *committer,
10342 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int allow_conflict,
10343 624411d2 2023-07-08 jrick struct got_repository *repo)
10344 624411d2 2023-07-08 jrick {
10345 624411d2 2023-07-08 jrick const struct got_error *error;
10346 624411d2 2023-07-08 jrick struct got_commit_object *commit;
10347 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id;
10348 624411d2 2023-07-08 jrick
10349 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10350 624411d2 2023-07-08 jrick if (error)
10351 624411d2 2023-07-08 jrick return error;
10352 624411d2 2023-07-08 jrick
10353 624411d2 2023-07-08 jrick error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
10354 624411d2 2023-07-08 jrick worktree, fileindex, tmp_branch, committer, commit, commit_id,
10355 624411d2 2023-07-08 jrick allow_conflict, repo);
10356 624411d2 2023-07-08 jrick if (error) {
10357 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
10358 624411d2 2023-07-08 jrick goto done;
10359 624411d2 2023-07-08 jrick error = show_rebase_progress(commit, commit_id, NULL);
10360 624411d2 2023-07-08 jrick } else {
10361 624411d2 2023-07-08 jrick error = show_rebase_progress(commit, commit_id, new_commit_id);
10362 624411d2 2023-07-08 jrick free(new_commit_id);
10363 624411d2 2023-07-08 jrick }
10364 624411d2 2023-07-08 jrick done:
10365 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10366 624411d2 2023-07-08 jrick return error;
10367 624411d2 2023-07-08 jrick }
10368 624411d2 2023-07-08 jrick
10369 624411d2 2023-07-08 jrick struct check_path_prefix_arg {
10370 624411d2 2023-07-08 jrick const char *path_prefix;
10371 624411d2 2023-07-08 jrick size_t len;
10372 624411d2 2023-07-08 jrick int errcode;
10373 624411d2 2023-07-08 jrick };
10374 624411d2 2023-07-08 jrick
10375 624411d2 2023-07-08 jrick static const struct got_error *
10376 624411d2 2023-07-08 jrick check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
10377 624411d2 2023-07-08 jrick struct got_blob_object *blob2, FILE *f1, FILE *f2,
10378 624411d2 2023-07-08 jrick struct got_object_id *id1, struct got_object_id *id2,
10379 624411d2 2023-07-08 jrick const char *path1, const char *path2,
10380 624411d2 2023-07-08 jrick mode_t mode1, mode_t mode2, struct got_repository *repo)
10381 624411d2 2023-07-08 jrick {
10382 624411d2 2023-07-08 jrick struct check_path_prefix_arg *a = arg;
10383 624411d2 2023-07-08 jrick
10384 624411d2 2023-07-08 jrick if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
10385 624411d2 2023-07-08 jrick (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
10386 624411d2 2023-07-08 jrick return got_error(a->errcode);
10387 624411d2 2023-07-08 jrick
10388 624411d2 2023-07-08 jrick return NULL;
10389 624411d2 2023-07-08 jrick }
10390 624411d2 2023-07-08 jrick
10391 624411d2 2023-07-08 jrick static const struct got_error *
10392 624411d2 2023-07-08 jrick check_path_prefix(struct got_object_id *parent_id,
10393 624411d2 2023-07-08 jrick struct got_object_id *commit_id, const char *path_prefix,
10394 624411d2 2023-07-08 jrick int errcode, struct got_repository *repo)
10395 624411d2 2023-07-08 jrick {
10396 624411d2 2023-07-08 jrick const struct got_error *err;
10397 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
10398 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL, *parent_commit = NULL;
10399 624411d2 2023-07-08 jrick struct check_path_prefix_arg cpp_arg;
10400 624411d2 2023-07-08 jrick
10401 624411d2 2023-07-08 jrick if (got_path_is_root_dir(path_prefix))
10402 624411d2 2023-07-08 jrick return NULL;
10403 624411d2 2023-07-08 jrick
10404 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
10405 624411d2 2023-07-08 jrick if (err)
10406 624411d2 2023-07-08 jrick goto done;
10407 624411d2 2023-07-08 jrick
10408 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&parent_commit, repo, parent_id);
10409 624411d2 2023-07-08 jrick if (err)
10410 624411d2 2023-07-08 jrick goto done;
10411 624411d2 2023-07-08 jrick
10412 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo,
10413 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(parent_commit));
10414 624411d2 2023-07-08 jrick if (err)
10415 624411d2 2023-07-08 jrick goto done;
10416 624411d2 2023-07-08 jrick
10417 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo,
10418 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(commit));
10419 624411d2 2023-07-08 jrick if (err)
10420 624411d2 2023-07-08 jrick goto done;
10421 624411d2 2023-07-08 jrick
10422 624411d2 2023-07-08 jrick cpp_arg.path_prefix = path_prefix;
10423 624411d2 2023-07-08 jrick while (cpp_arg.path_prefix[0] == '/')
10424 624411d2 2023-07-08 jrick cpp_arg.path_prefix++;
10425 624411d2 2023-07-08 jrick cpp_arg.len = strlen(cpp_arg.path_prefix);
10426 624411d2 2023-07-08 jrick cpp_arg.errcode = errcode;
10427 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo,
10428 624411d2 2023-07-08 jrick check_path_prefix_in_diff, &cpp_arg, 0);
10429 624411d2 2023-07-08 jrick done:
10430 624411d2 2023-07-08 jrick if (tree1)
10431 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
10432 624411d2 2023-07-08 jrick if (tree2)
10433 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
10434 624411d2 2023-07-08 jrick if (commit)
10435 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10436 624411d2 2023-07-08 jrick if (parent_commit)
10437 624411d2 2023-07-08 jrick got_object_commit_close(parent_commit);
10438 624411d2 2023-07-08 jrick return err;
10439 624411d2 2023-07-08 jrick }
10440 624411d2 2023-07-08 jrick
10441 624411d2 2023-07-08 jrick static const struct got_error *
10442 624411d2 2023-07-08 jrick collect_commits(struct got_object_id_queue *commits,
10443 624411d2 2023-07-08 jrick struct got_object_id *initial_commit_id,
10444 624411d2 2023-07-08 jrick struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
10445 624411d2 2023-07-08 jrick const char *path_prefix, int path_prefix_errcode,
10446 624411d2 2023-07-08 jrick struct got_repository *repo)
10447 624411d2 2023-07-08 jrick {
10448 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10449 624411d2 2023-07-08 jrick struct got_commit_graph *graph = NULL;
10450 624411d2 2023-07-08 jrick struct got_object_id parent_id, commit_id;
10451 624411d2 2023-07-08 jrick struct got_object_qid *qid;
10452 624411d2 2023-07-08 jrick
10453 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, "/", 1);
10454 624411d2 2023-07-08 jrick if (err)
10455 624411d2 2023-07-08 jrick return err;
10456 624411d2 2023-07-08 jrick
10457 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, iter_start_id, repo,
10458 624411d2 2023-07-08 jrick check_cancelled, NULL);
10459 624411d2 2023-07-08 jrick if (err)
10460 624411d2 2023-07-08 jrick goto done;
10461 624411d2 2023-07-08 jrick
10462 624411d2 2023-07-08 jrick memcpy(&commit_id, initial_commit_id, sizeof(commit_id));
10463 624411d2 2023-07-08 jrick while (got_object_id_cmp(&commit_id, iter_stop_id) != 0) {
10464 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&parent_id, graph, repo,
10465 624411d2 2023-07-08 jrick check_cancelled, NULL);
10466 624411d2 2023-07-08 jrick if (err) {
10467 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED) {
10468 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_ANCESTRY,
10469 624411d2 2023-07-08 jrick "ran out of commits to rebase before "
10470 624411d2 2023-07-08 jrick "youngest common ancestor commit has "
10471 624411d2 2023-07-08 jrick "been reached?!?");
10472 624411d2 2023-07-08 jrick }
10473 624411d2 2023-07-08 jrick goto done;
10474 624411d2 2023-07-08 jrick } else {
10475 624411d2 2023-07-08 jrick err = check_path_prefix(&parent_id, &commit_id,
10476 624411d2 2023-07-08 jrick path_prefix, path_prefix_errcode, repo);
10477 624411d2 2023-07-08 jrick if (err)
10478 624411d2 2023-07-08 jrick goto done;
10479 624411d2 2023-07-08 jrick
10480 624411d2 2023-07-08 jrick err = got_object_qid_alloc(&qid, &commit_id);
10481 624411d2 2023-07-08 jrick if (err)
10482 624411d2 2023-07-08 jrick goto done;
10483 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(commits, qid, entry);
10484 624411d2 2023-07-08 jrick
10485 624411d2 2023-07-08 jrick memcpy(&commit_id, &parent_id, sizeof(commit_id));
10486 624411d2 2023-07-08 jrick }
10487 624411d2 2023-07-08 jrick }
10488 624411d2 2023-07-08 jrick done:
10489 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
10490 624411d2 2023-07-08 jrick return err;
10491 624411d2 2023-07-08 jrick }
10492 624411d2 2023-07-08 jrick
10493 624411d2 2023-07-08 jrick static const struct got_error *
10494 624411d2 2023-07-08 jrick get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
10495 624411d2 2023-07-08 jrick {
10496 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10497 624411d2 2023-07-08 jrick time_t committer_time;
10498 624411d2 2023-07-08 jrick struct tm tm;
10499 624411d2 2023-07-08 jrick char datebuf[11]; /* YYYY-MM-DD + NUL */
10500 624411d2 2023-07-08 jrick char *author0 = NULL, *author, *smallerthan;
10501 624411d2 2023-07-08 jrick char *logmsg0 = NULL, *logmsg, *newline;
10502 624411d2 2023-07-08 jrick
10503 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
10504 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL)
10505 624411d2 2023-07-08 jrick return got_error_from_errno("gmtime_r");
10506 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
10507 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
10508 624411d2 2023-07-08 jrick
10509 624411d2 2023-07-08 jrick author0 = strdup(got_object_commit_get_author(commit));
10510 624411d2 2023-07-08 jrick if (author0 == NULL)
10511 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
10512 624411d2 2023-07-08 jrick author = author0;
10513 624411d2 2023-07-08 jrick smallerthan = strchr(author, '<');
10514 624411d2 2023-07-08 jrick if (smallerthan && smallerthan[1] != '\0')
10515 624411d2 2023-07-08 jrick author = smallerthan + 1;
10516 624411d2 2023-07-08 jrick author[strcspn(author, "@>")] = '\0';
10517 624411d2 2023-07-08 jrick
10518 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
10519 624411d2 2023-07-08 jrick if (err)
10520 624411d2 2023-07-08 jrick goto done;
10521 624411d2 2023-07-08 jrick logmsg = logmsg0;
10522 624411d2 2023-07-08 jrick while (*logmsg == '\n')
10523 624411d2 2023-07-08 jrick logmsg++;
10524 624411d2 2023-07-08 jrick newline = strchr(logmsg, '\n');
10525 624411d2 2023-07-08 jrick if (newline)
10526 624411d2 2023-07-08 jrick *newline = '\0';
10527 624411d2 2023-07-08 jrick
10528 624411d2 2023-07-08 jrick if (asprintf(brief_str, "%s %s %s",
10529 624411d2 2023-07-08 jrick datebuf, author, logmsg) == -1)
10530 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
10531 624411d2 2023-07-08 jrick done:
10532 624411d2 2023-07-08 jrick free(author0);
10533 624411d2 2023-07-08 jrick free(logmsg0);
10534 624411d2 2023-07-08 jrick return err;
10535 624411d2 2023-07-08 jrick }
10536 624411d2 2023-07-08 jrick
10537 624411d2 2023-07-08 jrick static const struct got_error *
10538 624411d2 2023-07-08 jrick delete_backup_ref(struct got_reference *ref, struct got_object_id *id,
10539 624411d2 2023-07-08 jrick struct got_repository *repo)
10540 624411d2 2023-07-08 jrick {
10541 624411d2 2023-07-08 jrick const struct got_error *err;
10542 624411d2 2023-07-08 jrick char *id_str;
10543 624411d2 2023-07-08 jrick
10544 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
10545 624411d2 2023-07-08 jrick if (err)
10546 624411d2 2023-07-08 jrick return err;
10547 624411d2 2023-07-08 jrick
10548 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
10549 624411d2 2023-07-08 jrick if (err)
10550 624411d2 2023-07-08 jrick goto done;
10551 624411d2 2023-07-08 jrick
10552 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str);
10553 624411d2 2023-07-08 jrick done:
10554 624411d2 2023-07-08 jrick free(id_str);
10555 624411d2 2023-07-08 jrick return err;
10556 624411d2 2023-07-08 jrick }
10557 624411d2 2023-07-08 jrick
10558 624411d2 2023-07-08 jrick static const struct got_error *
10559 624411d2 2023-07-08 jrick print_backup_ref(const char *branch_name, const char *new_id_str,
10560 624411d2 2023-07-08 jrick struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
10561 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap,
10562 624411d2 2023-07-08 jrick struct got_repository *repo)
10563 624411d2 2023-07-08 jrick {
10564 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10565 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
10566 624411d2 2023-07-08 jrick char *refs_str = NULL;
10567 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id = NULL;
10568 624411d2 2023-07-08 jrick struct got_commit_object *new_commit = NULL;
10569 624411d2 2023-07-08 jrick char *new_commit_brief_str = NULL;
10570 624411d2 2023-07-08 jrick struct got_object_id *yca_id = NULL;
10571 624411d2 2023-07-08 jrick struct got_commit_object *yca_commit = NULL;
10572 624411d2 2023-07-08 jrick char *yca_id_str = NULL, *yca_brief_str = NULL;
10573 624411d2 2023-07-08 jrick char *custom_refs_str;
10574 624411d2 2023-07-08 jrick
10575 624411d2 2023-07-08 jrick if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
10576 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
10577 624411d2 2023-07-08 jrick
10578 624411d2 2023-07-08 jrick err = print_commit(old_commit, old_commit_id, repo, NULL, NULL, NULL,
10579 624411d2 2023-07-08 jrick 0, 0, refs_idmap, custom_refs_str, NULL);
10580 624411d2 2023-07-08 jrick if (err)
10581 624411d2 2023-07-08 jrick goto done;
10582 624411d2 2023-07-08 jrick
10583 624411d2 2023-07-08 jrick err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
10584 624411d2 2023-07-08 jrick if (err)
10585 624411d2 2023-07-08 jrick goto done;
10586 624411d2 2023-07-08 jrick
10587 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
10588 624411d2 2023-07-08 jrick if (refs) {
10589 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, new_commit_id, repo, 0);
10590 624411d2 2023-07-08 jrick if (err)
10591 624411d2 2023-07-08 jrick goto done;
10592 624411d2 2023-07-08 jrick }
10593 624411d2 2023-07-08 jrick
10594 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
10595 624411d2 2023-07-08 jrick if (err)
10596 624411d2 2023-07-08 jrick goto done;
10597 624411d2 2023-07-08 jrick
10598 624411d2 2023-07-08 jrick err = get_commit_brief_str(&new_commit_brief_str, new_commit);
10599 624411d2 2023-07-08 jrick if (err)
10600 624411d2 2023-07-08 jrick goto done;
10601 624411d2 2023-07-08 jrick
10602 624411d2 2023-07-08 jrick err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
10603 624411d2 2023-07-08 jrick old_commit_id, new_commit_id, 1, repo, check_cancelled, NULL);
10604 624411d2 2023-07-08 jrick if (err)
10605 624411d2 2023-07-08 jrick goto done;
10606 624411d2 2023-07-08 jrick
10607 624411d2 2023-07-08 jrick printf("has become commit %s%s%s%s\n %s\n", new_id_str,
10608 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
10609 624411d2 2023-07-08 jrick refs_str ? ")" : "", new_commit_brief_str);
10610 624411d2 2023-07-08 jrick if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
10611 624411d2 2023-07-08 jrick got_object_id_cmp(yca_id, old_commit_id) != 0) {
10612 624411d2 2023-07-08 jrick free(refs_str);
10613 624411d2 2023-07-08 jrick refs_str = NULL;
10614 624411d2 2023-07-08 jrick
10615 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&yca_commit, repo, yca_id);
10616 624411d2 2023-07-08 jrick if (err)
10617 624411d2 2023-07-08 jrick goto done;
10618 624411d2 2023-07-08 jrick
10619 624411d2 2023-07-08 jrick err = get_commit_brief_str(&yca_brief_str, yca_commit);
10620 624411d2 2023-07-08 jrick if (err)
10621 624411d2 2023-07-08 jrick goto done;
10622 624411d2 2023-07-08 jrick
10623 624411d2 2023-07-08 jrick err = got_object_id_str(&yca_id_str, yca_id);
10624 624411d2 2023-07-08 jrick if (err)
10625 624411d2 2023-07-08 jrick goto done;
10626 624411d2 2023-07-08 jrick
10627 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
10628 624411d2 2023-07-08 jrick if (refs) {
10629 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, yca_id, repo, 0);
10630 624411d2 2023-07-08 jrick if (err)
10631 624411d2 2023-07-08 jrick goto done;
10632 624411d2 2023-07-08 jrick }
10633 624411d2 2023-07-08 jrick printf("history forked at %s%s%s%s\n %s\n",
10634 624411d2 2023-07-08 jrick yca_id_str,
10635 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
10636 624411d2 2023-07-08 jrick refs_str ? ")" : "", yca_brief_str);
10637 624411d2 2023-07-08 jrick }
10638 624411d2 2023-07-08 jrick done:
10639 624411d2 2023-07-08 jrick free(custom_refs_str);
10640 624411d2 2023-07-08 jrick free(new_commit_id);
10641 624411d2 2023-07-08 jrick free(refs_str);
10642 624411d2 2023-07-08 jrick free(yca_id);
10643 624411d2 2023-07-08 jrick free(yca_id_str);
10644 624411d2 2023-07-08 jrick free(yca_brief_str);
10645 624411d2 2023-07-08 jrick if (new_commit)
10646 624411d2 2023-07-08 jrick got_object_commit_close(new_commit);
10647 624411d2 2023-07-08 jrick if (yca_commit)
10648 624411d2 2023-07-08 jrick got_object_commit_close(yca_commit);
10649 624411d2 2023-07-08 jrick
10650 624411d2 2023-07-08 jrick return err;
10651 624411d2 2023-07-08 jrick }
10652 624411d2 2023-07-08 jrick
10653 624411d2 2023-07-08 jrick static const struct got_error *
10654 624411d2 2023-07-08 jrick worktree_has_logmsg_ref(const char *caller, struct got_worktree *worktree,
10655 624411d2 2023-07-08 jrick struct got_repository *repo)
10656 624411d2 2023-07-08 jrick {
10657 624411d2 2023-07-08 jrick const struct got_error *err;
10658 624411d2 2023-07-08 jrick struct got_reflist_head refs;
10659 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
10660 624411d2 2023-07-08 jrick char *uuidstr = NULL;
10661 624411d2 2023-07-08 jrick static char msg[160];
10662 624411d2 2023-07-08 jrick
10663 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
10664 624411d2 2023-07-08 jrick
10665 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
10666 624411d2 2023-07-08 jrick if (err)
10667 624411d2 2023-07-08 jrick goto done;
10668 624411d2 2023-07-08 jrick
10669 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
10670 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
10671 624411d2 2023-07-08 jrick if (err)
10672 624411d2 2023-07-08 jrick goto done;
10673 624411d2 2023-07-08 jrick
10674 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
10675 624411d2 2023-07-08 jrick const char *cmd, *refname, *type;
10676 624411d2 2023-07-08 jrick
10677 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
10678 624411d2 2023-07-08 jrick
10679 624411d2 2023-07-08 jrick if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
10680 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) {
10681 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
10682 624411d2 2023-07-08 jrick cmd = "cherrypick";
10683 624411d2 2023-07-08 jrick type = "cherrypicked";
10684 624411d2 2023-07-08 jrick } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
10685 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) {
10686 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
10687 624411d2 2023-07-08 jrick cmd = "backout";
10688 624411d2 2023-07-08 jrick type = "backed-out";
10689 624411d2 2023-07-08 jrick } else
10690 624411d2 2023-07-08 jrick continue;
10691 624411d2 2023-07-08 jrick
10692 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) != 0)
10693 624411d2 2023-07-08 jrick continue;
10694 624411d2 2023-07-08 jrick
10695 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
10696 624411d2 2023-07-08 jrick "work tree has references created by %s commits which "
10697 624411d2 2023-07-08 jrick "must be removed with 'got %s -X' before running the %s "
10698 624411d2 2023-07-08 jrick "command", type, cmd, caller);
10699 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_WORKTREE_META, msg);
10700 624411d2 2023-07-08 jrick goto done;
10701 624411d2 2023-07-08 jrick }
10702 624411d2 2023-07-08 jrick
10703 624411d2 2023-07-08 jrick done:
10704 624411d2 2023-07-08 jrick free(uuidstr);
10705 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
10706 624411d2 2023-07-08 jrick return err;
10707 624411d2 2023-07-08 jrick }
10708 624411d2 2023-07-08 jrick
10709 624411d2 2023-07-08 jrick static const struct got_error *
10710 624411d2 2023-07-08 jrick process_backup_refs(const char *backup_ref_prefix,
10711 624411d2 2023-07-08 jrick const char *wanted_branch_name,
10712 624411d2 2023-07-08 jrick int delete, struct got_repository *repo)
10713 624411d2 2023-07-08 jrick {
10714 624411d2 2023-07-08 jrick const struct got_error *err;
10715 624411d2 2023-07-08 jrick struct got_reflist_head refs, backup_refs;
10716 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
10717 624411d2 2023-07-08 jrick const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
10718 624411d2 2023-07-08 jrick struct got_object_id *old_commit_id = NULL;
10719 624411d2 2023-07-08 jrick char *branch_name = NULL;
10720 624411d2 2023-07-08 jrick struct got_commit_object *old_commit = NULL;
10721 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
10722 624411d2 2023-07-08 jrick int wanted_branch_found = 0;
10723 624411d2 2023-07-08 jrick
10724 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
10725 624411d2 2023-07-08 jrick TAILQ_INIT(&backup_refs);
10726 624411d2 2023-07-08 jrick
10727 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
10728 624411d2 2023-07-08 jrick if (err)
10729 624411d2 2023-07-08 jrick return err;
10730 624411d2 2023-07-08 jrick
10731 624411d2 2023-07-08 jrick err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
10732 624411d2 2023-07-08 jrick if (err)
10733 624411d2 2023-07-08 jrick goto done;
10734 624411d2 2023-07-08 jrick
10735 624411d2 2023-07-08 jrick if (wanted_branch_name) {
10736 624411d2 2023-07-08 jrick if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
10737 624411d2 2023-07-08 jrick wanted_branch_name += 11;
10738 624411d2 2023-07-08 jrick }
10739 624411d2 2023-07-08 jrick
10740 624411d2 2023-07-08 jrick err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
10741 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending, repo);
10742 624411d2 2023-07-08 jrick if (err)
10743 624411d2 2023-07-08 jrick goto done;
10744 624411d2 2023-07-08 jrick
10745 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &backup_refs, entry) {
10746 624411d2 2023-07-08 jrick const char *refname = got_ref_get_name(re->ref);
10747 624411d2 2023-07-08 jrick char *slash;
10748 624411d2 2023-07-08 jrick
10749 624411d2 2023-07-08 jrick err = check_cancelled(NULL);
10750 624411d2 2023-07-08 jrick if (err)
10751 624411d2 2023-07-08 jrick break;
10752 624411d2 2023-07-08 jrick
10753 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_commit_id, repo, re->ref);
10754 624411d2 2023-07-08 jrick if (err)
10755 624411d2 2023-07-08 jrick break;
10756 624411d2 2023-07-08 jrick
10757 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&old_commit, repo,
10758 624411d2 2023-07-08 jrick old_commit_id);
10759 624411d2 2023-07-08 jrick if (err)
10760 624411d2 2023-07-08 jrick break;
10761 624411d2 2023-07-08 jrick
10762 624411d2 2023-07-08 jrick if (strncmp(backup_ref_prefix, refname,
10763 624411d2 2023-07-08 jrick backup_ref_prefix_len) == 0)
10764 624411d2 2023-07-08 jrick refname += backup_ref_prefix_len;
10765 624411d2 2023-07-08 jrick
10766 624411d2 2023-07-08 jrick while (refname[0] == '/')
10767 624411d2 2023-07-08 jrick refname++;
10768 624411d2 2023-07-08 jrick
10769 624411d2 2023-07-08 jrick branch_name = strdup(refname);
10770 624411d2 2023-07-08 jrick if (branch_name == NULL) {
10771 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
10772 624411d2 2023-07-08 jrick break;
10773 624411d2 2023-07-08 jrick }
10774 624411d2 2023-07-08 jrick slash = strrchr(branch_name, '/');
10775 624411d2 2023-07-08 jrick if (slash) {
10776 624411d2 2023-07-08 jrick *slash = '\0';
10777 624411d2 2023-07-08 jrick refname += strlen(branch_name) + 1;
10778 624411d2 2023-07-08 jrick }
10779 624411d2 2023-07-08 jrick
10780 624411d2 2023-07-08 jrick if (wanted_branch_name == NULL ||
10781 624411d2 2023-07-08 jrick strcmp(wanted_branch_name, branch_name) == 0) {
10782 624411d2 2023-07-08 jrick wanted_branch_found = 1;
10783 624411d2 2023-07-08 jrick if (delete) {
10784 624411d2 2023-07-08 jrick err = delete_backup_ref(re->ref,
10785 624411d2 2023-07-08 jrick old_commit_id, repo);
10786 624411d2 2023-07-08 jrick } else {
10787 624411d2 2023-07-08 jrick err = print_backup_ref(branch_name, refname,
10788 624411d2 2023-07-08 jrick old_commit_id, old_commit, refs_idmap,
10789 624411d2 2023-07-08 jrick repo);
10790 624411d2 2023-07-08 jrick }
10791 624411d2 2023-07-08 jrick if (err)
10792 624411d2 2023-07-08 jrick break;
10793 624411d2 2023-07-08 jrick }
10794 624411d2 2023-07-08 jrick
10795 624411d2 2023-07-08 jrick free(old_commit_id);
10796 624411d2 2023-07-08 jrick old_commit_id = NULL;
10797 624411d2 2023-07-08 jrick free(branch_name);
10798 624411d2 2023-07-08 jrick branch_name = NULL;
10799 624411d2 2023-07-08 jrick got_object_commit_close(old_commit);
10800 624411d2 2023-07-08 jrick old_commit = NULL;
10801 624411d2 2023-07-08 jrick }
10802 624411d2 2023-07-08 jrick
10803 624411d2 2023-07-08 jrick if (wanted_branch_name && !wanted_branch_found) {
10804 624411d2 2023-07-08 jrick err = got_error_fmt(GOT_ERR_NOT_REF,
10805 624411d2 2023-07-08 jrick "%s/%s/", backup_ref_prefix, wanted_branch_name);
10806 624411d2 2023-07-08 jrick }
10807 624411d2 2023-07-08 jrick done:
10808 624411d2 2023-07-08 jrick if (refs_idmap)
10809 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
10810 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
10811 624411d2 2023-07-08 jrick got_ref_list_free(&backup_refs);
10812 624411d2 2023-07-08 jrick free(old_commit_id);
10813 624411d2 2023-07-08 jrick free(branch_name);
10814 624411d2 2023-07-08 jrick if (old_commit)
10815 624411d2 2023-07-08 jrick got_object_commit_close(old_commit);
10816 624411d2 2023-07-08 jrick return err;
10817 624411d2 2023-07-08 jrick }
10818 624411d2 2023-07-08 jrick
10819 624411d2 2023-07-08 jrick static const struct got_error *
10820 624411d2 2023-07-08 jrick abort_progress(void *arg, unsigned char status, const char *path)
10821 624411d2 2023-07-08 jrick {
10822 624411d2 2023-07-08 jrick /*
10823 624411d2 2023-07-08 jrick * Unversioned files should not clutter progress output when
10824 624411d2 2023-07-08 jrick * an operation is aborted.
10825 624411d2 2023-07-08 jrick */
10826 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
10827 624411d2 2023-07-08 jrick return NULL;
10828 624411d2 2023-07-08 jrick
10829 624411d2 2023-07-08 jrick return update_progress(arg, status, path);
10830 624411d2 2023-07-08 jrick }
10831 624411d2 2023-07-08 jrick
10832 624411d2 2023-07-08 jrick static const struct got_error *
10833 624411d2 2023-07-08 jrick cmd_rebase(int argc, char *argv[])
10834 624411d2 2023-07-08 jrick {
10835 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
10836 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
10837 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
10838 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
10839 624411d2 2023-07-08 jrick char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
10840 624411d2 2023-07-08 jrick struct got_reference *branch = NULL;
10841 624411d2 2023-07-08 jrick struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
10842 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *parent_id = NULL;
10843 624411d2 2023-07-08 jrick struct got_object_id *resume_commit_id = NULL;
10844 624411d2 2023-07-08 jrick struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
10845 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
10846 624411d2 2023-07-08 jrick struct got_reference *head_ref = NULL;
10847 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10848 624411d2 2023-07-08 jrick int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
10849 624411d2 2023-07-08 jrick int histedit_in_progress = 0, merge_in_progress = 0;
10850 624411d2 2023-07-08 jrick int create_backup = 1, list_backups = 0, delete_backups = 0;
10851 624411d2 2023-07-08 jrick int allow_conflict = 0;
10852 624411d2 2023-07-08 jrick struct got_object_id_queue commits;
10853 624411d2 2023-07-08 jrick struct got_pathlist_head merged_paths;
10854 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
10855 624411d2 2023-07-08 jrick struct got_object_qid *qid, *pid;
10856 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
10857 624411d2 2023-07-08 jrick int *pack_fds = NULL;
10858 624411d2 2023-07-08 jrick
10859 624411d2 2023-07-08 jrick STAILQ_INIT(&commits);
10860 624411d2 2023-07-08 jrick TAILQ_INIT(&merged_paths);
10861 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10862 624411d2 2023-07-08 jrick
10863 624411d2 2023-07-08 jrick #ifndef PROFILE
10864 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10865 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
10866 624411d2 2023-07-08 jrick err(1, "pledge");
10867 624411d2 2023-07-08 jrick #endif
10868 624411d2 2023-07-08 jrick
10869 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCclX")) != -1) {
10870 624411d2 2023-07-08 jrick switch (ch) {
10871 624411d2 2023-07-08 jrick case 'a':
10872 624411d2 2023-07-08 jrick abort_rebase = 1;
10873 624411d2 2023-07-08 jrick break;
10874 624411d2 2023-07-08 jrick case 'C':
10875 624411d2 2023-07-08 jrick allow_conflict = 1;
10876 624411d2 2023-07-08 jrick break;
10877 624411d2 2023-07-08 jrick case 'c':
10878 624411d2 2023-07-08 jrick continue_rebase = 1;
10879 624411d2 2023-07-08 jrick break;
10880 624411d2 2023-07-08 jrick case 'l':
10881 624411d2 2023-07-08 jrick list_backups = 1;
10882 624411d2 2023-07-08 jrick break;
10883 624411d2 2023-07-08 jrick case 'X':
10884 624411d2 2023-07-08 jrick delete_backups = 1;
10885 624411d2 2023-07-08 jrick break;
10886 624411d2 2023-07-08 jrick default:
10887 624411d2 2023-07-08 jrick usage_rebase();
10888 624411d2 2023-07-08 jrick /* NOTREACHED */
10889 624411d2 2023-07-08 jrick }
10890 624411d2 2023-07-08 jrick }
10891 624411d2 2023-07-08 jrick
10892 624411d2 2023-07-08 jrick argc -= optind;
10893 624411d2 2023-07-08 jrick argv += optind;
10894 624411d2 2023-07-08 jrick
10895 624411d2 2023-07-08 jrick if (list_backups) {
10896 624411d2 2023-07-08 jrick if (abort_rebase)
10897 624411d2 2023-07-08 jrick option_conflict('l', 'a');
10898 624411d2 2023-07-08 jrick if (allow_conflict)
10899 624411d2 2023-07-08 jrick option_conflict('l', 'C');
10900 624411d2 2023-07-08 jrick if (continue_rebase)
10901 624411d2 2023-07-08 jrick option_conflict('l', 'c');
10902 624411d2 2023-07-08 jrick if (delete_backups)
10903 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10904 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10905 624411d2 2023-07-08 jrick usage_rebase();
10906 624411d2 2023-07-08 jrick } else if (delete_backups) {
10907 624411d2 2023-07-08 jrick if (abort_rebase)
10908 624411d2 2023-07-08 jrick option_conflict('X', 'a');
10909 624411d2 2023-07-08 jrick if (allow_conflict)
10910 624411d2 2023-07-08 jrick option_conflict('X', 'C');
10911 624411d2 2023-07-08 jrick if (continue_rebase)
10912 624411d2 2023-07-08 jrick option_conflict('X', 'c');
10913 624411d2 2023-07-08 jrick if (list_backups)
10914 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10915 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10916 624411d2 2023-07-08 jrick usage_rebase();
10917 624411d2 2023-07-08 jrick } else if (allow_conflict) {
10918 624411d2 2023-07-08 jrick if (abort_rebase)
10919 624411d2 2023-07-08 jrick option_conflict('C', 'a');
10920 624411d2 2023-07-08 jrick if (!continue_rebase)
10921 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
10922 624411d2 2023-07-08 jrick } else {
10923 624411d2 2023-07-08 jrick if (abort_rebase && continue_rebase)
10924 624411d2 2023-07-08 jrick usage_rebase();
10925 624411d2 2023-07-08 jrick else if (abort_rebase || continue_rebase) {
10926 624411d2 2023-07-08 jrick if (argc != 0)
10927 624411d2 2023-07-08 jrick usage_rebase();
10928 624411d2 2023-07-08 jrick } else if (argc != 1)
10929 624411d2 2023-07-08 jrick usage_rebase();
10930 624411d2 2023-07-08 jrick }
10931 624411d2 2023-07-08 jrick
10932 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
10933 624411d2 2023-07-08 jrick if (cwd == NULL) {
10934 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
10935 624411d2 2023-07-08 jrick goto done;
10936 624411d2 2023-07-08 jrick }
10937 624411d2 2023-07-08 jrick
10938 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
10939 624411d2 2023-07-08 jrick if (error != NULL)
10940 624411d2 2023-07-08 jrick goto done;
10941 624411d2 2023-07-08 jrick
10942 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
10943 624411d2 2023-07-08 jrick if (error) {
10944 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
10945 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
10946 624411d2 2023-07-08 jrick goto done;
10947 624411d2 2023-07-08 jrick } else {
10948 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
10949 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
10950 624411d2 2023-07-08 jrick "rebase", cwd);
10951 624411d2 2023-07-08 jrick goto done;
10952 624411d2 2023-07-08 jrick }
10953 624411d2 2023-07-08 jrick }
10954 624411d2 2023-07-08 jrick
10955 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
10956 624411d2 2023-07-08 jrick if (error)
10957 624411d2 2023-07-08 jrick goto done;
10958 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10959 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10960 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
10961 624411d2 2023-07-08 jrick if (error != NULL)
10962 624411d2 2023-07-08 jrick goto done;
10963 624411d2 2023-07-08 jrick
10964 624411d2 2023-07-08 jrick if (worktree != NULL && !list_backups && !delete_backups) {
10965 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("rebase", worktree, repo);
10966 624411d2 2023-07-08 jrick if (error)
10967 624411d2 2023-07-08 jrick goto done;
10968 624411d2 2023-07-08 jrick }
10969 624411d2 2023-07-08 jrick
10970 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
10971 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_COMMIT_NO_AUTHOR)
10972 624411d2 2023-07-08 jrick goto done;
10973 624411d2 2023-07-08 jrick
10974 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10975 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10976 624411d2 2023-07-08 jrick if (error)
10977 624411d2 2023-07-08 jrick goto done;
10978 624411d2 2023-07-08 jrick
10979 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
10980 624411d2 2023-07-08 jrick error = process_backup_refs(
10981 624411d2 2023-07-08 jrick GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
10982 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, delete_backups, repo);
10983 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
10984 624411d2 2023-07-08 jrick }
10985 624411d2 2023-07-08 jrick
10986 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&histedit_in_progress,
10987 624411d2 2023-07-08 jrick worktree);
10988 624411d2 2023-07-08 jrick if (error)
10989 624411d2 2023-07-08 jrick goto done;
10990 624411d2 2023-07-08 jrick if (histedit_in_progress) {
10991 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_HISTEDIT_BUSY);
10992 624411d2 2023-07-08 jrick goto done;
10993 624411d2 2023-07-08 jrick }
10994 624411d2 2023-07-08 jrick
10995 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress,
10996 624411d2 2023-07-08 jrick worktree, repo);
10997 624411d2 2023-07-08 jrick if (error)
10998 624411d2 2023-07-08 jrick goto done;
10999 624411d2 2023-07-08 jrick if (merge_in_progress) {
11000 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
11001 624411d2 2023-07-08 jrick goto done;
11002 624411d2 2023-07-08 jrick }
11003 624411d2 2023-07-08 jrick
11004 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
11005 624411d2 2023-07-08 jrick if (error)
11006 624411d2 2023-07-08 jrick goto done;
11007 624411d2 2023-07-08 jrick
11008 624411d2 2023-07-08 jrick if (abort_rebase) {
11009 624411d2 2023-07-08 jrick if (!rebase_in_progress) {
11010 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_REBASING);
11011 624411d2 2023-07-08 jrick goto done;
11012 624411d2 2023-07-08 jrick }
11013 624411d2 2023-07-08 jrick error = got_worktree_rebase_continue(&resume_commit_id,
11014 624411d2 2023-07-08 jrick &new_base_branch, &tmp_branch, &branch, &fileindex,
11015 624411d2 2023-07-08 jrick worktree, repo);
11016 624411d2 2023-07-08 jrick if (error)
11017 624411d2 2023-07-08 jrick goto done;
11018 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
11019 624411d2 2023-07-08 jrick got_ref_get_symref_target(new_base_branch));
11020 624411d2 2023-07-08 jrick error = got_worktree_rebase_abort(worktree, fileindex, repo,
11021 624411d2 2023-07-08 jrick new_base_branch, abort_progress, &upa);
11022 624411d2 2023-07-08 jrick if (error)
11023 624411d2 2023-07-08 jrick goto done;
11024 624411d2 2023-07-08 jrick printf("Rebase of %s aborted\n", got_ref_get_name(branch));
11025 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
11026 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
11027 624411d2 2023-07-08 jrick }
11028 624411d2 2023-07-08 jrick
11029 624411d2 2023-07-08 jrick if (continue_rebase) {
11030 624411d2 2023-07-08 jrick if (!rebase_in_progress) {
11031 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_REBASING);
11032 624411d2 2023-07-08 jrick goto done;
11033 624411d2 2023-07-08 jrick }
11034 624411d2 2023-07-08 jrick error = got_worktree_rebase_continue(&resume_commit_id,
11035 624411d2 2023-07-08 jrick &new_base_branch, &tmp_branch, &branch, &fileindex,
11036 624411d2 2023-07-08 jrick worktree, repo);
11037 624411d2 2023-07-08 jrick if (error)
11038 624411d2 2023-07-08 jrick goto done;
11039 624411d2 2023-07-08 jrick
11040 624411d2 2023-07-08 jrick error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
11041 624411d2 2023-07-08 jrick committer, resume_commit_id, allow_conflict, repo);
11042 624411d2 2023-07-08 jrick if (error)
11043 624411d2 2023-07-08 jrick goto done;
11044 624411d2 2023-07-08 jrick
11045 624411d2 2023-07-08 jrick yca_id = got_object_id_dup(resume_commit_id);
11046 624411d2 2023-07-08 jrick if (yca_id == NULL) {
11047 624411d2 2023-07-08 jrick error = got_error_from_errno("got_object_id_dup");
11048 624411d2 2023-07-08 jrick goto done;
11049 624411d2 2023-07-08 jrick }
11050 624411d2 2023-07-08 jrick } else {
11051 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo, argv[0], 0);
11052 624411d2 2023-07-08 jrick if (error != NULL)
11053 624411d2 2023-07-08 jrick goto done;
11054 624411d2 2023-07-08 jrick if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
11055 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
11056 624411d2 2023-07-08 jrick "will not rebase a branch which lives outside "
11057 624411d2 2023-07-08 jrick "the \"refs/heads/\" reference namespace");
11058 624411d2 2023-07-08 jrick goto done;
11059 624411d2 2023-07-08 jrick }
11060 624411d2 2023-07-08 jrick }
11061 624411d2 2023-07-08 jrick
11062 624411d2 2023-07-08 jrick error = got_ref_resolve(&branch_head_commit_id, repo, branch);
11063 624411d2 2023-07-08 jrick if (error)
11064 624411d2 2023-07-08 jrick goto done;
11065 624411d2 2023-07-08 jrick
11066 624411d2 2023-07-08 jrick if (!continue_rebase) {
11067 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id;
11068 624411d2 2023-07-08 jrick
11069 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
11070 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
11071 624411d2 2023-07-08 jrick if (error)
11072 624411d2 2023-07-08 jrick goto done;
11073 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, head_ref);
11074 624411d2 2023-07-08 jrick if (error)
11075 624411d2 2023-07-08 jrick goto done;
11076 624411d2 2023-07-08 jrick base_commit_id = got_worktree_get_base_commit_id(worktree);
11077 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, head_commit_id) != 0) {
11078 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
11079 624411d2 2023-07-08 jrick goto done;
11080 624411d2 2023-07-08 jrick }
11081 624411d2 2023-07-08 jrick
11082 624411d2 2023-07-08 jrick error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
11083 624411d2 2023-07-08 jrick base_commit_id, branch_head_commit_id, 1, repo,
11084 624411d2 2023-07-08 jrick check_cancelled, NULL);
11085 624411d2 2023-07-08 jrick if (error) {
11086 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
11087 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_ANCESTRY,
11088 624411d2 2023-07-08 jrick "specified branch shares no common "
11089 624411d2 2023-07-08 jrick "ancestry with work tree's branch");
11090 624411d2 2023-07-08 jrick }
11091 624411d2 2023-07-08 jrick goto done;
11092 624411d2 2023-07-08 jrick }
11093 624411d2 2023-07-08 jrick
11094 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, yca_id) == 0) {
11095 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
11096 624411d2 2023-07-08 jrick printf("%s is already based on %s\n",
11097 624411d2 2023-07-08 jrick got_ref_get_name(branch),
11098 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
11099 624411d2 2023-07-08 jrick error = switch_head_ref(branch, branch_head_commit_id,
11100 624411d2 2023-07-08 jrick worktree, repo);
11101 624411d2 2023-07-08 jrick if (error)
11102 624411d2 2023-07-08 jrick goto done;
11103 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
11104 624411d2 2023-07-08 jrick branch_head_commit_id);
11105 624411d2 2023-07-08 jrick if (error)
11106 624411d2 2023-07-08 jrick goto done;
11107 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
11108 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
11109 624411d2 2023-07-08 jrick if (error)
11110 624411d2 2023-07-08 jrick goto done;
11111 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree,
11112 624411d2 2023-07-08 jrick &paths, repo, update_progress, &upa,
11113 624411d2 2023-07-08 jrick check_cancelled, NULL);
11114 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
11115 624411d2 2023-07-08 jrick if (error)
11116 624411d2 2023-07-08 jrick goto done;
11117 624411d2 2023-07-08 jrick if (upa.did_something) {
11118 624411d2 2023-07-08 jrick char *id_str;
11119 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
11120 624411d2 2023-07-08 jrick branch_head_commit_id);
11121 624411d2 2023-07-08 jrick if (error)
11122 624411d2 2023-07-08 jrick goto done;
11123 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
11124 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
11125 624411d2 2023-07-08 jrick id_str);
11126 624411d2 2023-07-08 jrick free(id_str);
11127 624411d2 2023-07-08 jrick } else
11128 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
11129 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
11130 624411d2 2023-07-08 jrick goto done;
11131 624411d2 2023-07-08 jrick }
11132 624411d2 2023-07-08 jrick }
11133 624411d2 2023-07-08 jrick
11134 624411d2 2023-07-08 jrick commit_id = branch_head_commit_id;
11135 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
11136 624411d2 2023-07-08 jrick if (error)
11137 624411d2 2023-07-08 jrick goto done;
11138 624411d2 2023-07-08 jrick
11139 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
11140 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
11141 624411d2 2023-07-08 jrick if (pid) {
11142 624411d2 2023-07-08 jrick error = collect_commits(&commits, commit_id, &pid->id,
11143 624411d2 2023-07-08 jrick yca_id, got_worktree_get_path_prefix(worktree),
11144 624411d2 2023-07-08 jrick GOT_ERR_REBASE_PATH, repo);
11145 624411d2 2023-07-08 jrick if (error)
11146 624411d2 2023-07-08 jrick goto done;
11147 624411d2 2023-07-08 jrick }
11148 624411d2 2023-07-08 jrick
11149 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11150 624411d2 2023-07-08 jrick commit = NULL;
11151 624411d2 2023-07-08 jrick
11152 624411d2 2023-07-08 jrick if (!continue_rebase) {
11153 624411d2 2023-07-08 jrick error = got_worktree_rebase_prepare(&new_base_branch,
11154 624411d2 2023-07-08 jrick &tmp_branch, &fileindex, worktree, branch, repo);
11155 624411d2 2023-07-08 jrick if (error)
11156 624411d2 2023-07-08 jrick goto done;
11157 624411d2 2023-07-08 jrick }
11158 624411d2 2023-07-08 jrick
11159 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(&commits)) {
11160 624411d2 2023-07-08 jrick if (continue_rebase) {
11161 624411d2 2023-07-08 jrick error = rebase_complete(worktree, fileindex,
11162 624411d2 2023-07-08 jrick branch, tmp_branch, repo, create_backup);
11163 624411d2 2023-07-08 jrick goto done;
11164 624411d2 2023-07-08 jrick } else {
11165 624411d2 2023-07-08 jrick /* Fast-forward the reference of the branch. */
11166 624411d2 2023-07-08 jrick struct got_object_id *new_head_commit_id;
11167 624411d2 2023-07-08 jrick char *id_str;
11168 624411d2 2023-07-08 jrick error = got_ref_resolve(&new_head_commit_id, repo,
11169 624411d2 2023-07-08 jrick new_base_branch);
11170 624411d2 2023-07-08 jrick if (error)
11171 624411d2 2023-07-08 jrick goto done;
11172 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, new_head_commit_id);
11173 624411d2 2023-07-08 jrick if (error)
11174 624411d2 2023-07-08 jrick goto done;
11175 624411d2 2023-07-08 jrick printf("Forwarding %s to commit %s\n",
11176 624411d2 2023-07-08 jrick got_ref_get_name(branch), id_str);
11177 624411d2 2023-07-08 jrick free(id_str);
11178 624411d2 2023-07-08 jrick error = got_ref_change_ref(branch,
11179 624411d2 2023-07-08 jrick new_head_commit_id);
11180 624411d2 2023-07-08 jrick if (error)
11181 624411d2 2023-07-08 jrick goto done;
11182 624411d2 2023-07-08 jrick /* No backup needed since objects did not change. */
11183 624411d2 2023-07-08 jrick create_backup = 0;
11184 624411d2 2023-07-08 jrick }
11185 624411d2 2023-07-08 jrick }
11186 624411d2 2023-07-08 jrick
11187 624411d2 2023-07-08 jrick pid = NULL;
11188 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, &commits, entry) {
11189 624411d2 2023-07-08 jrick
11190 624411d2 2023-07-08 jrick commit_id = &qid->id;
11191 624411d2 2023-07-08 jrick parent_id = pid ? &pid->id : yca_id;
11192 624411d2 2023-07-08 jrick pid = qid;
11193 624411d2 2023-07-08 jrick
11194 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
11195 624411d2 2023-07-08 jrick error = got_worktree_rebase_merge_files(&merged_paths,
11196 624411d2 2023-07-08 jrick worktree, fileindex, parent_id, commit_id, repo,
11197 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
11198 624411d2 2023-07-08 jrick if (error)
11199 624411d2 2023-07-08 jrick goto done;
11200 624411d2 2023-07-08 jrick
11201 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
11202 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
11203 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
11204 624411d2 2023-07-08 jrick if (upa.conflicts > 0) {
11205 624411d2 2023-07-08 jrick error = show_rebase_merge_conflict(&qid->id,
11206 624411d2 2023-07-08 jrick repo);
11207 624411d2 2023-07-08 jrick if (error)
11208 624411d2 2023-07-08 jrick goto done;
11209 624411d2 2023-07-08 jrick }
11210 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
11211 624411d2 2023-07-08 jrick break;
11212 624411d2 2023-07-08 jrick }
11213 624411d2 2023-07-08 jrick
11214 624411d2 2023-07-08 jrick error = rebase_commit(&merged_paths, worktree, fileindex,
11215 624411d2 2023-07-08 jrick tmp_branch, committer, commit_id, 0, repo);
11216 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
11217 624411d2 2023-07-08 jrick if (error)
11218 624411d2 2023-07-08 jrick goto done;
11219 624411d2 2023-07-08 jrick }
11220 624411d2 2023-07-08 jrick
11221 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
11222 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
11223 624411d2 2023-07-08 jrick error = got_worktree_rebase_postpone(worktree, fileindex);
11224 624411d2 2023-07-08 jrick if (error)
11225 624411d2 2023-07-08 jrick goto done;
11226 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
11227 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
11228 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11229 624411d2 2023-07-08 jrick "conflicts must be resolved before rebasing "
11230 624411d2 2023-07-08 jrick "can continue");
11231 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
11232 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11233 624411d2 2023-07-08 jrick "conflicts must be resolved before rebasing "
11234 624411d2 2023-07-08 jrick "can continue; changes destined for some "
11235 624411d2 2023-07-08 jrick "files were not yet merged and should be "
11236 624411d2 2023-07-08 jrick "merged manually if required before the "
11237 624411d2 2023-07-08 jrick "rebase operation is continued");
11238 624411d2 2023-07-08 jrick } else {
11239 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11240 624411d2 2023-07-08 jrick "changes destined for some files were not "
11241 624411d2 2023-07-08 jrick "yet merged and should be merged manually "
11242 624411d2 2023-07-08 jrick "if required before the rebase operation "
11243 624411d2 2023-07-08 jrick "is continued");
11244 624411d2 2023-07-08 jrick }
11245 624411d2 2023-07-08 jrick } else
11246 624411d2 2023-07-08 jrick error = rebase_complete(worktree, fileindex, branch,
11247 624411d2 2023-07-08 jrick tmp_branch, repo, create_backup);
11248 624411d2 2023-07-08 jrick done:
11249 624411d2 2023-07-08 jrick free(cwd);
11250 624411d2 2023-07-08 jrick free(committer);
11251 624411d2 2023-07-08 jrick free(gitconfig_path);
11252 624411d2 2023-07-08 jrick got_object_id_queue_free(&commits);
11253 624411d2 2023-07-08 jrick free(branch_head_commit_id);
11254 624411d2 2023-07-08 jrick free(resume_commit_id);
11255 624411d2 2023-07-08 jrick free(head_commit_id);
11256 624411d2 2023-07-08 jrick free(yca_id);
11257 624411d2 2023-07-08 jrick if (commit)
11258 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11259 624411d2 2023-07-08 jrick if (branch)
11260 624411d2 2023-07-08 jrick got_ref_close(branch);
11261 624411d2 2023-07-08 jrick if (new_base_branch)
11262 624411d2 2023-07-08 jrick got_ref_close(new_base_branch);
11263 624411d2 2023-07-08 jrick if (tmp_branch)
11264 624411d2 2023-07-08 jrick got_ref_close(tmp_branch);
11265 624411d2 2023-07-08 jrick if (head_ref)
11266 624411d2 2023-07-08 jrick got_ref_close(head_ref);
11267 624411d2 2023-07-08 jrick if (worktree)
11268 624411d2 2023-07-08 jrick got_worktree_close(worktree);
11269 624411d2 2023-07-08 jrick if (repo) {
11270 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
11271 624411d2 2023-07-08 jrick if (error == NULL)
11272 624411d2 2023-07-08 jrick error = close_err;
11273 624411d2 2023-07-08 jrick }
11274 624411d2 2023-07-08 jrick if (pack_fds) {
11275 624411d2 2023-07-08 jrick const struct got_error *pack_err =
11276 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
11277 624411d2 2023-07-08 jrick if (error == NULL)
11278 624411d2 2023-07-08 jrick error = pack_err;
11279 624411d2 2023-07-08 jrick }
11280 624411d2 2023-07-08 jrick return error;
11281 624411d2 2023-07-08 jrick }
11282 624411d2 2023-07-08 jrick
11283 624411d2 2023-07-08 jrick __dead static void
11284 624411d2 2023-07-08 jrick usage_histedit(void)
11285 624411d2 2023-07-08 jrick {
11286 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
11287 624411d2 2023-07-08 jrick "[branch]\n", getprogname());
11288 624411d2 2023-07-08 jrick exit(1);
11289 624411d2 2023-07-08 jrick }
11290 624411d2 2023-07-08 jrick
11291 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_PICK 'p'
11292 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_EDIT 'e'
11293 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_FOLD 'f'
11294 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_DROP 'd'
11295 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_MESG 'm'
11296 624411d2 2023-07-08 jrick
11297 624411d2 2023-07-08 jrick static const struct got_histedit_cmd {
11298 624411d2 2023-07-08 jrick unsigned char code;
11299 624411d2 2023-07-08 jrick const char *name;
11300 624411d2 2023-07-08 jrick const char *desc;
11301 624411d2 2023-07-08 jrick } got_histedit_cmds[] = {
11302 624411d2 2023-07-08 jrick { GOT_HISTEDIT_PICK, "pick", "use commit" },
11303 624411d2 2023-07-08 jrick { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
11304 624411d2 2023-07-08 jrick { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
11305 624411d2 2023-07-08 jrick "be used" },
11306 624411d2 2023-07-08 jrick { GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
11307 624411d2 2023-07-08 jrick { GOT_HISTEDIT_MESG, "mesg",
11308 624411d2 2023-07-08 jrick "single-line log message for commit above (open editor if empty)" },
11309 624411d2 2023-07-08 jrick };
11310 624411d2 2023-07-08 jrick
11311 624411d2 2023-07-08 jrick struct got_histedit_list_entry {
11312 624411d2 2023-07-08 jrick TAILQ_ENTRY(got_histedit_list_entry) entry;
11313 624411d2 2023-07-08 jrick struct got_object_id *commit_id;
11314 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd;
11315 624411d2 2023-07-08 jrick char *logmsg;
11316 624411d2 2023-07-08 jrick };
11317 624411d2 2023-07-08 jrick TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
11318 624411d2 2023-07-08 jrick
11319 624411d2 2023-07-08 jrick static const struct got_error *
11320 624411d2 2023-07-08 jrick histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
11321 624411d2 2023-07-08 jrick FILE *f, struct got_repository *repo)
11322 624411d2 2023-07-08 jrick {
11323 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11324 624411d2 2023-07-08 jrick char *logmsg = NULL, *id_str = NULL;
11325 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11326 624411d2 2023-07-08 jrick int n;
11327 624411d2 2023-07-08 jrick
11328 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
11329 624411d2 2023-07-08 jrick if (err)
11330 624411d2 2023-07-08 jrick goto done;
11331 624411d2 2023-07-08 jrick
11332 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 34, commit);
11333 624411d2 2023-07-08 jrick if (err)
11334 624411d2 2023-07-08 jrick goto done;
11335 624411d2 2023-07-08 jrick
11336 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, commit_id);
11337 624411d2 2023-07-08 jrick if (err)
11338 624411d2 2023-07-08 jrick goto done;
11339 624411d2 2023-07-08 jrick
11340 624411d2 2023-07-08 jrick n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
11341 624411d2 2023-07-08 jrick if (n < 0)
11342 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11343 624411d2 2023-07-08 jrick done:
11344 624411d2 2023-07-08 jrick if (commit)
11345 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11346 624411d2 2023-07-08 jrick free(id_str);
11347 624411d2 2023-07-08 jrick free(logmsg);
11348 624411d2 2023-07-08 jrick return err;
11349 624411d2 2023-07-08 jrick }
11350 624411d2 2023-07-08 jrick
11351 624411d2 2023-07-08 jrick static const struct got_error *
11352 624411d2 2023-07-08 jrick histedit_write_commit_list(struct got_object_id_queue *commits,
11353 624411d2 2023-07-08 jrick FILE *f, int edit_logmsg_only, int fold_only, int drop_only,
11354 624411d2 2023-07-08 jrick int edit_only, struct got_repository *repo)
11355 624411d2 2023-07-08 jrick {
11356 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11357 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11358 624411d2 2023-07-08 jrick const char *histedit_cmd = NULL;
11359 624411d2 2023-07-08 jrick
11360 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(commits))
11361 624411d2 2023-07-08 jrick return got_error(GOT_ERR_EMPTY_HISTEDIT);
11362 624411d2 2023-07-08 jrick
11363 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, commits, entry) {
11364 624411d2 2023-07-08 jrick histedit_cmd = got_histedit_cmds[0].name;
11365 624411d2 2023-07-08 jrick if (drop_only)
11366 624411d2 2023-07-08 jrick histedit_cmd = "drop";
11367 624411d2 2023-07-08 jrick else if (edit_only)
11368 624411d2 2023-07-08 jrick histedit_cmd = "edit";
11369 624411d2 2023-07-08 jrick else if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
11370 624411d2 2023-07-08 jrick histedit_cmd = "fold";
11371 624411d2 2023-07-08 jrick err = histedit_write_commit(&qid->id, histedit_cmd, f, repo);
11372 624411d2 2023-07-08 jrick if (err)
11373 624411d2 2023-07-08 jrick break;
11374 624411d2 2023-07-08 jrick if (edit_logmsg_only) {
11375 624411d2 2023-07-08 jrick int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
11376 624411d2 2023-07-08 jrick if (n < 0) {
11377 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11378 624411d2 2023-07-08 jrick break;
11379 624411d2 2023-07-08 jrick }
11380 624411d2 2023-07-08 jrick }
11381 624411d2 2023-07-08 jrick }
11382 624411d2 2023-07-08 jrick
11383 624411d2 2023-07-08 jrick return err;
11384 624411d2 2023-07-08 jrick }
11385 624411d2 2023-07-08 jrick
11386 624411d2 2023-07-08 jrick static const struct got_error *
11387 624411d2 2023-07-08 jrick write_cmd_list(FILE *f, const char *branch_name,
11388 624411d2 2023-07-08 jrick struct got_object_id_queue *commits)
11389 624411d2 2023-07-08 jrick {
11390 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11391 624411d2 2023-07-08 jrick size_t i;
11392 624411d2 2023-07-08 jrick int n;
11393 624411d2 2023-07-08 jrick char *id_str;
11394 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11395 624411d2 2023-07-08 jrick
11396 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(commits);
11397 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
11398 624411d2 2023-07-08 jrick if (err)
11399 624411d2 2023-07-08 jrick return err;
11400 624411d2 2023-07-08 jrick
11401 624411d2 2023-07-08 jrick n = fprintf(f,
11402 624411d2 2023-07-08 jrick "# Editing the history of branch '%s' starting at\n"
11403 624411d2 2023-07-08 jrick "# commit %s\n"
11404 624411d2 2023-07-08 jrick "# Commits will be processed in order from top to "
11405 624411d2 2023-07-08 jrick "bottom of this file.\n", branch_name, id_str);
11406 624411d2 2023-07-08 jrick if (n < 0) {
11407 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11408 624411d2 2023-07-08 jrick goto done;
11409 624411d2 2023-07-08 jrick }
11410 624411d2 2023-07-08 jrick
11411 624411d2 2023-07-08 jrick n = fprintf(f, "# Available histedit commands:\n");
11412 624411d2 2023-07-08 jrick if (n < 0) {
11413 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11414 624411d2 2023-07-08 jrick goto done;
11415 624411d2 2023-07-08 jrick }
11416 624411d2 2023-07-08 jrick
11417 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_histedit_cmds); i++) {
11418 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
11419 624411d2 2023-07-08 jrick n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
11420 624411d2 2023-07-08 jrick cmd->desc);
11421 624411d2 2023-07-08 jrick if (n < 0) {
11422 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11423 624411d2 2023-07-08 jrick break;
11424 624411d2 2023-07-08 jrick }
11425 624411d2 2023-07-08 jrick }
11426 624411d2 2023-07-08 jrick done:
11427 624411d2 2023-07-08 jrick free(id_str);
11428 624411d2 2023-07-08 jrick return err;
11429 624411d2 2023-07-08 jrick }
11430 624411d2 2023-07-08 jrick
11431 624411d2 2023-07-08 jrick static const struct got_error *
11432 624411d2 2023-07-08 jrick histedit_syntax_error(int lineno)
11433 624411d2 2023-07-08 jrick {
11434 624411d2 2023-07-08 jrick static char msg[42];
11435 624411d2 2023-07-08 jrick int ret;
11436 624411d2 2023-07-08 jrick
11437 624411d2 2023-07-08 jrick ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
11438 624411d2 2023-07-08 jrick lineno);
11439 624411d2 2023-07-08 jrick if (ret < 0 || (size_t)ret >= sizeof(msg))
11440 624411d2 2023-07-08 jrick return got_error(GOT_ERR_HISTEDIT_SYNTAX);
11441 624411d2 2023-07-08 jrick
11442 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
11443 624411d2 2023-07-08 jrick }
11444 624411d2 2023-07-08 jrick
11445 624411d2 2023-07-08 jrick static const struct got_error *
11446 624411d2 2023-07-08 jrick append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
11447 624411d2 2023-07-08 jrick char *logmsg, struct got_repository *repo)
11448 624411d2 2023-07-08 jrick {
11449 624411d2 2023-07-08 jrick const struct got_error *err;
11450 624411d2 2023-07-08 jrick struct got_commit_object *folded_commit = NULL;
11451 624411d2 2023-07-08 jrick char *id_str, *folded_logmsg = NULL;
11452 624411d2 2023-07-08 jrick
11453 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11454 624411d2 2023-07-08 jrick if (err)
11455 624411d2 2023-07-08 jrick return err;
11456 624411d2 2023-07-08 jrick
11457 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
11458 624411d2 2023-07-08 jrick if (err)
11459 624411d2 2023-07-08 jrick goto done;
11460 624411d2 2023-07-08 jrick
11461 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
11462 624411d2 2023-07-08 jrick if (err)
11463 624411d2 2023-07-08 jrick goto done;
11464 624411d2 2023-07-08 jrick if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
11465 624411d2 2023-07-08 jrick logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
11466 624411d2 2023-07-08 jrick folded_logmsg) == -1) {
11467 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
11468 624411d2 2023-07-08 jrick }
11469 624411d2 2023-07-08 jrick done:
11470 624411d2 2023-07-08 jrick if (folded_commit)
11471 624411d2 2023-07-08 jrick got_object_commit_close(folded_commit);
11472 624411d2 2023-07-08 jrick free(id_str);
11473 624411d2 2023-07-08 jrick free(folded_logmsg);
11474 624411d2 2023-07-08 jrick return err;
11475 624411d2 2023-07-08 jrick }
11476 624411d2 2023-07-08 jrick
11477 624411d2 2023-07-08 jrick static struct got_histedit_list_entry *
11478 624411d2 2023-07-08 jrick get_folded_commits(struct got_histedit_list_entry *hle)
11479 624411d2 2023-07-08 jrick {
11480 624411d2 2023-07-08 jrick struct got_histedit_list_entry *prev, *folded = NULL;
11481 624411d2 2023-07-08 jrick
11482 624411d2 2023-07-08 jrick prev = TAILQ_PREV(hle, got_histedit_list, entry);
11483 624411d2 2023-07-08 jrick while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
11484 624411d2 2023-07-08 jrick prev->cmd->code == GOT_HISTEDIT_DROP)) {
11485 624411d2 2023-07-08 jrick if (prev->cmd->code == GOT_HISTEDIT_FOLD)
11486 624411d2 2023-07-08 jrick folded = prev;
11487 624411d2 2023-07-08 jrick prev = TAILQ_PREV(prev, got_histedit_list, entry);
11488 624411d2 2023-07-08 jrick }
11489 624411d2 2023-07-08 jrick
11490 624411d2 2023-07-08 jrick return folded;
11491 624411d2 2023-07-08 jrick }
11492 624411d2 2023-07-08 jrick
11493 624411d2 2023-07-08 jrick static const struct got_error *
11494 624411d2 2023-07-08 jrick histedit_edit_logmsg(struct got_histedit_list_entry *hle,
11495 624411d2 2023-07-08 jrick struct got_repository *repo)
11496 624411d2 2023-07-08 jrick {
11497 624411d2 2023-07-08 jrick char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
11498 624411d2 2023-07-08 jrick char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
11499 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11500 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11501 624411d2 2023-07-08 jrick int logmsg_len;
11502 624411d2 2023-07-08 jrick int fd = -1;
11503 624411d2 2023-07-08 jrick struct got_histedit_list_entry *folded = NULL;
11504 624411d2 2023-07-08 jrick
11505 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, hle->commit_id);
11506 624411d2 2023-07-08 jrick if (err)
11507 624411d2 2023-07-08 jrick return err;
11508 624411d2 2023-07-08 jrick
11509 624411d2 2023-07-08 jrick folded = get_folded_commits(hle);
11510 624411d2 2023-07-08 jrick if (folded) {
11511 624411d2 2023-07-08 jrick while (folded != hle) {
11512 624411d2 2023-07-08 jrick if (folded->cmd->code == GOT_HISTEDIT_DROP) {
11513 624411d2 2023-07-08 jrick folded = TAILQ_NEXT(folded, entry);
11514 624411d2 2023-07-08 jrick continue;
11515 624411d2 2023-07-08 jrick }
11516 624411d2 2023-07-08 jrick err = append_folded_commit_msg(&new_msg, folded,
11517 624411d2 2023-07-08 jrick logmsg, repo);
11518 624411d2 2023-07-08 jrick if (err)
11519 624411d2 2023-07-08 jrick goto done;
11520 624411d2 2023-07-08 jrick free(logmsg);
11521 624411d2 2023-07-08 jrick logmsg = new_msg;
11522 624411d2 2023-07-08 jrick folded = TAILQ_NEXT(folded, entry);
11523 624411d2 2023-07-08 jrick }
11524 624411d2 2023-07-08 jrick }
11525 624411d2 2023-07-08 jrick
11526 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11527 624411d2 2023-07-08 jrick if (err)
11528 624411d2 2023-07-08 jrick goto done;
11529 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&orig_logmsg, commit);
11530 624411d2 2023-07-08 jrick if (err)
11531 624411d2 2023-07-08 jrick goto done;
11532 624411d2 2023-07-08 jrick logmsg_len = asprintf(&new_msg,
11533 624411d2 2023-07-08 jrick "%s\n# original log message of commit %s: %s",
11534 624411d2 2023-07-08 jrick logmsg ? logmsg : "", id_str, orig_logmsg);
11535 624411d2 2023-07-08 jrick if (logmsg_len == -1) {
11536 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
11537 624411d2 2023-07-08 jrick goto done;
11538 624411d2 2023-07-08 jrick }
11539 624411d2 2023-07-08 jrick free(logmsg);
11540 624411d2 2023-07-08 jrick logmsg = new_msg;
11541 624411d2 2023-07-08 jrick
11542 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11543 624411d2 2023-07-08 jrick if (err)
11544 624411d2 2023-07-08 jrick goto done;
11545 624411d2 2023-07-08 jrick
11546 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(&logmsg_path, &fd,
11547 624411d2 2023-07-08 jrick GOT_TMPDIR_STR "/got-logmsg", "");
11548 624411d2 2023-07-08 jrick if (err)
11549 624411d2 2023-07-08 jrick goto done;
11550 624411d2 2023-07-08 jrick
11551 624411d2 2023-07-08 jrick if (write(fd, logmsg, logmsg_len) == -1) {
11552 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", logmsg_path);
11553 624411d2 2023-07-08 jrick goto done;
11554 624411d2 2023-07-08 jrick }
11555 624411d2 2023-07-08 jrick if (close(fd) == -1) {
11556 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", logmsg_path);
11557 624411d2 2023-07-08 jrick goto done;
11558 624411d2 2023-07-08 jrick }
11559 624411d2 2023-07-08 jrick fd = -1;
11560 624411d2 2023-07-08 jrick
11561 624411d2 2023-07-08 jrick err = get_editor(&editor);
11562 624411d2 2023-07-08 jrick if (err)
11563 624411d2 2023-07-08 jrick goto done;
11564 624411d2 2023-07-08 jrick
11565 624411d2 2023-07-08 jrick err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
11566 624411d2 2023-07-08 jrick logmsg_len, 0);
11567 624411d2 2023-07-08 jrick if (err) {
11568 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
11569 624411d2 2023-07-08 jrick goto done;
11570 624411d2 2023-07-08 jrick err = NULL;
11571 624411d2 2023-07-08 jrick hle->logmsg = strdup(new_msg);
11572 624411d2 2023-07-08 jrick if (hle->logmsg == NULL)
11573 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11574 624411d2 2023-07-08 jrick }
11575 624411d2 2023-07-08 jrick done:
11576 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
11577 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", logmsg_path);
11578 624411d2 2023-07-08 jrick if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
11579 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", logmsg_path);
11580 624411d2 2023-07-08 jrick free(logmsg_path);
11581 624411d2 2023-07-08 jrick free(logmsg);
11582 624411d2 2023-07-08 jrick free(orig_logmsg);
11583 624411d2 2023-07-08 jrick free(editor);
11584 624411d2 2023-07-08 jrick if (commit)
11585 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11586 624411d2 2023-07-08 jrick return err;
11587 624411d2 2023-07-08 jrick }
11588 624411d2 2023-07-08 jrick
11589 624411d2 2023-07-08 jrick static const struct got_error *
11590 624411d2 2023-07-08 jrick histedit_parse_list(struct got_histedit_list *histedit_cmds,
11591 624411d2 2023-07-08 jrick FILE *f, struct got_repository *repo)
11592 624411d2 2023-07-08 jrick {
11593 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11594 624411d2 2023-07-08 jrick char *line = NULL, *p, *end;
11595 624411d2 2023-07-08 jrick size_t i, linesize = 0;
11596 624411d2 2023-07-08 jrick ssize_t linelen;
11597 624411d2 2023-07-08 jrick int lineno = 0, lastcmd = -1;
11598 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd;
11599 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
11600 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle = NULL;
11601 624411d2 2023-07-08 jrick
11602 624411d2 2023-07-08 jrick for (;;) {
11603 624411d2 2023-07-08 jrick linelen = getline(&line, &linesize, f);
11604 624411d2 2023-07-08 jrick if (linelen == -1) {
11605 624411d2 2023-07-08 jrick const struct got_error *getline_err;
11606 624411d2 2023-07-08 jrick if (feof(f))
11607 624411d2 2023-07-08 jrick break;
11608 624411d2 2023-07-08 jrick getline_err = got_error_from_errno("getline");
11609 624411d2 2023-07-08 jrick err = got_ferror(f, getline_err->code);
11610 624411d2 2023-07-08 jrick break;
11611 624411d2 2023-07-08 jrick }
11612 624411d2 2023-07-08 jrick lineno++;
11613 624411d2 2023-07-08 jrick p = line;
11614 624411d2 2023-07-08 jrick while (isspace((unsigned char)p[0]))
11615 624411d2 2023-07-08 jrick p++;
11616 624411d2 2023-07-08 jrick if (p[0] == '#' || p[0] == '\0')
11617 624411d2 2023-07-08 jrick continue;
11618 624411d2 2023-07-08 jrick cmd = NULL;
11619 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_histedit_cmds); i++) {
11620 624411d2 2023-07-08 jrick cmd = &got_histedit_cmds[i];
11621 624411d2 2023-07-08 jrick if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
11622 624411d2 2023-07-08 jrick isspace((unsigned char)p[strlen(cmd->name)])) {
11623 624411d2 2023-07-08 jrick p += strlen(cmd->name);
11624 624411d2 2023-07-08 jrick break;
11625 624411d2 2023-07-08 jrick }
11626 624411d2 2023-07-08 jrick if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
11627 624411d2 2023-07-08 jrick p++;
11628 624411d2 2023-07-08 jrick break;
11629 624411d2 2023-07-08 jrick }
11630 624411d2 2023-07-08 jrick }
11631 624411d2 2023-07-08 jrick if (i == nitems(got_histedit_cmds)) {
11632 624411d2 2023-07-08 jrick err = histedit_syntax_error(lineno);
11633 624411d2 2023-07-08 jrick break;
11634 624411d2 2023-07-08 jrick }
11635 624411d2 2023-07-08 jrick while (isspace((unsigned char)p[0]))
11636 624411d2 2023-07-08 jrick p++;
11637 624411d2 2023-07-08 jrick if (cmd->code == GOT_HISTEDIT_MESG) {
11638 624411d2 2023-07-08 jrick if (lastcmd != GOT_HISTEDIT_PICK &&
11639 624411d2 2023-07-08 jrick lastcmd != GOT_HISTEDIT_EDIT) {
11640 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_HISTEDIT_CMD);
11641 624411d2 2023-07-08 jrick break;
11642 624411d2 2023-07-08 jrick }
11643 624411d2 2023-07-08 jrick if (p[0] == '\0') {
11644 624411d2 2023-07-08 jrick err = histedit_edit_logmsg(hle, repo);
11645 624411d2 2023-07-08 jrick if (err)
11646 624411d2 2023-07-08 jrick break;
11647 624411d2 2023-07-08 jrick } else {
11648 624411d2 2023-07-08 jrick hle->logmsg = strdup(p);
11649 624411d2 2023-07-08 jrick if (hle->logmsg == NULL) {
11650 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11651 624411d2 2023-07-08 jrick break;
11652 624411d2 2023-07-08 jrick }
11653 624411d2 2023-07-08 jrick }
11654 624411d2 2023-07-08 jrick lastcmd = cmd->code;
11655 624411d2 2023-07-08 jrick continue;
11656 624411d2 2023-07-08 jrick } else {
11657 624411d2 2023-07-08 jrick end = p;
11658 624411d2 2023-07-08 jrick while (end[0] && !isspace((unsigned char)end[0]))
11659 624411d2 2023-07-08 jrick end++;
11660 624411d2 2023-07-08 jrick *end = '\0';
11661 624411d2 2023-07-08 jrick
11662 624411d2 2023-07-08 jrick err = got_object_resolve_id_str(&commit_id, repo, p);
11663 624411d2 2023-07-08 jrick if (err) {
11664 624411d2 2023-07-08 jrick /* override error code */
11665 624411d2 2023-07-08 jrick err = histedit_syntax_error(lineno);
11666 624411d2 2023-07-08 jrick break;
11667 624411d2 2023-07-08 jrick }
11668 624411d2 2023-07-08 jrick }
11669 624411d2 2023-07-08 jrick hle = malloc(sizeof(*hle));
11670 624411d2 2023-07-08 jrick if (hle == NULL) {
11671 624411d2 2023-07-08 jrick err = got_error_from_errno("malloc");
11672 624411d2 2023-07-08 jrick break;
11673 624411d2 2023-07-08 jrick }
11674 624411d2 2023-07-08 jrick hle->cmd = cmd;
11675 624411d2 2023-07-08 jrick hle->commit_id = commit_id;
11676 624411d2 2023-07-08 jrick hle->logmsg = NULL;
11677 624411d2 2023-07-08 jrick commit_id = NULL;
11678 624411d2 2023-07-08 jrick TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
11679 624411d2 2023-07-08 jrick lastcmd = cmd->code;
11680 624411d2 2023-07-08 jrick }
11681 624411d2 2023-07-08 jrick
11682 624411d2 2023-07-08 jrick free(line);
11683 624411d2 2023-07-08 jrick free(commit_id);
11684 624411d2 2023-07-08 jrick return err;
11685 624411d2 2023-07-08 jrick }
11686 624411d2 2023-07-08 jrick
11687 624411d2 2023-07-08 jrick static const struct got_error *
11688 624411d2 2023-07-08 jrick histedit_check_script(struct got_histedit_list *histedit_cmds,
11689 624411d2 2023-07-08 jrick struct got_object_id_queue *commits, struct got_repository *repo)
11690 624411d2 2023-07-08 jrick {
11691 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11692 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11693 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11694 624411d2 2023-07-08 jrick static char msg[92];
11695 624411d2 2023-07-08 jrick char *id_str;
11696 624411d2 2023-07-08 jrick
11697 624411d2 2023-07-08 jrick if (TAILQ_EMPTY(histedit_cmds))
11698 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
11699 624411d2 2023-07-08 jrick "histedit script contains no commands");
11700 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(commits))
11701 624411d2 2023-07-08 jrick return got_error(GOT_ERR_EMPTY_HISTEDIT);
11702 624411d2 2023-07-08 jrick
11703 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11704 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle2;
11705 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle2, histedit_cmds, entry) {
11706 624411d2 2023-07-08 jrick if (hle == hle2)
11707 624411d2 2023-07-08 jrick continue;
11708 624411d2 2023-07-08 jrick if (got_object_id_cmp(hle->commit_id,
11709 624411d2 2023-07-08 jrick hle2->commit_id) != 0)
11710 624411d2 2023-07-08 jrick continue;
11711 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11712 624411d2 2023-07-08 jrick if (err)
11713 624411d2 2023-07-08 jrick return err;
11714 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg), "commit %s is listed "
11715 624411d2 2023-07-08 jrick "more than once in histedit script", id_str);
11716 624411d2 2023-07-08 jrick free(id_str);
11717 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
11718 624411d2 2023-07-08 jrick }
11719 624411d2 2023-07-08 jrick }
11720 624411d2 2023-07-08 jrick
11721 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, commits, entry) {
11722 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11723 624411d2 2023-07-08 jrick if (got_object_id_cmp(&qid->id, hle->commit_id) == 0)
11724 624411d2 2023-07-08 jrick break;
11725 624411d2 2023-07-08 jrick }
11726 624411d2 2023-07-08 jrick if (hle == NULL) {
11727 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
11728 624411d2 2023-07-08 jrick if (err)
11729 624411d2 2023-07-08 jrick return err;
11730 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
11731 624411d2 2023-07-08 jrick "commit %s missing from histedit script", id_str);
11732 624411d2 2023-07-08 jrick free(id_str);
11733 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
11734 624411d2 2023-07-08 jrick }
11735 624411d2 2023-07-08 jrick }
11736 624411d2 2023-07-08 jrick
11737 624411d2 2023-07-08 jrick hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
11738 624411d2 2023-07-08 jrick if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
11739 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD,
11740 624411d2 2023-07-08 jrick "last commit in histedit script cannot be folded");
11741 624411d2 2023-07-08 jrick
11742 624411d2 2023-07-08 jrick return NULL;
11743 624411d2 2023-07-08 jrick }
11744 624411d2 2023-07-08 jrick
11745 624411d2 2023-07-08 jrick static const struct got_error *
11746 624411d2 2023-07-08 jrick histedit_run_editor(struct got_histedit_list *histedit_cmds,
11747 624411d2 2023-07-08 jrick const char *path, struct got_object_id_queue *commits,
11748 624411d2 2023-07-08 jrick struct got_repository *repo)
11749 624411d2 2023-07-08 jrick {
11750 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11751 624411d2 2023-07-08 jrick char *editor;
11752 624411d2 2023-07-08 jrick FILE *f = NULL;
11753 624411d2 2023-07-08 jrick
11754 624411d2 2023-07-08 jrick err = get_editor(&editor);
11755 624411d2 2023-07-08 jrick if (err)
11756 624411d2 2023-07-08 jrick return err;
11757 624411d2 2023-07-08 jrick
11758 624411d2 2023-07-08 jrick if (spawn_editor(editor, path) == -1) {
11759 624411d2 2023-07-08 jrick err = got_error_from_errno("failed spawning editor");
11760 624411d2 2023-07-08 jrick goto done;
11761 624411d2 2023-07-08 jrick }
11762 624411d2 2023-07-08 jrick
11763 624411d2 2023-07-08 jrick f = fopen(path, "re");
11764 624411d2 2023-07-08 jrick if (f == NULL) {
11765 624411d2 2023-07-08 jrick err = got_error_from_errno("fopen");
11766 624411d2 2023-07-08 jrick goto done;
11767 624411d2 2023-07-08 jrick }
11768 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11769 624411d2 2023-07-08 jrick if (err)
11770 624411d2 2023-07-08 jrick goto done;
11771 624411d2 2023-07-08 jrick
11772 624411d2 2023-07-08 jrick err = histedit_check_script(histedit_cmds, commits, repo);
11773 624411d2 2023-07-08 jrick done:
11774 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11775 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11776 624411d2 2023-07-08 jrick free(editor);
11777 624411d2 2023-07-08 jrick return err;
11778 624411d2 2023-07-08 jrick }
11779 624411d2 2023-07-08 jrick
11780 624411d2 2023-07-08 jrick static const struct got_error *
11781 624411d2 2023-07-08 jrick histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
11782 624411d2 2023-07-08 jrick struct got_object_id_queue *, const char *, const char *,
11783 624411d2 2023-07-08 jrick struct got_repository *);
11784 624411d2 2023-07-08 jrick
11785 624411d2 2023-07-08 jrick static const struct got_error *
11786 624411d2 2023-07-08 jrick histedit_edit_script(struct got_histedit_list *histedit_cmds,
11787 624411d2 2023-07-08 jrick struct got_object_id_queue *commits, const char *branch_name,
11788 624411d2 2023-07-08 jrick int edit_logmsg_only, int fold_only, int drop_only, int edit_only,
11789 624411d2 2023-07-08 jrick struct got_repository *repo)
11790 624411d2 2023-07-08 jrick {
11791 624411d2 2023-07-08 jrick const struct got_error *err;
11792 624411d2 2023-07-08 jrick FILE *f = NULL;
11793 624411d2 2023-07-08 jrick char *path = NULL;
11794 624411d2 2023-07-08 jrick
11795 624411d2 2023-07-08 jrick err = got_opentemp_named(&path, &f, "got-histedit", "");
11796 624411d2 2023-07-08 jrick if (err)
11797 624411d2 2023-07-08 jrick return err;
11798 624411d2 2023-07-08 jrick
11799 624411d2 2023-07-08 jrick err = write_cmd_list(f, branch_name, commits);
11800 624411d2 2023-07-08 jrick if (err)
11801 624411d2 2023-07-08 jrick goto done;
11802 624411d2 2023-07-08 jrick
11803 624411d2 2023-07-08 jrick err = histedit_write_commit_list(commits, f, edit_logmsg_only,
11804 624411d2 2023-07-08 jrick fold_only, drop_only, edit_only, repo);
11805 624411d2 2023-07-08 jrick if (err)
11806 624411d2 2023-07-08 jrick goto done;
11807 624411d2 2023-07-08 jrick
11808 624411d2 2023-07-08 jrick if (drop_only || edit_logmsg_only || fold_only || edit_only) {
11809 624411d2 2023-07-08 jrick rewind(f);
11810 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11811 624411d2 2023-07-08 jrick } else {
11812 624411d2 2023-07-08 jrick if (fclose(f) == EOF) {
11813 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11814 624411d2 2023-07-08 jrick goto done;
11815 624411d2 2023-07-08 jrick }
11816 624411d2 2023-07-08 jrick f = NULL;
11817 624411d2 2023-07-08 jrick err = histedit_run_editor(histedit_cmds, path, commits, repo);
11818 624411d2 2023-07-08 jrick if (err) {
11819 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11820 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11821 624411d2 2023-07-08 jrick goto done;
11822 624411d2 2023-07-08 jrick err = histedit_edit_list_retry(histedit_cmds, err,
11823 624411d2 2023-07-08 jrick commits, path, branch_name, repo);
11824 624411d2 2023-07-08 jrick }
11825 624411d2 2023-07-08 jrick }
11826 624411d2 2023-07-08 jrick done:
11827 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11828 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11829 624411d2 2023-07-08 jrick if (path && unlink(path) != 0 && err == NULL)
11830 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", path);
11831 624411d2 2023-07-08 jrick free(path);
11832 624411d2 2023-07-08 jrick return err;
11833 624411d2 2023-07-08 jrick }
11834 624411d2 2023-07-08 jrick
11835 624411d2 2023-07-08 jrick static const struct got_error *
11836 624411d2 2023-07-08 jrick histedit_save_list(struct got_histedit_list *histedit_cmds,
11837 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
11838 624411d2 2023-07-08 jrick {
11839 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11840 624411d2 2023-07-08 jrick char *path = NULL;
11841 624411d2 2023-07-08 jrick FILE *f = NULL;
11842 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11843 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11844 624411d2 2023-07-08 jrick
11845 624411d2 2023-07-08 jrick err = got_worktree_get_histedit_script_path(&path, worktree);
11846 624411d2 2023-07-08 jrick if (err)
11847 624411d2 2023-07-08 jrick return err;
11848 624411d2 2023-07-08 jrick
11849 624411d2 2023-07-08 jrick f = fopen(path, "we");
11850 624411d2 2023-07-08 jrick if (f == NULL) {
11851 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", path);
11852 624411d2 2023-07-08 jrick goto done;
11853 624411d2 2023-07-08 jrick }
11854 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11855 624411d2 2023-07-08 jrick err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
11856 624411d2 2023-07-08 jrick repo);
11857 624411d2 2023-07-08 jrick if (err)
11858 624411d2 2023-07-08 jrick break;
11859 624411d2 2023-07-08 jrick
11860 624411d2 2023-07-08 jrick if (hle->logmsg) {
11861 624411d2 2023-07-08 jrick int n = fprintf(f, "%c %s\n",
11862 624411d2 2023-07-08 jrick GOT_HISTEDIT_MESG, hle->logmsg);
11863 624411d2 2023-07-08 jrick if (n < 0) {
11864 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11865 624411d2 2023-07-08 jrick break;
11866 624411d2 2023-07-08 jrick }
11867 624411d2 2023-07-08 jrick }
11868 624411d2 2023-07-08 jrick }
11869 624411d2 2023-07-08 jrick done:
11870 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11871 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11872 624411d2 2023-07-08 jrick free(path);
11873 624411d2 2023-07-08 jrick if (commit)
11874 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11875 624411d2 2023-07-08 jrick return err;
11876 624411d2 2023-07-08 jrick }
11877 624411d2 2023-07-08 jrick
11878 624411d2 2023-07-08 jrick static void
11879 624411d2 2023-07-08 jrick histedit_free_list(struct got_histedit_list *histedit_cmds)
11880 624411d2 2023-07-08 jrick {
11881 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11882 624411d2 2023-07-08 jrick
11883 624411d2 2023-07-08 jrick while ((hle = TAILQ_FIRST(histedit_cmds))) {
11884 624411d2 2023-07-08 jrick TAILQ_REMOVE(histedit_cmds, hle, entry);
11885 624411d2 2023-07-08 jrick free(hle);
11886 624411d2 2023-07-08 jrick }
11887 624411d2 2023-07-08 jrick }
11888 624411d2 2023-07-08 jrick
11889 624411d2 2023-07-08 jrick static const struct got_error *
11890 624411d2 2023-07-08 jrick histedit_load_list(struct got_histedit_list *histedit_cmds,
11891 624411d2 2023-07-08 jrick const char *path, struct got_repository *repo)
11892 624411d2 2023-07-08 jrick {
11893 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11894 624411d2 2023-07-08 jrick FILE *f = NULL;
11895 624411d2 2023-07-08 jrick
11896 624411d2 2023-07-08 jrick f = fopen(path, "re");
11897 624411d2 2023-07-08 jrick if (f == NULL) {
11898 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", path);
11899 624411d2 2023-07-08 jrick goto done;
11900 624411d2 2023-07-08 jrick }
11901 624411d2 2023-07-08 jrick
11902 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11903 624411d2 2023-07-08 jrick done:
11904 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11905 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11906 624411d2 2023-07-08 jrick return err;
11907 624411d2 2023-07-08 jrick }
11908 624411d2 2023-07-08 jrick
11909 624411d2 2023-07-08 jrick static const struct got_error *
11910 624411d2 2023-07-08 jrick histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
11911 624411d2 2023-07-08 jrick const struct got_error *edit_err, struct got_object_id_queue *commits,
11912 624411d2 2023-07-08 jrick const char *path, const char *branch_name, struct got_repository *repo)
11913 624411d2 2023-07-08 jrick {
11914 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *prev_err = edit_err;
11915 624411d2 2023-07-08 jrick int resp = ' ';
11916 624411d2 2023-07-08 jrick
11917 624411d2 2023-07-08 jrick while (resp != 'c' && resp != 'r' && resp != 'a') {
11918 624411d2 2023-07-08 jrick printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
11919 624411d2 2023-07-08 jrick "or (a)bort: ", getprogname(), prev_err->msg);
11920 624411d2 2023-07-08 jrick resp = getchar();
11921 624411d2 2023-07-08 jrick if (resp == '\n')
11922 624411d2 2023-07-08 jrick resp = getchar();
11923 624411d2 2023-07-08 jrick if (resp == 'c') {
11924 624411d2 2023-07-08 jrick histedit_free_list(histedit_cmds);
11925 624411d2 2023-07-08 jrick err = histedit_run_editor(histedit_cmds, path, commits,
11926 624411d2 2023-07-08 jrick repo);
11927 624411d2 2023-07-08 jrick if (err) {
11928 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11929 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11930 624411d2 2023-07-08 jrick break;
11931 624411d2 2023-07-08 jrick prev_err = err;
11932 624411d2 2023-07-08 jrick resp = ' ';
11933 624411d2 2023-07-08 jrick continue;
11934 624411d2 2023-07-08 jrick }
11935 624411d2 2023-07-08 jrick break;
11936 624411d2 2023-07-08 jrick } else if (resp == 'r') {
11937 624411d2 2023-07-08 jrick histedit_free_list(histedit_cmds);
11938 624411d2 2023-07-08 jrick err = histedit_edit_script(histedit_cmds,
11939 624411d2 2023-07-08 jrick commits, branch_name, 0, 0, 0, 0, repo);
11940 624411d2 2023-07-08 jrick if (err) {
11941 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11942 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11943 624411d2 2023-07-08 jrick break;
11944 624411d2 2023-07-08 jrick prev_err = err;
11945 624411d2 2023-07-08 jrick resp = ' ';
11946 624411d2 2023-07-08 jrick continue;
11947 624411d2 2023-07-08 jrick }
11948 624411d2 2023-07-08 jrick break;
11949 624411d2 2023-07-08 jrick } else if (resp == 'a') {
11950 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_HISTEDIT_CANCEL);
11951 624411d2 2023-07-08 jrick break;
11952 624411d2 2023-07-08 jrick } else
11953 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
11954 624411d2 2023-07-08 jrick }
11955 624411d2 2023-07-08 jrick
11956 624411d2 2023-07-08 jrick return err;
11957 624411d2 2023-07-08 jrick }
11958 624411d2 2023-07-08 jrick
11959 624411d2 2023-07-08 jrick static const struct got_error *
11960 624411d2 2023-07-08 jrick histedit_complete(struct got_worktree *worktree,
11961 624411d2 2023-07-08 jrick struct got_fileindex *fileindex, struct got_reference *tmp_branch,
11962 624411d2 2023-07-08 jrick struct got_reference *branch, struct got_repository *repo)
11963 624411d2 2023-07-08 jrick {
11964 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
11965 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
11966 624411d2 2023-07-08 jrick return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
11967 624411d2 2023-07-08 jrick branch, repo);
11968 624411d2 2023-07-08 jrick }
11969 624411d2 2023-07-08 jrick
11970 624411d2 2023-07-08 jrick static const struct got_error *
11971 624411d2 2023-07-08 jrick show_histedit_progress(struct got_commit_object *commit,
11972 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle, struct got_object_id *new_id)
11973 624411d2 2023-07-08 jrick {
11974 624411d2 2023-07-08 jrick const struct got_error *err;
11975 624411d2 2023-07-08 jrick char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
11976 624411d2 2023-07-08 jrick
11977 624411d2 2023-07-08 jrick err = got_object_id_str(&old_id_str, hle->commit_id);
11978 624411d2 2023-07-08 jrick if (err)
11979 624411d2 2023-07-08 jrick goto done;
11980 624411d2 2023-07-08 jrick
11981 624411d2 2023-07-08 jrick if (new_id) {
11982 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
11983 624411d2 2023-07-08 jrick if (err)
11984 624411d2 2023-07-08 jrick goto done;
11985 624411d2 2023-07-08 jrick }
11986 624411d2 2023-07-08 jrick
11987 624411d2 2023-07-08 jrick old_id_str[12] = '\0';
11988 624411d2 2023-07-08 jrick if (new_id_str)
11989 624411d2 2023-07-08 jrick new_id_str[12] = '\0';
11990 624411d2 2023-07-08 jrick
11991 624411d2 2023-07-08 jrick if (hle->logmsg) {
11992 624411d2 2023-07-08 jrick logmsg = strdup(hle->logmsg);
11993 624411d2 2023-07-08 jrick if (logmsg == NULL) {
11994 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11995 624411d2 2023-07-08 jrick goto done;
11996 624411d2 2023-07-08 jrick }
11997 624411d2 2023-07-08 jrick trim_logmsg(logmsg, 42);
11998 624411d2 2023-07-08 jrick } else {
11999 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
12000 624411d2 2023-07-08 jrick if (err)
12001 624411d2 2023-07-08 jrick goto done;
12002 624411d2 2023-07-08 jrick }
12003 624411d2 2023-07-08 jrick
12004 624411d2 2023-07-08 jrick switch (hle->cmd->code) {
12005 624411d2 2023-07-08 jrick case GOT_HISTEDIT_PICK:
12006 624411d2 2023-07-08 jrick case GOT_HISTEDIT_EDIT:
12007 624411d2 2023-07-08 jrick printf("%s -> %s: %s\n", old_id_str,
12008 624411d2 2023-07-08 jrick new_id_str ? new_id_str : "no-op change", logmsg);
12009 624411d2 2023-07-08 jrick break;
12010 624411d2 2023-07-08 jrick case GOT_HISTEDIT_DROP:
12011 624411d2 2023-07-08 jrick case GOT_HISTEDIT_FOLD:
12012 624411d2 2023-07-08 jrick printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
12013 624411d2 2023-07-08 jrick logmsg);
12014 624411d2 2023-07-08 jrick break;
12015 624411d2 2023-07-08 jrick default:
12016 624411d2 2023-07-08 jrick break;
12017 624411d2 2023-07-08 jrick }
12018 624411d2 2023-07-08 jrick done:
12019 624411d2 2023-07-08 jrick free(old_id_str);
12020 624411d2 2023-07-08 jrick free(new_id_str);
12021 624411d2 2023-07-08 jrick return err;
12022 624411d2 2023-07-08 jrick }
12023 624411d2 2023-07-08 jrick
12024 624411d2 2023-07-08 jrick static const struct got_error *
12025 624411d2 2023-07-08 jrick histedit_commit(struct got_pathlist_head *merged_paths,
12026 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_fileindex *fileindex,
12027 624411d2 2023-07-08 jrick struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
12028 624411d2 2023-07-08 jrick const char *committer, int allow_conflict, struct got_repository *repo)
12029 624411d2 2023-07-08 jrick {
12030 624411d2 2023-07-08 jrick const struct got_error *err;
12031 624411d2 2023-07-08 jrick struct got_commit_object *commit;
12032 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id;
12033 624411d2 2023-07-08 jrick
12034 624411d2 2023-07-08 jrick if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
12035 624411d2 2023-07-08 jrick && hle->logmsg == NULL) {
12036 624411d2 2023-07-08 jrick err = histedit_edit_logmsg(hle, repo);
12037 624411d2 2023-07-08 jrick if (err)
12038 624411d2 2023-07-08 jrick return err;
12039 624411d2 2023-07-08 jrick }
12040 624411d2 2023-07-08 jrick
12041 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, hle->commit_id);
12042 624411d2 2023-07-08 jrick if (err)
12043 624411d2 2023-07-08 jrick return err;
12044 624411d2 2023-07-08 jrick
12045 624411d2 2023-07-08 jrick err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
12046 624411d2 2023-07-08 jrick worktree, fileindex, tmp_branch, committer, commit, hle->commit_id,
12047 624411d2 2023-07-08 jrick hle->logmsg, allow_conflict, repo);
12048 624411d2 2023-07-08 jrick if (err) {
12049 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
12050 624411d2 2023-07-08 jrick goto done;
12051 624411d2 2023-07-08 jrick err = show_histedit_progress(commit, hle, NULL);
12052 624411d2 2023-07-08 jrick } else {
12053 624411d2 2023-07-08 jrick err = show_histedit_progress(commit, hle, new_commit_id);
12054 624411d2 2023-07-08 jrick free(new_commit_id);
12055 624411d2 2023-07-08 jrick }
12056 624411d2 2023-07-08 jrick done:
12057 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12058 624411d2 2023-07-08 jrick return err;
12059 624411d2 2023-07-08 jrick }
12060 624411d2 2023-07-08 jrick
12061 624411d2 2023-07-08 jrick static const struct got_error *
12062 624411d2 2023-07-08 jrick histedit_skip_commit(struct got_histedit_list_entry *hle,
12063 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
12064 624411d2 2023-07-08 jrick {
12065 624411d2 2023-07-08 jrick const struct got_error *error;
12066 624411d2 2023-07-08 jrick struct got_commit_object *commit;
12067 624411d2 2023-07-08 jrick
12068 624411d2 2023-07-08 jrick error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
12069 624411d2 2023-07-08 jrick repo);
12070 624411d2 2023-07-08 jrick if (error)
12071 624411d2 2023-07-08 jrick return error;
12072 624411d2 2023-07-08 jrick
12073 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, hle->commit_id);
12074 624411d2 2023-07-08 jrick if (error)
12075 624411d2 2023-07-08 jrick return error;
12076 624411d2 2023-07-08 jrick
12077 624411d2 2023-07-08 jrick error = show_histedit_progress(commit, hle, NULL);
12078 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12079 624411d2 2023-07-08 jrick return error;
12080 624411d2 2023-07-08 jrick }
12081 624411d2 2023-07-08 jrick
12082 624411d2 2023-07-08 jrick static const struct got_error *
12083 624411d2 2023-07-08 jrick check_local_changes(void *arg, unsigned char status,
12084 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path,
12085 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
12086 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int dirfd, const char *de_name)
12087 624411d2 2023-07-08 jrick {
12088 624411d2 2023-07-08 jrick int *have_local_changes = arg;
12089 624411d2 2023-07-08 jrick
12090 624411d2 2023-07-08 jrick switch (status) {
12091 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
12092 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
12093 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
12094 624411d2 2023-07-08 jrick case GOT_STATUS_CONFLICT:
12095 624411d2 2023-07-08 jrick *have_local_changes = 1;
12096 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
12097 624411d2 2023-07-08 jrick default:
12098 624411d2 2023-07-08 jrick break;
12099 624411d2 2023-07-08 jrick }
12100 624411d2 2023-07-08 jrick
12101 624411d2 2023-07-08 jrick switch (staged_status) {
12102 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
12103 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
12104 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
12105 624411d2 2023-07-08 jrick *have_local_changes = 1;
12106 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
12107 624411d2 2023-07-08 jrick default:
12108 624411d2 2023-07-08 jrick break;
12109 624411d2 2023-07-08 jrick }
12110 624411d2 2023-07-08 jrick
12111 624411d2 2023-07-08 jrick return NULL;
12112 624411d2 2023-07-08 jrick }
12113 624411d2 2023-07-08 jrick
12114 624411d2 2023-07-08 jrick static const struct got_error *
12115 624411d2 2023-07-08 jrick cmd_histedit(int argc, char *argv[])
12116 624411d2 2023-07-08 jrick {
12117 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12118 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12119 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12120 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12121 624411d2 2023-07-08 jrick char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
12122 624411d2 2023-07-08 jrick struct got_reference *branch = NULL;
12123 624411d2 2023-07-08 jrick struct got_reference *tmp_branch = NULL;
12124 624411d2 2023-07-08 jrick struct got_object_id *resume_commit_id = NULL;
12125 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id = NULL;
12126 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
12127 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
12128 624411d2 2023-07-08 jrick int ch, rebase_in_progress = 0, merge_in_progress = 0;
12129 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12130 624411d2 2023-07-08 jrick int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
12131 624411d2 2023-07-08 jrick int drop_only = 0, edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
12132 624411d2 2023-07-08 jrick int allow_conflict = 0, list_backups = 0, delete_backups = 0;
12133 624411d2 2023-07-08 jrick const char *edit_script_path = NULL;
12134 624411d2 2023-07-08 jrick struct got_object_id_queue commits;
12135 624411d2 2023-07-08 jrick struct got_pathlist_head merged_paths;
12136 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
12137 624411d2 2023-07-08 jrick struct got_object_qid *pid;
12138 624411d2 2023-07-08 jrick struct got_histedit_list histedit_cmds;
12139 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
12140 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12141 624411d2 2023-07-08 jrick
12142 624411d2 2023-07-08 jrick STAILQ_INIT(&commits);
12143 624411d2 2023-07-08 jrick TAILQ_INIT(&histedit_cmds);
12144 624411d2 2023-07-08 jrick TAILQ_INIT(&merged_paths);
12145 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12146 624411d2 2023-07-08 jrick
12147 624411d2 2023-07-08 jrick #ifndef PROFILE
12148 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12149 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12150 624411d2 2023-07-08 jrick err(1, "pledge");
12151 624411d2 2023-07-08 jrick #endif
12152 624411d2 2023-07-08 jrick
12153 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCcdeF:flmX")) != -1) {
12154 624411d2 2023-07-08 jrick switch (ch) {
12155 624411d2 2023-07-08 jrick case 'a':
12156 624411d2 2023-07-08 jrick abort_edit = 1;
12157 624411d2 2023-07-08 jrick break;
12158 624411d2 2023-07-08 jrick case 'C':
12159 624411d2 2023-07-08 jrick allow_conflict = 1;
12160 624411d2 2023-07-08 jrick break;
12161 624411d2 2023-07-08 jrick case 'c':
12162 624411d2 2023-07-08 jrick continue_edit = 1;
12163 624411d2 2023-07-08 jrick break;
12164 624411d2 2023-07-08 jrick case 'd':
12165 624411d2 2023-07-08 jrick drop_only = 1;
12166 624411d2 2023-07-08 jrick break;
12167 624411d2 2023-07-08 jrick case 'e':
12168 624411d2 2023-07-08 jrick edit_only = 1;
12169 624411d2 2023-07-08 jrick break;
12170 624411d2 2023-07-08 jrick case 'F':
12171 624411d2 2023-07-08 jrick edit_script_path = optarg;
12172 624411d2 2023-07-08 jrick break;
12173 624411d2 2023-07-08 jrick case 'f':
12174 624411d2 2023-07-08 jrick fold_only = 1;
12175 624411d2 2023-07-08 jrick break;
12176 624411d2 2023-07-08 jrick case 'l':
12177 624411d2 2023-07-08 jrick list_backups = 1;
12178 624411d2 2023-07-08 jrick break;
12179 624411d2 2023-07-08 jrick case 'm':
12180 624411d2 2023-07-08 jrick edit_logmsg_only = 1;
12181 624411d2 2023-07-08 jrick break;
12182 624411d2 2023-07-08 jrick case 'X':
12183 624411d2 2023-07-08 jrick delete_backups = 1;
12184 624411d2 2023-07-08 jrick break;
12185 624411d2 2023-07-08 jrick default:
12186 624411d2 2023-07-08 jrick usage_histedit();
12187 624411d2 2023-07-08 jrick /* NOTREACHED */
12188 624411d2 2023-07-08 jrick }
12189 624411d2 2023-07-08 jrick }
12190 624411d2 2023-07-08 jrick
12191 624411d2 2023-07-08 jrick argc -= optind;
12192 624411d2 2023-07-08 jrick argv += optind;
12193 624411d2 2023-07-08 jrick
12194 624411d2 2023-07-08 jrick if (abort_edit && allow_conflict)
12195 624411d2 2023-07-08 jrick option_conflict('a', 'C');
12196 624411d2 2023-07-08 jrick if (abort_edit && continue_edit)
12197 624411d2 2023-07-08 jrick option_conflict('a', 'c');
12198 624411d2 2023-07-08 jrick if (edit_script_path && allow_conflict)
12199 624411d2 2023-07-08 jrick option_conflict('F', 'C');
12200 624411d2 2023-07-08 jrick if (edit_script_path && edit_logmsg_only)
12201 624411d2 2023-07-08 jrick option_conflict('F', 'm');
12202 624411d2 2023-07-08 jrick if (abort_edit && edit_logmsg_only)
12203 624411d2 2023-07-08 jrick option_conflict('a', 'm');
12204 624411d2 2023-07-08 jrick if (edit_logmsg_only && allow_conflict)
12205 624411d2 2023-07-08 jrick option_conflict('m', 'C');
12206 624411d2 2023-07-08 jrick if (continue_edit && edit_logmsg_only)
12207 624411d2 2023-07-08 jrick option_conflict('c', 'm');
12208 624411d2 2023-07-08 jrick if (abort_edit && fold_only)
12209 624411d2 2023-07-08 jrick option_conflict('a', 'f');
12210 624411d2 2023-07-08 jrick if (fold_only && allow_conflict)
12211 624411d2 2023-07-08 jrick option_conflict('f', 'C');
12212 624411d2 2023-07-08 jrick if (continue_edit && fold_only)
12213 624411d2 2023-07-08 jrick option_conflict('c', 'f');
12214 624411d2 2023-07-08 jrick if (fold_only && edit_logmsg_only)
12215 624411d2 2023-07-08 jrick option_conflict('f', 'm');
12216 624411d2 2023-07-08 jrick if (edit_script_path && fold_only)
12217 624411d2 2023-07-08 jrick option_conflict('F', 'f');
12218 624411d2 2023-07-08 jrick if (abort_edit && edit_only)
12219 624411d2 2023-07-08 jrick option_conflict('a', 'e');
12220 624411d2 2023-07-08 jrick if (continue_edit && edit_only)
12221 624411d2 2023-07-08 jrick option_conflict('c', 'e');
12222 624411d2 2023-07-08 jrick if (edit_only && edit_logmsg_only)
12223 624411d2 2023-07-08 jrick option_conflict('e', 'm');
12224 624411d2 2023-07-08 jrick if (edit_script_path && edit_only)
12225 624411d2 2023-07-08 jrick option_conflict('F', 'e');
12226 624411d2 2023-07-08 jrick if (fold_only && edit_only)
12227 624411d2 2023-07-08 jrick option_conflict('f', 'e');
12228 624411d2 2023-07-08 jrick if (drop_only && abort_edit)
12229 624411d2 2023-07-08 jrick option_conflict('d', 'a');
12230 624411d2 2023-07-08 jrick if (drop_only && allow_conflict)
12231 624411d2 2023-07-08 jrick option_conflict('d', 'C');
12232 624411d2 2023-07-08 jrick if (drop_only && continue_edit)
12233 624411d2 2023-07-08 jrick option_conflict('d', 'c');
12234 624411d2 2023-07-08 jrick if (drop_only && edit_logmsg_only)
12235 624411d2 2023-07-08 jrick option_conflict('d', 'm');
12236 624411d2 2023-07-08 jrick if (drop_only && edit_only)
12237 624411d2 2023-07-08 jrick option_conflict('d', 'e');
12238 624411d2 2023-07-08 jrick if (drop_only && edit_script_path)
12239 624411d2 2023-07-08 jrick option_conflict('d', 'F');
12240 624411d2 2023-07-08 jrick if (drop_only && fold_only)
12241 624411d2 2023-07-08 jrick option_conflict('d', 'f');
12242 624411d2 2023-07-08 jrick if (list_backups) {
12243 624411d2 2023-07-08 jrick if (abort_edit)
12244 624411d2 2023-07-08 jrick option_conflict('l', 'a');
12245 624411d2 2023-07-08 jrick if (allow_conflict)
12246 624411d2 2023-07-08 jrick option_conflict('l', 'C');
12247 624411d2 2023-07-08 jrick if (continue_edit)
12248 624411d2 2023-07-08 jrick option_conflict('l', 'c');
12249 624411d2 2023-07-08 jrick if (edit_script_path)
12250 624411d2 2023-07-08 jrick option_conflict('l', 'F');
12251 624411d2 2023-07-08 jrick if (edit_logmsg_only)
12252 624411d2 2023-07-08 jrick option_conflict('l', 'm');
12253 624411d2 2023-07-08 jrick if (drop_only)
12254 624411d2 2023-07-08 jrick option_conflict('l', 'd');
12255 624411d2 2023-07-08 jrick if (fold_only)
12256 624411d2 2023-07-08 jrick option_conflict('l', 'f');
12257 624411d2 2023-07-08 jrick if (edit_only)
12258 624411d2 2023-07-08 jrick option_conflict('l', 'e');
12259 624411d2 2023-07-08 jrick if (delete_backups)
12260 624411d2 2023-07-08 jrick option_conflict('l', 'X');
12261 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
12262 624411d2 2023-07-08 jrick usage_histedit();
12263 624411d2 2023-07-08 jrick } else if (delete_backups) {
12264 624411d2 2023-07-08 jrick if (abort_edit)
12265 624411d2 2023-07-08 jrick option_conflict('X', 'a');
12266 624411d2 2023-07-08 jrick if (allow_conflict)
12267 624411d2 2023-07-08 jrick option_conflict('X', 'C');
12268 624411d2 2023-07-08 jrick if (continue_edit)
12269 624411d2 2023-07-08 jrick option_conflict('X', 'c');
12270 624411d2 2023-07-08 jrick if (drop_only)
12271 624411d2 2023-07-08 jrick option_conflict('X', 'd');
12272 624411d2 2023-07-08 jrick if (edit_script_path)
12273 624411d2 2023-07-08 jrick option_conflict('X', 'F');
12274 624411d2 2023-07-08 jrick if (edit_logmsg_only)
12275 624411d2 2023-07-08 jrick option_conflict('X', 'm');
12276 624411d2 2023-07-08 jrick if (fold_only)
12277 624411d2 2023-07-08 jrick option_conflict('X', 'f');
12278 624411d2 2023-07-08 jrick if (edit_only)
12279 624411d2 2023-07-08 jrick option_conflict('X', 'e');
12280 624411d2 2023-07-08 jrick if (list_backups)
12281 624411d2 2023-07-08 jrick option_conflict('X', 'l');
12282 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
12283 624411d2 2023-07-08 jrick usage_histedit();
12284 624411d2 2023-07-08 jrick } else if (allow_conflict && !continue_edit)
12285 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
12286 624411d2 2023-07-08 jrick else if (argc != 0)
12287 624411d2 2023-07-08 jrick usage_histedit();
12288 624411d2 2023-07-08 jrick
12289 624411d2 2023-07-08 jrick /*
12290 624411d2 2023-07-08 jrick * This command cannot apply unveil(2) in all cases because the
12291 624411d2 2023-07-08 jrick * user may choose to run an editor to edit the histedit script
12292 624411d2 2023-07-08 jrick * and to edit individual commit log messages.
12293 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have to
12294 624411d2 2023-07-08 jrick * apply unveil after edit script and log messages have been written.
12295 624411d2 2023-07-08 jrick * XXX TODO: Make use of unveil(2) where possible.
12296 624411d2 2023-07-08 jrick */
12297 624411d2 2023-07-08 jrick
12298 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12299 624411d2 2023-07-08 jrick if (cwd == NULL) {
12300 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12301 624411d2 2023-07-08 jrick goto done;
12302 624411d2 2023-07-08 jrick }
12303 624411d2 2023-07-08 jrick
12304 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12305 624411d2 2023-07-08 jrick if (error != NULL)
12306 624411d2 2023-07-08 jrick goto done;
12307 624411d2 2023-07-08 jrick
12308 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
12309 624411d2 2023-07-08 jrick if (error) {
12310 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
12311 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
12312 624411d2 2023-07-08 jrick goto done;
12313 624411d2 2023-07-08 jrick } else {
12314 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
12315 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
12316 624411d2 2023-07-08 jrick "histedit", cwd);
12317 624411d2 2023-07-08 jrick goto done;
12318 624411d2 2023-07-08 jrick }
12319 624411d2 2023-07-08 jrick }
12320 624411d2 2023-07-08 jrick
12321 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
12322 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
12323 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
12324 624411d2 2023-07-08 jrick NULL, pack_fds);
12325 624411d2 2023-07-08 jrick if (error != NULL)
12326 624411d2 2023-07-08 jrick goto done;
12327 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
12328 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
12329 624411d2 2023-07-08 jrick if (error)
12330 624411d2 2023-07-08 jrick goto done;
12331 624411d2 2023-07-08 jrick error = process_backup_refs(
12332 624411d2 2023-07-08 jrick GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
12333 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, delete_backups, repo);
12334 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
12335 624411d2 2023-07-08 jrick }
12336 624411d2 2023-07-08 jrick
12337 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
12338 624411d2 2023-07-08 jrick if (error)
12339 624411d2 2023-07-08 jrick goto done;
12340 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
12341 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
12342 624411d2 2023-07-08 jrick if (error != NULL)
12343 624411d2 2023-07-08 jrick goto done;
12344 624411d2 2023-07-08 jrick
12345 624411d2 2023-07-08 jrick if (worktree != NULL && !list_backups && !delete_backups) {
12346 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("histedit", worktree, repo);
12347 624411d2 2023-07-08 jrick if (error)
12348 624411d2 2023-07-08 jrick goto done;
12349 624411d2 2023-07-08 jrick }
12350 624411d2 2023-07-08 jrick
12351 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
12352 624411d2 2023-07-08 jrick if (error)
12353 624411d2 2023-07-08 jrick goto done;
12354 624411d2 2023-07-08 jrick if (rebase_in_progress) {
12355 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASING);
12356 624411d2 2023-07-08 jrick goto done;
12357 624411d2 2023-07-08 jrick }
12358 624411d2 2023-07-08 jrick
12359 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
12360 624411d2 2023-07-08 jrick repo);
12361 624411d2 2023-07-08 jrick if (error)
12362 624411d2 2023-07-08 jrick goto done;
12363 624411d2 2023-07-08 jrick if (merge_in_progress) {
12364 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
12365 624411d2 2023-07-08 jrick goto done;
12366 624411d2 2023-07-08 jrick }
12367 624411d2 2023-07-08 jrick
12368 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
12369 624411d2 2023-07-08 jrick if (error)
12370 624411d2 2023-07-08 jrick goto done;
12371 624411d2 2023-07-08 jrick
12372 624411d2 2023-07-08 jrick if (edit_in_progress && edit_logmsg_only) {
12373 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12374 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12375 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12376 624411d2 2023-07-08 jrick "before the -m option can be used");
12377 624411d2 2023-07-08 jrick goto done;
12378 624411d2 2023-07-08 jrick }
12379 624411d2 2023-07-08 jrick if (edit_in_progress && drop_only) {
12380 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12381 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12382 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12383 624411d2 2023-07-08 jrick "before the -d option can be used");
12384 624411d2 2023-07-08 jrick goto done;
12385 624411d2 2023-07-08 jrick }
12386 624411d2 2023-07-08 jrick if (edit_in_progress && fold_only) {
12387 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12388 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12389 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12390 624411d2 2023-07-08 jrick "before the -f option can be used");
12391 624411d2 2023-07-08 jrick goto done;
12392 624411d2 2023-07-08 jrick }
12393 624411d2 2023-07-08 jrick if (edit_in_progress && edit_only) {
12394 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12395 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12396 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12397 624411d2 2023-07-08 jrick "before the -e option can be used");
12398 624411d2 2023-07-08 jrick goto done;
12399 624411d2 2023-07-08 jrick }
12400 624411d2 2023-07-08 jrick
12401 624411d2 2023-07-08 jrick if (edit_in_progress && abort_edit) {
12402 624411d2 2023-07-08 jrick error = got_worktree_histedit_continue(&resume_commit_id,
12403 624411d2 2023-07-08 jrick &tmp_branch, &branch, &base_commit_id, &fileindex,
12404 624411d2 2023-07-08 jrick worktree, repo);
12405 624411d2 2023-07-08 jrick if (error)
12406 624411d2 2023-07-08 jrick goto done;
12407 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
12408 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
12409 624411d2 2023-07-08 jrick error = got_worktree_histedit_abort(worktree, fileindex, repo,
12410 624411d2 2023-07-08 jrick branch, base_commit_id, abort_progress, &upa);
12411 624411d2 2023-07-08 jrick if (error)
12412 624411d2 2023-07-08 jrick goto done;
12413 624411d2 2023-07-08 jrick printf("Histedit of %s aborted\n",
12414 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
12415 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12416 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
12417 624411d2 2023-07-08 jrick } else if (abort_edit) {
12418 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_HISTEDIT);
12419 624411d2 2023-07-08 jrick goto done;
12420 624411d2 2023-07-08 jrick }
12421 624411d2 2023-07-08 jrick
12422 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
12423 624411d2 2023-07-08 jrick if (error)
12424 624411d2 2023-07-08 jrick goto done;
12425 624411d2 2023-07-08 jrick
12426 624411d2 2023-07-08 jrick if (continue_edit) {
12427 624411d2 2023-07-08 jrick char *path;
12428 624411d2 2023-07-08 jrick
12429 624411d2 2023-07-08 jrick if (!edit_in_progress) {
12430 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_HISTEDIT);
12431 624411d2 2023-07-08 jrick goto done;
12432 624411d2 2023-07-08 jrick }
12433 624411d2 2023-07-08 jrick
12434 624411d2 2023-07-08 jrick error = got_worktree_get_histedit_script_path(&path, worktree);
12435 624411d2 2023-07-08 jrick if (error)
12436 624411d2 2023-07-08 jrick goto done;
12437 624411d2 2023-07-08 jrick
12438 624411d2 2023-07-08 jrick error = histedit_load_list(&histedit_cmds, path, repo);
12439 624411d2 2023-07-08 jrick free(path);
12440 624411d2 2023-07-08 jrick if (error)
12441 624411d2 2023-07-08 jrick goto done;
12442 624411d2 2023-07-08 jrick
12443 624411d2 2023-07-08 jrick error = got_worktree_histedit_continue(&resume_commit_id,
12444 624411d2 2023-07-08 jrick &tmp_branch, &branch, &base_commit_id, &fileindex,
12445 624411d2 2023-07-08 jrick worktree, repo);
12446 624411d2 2023-07-08 jrick if (error)
12447 624411d2 2023-07-08 jrick goto done;
12448 624411d2 2023-07-08 jrick
12449 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, branch);
12450 624411d2 2023-07-08 jrick if (error)
12451 624411d2 2023-07-08 jrick goto done;
12452 624411d2 2023-07-08 jrick
12453 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12454 624411d2 2023-07-08 jrick head_commit_id);
12455 624411d2 2023-07-08 jrick if (error)
12456 624411d2 2023-07-08 jrick goto done;
12457 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12458 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12459 624411d2 2023-07-08 jrick if (pid == NULL) {
12460 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12461 624411d2 2023-07-08 jrick goto done;
12462 624411d2 2023-07-08 jrick }
12463 624411d2 2023-07-08 jrick error = collect_commits(&commits, head_commit_id, &pid->id,
12464 624411d2 2023-07-08 jrick base_commit_id, got_worktree_get_path_prefix(worktree),
12465 624411d2 2023-07-08 jrick GOT_ERR_HISTEDIT_PATH, repo);
12466 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12467 624411d2 2023-07-08 jrick commit = NULL;
12468 624411d2 2023-07-08 jrick if (error)
12469 624411d2 2023-07-08 jrick goto done;
12470 624411d2 2023-07-08 jrick } else {
12471 624411d2 2023-07-08 jrick if (edit_in_progress) {
12472 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_HISTEDIT_BUSY);
12473 624411d2 2023-07-08 jrick goto done;
12474 624411d2 2023-07-08 jrick }
12475 624411d2 2023-07-08 jrick
12476 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo,
12477 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
12478 624411d2 2023-07-08 jrick if (error != NULL)
12479 624411d2 2023-07-08 jrick goto done;
12480 624411d2 2023-07-08 jrick
12481 624411d2 2023-07-08 jrick if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
12482 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
12483 624411d2 2023-07-08 jrick "will not edit commit history of a branch outside "
12484 624411d2 2023-07-08 jrick "the \"refs/heads/\" reference namespace");
12485 624411d2 2023-07-08 jrick goto done;
12486 624411d2 2023-07-08 jrick }
12487 624411d2 2023-07-08 jrick
12488 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, branch);
12489 624411d2 2023-07-08 jrick got_ref_close(branch);
12490 624411d2 2023-07-08 jrick branch = NULL;
12491 624411d2 2023-07-08 jrick if (error)
12492 624411d2 2023-07-08 jrick goto done;
12493 624411d2 2023-07-08 jrick
12494 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12495 624411d2 2023-07-08 jrick head_commit_id);
12496 624411d2 2023-07-08 jrick if (error)
12497 624411d2 2023-07-08 jrick goto done;
12498 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12499 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12500 624411d2 2023-07-08 jrick if (pid == NULL) {
12501 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12502 624411d2 2023-07-08 jrick goto done;
12503 624411d2 2023-07-08 jrick }
12504 624411d2 2023-07-08 jrick error = collect_commits(&commits, head_commit_id, &pid->id,
12505 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree),
12506 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree),
12507 624411d2 2023-07-08 jrick GOT_ERR_HISTEDIT_PATH, repo);
12508 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12509 624411d2 2023-07-08 jrick commit = NULL;
12510 624411d2 2023-07-08 jrick if (error)
12511 624411d2 2023-07-08 jrick goto done;
12512 624411d2 2023-07-08 jrick
12513 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(&commits)) {
12514 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12515 624411d2 2023-07-08 jrick goto done;
12516 624411d2 2023-07-08 jrick }
12517 624411d2 2023-07-08 jrick
12518 624411d2 2023-07-08 jrick error = got_worktree_histedit_prepare(&tmp_branch, &branch,
12519 624411d2 2023-07-08 jrick &base_commit_id, &fileindex, worktree, repo);
12520 624411d2 2023-07-08 jrick if (error)
12521 624411d2 2023-07-08 jrick goto done;
12522 624411d2 2023-07-08 jrick
12523 624411d2 2023-07-08 jrick if (edit_script_path) {
12524 624411d2 2023-07-08 jrick error = histedit_load_list(&histedit_cmds,
12525 624411d2 2023-07-08 jrick edit_script_path, repo);
12526 624411d2 2023-07-08 jrick if (error) {
12527 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12528 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12529 624411d2 2023-07-08 jrick abort_progress, &upa);
12530 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12531 624411d2 2023-07-08 jrick goto done;
12532 624411d2 2023-07-08 jrick }
12533 624411d2 2023-07-08 jrick } else {
12534 624411d2 2023-07-08 jrick const char *branch_name;
12535 624411d2 2023-07-08 jrick branch_name = got_ref_get_symref_target(branch);
12536 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/heads/", 11) == 0)
12537 624411d2 2023-07-08 jrick branch_name += 11;
12538 624411d2 2023-07-08 jrick error = histedit_edit_script(&histedit_cmds, &commits,
12539 624411d2 2023-07-08 jrick branch_name, edit_logmsg_only, fold_only,
12540 624411d2 2023-07-08 jrick drop_only, edit_only, repo);
12541 624411d2 2023-07-08 jrick if (error) {
12542 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12543 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12544 624411d2 2023-07-08 jrick abort_progress, &upa);
12545 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12546 624411d2 2023-07-08 jrick goto done;
12547 624411d2 2023-07-08 jrick }
12548 624411d2 2023-07-08 jrick
12549 624411d2 2023-07-08 jrick }
12550 624411d2 2023-07-08 jrick
12551 624411d2 2023-07-08 jrick error = histedit_save_list(&histedit_cmds, worktree,
12552 624411d2 2023-07-08 jrick repo);
12553 624411d2 2023-07-08 jrick if (error) {
12554 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12555 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12556 624411d2 2023-07-08 jrick abort_progress, &upa);
12557 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12558 624411d2 2023-07-08 jrick goto done;
12559 624411d2 2023-07-08 jrick }
12560 624411d2 2023-07-08 jrick
12561 624411d2 2023-07-08 jrick }
12562 624411d2 2023-07-08 jrick
12563 624411d2 2023-07-08 jrick error = histedit_check_script(&histedit_cmds, &commits, repo);
12564 624411d2 2023-07-08 jrick if (error)
12565 624411d2 2023-07-08 jrick goto done;
12566 624411d2 2023-07-08 jrick
12567 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, &histedit_cmds, entry) {
12568 624411d2 2023-07-08 jrick if (resume_commit_id) {
12569 624411d2 2023-07-08 jrick if (got_object_id_cmp(hle->commit_id,
12570 624411d2 2023-07-08 jrick resume_commit_id) != 0)
12571 624411d2 2023-07-08 jrick continue;
12572 624411d2 2023-07-08 jrick
12573 624411d2 2023-07-08 jrick resume_commit_id = NULL;
12574 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_DROP ||
12575 624411d2 2023-07-08 jrick hle->cmd->code == GOT_HISTEDIT_FOLD) {
12576 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree,
12577 624411d2 2023-07-08 jrick repo);
12578 624411d2 2023-07-08 jrick if (error)
12579 624411d2 2023-07-08 jrick goto done;
12580 624411d2 2023-07-08 jrick } else {
12581 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
12582 624411d2 2023-07-08 jrick int have_changes = 0;
12583 624411d2 2023-07-08 jrick
12584 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
12585 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
12586 624411d2 2023-07-08 jrick if (error)
12587 624411d2 2023-07-08 jrick goto done;
12588 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths,
12589 624411d2 2023-07-08 jrick repo, 0, check_local_changes, &have_changes,
12590 624411d2 2023-07-08 jrick check_cancelled, NULL);
12591 624411d2 2023-07-08 jrick got_pathlist_free(&paths,
12592 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_NONE);
12593 624411d2 2023-07-08 jrick if (error) {
12594 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_CANCELLED)
12595 624411d2 2023-07-08 jrick goto done;
12596 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
12597 624411d2 2023-07-08 jrick goto done;
12598 624411d2 2023-07-08 jrick }
12599 624411d2 2023-07-08 jrick if (have_changes) {
12600 624411d2 2023-07-08 jrick error = histedit_commit(NULL, worktree,
12601 624411d2 2023-07-08 jrick fileindex, tmp_branch, hle,
12602 624411d2 2023-07-08 jrick committer, allow_conflict, repo);
12603 624411d2 2023-07-08 jrick if (error)
12604 624411d2 2023-07-08 jrick goto done;
12605 624411d2 2023-07-08 jrick } else {
12606 624411d2 2023-07-08 jrick error = got_object_open_as_commit(
12607 624411d2 2023-07-08 jrick &commit, repo, hle->commit_id);
12608 624411d2 2023-07-08 jrick if (error)
12609 624411d2 2023-07-08 jrick goto done;
12610 624411d2 2023-07-08 jrick error = show_histedit_progress(commit,
12611 624411d2 2023-07-08 jrick hle, NULL);
12612 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12613 624411d2 2023-07-08 jrick commit = NULL;
12614 624411d2 2023-07-08 jrick if (error)
12615 624411d2 2023-07-08 jrick goto done;
12616 624411d2 2023-07-08 jrick }
12617 624411d2 2023-07-08 jrick }
12618 624411d2 2023-07-08 jrick continue;
12619 624411d2 2023-07-08 jrick }
12620 624411d2 2023-07-08 jrick
12621 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_DROP) {
12622 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree, repo);
12623 624411d2 2023-07-08 jrick if (error)
12624 624411d2 2023-07-08 jrick goto done;
12625 624411d2 2023-07-08 jrick continue;
12626 624411d2 2023-07-08 jrick }
12627 624411d2 2023-07-08 jrick
12628 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12629 624411d2 2023-07-08 jrick hle->commit_id);
12630 624411d2 2023-07-08 jrick if (error)
12631 624411d2 2023-07-08 jrick goto done;
12632 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12633 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12634 624411d2 2023-07-08 jrick
12635 624411d2 2023-07-08 jrick error = got_worktree_histedit_merge_files(&merged_paths,
12636 624411d2 2023-07-08 jrick worktree, fileindex, &pid->id, hle->commit_id, repo,
12637 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
12638 624411d2 2023-07-08 jrick if (error)
12639 624411d2 2023-07-08 jrick goto done;
12640 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12641 624411d2 2023-07-08 jrick commit = NULL;
12642 624411d2 2023-07-08 jrick
12643 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12644 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
12645 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
12646 624411d2 2023-07-08 jrick if (upa.conflicts > 0) {
12647 624411d2 2023-07-08 jrick error = show_rebase_merge_conflict(
12648 624411d2 2023-07-08 jrick hle->commit_id, repo);
12649 624411d2 2023-07-08 jrick if (error)
12650 624411d2 2023-07-08 jrick goto done;
12651 624411d2 2023-07-08 jrick }
12652 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12653 624411d2 2023-07-08 jrick break;
12654 624411d2 2023-07-08 jrick }
12655 624411d2 2023-07-08 jrick
12656 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
12657 624411d2 2023-07-08 jrick char *id_str;
12658 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, hle->commit_id);
12659 624411d2 2023-07-08 jrick if (error)
12660 624411d2 2023-07-08 jrick goto done;
12661 624411d2 2023-07-08 jrick printf("Stopping histedit for amending commit %s\n",
12662 624411d2 2023-07-08 jrick id_str);
12663 624411d2 2023-07-08 jrick free(id_str);
12664 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12665 624411d2 2023-07-08 jrick error = got_worktree_histedit_postpone(worktree,
12666 624411d2 2023-07-08 jrick fileindex);
12667 624411d2 2023-07-08 jrick goto done;
12668 624411d2 2023-07-08 jrick }
12669 624411d2 2023-07-08 jrick
12670 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
12671 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree, repo);
12672 624411d2 2023-07-08 jrick if (error)
12673 624411d2 2023-07-08 jrick goto done;
12674 624411d2 2023-07-08 jrick continue;
12675 624411d2 2023-07-08 jrick }
12676 624411d2 2023-07-08 jrick
12677 624411d2 2023-07-08 jrick error = histedit_commit(&merged_paths, worktree, fileindex,
12678 624411d2 2023-07-08 jrick tmp_branch, hle, committer, allow_conflict, repo);
12679 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12680 624411d2 2023-07-08 jrick if (error)
12681 624411d2 2023-07-08 jrick goto done;
12682 624411d2 2023-07-08 jrick }
12683 624411d2 2023-07-08 jrick
12684 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
12685 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
12686 624411d2 2023-07-08 jrick error = got_worktree_histedit_postpone(worktree, fileindex);
12687 624411d2 2023-07-08 jrick if (error)
12688 624411d2 2023-07-08 jrick goto done;
12689 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
12690 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
12691 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12692 624411d2 2023-07-08 jrick "conflicts must be resolved before histedit "
12693 624411d2 2023-07-08 jrick "can continue");
12694 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
12695 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12696 624411d2 2023-07-08 jrick "conflicts must be resolved before histedit "
12697 624411d2 2023-07-08 jrick "can continue; changes destined for some "
12698 624411d2 2023-07-08 jrick "files were not yet merged and should be "
12699 624411d2 2023-07-08 jrick "merged manually if required before the "
12700 624411d2 2023-07-08 jrick "histedit operation is continued");
12701 624411d2 2023-07-08 jrick } else {
12702 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12703 624411d2 2023-07-08 jrick "changes destined for some files were not "
12704 624411d2 2023-07-08 jrick "yet merged and should be merged manually "
12705 624411d2 2023-07-08 jrick "if required before the histedit operation "
12706 624411d2 2023-07-08 jrick "is continued");
12707 624411d2 2023-07-08 jrick }
12708 624411d2 2023-07-08 jrick } else
12709 624411d2 2023-07-08 jrick error = histedit_complete(worktree, fileindex, tmp_branch,
12710 624411d2 2023-07-08 jrick branch, repo);
12711 624411d2 2023-07-08 jrick done:
12712 624411d2 2023-07-08 jrick free(cwd);
12713 624411d2 2023-07-08 jrick free(committer);
12714 624411d2 2023-07-08 jrick free(gitconfig_path);
12715 624411d2 2023-07-08 jrick got_object_id_queue_free(&commits);
12716 624411d2 2023-07-08 jrick histedit_free_list(&histedit_cmds);
12717 624411d2 2023-07-08 jrick free(head_commit_id);
12718 624411d2 2023-07-08 jrick free(base_commit_id);
12719 624411d2 2023-07-08 jrick free(resume_commit_id);
12720 624411d2 2023-07-08 jrick if (commit)
12721 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12722 624411d2 2023-07-08 jrick if (branch)
12723 624411d2 2023-07-08 jrick got_ref_close(branch);
12724 624411d2 2023-07-08 jrick if (tmp_branch)
12725 624411d2 2023-07-08 jrick got_ref_close(tmp_branch);
12726 624411d2 2023-07-08 jrick if (worktree)
12727 624411d2 2023-07-08 jrick got_worktree_close(worktree);
12728 624411d2 2023-07-08 jrick if (repo) {
12729 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
12730 624411d2 2023-07-08 jrick if (error == NULL)
12731 624411d2 2023-07-08 jrick error = close_err;
12732 624411d2 2023-07-08 jrick }
12733 624411d2 2023-07-08 jrick if (pack_fds) {
12734 624411d2 2023-07-08 jrick const struct got_error *pack_err =
12735 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
12736 624411d2 2023-07-08 jrick if (error == NULL)
12737 624411d2 2023-07-08 jrick error = pack_err;
12738 624411d2 2023-07-08 jrick }
12739 624411d2 2023-07-08 jrick return error;
12740 624411d2 2023-07-08 jrick }
12741 624411d2 2023-07-08 jrick
12742 624411d2 2023-07-08 jrick __dead static void
12743 624411d2 2023-07-08 jrick usage_integrate(void)
12744 624411d2 2023-07-08 jrick {
12745 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s integrate branch\n", getprogname());
12746 624411d2 2023-07-08 jrick exit(1);
12747 624411d2 2023-07-08 jrick }
12748 624411d2 2023-07-08 jrick
12749 624411d2 2023-07-08 jrick static const struct got_error *
12750 624411d2 2023-07-08 jrick cmd_integrate(int argc, char *argv[])
12751 624411d2 2023-07-08 jrick {
12752 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12753 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12754 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12755 624411d2 2023-07-08 jrick char *cwd = NULL, *refname = NULL, *base_refname = NULL;
12756 624411d2 2023-07-08 jrick const char *branch_arg = NULL;
12757 624411d2 2023-07-08 jrick struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
12758 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12759 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
12760 624411d2 2023-07-08 jrick int ch;
12761 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12762 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12763 624411d2 2023-07-08 jrick
12764 624411d2 2023-07-08 jrick #ifndef PROFILE
12765 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12766 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12767 624411d2 2023-07-08 jrick err(1, "pledge");
12768 624411d2 2023-07-08 jrick #endif
12769 624411d2 2023-07-08 jrick
12770 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "")) != -1) {
12771 624411d2 2023-07-08 jrick switch (ch) {
12772 624411d2 2023-07-08 jrick default:
12773 624411d2 2023-07-08 jrick usage_integrate();
12774 624411d2 2023-07-08 jrick /* NOTREACHED */
12775 624411d2 2023-07-08 jrick }
12776 624411d2 2023-07-08 jrick }
12777 624411d2 2023-07-08 jrick
12778 624411d2 2023-07-08 jrick argc -= optind;
12779 624411d2 2023-07-08 jrick argv += optind;
12780 624411d2 2023-07-08 jrick
12781 624411d2 2023-07-08 jrick if (argc != 1)
12782 624411d2 2023-07-08 jrick usage_integrate();
12783 624411d2 2023-07-08 jrick branch_arg = argv[0];
12784 624411d2 2023-07-08 jrick
12785 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12786 624411d2 2023-07-08 jrick if (cwd == NULL) {
12787 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12788 624411d2 2023-07-08 jrick goto done;
12789 624411d2 2023-07-08 jrick }
12790 624411d2 2023-07-08 jrick
12791 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12792 624411d2 2023-07-08 jrick if (error != NULL)
12793 624411d2 2023-07-08 jrick goto done;
12794 624411d2 2023-07-08 jrick
12795 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
12796 624411d2 2023-07-08 jrick if (error) {
12797 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
12798 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "integrate",
12799 624411d2 2023-07-08 jrick cwd);
12800 624411d2 2023-07-08 jrick goto done;
12801 624411d2 2023-07-08 jrick }
12802 624411d2 2023-07-08 jrick
12803 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
12804 624411d2 2023-07-08 jrick if (error)
12805 624411d2 2023-07-08 jrick goto done;
12806 624411d2 2023-07-08 jrick
12807 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
12808 624411d2 2023-07-08 jrick NULL, pack_fds);
12809 624411d2 2023-07-08 jrick if (error != NULL)
12810 624411d2 2023-07-08 jrick goto done;
12811 624411d2 2023-07-08 jrick
12812 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
12813 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
12814 624411d2 2023-07-08 jrick if (error)
12815 624411d2 2023-07-08 jrick goto done;
12816 624411d2 2023-07-08 jrick
12817 624411d2 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
12818 624411d2 2023-07-08 jrick if (error)
12819 624411d2 2023-07-08 jrick goto done;
12820 624411d2 2023-07-08 jrick
12821 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
12822 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
12823 624411d2 2023-07-08 jrick goto done;
12824 624411d2 2023-07-08 jrick }
12825 624411d2 2023-07-08 jrick
12826 624411d2 2023-07-08 jrick error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
12827 624411d2 2023-07-08 jrick &base_branch_ref, worktree, refname, repo);
12828 624411d2 2023-07-08 jrick if (error)
12829 624411d2 2023-07-08 jrick goto done;
12830 624411d2 2023-07-08 jrick
12831 624411d2 2023-07-08 jrick refname = strdup(got_ref_get_name(branch_ref));
12832 624411d2 2023-07-08 jrick if (refname == NULL) {
12833 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
12834 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12835 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12836 624411d2 2023-07-08 jrick goto done;
12837 624411d2 2023-07-08 jrick }
12838 624411d2 2023-07-08 jrick base_refname = strdup(got_ref_get_name(base_branch_ref));
12839 624411d2 2023-07-08 jrick if (base_refname == NULL) {
12840 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
12841 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12842 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12843 624411d2 2023-07-08 jrick goto done;
12844 624411d2 2023-07-08 jrick }
12845 624411d2 2023-07-08 jrick if (strncmp(base_refname, "refs/heads/", 11) != 0) {
12846 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_INTEGRATE_BRANCH);
12847 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12848 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12849 624411d2 2023-07-08 jrick goto done;
12850 624411d2 2023-07-08 jrick }
12851 624411d2 2023-07-08 jrick
12852 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, branch_ref);
12853 624411d2 2023-07-08 jrick if (error)
12854 624411d2 2023-07-08 jrick goto done;
12855 624411d2 2023-07-08 jrick
12856 624411d2 2023-07-08 jrick error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
12857 624411d2 2023-07-08 jrick if (error)
12858 624411d2 2023-07-08 jrick goto done;
12859 624411d2 2023-07-08 jrick
12860 624411d2 2023-07-08 jrick if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
12861 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_SAME_BRANCH,
12862 624411d2 2023-07-08 jrick "specified branch has already been integrated");
12863 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12864 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12865 624411d2 2023-07-08 jrick goto done;
12866 624411d2 2023-07-08 jrick }
12867 624411d2 2023-07-08 jrick
12868 624411d2 2023-07-08 jrick error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
12869 624411d2 2023-07-08 jrick if (error) {
12870 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY)
12871 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASE_REQUIRED);
12872 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12873 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12874 624411d2 2023-07-08 jrick goto done;
12875 624411d2 2023-07-08 jrick }
12876 624411d2 2023-07-08 jrick
12877 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12878 624411d2 2023-07-08 jrick error = got_worktree_integrate_continue(worktree, fileindex, repo,
12879 624411d2 2023-07-08 jrick branch_ref, base_branch_ref, update_progress, &upa,
12880 624411d2 2023-07-08 jrick check_cancelled, NULL);
12881 624411d2 2023-07-08 jrick if (error)
12882 624411d2 2023-07-08 jrick goto done;
12883 624411d2 2023-07-08 jrick
12884 624411d2 2023-07-08 jrick printf("Integrated %s into %s\n", refname, base_refname);
12885 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
12886 624411d2 2023-07-08 jrick done:
12887 624411d2 2023-07-08 jrick if (repo) {
12888 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
12889 624411d2 2023-07-08 jrick if (error == NULL)
12890 624411d2 2023-07-08 jrick error = close_err;
12891 624411d2 2023-07-08 jrick }
12892 624411d2 2023-07-08 jrick if (worktree)
12893 624411d2 2023-07-08 jrick got_worktree_close(worktree);
12894 624411d2 2023-07-08 jrick if (pack_fds) {
12895 624411d2 2023-07-08 jrick const struct got_error *pack_err =
12896 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
12897 624411d2 2023-07-08 jrick if (error == NULL)
12898 624411d2 2023-07-08 jrick error = pack_err;
12899 624411d2 2023-07-08 jrick }
12900 624411d2 2023-07-08 jrick free(cwd);
12901 624411d2 2023-07-08 jrick free(base_commit_id);
12902 624411d2 2023-07-08 jrick free(commit_id);
12903 624411d2 2023-07-08 jrick free(refname);
12904 624411d2 2023-07-08 jrick free(base_refname);
12905 624411d2 2023-07-08 jrick return error;
12906 624411d2 2023-07-08 jrick }
12907 624411d2 2023-07-08 jrick
12908 624411d2 2023-07-08 jrick __dead static void
12909 624411d2 2023-07-08 jrick usage_merge(void)
12910 624411d2 2023-07-08 jrick {
12911 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s merge [-aCcn] [branch]\n", getprogname());
12912 624411d2 2023-07-08 jrick exit(1);
12913 624411d2 2023-07-08 jrick }
12914 624411d2 2023-07-08 jrick
12915 624411d2 2023-07-08 jrick static const struct got_error *
12916 624411d2 2023-07-08 jrick cmd_merge(int argc, char *argv[])
12917 624411d2 2023-07-08 jrick {
12918 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12919 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12920 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12921 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12922 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL, *author = NULL;
12923 624411d2 2023-07-08 jrick char *gitconfig_path = NULL;
12924 624411d2 2023-07-08 jrick struct got_reference *branch = NULL, *wt_branch = NULL;
12925 624411d2 2023-07-08 jrick struct got_object_id *branch_tip = NULL, *yca_id = NULL;
12926 624411d2 2023-07-08 jrick struct got_object_id *wt_branch_tip = NULL;
12927 624411d2 2023-07-08 jrick int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
12928 624411d2 2023-07-08 jrick int allow_conflict = 0, prefer_fast_forward = 1, interrupt_merge = 0;
12929 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12930 624411d2 2023-07-08 jrick struct got_object_id *merge_commit_id = NULL;
12931 624411d2 2023-07-08 jrick char *branch_name = NULL;
12932 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12933 624411d2 2023-07-08 jrick
12934 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12935 624411d2 2023-07-08 jrick
12936 624411d2 2023-07-08 jrick #ifndef PROFILE
12937 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12938 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12939 624411d2 2023-07-08 jrick err(1, "pledge");
12940 624411d2 2023-07-08 jrick #endif
12941 624411d2 2023-07-08 jrick
12942 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCcMn")) != -1) {
12943 624411d2 2023-07-08 jrick switch (ch) {
12944 624411d2 2023-07-08 jrick case 'a':
12945 624411d2 2023-07-08 jrick abort_merge = 1;
12946 624411d2 2023-07-08 jrick break;
12947 624411d2 2023-07-08 jrick case 'C':
12948 624411d2 2023-07-08 jrick allow_conflict = 1;
12949 624411d2 2023-07-08 jrick break;
12950 624411d2 2023-07-08 jrick case 'c':
12951 624411d2 2023-07-08 jrick continue_merge = 1;
12952 624411d2 2023-07-08 jrick break;
12953 624411d2 2023-07-08 jrick case 'M':
12954 624411d2 2023-07-08 jrick prefer_fast_forward = 0;
12955 624411d2 2023-07-08 jrick break;
12956 624411d2 2023-07-08 jrick case 'n':
12957 624411d2 2023-07-08 jrick interrupt_merge = 1;
12958 624411d2 2023-07-08 jrick break;
12959 624411d2 2023-07-08 jrick default:
12960 624411d2 2023-07-08 jrick usage_merge();
12961 624411d2 2023-07-08 jrick /* NOTREACHED */
12962 624411d2 2023-07-08 jrick }
12963 624411d2 2023-07-08 jrick }
12964 624411d2 2023-07-08 jrick
12965 624411d2 2023-07-08 jrick argc -= optind;
12966 624411d2 2023-07-08 jrick argv += optind;
12967 624411d2 2023-07-08 jrick
12968 624411d2 2023-07-08 jrick if (abort_merge) {
12969 624411d2 2023-07-08 jrick if (continue_merge)
12970 624411d2 2023-07-08 jrick option_conflict('a', 'c');
12971 624411d2 2023-07-08 jrick if (!prefer_fast_forward)
12972 624411d2 2023-07-08 jrick option_conflict('a', 'M');
12973 624411d2 2023-07-08 jrick if (interrupt_merge)
12974 624411d2 2023-07-08 jrick option_conflict('a', 'n');
12975 624411d2 2023-07-08 jrick } else if (continue_merge) {
12976 624411d2 2023-07-08 jrick if (!prefer_fast_forward)
12977 624411d2 2023-07-08 jrick option_conflict('c', 'M');
12978 624411d2 2023-07-08 jrick if (interrupt_merge)
12979 624411d2 2023-07-08 jrick option_conflict('c', 'n');
12980 624411d2 2023-07-08 jrick }
12981 624411d2 2023-07-08 jrick if (allow_conflict) {
12982 624411d2 2023-07-08 jrick if (!continue_merge)
12983 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
12984 624411d2 2023-07-08 jrick }
12985 624411d2 2023-07-08 jrick if (abort_merge || continue_merge) {
12986 624411d2 2023-07-08 jrick if (argc != 0)
12987 624411d2 2023-07-08 jrick usage_merge();
12988 624411d2 2023-07-08 jrick } else if (argc != 1)
12989 624411d2 2023-07-08 jrick usage_merge();
12990 624411d2 2023-07-08 jrick
12991 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12992 624411d2 2023-07-08 jrick if (cwd == NULL) {
12993 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12994 624411d2 2023-07-08 jrick goto done;
12995 624411d2 2023-07-08 jrick }
12996 624411d2 2023-07-08 jrick
12997 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12998 624411d2 2023-07-08 jrick if (error != NULL)
12999 624411d2 2023-07-08 jrick goto done;
13000 624411d2 2023-07-08 jrick
13001 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13002 624411d2 2023-07-08 jrick if (error) {
13003 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13004 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
13005 624411d2 2023-07-08 jrick "merge", cwd);
13006 624411d2 2023-07-08 jrick goto done;
13007 624411d2 2023-07-08 jrick }
13008 624411d2 2023-07-08 jrick
13009 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
13010 624411d2 2023-07-08 jrick if (error)
13011 624411d2 2023-07-08 jrick goto done;
13012 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
13013 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
13014 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
13015 624411d2 2023-07-08 jrick if (error != NULL)
13016 624411d2 2023-07-08 jrick goto done;
13017 624411d2 2023-07-08 jrick
13018 624411d2 2023-07-08 jrick if (worktree != NULL) {
13019 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("merge", worktree, repo);
13020 624411d2 2023-07-08 jrick if (error)
13021 624411d2 2023-07-08 jrick goto done;
13022 624411d2 2023-07-08 jrick }
13023 624411d2 2023-07-08 jrick
13024 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13025 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
13026 624411d2 2023-07-08 jrick if (error)
13027 624411d2 2023-07-08 jrick goto done;
13028 624411d2 2023-07-08 jrick
13029 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
13030 624411d2 2023-07-08 jrick if (error)
13031 624411d2 2023-07-08 jrick goto done;
13032 624411d2 2023-07-08 jrick
13033 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
13034 624411d2 2023-07-08 jrick repo);
13035 624411d2 2023-07-08 jrick if (error)
13036 624411d2 2023-07-08 jrick goto done;
13037 624411d2 2023-07-08 jrick
13038 624411d2 2023-07-08 jrick if (merge_in_progress && !(abort_merge || continue_merge)) {
13039 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
13040 624411d2 2023-07-08 jrick goto done;
13041 624411d2 2023-07-08 jrick }
13042 624411d2 2023-07-08 jrick
13043 624411d2 2023-07-08 jrick if (!merge_in_progress && (abort_merge || continue_merge)) {
13044 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_MERGING);
13045 624411d2 2023-07-08 jrick goto done;
13046 624411d2 2023-07-08 jrick }
13047 624411d2 2023-07-08 jrick
13048 624411d2 2023-07-08 jrick if (abort_merge) {
13049 624411d2 2023-07-08 jrick error = got_worktree_merge_continue(&branch_name,
13050 624411d2 2023-07-08 jrick &branch_tip, &fileindex, worktree, repo);
13051 624411d2 2023-07-08 jrick if (error)
13052 624411d2 2023-07-08 jrick goto done;
13053 624411d2 2023-07-08 jrick error = got_worktree_merge_abort(worktree, fileindex, repo,
13054 624411d2 2023-07-08 jrick abort_progress, &upa);
13055 624411d2 2023-07-08 jrick if (error)
13056 624411d2 2023-07-08 jrick goto done;
13057 624411d2 2023-07-08 jrick printf("Merge of %s aborted\n", branch_name);
13058 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
13059 624411d2 2023-07-08 jrick }
13060 624411d2 2023-07-08 jrick
13061 624411d2 2023-07-08 jrick if (strncmp(got_worktree_get_head_ref_name(worktree),
13062 624411d2 2023-07-08 jrick "refs/heads/", 11) != 0) {
13063 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_COMMIT_BRANCH,
13064 624411d2 2023-07-08 jrick "work tree's current branch %s is outside the "
13065 624411d2 2023-07-08 jrick "\"refs/heads/\" reference namespace; "
13066 624411d2 2023-07-08 jrick "update -b required",
13067 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
13068 624411d2 2023-07-08 jrick goto done;
13069 624411d2 2023-07-08 jrick }
13070 624411d2 2023-07-08 jrick
13071 624411d2 2023-07-08 jrick error = get_author(&author, repo, worktree);
13072 624411d2 2023-07-08 jrick if (error)
13073 624411d2 2023-07-08 jrick goto done;
13074 624411d2 2023-07-08 jrick
13075 624411d2 2023-07-08 jrick error = got_ref_open(&wt_branch, repo,
13076 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
13077 624411d2 2023-07-08 jrick if (error)
13078 624411d2 2023-07-08 jrick goto done;
13079 624411d2 2023-07-08 jrick error = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
13080 624411d2 2023-07-08 jrick if (error)
13081 624411d2 2023-07-08 jrick goto done;
13082 624411d2 2023-07-08 jrick
13083 624411d2 2023-07-08 jrick if (continue_merge) {
13084 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id;
13085 624411d2 2023-07-08 jrick base_commit_id = got_worktree_get_base_commit_id(worktree);
13086 624411d2 2023-07-08 jrick if (got_object_id_cmp(wt_branch_tip, base_commit_id) != 0) {
13087 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_COMMIT_OUT_OF_DATE);
13088 624411d2 2023-07-08 jrick goto done;
13089 624411d2 2023-07-08 jrick }
13090 624411d2 2023-07-08 jrick error = got_worktree_merge_continue(&branch_name,
13091 624411d2 2023-07-08 jrick &branch_tip, &fileindex, worktree, repo);
13092 624411d2 2023-07-08 jrick if (error)
13093 624411d2 2023-07-08 jrick goto done;
13094 624411d2 2023-07-08 jrick } else {
13095 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo, argv[0], 0);
13096 624411d2 2023-07-08 jrick if (error != NULL)
13097 624411d2 2023-07-08 jrick goto done;
13098 624411d2 2023-07-08 jrick branch_name = strdup(got_ref_get_name(branch));
13099 624411d2 2023-07-08 jrick if (branch_name == NULL) {
13100 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
13101 624411d2 2023-07-08 jrick goto done;
13102 624411d2 2023-07-08 jrick }
13103 624411d2 2023-07-08 jrick error = got_ref_resolve(&branch_tip, repo, branch);
13104 624411d2 2023-07-08 jrick if (error)
13105 624411d2 2023-07-08 jrick goto done;
13106 624411d2 2023-07-08 jrick }
13107 624411d2 2023-07-08 jrick
13108 624411d2 2023-07-08 jrick error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
13109 624411d2 2023-07-08 jrick wt_branch_tip, branch_tip, 0, repo,
13110 624411d2 2023-07-08 jrick check_cancelled, NULL);
13111 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_ANCESTRY)
13112 624411d2 2023-07-08 jrick goto done;
13113 624411d2 2023-07-08 jrick
13114 624411d2 2023-07-08 jrick if (!continue_merge) {
13115 624411d2 2023-07-08 jrick error = check_path_prefix(wt_branch_tip, branch_tip,
13116 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree),
13117 624411d2 2023-07-08 jrick GOT_ERR_MERGE_PATH, repo);
13118 624411d2 2023-07-08 jrick if (error)
13119 624411d2 2023-07-08 jrick goto done;
13120 624411d2 2023-07-08 jrick error = got_worktree_merge_prepare(&fileindex, worktree, repo);
13121 624411d2 2023-07-08 jrick if (error)
13122 624411d2 2023-07-08 jrick goto done;
13123 624411d2 2023-07-08 jrick if (prefer_fast_forward && yca_id &&
13124 624411d2 2023-07-08 jrick got_object_id_cmp(wt_branch_tip, yca_id) == 0) {
13125 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13126 624411d2 2023-07-08 jrick if (interrupt_merge) {
13127 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_BAD_OPTION,
13128 624411d2 2023-07-08 jrick "there are no changes to merge since %s "
13129 624411d2 2023-07-08 jrick "is already based on %s; merge cannot be "
13130 624411d2 2023-07-08 jrick "interrupted for amending; -n",
13131 624411d2 2023-07-08 jrick branch_name, got_ref_get_name(wt_branch));
13132 624411d2 2023-07-08 jrick goto done;
13133 624411d2 2023-07-08 jrick }
13134 624411d2 2023-07-08 jrick printf("Forwarding %s to %s\n",
13135 624411d2 2023-07-08 jrick got_ref_get_name(wt_branch), branch_name);
13136 624411d2 2023-07-08 jrick error = got_ref_change_ref(wt_branch, branch_tip);
13137 624411d2 2023-07-08 jrick if (error)
13138 624411d2 2023-07-08 jrick goto done;
13139 624411d2 2023-07-08 jrick error = got_ref_write(wt_branch, repo);
13140 624411d2 2023-07-08 jrick if (error)
13141 624411d2 2023-07-08 jrick goto done;
13142 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
13143 624411d2 2023-07-08 jrick branch_tip);
13144 624411d2 2023-07-08 jrick if (error)
13145 624411d2 2023-07-08 jrick goto done;
13146 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13147 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
13148 624411d2 2023-07-08 jrick if (error)
13149 624411d2 2023-07-08 jrick goto done;
13150 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree,
13151 624411d2 2023-07-08 jrick &paths, repo, update_progress, &upa,
13152 624411d2 2023-07-08 jrick check_cancelled, NULL);
13153 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
13154 624411d2 2023-07-08 jrick if (error)
13155 624411d2 2023-07-08 jrick goto done;
13156 624411d2 2023-07-08 jrick if (upa.did_something) {
13157 624411d2 2023-07-08 jrick char *id_str;
13158 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, branch_tip);
13159 624411d2 2023-07-08 jrick if (error)
13160 624411d2 2023-07-08 jrick goto done;
13161 624411d2 2023-07-08 jrick printf("Updated to commit %s\n", id_str);
13162 624411d2 2023-07-08 jrick free(id_str);
13163 624411d2 2023-07-08 jrick } else
13164 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
13165 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
13166 624411d2 2023-07-08 jrick goto done;
13167 624411d2 2023-07-08 jrick }
13168 624411d2 2023-07-08 jrick error = got_worktree_merge_write_refs(worktree, branch, repo);
13169 624411d2 2023-07-08 jrick if (error)
13170 624411d2 2023-07-08 jrick goto done;
13171 624411d2 2023-07-08 jrick
13172 624411d2 2023-07-08 jrick error = got_worktree_merge_branch(worktree, fileindex,
13173 624411d2 2023-07-08 jrick yca_id, branch_tip, repo, update_progress, &upa,
13174 624411d2 2023-07-08 jrick check_cancelled, NULL);
13175 624411d2 2023-07-08 jrick if (error)
13176 624411d2 2023-07-08 jrick goto done;
13177 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
13178 624411d2 2023-07-08 jrick if (!upa.did_something) {
13179 624411d2 2023-07-08 jrick error = got_worktree_merge_abort(worktree, fileindex,
13180 624411d2 2023-07-08 jrick repo, abort_progress, &upa);
13181 624411d2 2023-07-08 jrick if (error)
13182 624411d2 2023-07-08 jrick goto done;
13183 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
13184 624411d2 2023-07-08 jrick goto done;
13185 624411d2 2023-07-08 jrick }
13186 624411d2 2023-07-08 jrick }
13187 624411d2 2023-07-08 jrick
13188 624411d2 2023-07-08 jrick if (interrupt_merge) {
13189 624411d2 2023-07-08 jrick error = got_worktree_merge_postpone(worktree, fileindex);
13190 624411d2 2023-07-08 jrick if (error)
13191 624411d2 2023-07-08 jrick goto done;
13192 624411d2 2023-07-08 jrick printf("Merge of %s interrupted on request\n", branch_name);
13193 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0 || upa.missing > 0 ||
13194 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
13195 624411d2 2023-07-08 jrick error = got_worktree_merge_postpone(worktree, fileindex);
13196 624411d2 2023-07-08 jrick if (error)
13197 624411d2 2023-07-08 jrick goto done;
13198 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
13199 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
13200 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13201 624411d2 2023-07-08 jrick "conflicts must be resolved before merging "
13202 624411d2 2023-07-08 jrick "can continue");
13203 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
13204 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13205 624411d2 2023-07-08 jrick "conflicts must be resolved before merging "
13206 624411d2 2023-07-08 jrick "can continue; changes destined for some "
13207 624411d2 2023-07-08 jrick "files were not yet merged and "
13208 624411d2 2023-07-08 jrick "should be merged manually if required before the "
13209 624411d2 2023-07-08 jrick "merge operation is continued");
13210 624411d2 2023-07-08 jrick } else {
13211 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13212 624411d2 2023-07-08 jrick "changes destined for some "
13213 624411d2 2023-07-08 jrick "files were not yet merged and should be "
13214 624411d2 2023-07-08 jrick "merged manually if required before the "
13215 624411d2 2023-07-08 jrick "merge operation is continued");
13216 624411d2 2023-07-08 jrick }
13217 624411d2 2023-07-08 jrick goto done;
13218 624411d2 2023-07-08 jrick } else {
13219 624411d2 2023-07-08 jrick error = got_worktree_merge_commit(&merge_commit_id, worktree,
13220 624411d2 2023-07-08 jrick fileindex, author, NULL, 1, branch_tip, branch_name,
13221 624411d2 2023-07-08 jrick allow_conflict, repo, continue_merge ? print_status : NULL,
13222 624411d2 2023-07-08 jrick NULL);
13223 624411d2 2023-07-08 jrick if (error)
13224 624411d2 2023-07-08 jrick goto done;
13225 624411d2 2023-07-08 jrick error = got_worktree_merge_complete(worktree, fileindex, repo);
13226 624411d2 2023-07-08 jrick if (error)
13227 624411d2 2023-07-08 jrick goto done;
13228 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, merge_commit_id);
13229 624411d2 2023-07-08 jrick if (error)
13230 624411d2 2023-07-08 jrick goto done;
13231 624411d2 2023-07-08 jrick printf("Merged %s into %s: %s\n", branch_name,
13232 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
13233 624411d2 2023-07-08 jrick id_str);
13234 624411d2 2023-07-08 jrick
13235 624411d2 2023-07-08 jrick }
13236 624411d2 2023-07-08 jrick done:
13237 624411d2 2023-07-08 jrick free(gitconfig_path);
13238 624411d2 2023-07-08 jrick free(id_str);
13239 624411d2 2023-07-08 jrick free(merge_commit_id);
13240 624411d2 2023-07-08 jrick free(author);
13241 624411d2 2023-07-08 jrick free(branch_tip);
13242 624411d2 2023-07-08 jrick free(branch_name);
13243 624411d2 2023-07-08 jrick free(yca_id);
13244 624411d2 2023-07-08 jrick if (branch)
13245 624411d2 2023-07-08 jrick got_ref_close(branch);
13246 624411d2 2023-07-08 jrick if (wt_branch)
13247 624411d2 2023-07-08 jrick got_ref_close(wt_branch);
13248 624411d2 2023-07-08 jrick if (worktree)
13249 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13250 624411d2 2023-07-08 jrick if (repo) {
13251 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13252 624411d2 2023-07-08 jrick if (error == NULL)
13253 624411d2 2023-07-08 jrick error = close_err;
13254 624411d2 2023-07-08 jrick }
13255 624411d2 2023-07-08 jrick if (pack_fds) {
13256 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13257 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13258 624411d2 2023-07-08 jrick if (error == NULL)
13259 624411d2 2023-07-08 jrick error = pack_err;
13260 624411d2 2023-07-08 jrick }
13261 624411d2 2023-07-08 jrick return error;
13262 624411d2 2023-07-08 jrick }
13263 624411d2 2023-07-08 jrick
13264 624411d2 2023-07-08 jrick __dead static void
13265 624411d2 2023-07-08 jrick usage_stage(void)
13266 624411d2 2023-07-08 jrick {
13267 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s stage [-lpS] [-F response-script] "
13268 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
13269 624411d2 2023-07-08 jrick exit(1);
13270 624411d2 2023-07-08 jrick }
13271 624411d2 2023-07-08 jrick
13272 624411d2 2023-07-08 jrick static const struct got_error *
13273 624411d2 2023-07-08 jrick print_stage(void *arg, unsigned char status, unsigned char staged_status,
13274 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
13275 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
13276 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
13277 624411d2 2023-07-08 jrick {
13278 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
13279 624411d2 2023-07-08 jrick char *id_str = NULL;
13280 624411d2 2023-07-08 jrick
13281 624411d2 2023-07-08 jrick if (staged_status != GOT_STATUS_ADD &&
13282 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_MODIFY &&
13283 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_DELETE)
13284 624411d2 2023-07-08 jrick return NULL;
13285 624411d2 2023-07-08 jrick
13286 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_ADD ||
13287 624411d2 2023-07-08 jrick staged_status == GOT_STATUS_MODIFY)
13288 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
13289 624411d2 2023-07-08 jrick else
13290 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, blob_id);
13291 624411d2 2023-07-08 jrick if (err)
13292 624411d2 2023-07-08 jrick return err;
13293 624411d2 2023-07-08 jrick
13294 624411d2 2023-07-08 jrick printf("%s %c %s\n", id_str, staged_status, path);
13295 624411d2 2023-07-08 jrick free(id_str);
13296 624411d2 2023-07-08 jrick return NULL;
13297 624411d2 2023-07-08 jrick }
13298 624411d2 2023-07-08 jrick
13299 624411d2 2023-07-08 jrick static const struct got_error *
13300 624411d2 2023-07-08 jrick cmd_stage(int argc, char *argv[])
13301 624411d2 2023-07-08 jrick {
13302 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13303 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13304 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13305 624411d2 2023-07-08 jrick char *cwd = NULL;
13306 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13307 624411d2 2023-07-08 jrick int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
13308 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
13309 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
13310 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
13311 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13312 624411d2 2023-07-08 jrick
13313 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13314 624411d2 2023-07-08 jrick
13315 624411d2 2023-07-08 jrick #ifndef PROFILE
13316 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13317 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
13318 624411d2 2023-07-08 jrick err(1, "pledge");
13319 624411d2 2023-07-08 jrick #endif
13320 624411d2 2023-07-08 jrick
13321 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:lpS")) != -1) {
13322 624411d2 2023-07-08 jrick switch (ch) {
13323 624411d2 2023-07-08 jrick case 'F':
13324 624411d2 2023-07-08 jrick patch_script_path = optarg;
13325 624411d2 2023-07-08 jrick break;
13326 624411d2 2023-07-08 jrick case 'l':
13327 624411d2 2023-07-08 jrick list_stage = 1;
13328 624411d2 2023-07-08 jrick break;
13329 624411d2 2023-07-08 jrick case 'p':
13330 624411d2 2023-07-08 jrick pflag = 1;
13331 624411d2 2023-07-08 jrick break;
13332 624411d2 2023-07-08 jrick case 'S':
13333 624411d2 2023-07-08 jrick allow_bad_symlinks = 1;
13334 624411d2 2023-07-08 jrick break;
13335 624411d2 2023-07-08 jrick default:
13336 624411d2 2023-07-08 jrick usage_stage();
13337 624411d2 2023-07-08 jrick /* NOTREACHED */
13338 624411d2 2023-07-08 jrick }
13339 624411d2 2023-07-08 jrick }
13340 624411d2 2023-07-08 jrick
13341 624411d2 2023-07-08 jrick argc -= optind;
13342 624411d2 2023-07-08 jrick argv += optind;
13343 624411d2 2023-07-08 jrick
13344 624411d2 2023-07-08 jrick if (list_stage && (pflag || patch_script_path))
13345 624411d2 2023-07-08 jrick errx(1, "-l option cannot be used with other options");
13346 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
13347 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
13348 624411d2 2023-07-08 jrick
13349 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13350 624411d2 2023-07-08 jrick if (cwd == NULL) {
13351 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13352 624411d2 2023-07-08 jrick goto done;
13353 624411d2 2023-07-08 jrick }
13354 624411d2 2023-07-08 jrick
13355 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13356 624411d2 2023-07-08 jrick if (error != NULL)
13357 624411d2 2023-07-08 jrick goto done;
13358 624411d2 2023-07-08 jrick
13359 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13360 624411d2 2023-07-08 jrick if (error) {
13361 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13362 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "stage", cwd);
13363 624411d2 2023-07-08 jrick goto done;
13364 624411d2 2023-07-08 jrick }
13365 624411d2 2023-07-08 jrick
13366 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
13367 624411d2 2023-07-08 jrick NULL, pack_fds);
13368 624411d2 2023-07-08 jrick if (error != NULL)
13369 624411d2 2023-07-08 jrick goto done;
13370 624411d2 2023-07-08 jrick
13371 624411d2 2023-07-08 jrick if (patch_script_path) {
13372 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
13373 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
13374 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
13375 624411d2 2023-07-08 jrick patch_script_path);
13376 624411d2 2023-07-08 jrick goto done;
13377 624411d2 2023-07-08 jrick }
13378 624411d2 2023-07-08 jrick }
13379 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13380 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
13381 624411d2 2023-07-08 jrick if (error)
13382 624411d2 2023-07-08 jrick goto done;
13383 624411d2 2023-07-08 jrick
13384 624411d2 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
13385 624411d2 2023-07-08 jrick if (error)
13386 624411d2 2023-07-08 jrick goto done;
13387 624411d2 2023-07-08 jrick
13388 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
13389 624411d2 2023-07-08 jrick if (error)
13390 624411d2 2023-07-08 jrick goto done;
13391 624411d2 2023-07-08 jrick
13392 624411d2 2023-07-08 jrick if (list_stage)
13393 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, 0,
13394 624411d2 2023-07-08 jrick print_stage, NULL, check_cancelled, NULL);
13395 624411d2 2023-07-08 jrick else {
13396 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
13397 624411d2 2023-07-08 jrick cpa.action = "stage";
13398 624411d2 2023-07-08 jrick error = got_worktree_stage(worktree, &paths,
13399 624411d2 2023-07-08 jrick pflag ? NULL : print_status, NULL,
13400 624411d2 2023-07-08 jrick pflag ? choose_patch : NULL, &cpa,
13401 624411d2 2023-07-08 jrick allow_bad_symlinks, repo);
13402 624411d2 2023-07-08 jrick }
13403 624411d2 2023-07-08 jrick done:
13404 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
13405 624411d2 2023-07-08 jrick error == NULL)
13406 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
13407 624411d2 2023-07-08 jrick if (repo) {
13408 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13409 624411d2 2023-07-08 jrick if (error == NULL)
13410 624411d2 2023-07-08 jrick error = close_err;
13411 624411d2 2023-07-08 jrick }
13412 624411d2 2023-07-08 jrick if (worktree)
13413 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13414 624411d2 2023-07-08 jrick if (pack_fds) {
13415 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13416 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13417 624411d2 2023-07-08 jrick if (error == NULL)
13418 624411d2 2023-07-08 jrick error = pack_err;
13419 624411d2 2023-07-08 jrick }
13420 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
13421 624411d2 2023-07-08 jrick free(cwd);
13422 624411d2 2023-07-08 jrick return error;
13423 624411d2 2023-07-08 jrick }
13424 624411d2 2023-07-08 jrick
13425 624411d2 2023-07-08 jrick __dead static void
13426 624411d2 2023-07-08 jrick usage_unstage(void)
13427 624411d2 2023-07-08 jrick {
13428 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
13429 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
13430 624411d2 2023-07-08 jrick exit(1);
13431 624411d2 2023-07-08 jrick }
13432 624411d2 2023-07-08 jrick
13433 624411d2 2023-07-08 jrick
13434 624411d2 2023-07-08 jrick static const struct got_error *
13435 624411d2 2023-07-08 jrick cmd_unstage(int argc, char *argv[])
13436 624411d2 2023-07-08 jrick {
13437 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13438 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13439 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13440 624411d2 2023-07-08 jrick char *cwd = NULL;
13441 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13442 624411d2 2023-07-08 jrick int ch, pflag = 0;
13443 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
13444 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
13445 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
13446 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
13447 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13448 624411d2 2023-07-08 jrick
13449 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13450 624411d2 2023-07-08 jrick
13451 624411d2 2023-07-08 jrick #ifndef PROFILE
13452 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13453 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
13454 624411d2 2023-07-08 jrick err(1, "pledge");
13455 624411d2 2023-07-08 jrick #endif
13456 624411d2 2023-07-08 jrick
13457 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:p")) != -1) {
13458 624411d2 2023-07-08 jrick switch (ch) {
13459 624411d2 2023-07-08 jrick case 'F':
13460 624411d2 2023-07-08 jrick patch_script_path = optarg;
13461 624411d2 2023-07-08 jrick break;
13462 624411d2 2023-07-08 jrick case 'p':
13463 624411d2 2023-07-08 jrick pflag = 1;
13464 624411d2 2023-07-08 jrick break;
13465 624411d2 2023-07-08 jrick default:
13466 624411d2 2023-07-08 jrick usage_unstage();
13467 624411d2 2023-07-08 jrick /* NOTREACHED */
13468 624411d2 2023-07-08 jrick }
13469 624411d2 2023-07-08 jrick }
13470 624411d2 2023-07-08 jrick
13471 624411d2 2023-07-08 jrick argc -= optind;
13472 624411d2 2023-07-08 jrick argv += optind;
13473 624411d2 2023-07-08 jrick
13474 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
13475 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
13476 624411d2 2023-07-08 jrick
13477 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13478 624411d2 2023-07-08 jrick if (cwd == NULL) {
13479 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13480 624411d2 2023-07-08 jrick goto done;
13481 624411d2 2023-07-08 jrick }
13482 624411d2 2023-07-08 jrick
13483 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13484 624411d2 2023-07-08 jrick if (error != NULL)
13485 624411d2 2023-07-08 jrick goto done;
13486 624411d2 2023-07-08 jrick
13487 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13488 624411d2 2023-07-08 jrick if (error) {
13489 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13490 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "unstage", cwd);
13491 624411d2 2023-07-08 jrick goto done;
13492 624411d2 2023-07-08 jrick }
13493 624411d2 2023-07-08 jrick
13494 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
13495 624411d2 2023-07-08 jrick NULL, pack_fds);
13496 624411d2 2023-07-08 jrick if (error != NULL)
13497 624411d2 2023-07-08 jrick goto done;
13498 624411d2 2023-07-08 jrick
13499 624411d2 2023-07-08 jrick if (patch_script_path) {
13500 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
13501 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
13502 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
13503 624411d2 2023-07-08 jrick patch_script_path);
13504 624411d2 2023-07-08 jrick goto done;
13505 624411d2 2023-07-08 jrick }
13506 624411d2 2023-07-08 jrick }
13507 624411d2 2023-07-08 jrick
13508 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13509 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
13510 624411d2 2023-07-08 jrick if (error)
13511 624411d2 2023-07-08 jrick goto done;
13512 624411d2 2023-07-08 jrick
13513 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
13514 624411d2 2023-07-08 jrick if (error)
13515 624411d2 2023-07-08 jrick goto done;
13516 624411d2 2023-07-08 jrick
13517 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
13518 624411d2 2023-07-08 jrick cpa.action = "unstage";
13519 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
13520 624411d2 2023-07-08 jrick error = got_worktree_unstage(worktree, &paths, update_progress,
13521 624411d2 2023-07-08 jrick &upa, pflag ? choose_patch : NULL, &cpa, repo);
13522 624411d2 2023-07-08 jrick if (!error)
13523 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
13524 624411d2 2023-07-08 jrick done:
13525 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
13526 624411d2 2023-07-08 jrick error == NULL)
13527 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
13528 624411d2 2023-07-08 jrick if (repo) {
13529 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13530 624411d2 2023-07-08 jrick if (error == NULL)
13531 624411d2 2023-07-08 jrick error = close_err;
13532 624411d2 2023-07-08 jrick }
13533 624411d2 2023-07-08 jrick if (worktree)
13534 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13535 624411d2 2023-07-08 jrick if (pack_fds) {
13536 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13537 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13538 624411d2 2023-07-08 jrick if (error == NULL)
13539 624411d2 2023-07-08 jrick error = pack_err;
13540 624411d2 2023-07-08 jrick }
13541 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
13542 624411d2 2023-07-08 jrick free(cwd);
13543 624411d2 2023-07-08 jrick return error;
13544 624411d2 2023-07-08 jrick }
13545 624411d2 2023-07-08 jrick
13546 624411d2 2023-07-08 jrick __dead static void
13547 624411d2 2023-07-08 jrick usage_cat(void)
13548 624411d2 2023-07-08 jrick {
13549 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] "
13550 624411d2 2023-07-08 jrick "arg ...\n", getprogname());
13551 624411d2 2023-07-08 jrick exit(1);
13552 624411d2 2023-07-08 jrick }
13553 624411d2 2023-07-08 jrick
13554 624411d2 2023-07-08 jrick static const struct got_error *
13555 624411d2 2023-07-08 jrick cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13556 624411d2 2023-07-08 jrick {
13557 624411d2 2023-07-08 jrick const struct got_error *err;
13558 624411d2 2023-07-08 jrick struct got_blob_object *blob;
13559 624411d2 2023-07-08 jrick int fd = -1;
13560 624411d2 2023-07-08 jrick
13561 624411d2 2023-07-08 jrick fd = got_opentempfd();
13562 624411d2 2023-07-08 jrick if (fd == -1)
13563 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
13564 624411d2 2023-07-08 jrick
13565 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob, repo, id, 8192, fd);
13566 624411d2 2023-07-08 jrick if (err)
13567 624411d2 2023-07-08 jrick goto done;
13568 624411d2 2023-07-08 jrick
13569 624411d2 2023-07-08 jrick err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob);
13570 624411d2 2023-07-08 jrick done:
13571 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
13572 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
13573 624411d2 2023-07-08 jrick if (blob)
13574 624411d2 2023-07-08 jrick got_object_blob_close(blob);
13575 624411d2 2023-07-08 jrick return err;
13576 624411d2 2023-07-08 jrick }
13577 624411d2 2023-07-08 jrick
13578 624411d2 2023-07-08 jrick static const struct got_error *
13579 624411d2 2023-07-08 jrick cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13580 624411d2 2023-07-08 jrick {
13581 624411d2 2023-07-08 jrick const struct got_error *err;
13582 624411d2 2023-07-08 jrick struct got_tree_object *tree;
13583 624411d2 2023-07-08 jrick int nentries, i;
13584 624411d2 2023-07-08 jrick
13585 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo, id);
13586 624411d2 2023-07-08 jrick if (err)
13587 624411d2 2023-07-08 jrick return err;
13588 624411d2 2023-07-08 jrick
13589 624411d2 2023-07-08 jrick nentries = got_object_tree_get_nentries(tree);
13590 624411d2 2023-07-08 jrick for (i = 0; i < nentries; i++) {
13591 624411d2 2023-07-08 jrick struct got_tree_entry *te;
13592 624411d2 2023-07-08 jrick char *id_str;
13593 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
13594 624411d2 2023-07-08 jrick break;
13595 624411d2 2023-07-08 jrick te = got_object_tree_get_entry(tree, i);
13596 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
13597 624411d2 2023-07-08 jrick if (err)
13598 624411d2 2023-07-08 jrick break;
13599 624411d2 2023-07-08 jrick fprintf(outfile, "%s %.7o %s\n", id_str,
13600 624411d2 2023-07-08 jrick got_tree_entry_get_mode(te),
13601 624411d2 2023-07-08 jrick got_tree_entry_get_name(te));
13602 624411d2 2023-07-08 jrick free(id_str);
13603 624411d2 2023-07-08 jrick }
13604 624411d2 2023-07-08 jrick
13605 624411d2 2023-07-08 jrick got_object_tree_close(tree);
13606 624411d2 2023-07-08 jrick return err;
13607 624411d2 2023-07-08 jrick }
13608 624411d2 2023-07-08 jrick
13609 624411d2 2023-07-08 jrick static const struct got_error *
13610 624411d2 2023-07-08 jrick cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13611 624411d2 2023-07-08 jrick {
13612 624411d2 2023-07-08 jrick const struct got_error *err;
13613 624411d2 2023-07-08 jrick struct got_commit_object *commit;
13614 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
13615 624411d2 2023-07-08 jrick struct got_object_qid *pid;
13616 624411d2 2023-07-08 jrick char *id_str = NULL;
13617 624411d2 2023-07-08 jrick const char *logmsg = NULL;
13618 624411d2 2023-07-08 jrick char gmtoff[6];
13619 624411d2 2023-07-08 jrick
13620 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
13621 624411d2 2023-07-08 jrick if (err)
13622 624411d2 2023-07-08 jrick return err;
13623 624411d2 2023-07-08 jrick
13624 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
13625 624411d2 2023-07-08 jrick if (err)
13626 624411d2 2023-07-08 jrick goto done;
13627 624411d2 2023-07-08 jrick
13628 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str);
13629 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
13630 624411d2 2023-07-08 jrick fprintf(outfile, "numparents %d\n",
13631 624411d2 2023-07-08 jrick got_object_commit_get_nparents(commit));
13632 624411d2 2023-07-08 jrick STAILQ_FOREACH(pid, parent_ids, entry) {
13633 624411d2 2023-07-08 jrick char *pid_str;
13634 624411d2 2023-07-08 jrick err = got_object_id_str(&pid_str, &pid->id);
13635 624411d2 2023-07-08 jrick if (err)
13636 624411d2 2023-07-08 jrick goto done;
13637 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str);
13638 624411d2 2023-07-08 jrick free(pid_str);
13639 624411d2 2023-07-08 jrick }
13640 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13641 624411d2 2023-07-08 jrick got_object_commit_get_author_gmtoff(commit));
13642 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR,
13643 624411d2 2023-07-08 jrick got_object_commit_get_author(commit),
13644 624411d2 2023-07-08 jrick (long long)got_object_commit_get_author_time(commit),
13645 624411d2 2023-07-08 jrick gmtoff);
13646 624411d2 2023-07-08 jrick
13647 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13648 624411d2 2023-07-08 jrick got_object_commit_get_committer_gmtoff(commit));
13649 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER,
13650 624411d2 2023-07-08 jrick got_object_commit_get_committer(commit),
13651 624411d2 2023-07-08 jrick (long long)got_object_commit_get_committer_time(commit),
13652 624411d2 2023-07-08 jrick gmtoff);
13653 624411d2 2023-07-08 jrick
13654 624411d2 2023-07-08 jrick logmsg = got_object_commit_get_logmsg_raw(commit);
13655 624411d2 2023-07-08 jrick fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
13656 624411d2 2023-07-08 jrick fprintf(outfile, "%s", logmsg);
13657 624411d2 2023-07-08 jrick done:
13658 624411d2 2023-07-08 jrick free(id_str);
13659 624411d2 2023-07-08 jrick got_object_commit_close(commit);
13660 624411d2 2023-07-08 jrick return err;
13661 624411d2 2023-07-08 jrick }
13662 624411d2 2023-07-08 jrick
13663 624411d2 2023-07-08 jrick static const struct got_error *
13664 624411d2 2023-07-08 jrick cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13665 624411d2 2023-07-08 jrick {
13666 624411d2 2023-07-08 jrick const struct got_error *err;
13667 624411d2 2023-07-08 jrick struct got_tag_object *tag;
13668 624411d2 2023-07-08 jrick char *id_str = NULL;
13669 624411d2 2023-07-08 jrick const char *tagmsg = NULL;
13670 624411d2 2023-07-08 jrick char gmtoff[6];
13671 624411d2 2023-07-08 jrick
13672 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, id);
13673 624411d2 2023-07-08 jrick if (err)
13674 624411d2 2023-07-08 jrick return err;
13675 624411d2 2023-07-08 jrick
13676 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
13677 624411d2 2023-07-08 jrick if (err)
13678 624411d2 2023-07-08 jrick goto done;
13679 624411d2 2023-07-08 jrick
13680 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str);
13681 624411d2 2023-07-08 jrick
13682 624411d2 2023-07-08 jrick switch (got_object_tag_get_object_type(tag)) {
13683 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
13684 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13685 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_BLOB);
13686 624411d2 2023-07-08 jrick break;
13687 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
13688 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13689 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_TREE);
13690 624411d2 2023-07-08 jrick break;
13691 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
13692 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13693 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_COMMIT);
13694 624411d2 2023-07-08 jrick break;
13695 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
13696 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13697 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_TAG);
13698 624411d2 2023-07-08 jrick break;
13699 624411d2 2023-07-08 jrick default:
13700 624411d2 2023-07-08 jrick break;
13701 624411d2 2023-07-08 jrick }
13702 624411d2 2023-07-08 jrick
13703 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG,
13704 624411d2 2023-07-08 jrick got_object_tag_get_name(tag));
13705 624411d2 2023-07-08 jrick
13706 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13707 624411d2 2023-07-08 jrick got_object_tag_get_tagger_gmtoff(tag));
13708 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER,
13709 624411d2 2023-07-08 jrick got_object_tag_get_tagger(tag),
13710 624411d2 2023-07-08 jrick (long long)got_object_tag_get_tagger_time(tag),
13711 624411d2 2023-07-08 jrick gmtoff);
13712 624411d2 2023-07-08 jrick
13713 624411d2 2023-07-08 jrick tagmsg = got_object_tag_get_message(tag);
13714 624411d2 2023-07-08 jrick fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
13715 624411d2 2023-07-08 jrick fprintf(outfile, "%s", tagmsg);
13716 624411d2 2023-07-08 jrick done:
13717 624411d2 2023-07-08 jrick free(id_str);
13718 624411d2 2023-07-08 jrick got_object_tag_close(tag);
13719 624411d2 2023-07-08 jrick return err;
13720 624411d2 2023-07-08 jrick }
13721 624411d2 2023-07-08 jrick
13722 624411d2 2023-07-08 jrick static const struct got_error *
13723 624411d2 2023-07-08 jrick cmd_cat(int argc, char *argv[])
13724 624411d2 2023-07-08 jrick {
13725 624411d2 2023-07-08 jrick const struct got_error *error;
13726 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13727 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13728 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *label = NULL;
13729 624411d2 2023-07-08 jrick const char *commit_id_str = NULL;
13730 624411d2 2023-07-08 jrick struct got_object_id *id = NULL, *commit_id = NULL;
13731 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
13732 624411d2 2023-07-08 jrick int ch, obj_type, i, force_path = 0;
13733 624411d2 2023-07-08 jrick struct got_reflist_head refs;
13734 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13735 624411d2 2023-07-08 jrick
13736 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
13737 624411d2 2023-07-08 jrick
13738 624411d2 2023-07-08 jrick #ifndef PROFILE
13739 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
13740 624411d2 2023-07-08 jrick NULL) == -1)
13741 624411d2 2023-07-08 jrick err(1, "pledge");
13742 624411d2 2023-07-08 jrick #endif
13743 624411d2 2023-07-08 jrick
13744 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:Pr:")) != -1) {
13745 624411d2 2023-07-08 jrick switch (ch) {
13746 624411d2 2023-07-08 jrick case 'c':
13747 624411d2 2023-07-08 jrick commit_id_str = optarg;
13748 624411d2 2023-07-08 jrick break;
13749 624411d2 2023-07-08 jrick case 'P':
13750 624411d2 2023-07-08 jrick force_path = 1;
13751 624411d2 2023-07-08 jrick break;
13752 624411d2 2023-07-08 jrick case 'r':
13753 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
13754 624411d2 2023-07-08 jrick if (repo_path == NULL)
13755 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
13756 624411d2 2023-07-08 jrick optarg);
13757 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
13758 624411d2 2023-07-08 jrick break;
13759 624411d2 2023-07-08 jrick default:
13760 624411d2 2023-07-08 jrick usage_cat();
13761 624411d2 2023-07-08 jrick /* NOTREACHED */
13762 624411d2 2023-07-08 jrick }
13763 624411d2 2023-07-08 jrick }
13764 624411d2 2023-07-08 jrick
13765 624411d2 2023-07-08 jrick argc -= optind;
13766 624411d2 2023-07-08 jrick argv += optind;
13767 624411d2 2023-07-08 jrick
13768 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13769 624411d2 2023-07-08 jrick if (cwd == NULL) {
13770 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13771 624411d2 2023-07-08 jrick goto done;
13772 624411d2 2023-07-08 jrick }
13773 624411d2 2023-07-08 jrick
13774 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13775 624411d2 2023-07-08 jrick if (error != NULL)
13776 624411d2 2023-07-08 jrick goto done;
13777 624411d2 2023-07-08 jrick
13778 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13779 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13780 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
13781 624411d2 2023-07-08 jrick goto done;
13782 624411d2 2023-07-08 jrick if (worktree) {
13783 624411d2 2023-07-08 jrick repo_path = strdup(
13784 624411d2 2023-07-08 jrick got_worktree_get_repo_path(worktree));
13785 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13786 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
13787 624411d2 2023-07-08 jrick goto done;
13788 624411d2 2023-07-08 jrick }
13789 624411d2 2023-07-08 jrick
13790 624411d2 2023-07-08 jrick /* Release work tree lock. */
13791 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13792 624411d2 2023-07-08 jrick worktree = NULL;
13793 624411d2 2023-07-08 jrick }
13794 624411d2 2023-07-08 jrick }
13795 624411d2 2023-07-08 jrick
13796 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13797 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
13798 624411d2 2023-07-08 jrick if (repo_path == NULL)
13799 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
13800 624411d2 2023-07-08 jrick }
13801 624411d2 2023-07-08 jrick
13802 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
13803 624411d2 2023-07-08 jrick free(repo_path);
13804 624411d2 2023-07-08 jrick if (error != NULL)
13805 624411d2 2023-07-08 jrick goto done;
13806 624411d2 2023-07-08 jrick
13807 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
13808 624411d2 2023-07-08 jrick if (error)
13809 624411d2 2023-07-08 jrick goto done;
13810 624411d2 2023-07-08 jrick
13811 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
13812 624411d2 2023-07-08 jrick if (error)
13813 624411d2 2023-07-08 jrick goto done;
13814 624411d2 2023-07-08 jrick
13815 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
13816 624411d2 2023-07-08 jrick commit_id_str = GOT_REF_HEAD;
13817 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
13818 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
13819 624411d2 2023-07-08 jrick if (error)
13820 624411d2 2023-07-08 jrick goto done;
13821 624411d2 2023-07-08 jrick
13822 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
13823 624411d2 2023-07-08 jrick if (error)
13824 624411d2 2023-07-08 jrick goto done;
13825 624411d2 2023-07-08 jrick
13826 624411d2 2023-07-08 jrick for (i = 0; i < argc; i++) {
13827 624411d2 2023-07-08 jrick if (force_path) {
13828 624411d2 2023-07-08 jrick error = got_object_id_by_path(&id, repo, commit,
13829 624411d2 2023-07-08 jrick argv[i]);
13830 624411d2 2023-07-08 jrick if (error)
13831 624411d2 2023-07-08 jrick break;
13832 624411d2 2023-07-08 jrick } else {
13833 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&id, &label, argv[i],
13834 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */,
13835 624411d2 2023-07-08 jrick repo);
13836 624411d2 2023-07-08 jrick if (error) {
13837 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_BAD_OBJ_ID_STR &&
13838 624411d2 2023-07-08 jrick error->code != GOT_ERR_NOT_REF)
13839 624411d2 2023-07-08 jrick break;
13840 624411d2 2023-07-08 jrick error = got_object_id_by_path(&id, repo,
13841 624411d2 2023-07-08 jrick commit, argv[i]);
13842 624411d2 2023-07-08 jrick if (error)
13843 624411d2 2023-07-08 jrick break;
13844 624411d2 2023-07-08 jrick }
13845 624411d2 2023-07-08 jrick }
13846 624411d2 2023-07-08 jrick
13847 624411d2 2023-07-08 jrick error = got_object_get_type(&obj_type, repo, id);
13848 624411d2 2023-07-08 jrick if (error)
13849 624411d2 2023-07-08 jrick break;
13850 624411d2 2023-07-08 jrick
13851 624411d2 2023-07-08 jrick switch (obj_type) {
13852 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
13853 624411d2 2023-07-08 jrick error = cat_blob(id, repo, stdout);
13854 624411d2 2023-07-08 jrick break;
13855 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
13856 624411d2 2023-07-08 jrick error = cat_tree(id, repo, stdout);
13857 624411d2 2023-07-08 jrick break;
13858 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
13859 624411d2 2023-07-08 jrick error = cat_commit(id, repo, stdout);
13860 624411d2 2023-07-08 jrick break;
13861 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
13862 624411d2 2023-07-08 jrick error = cat_tag(id, repo, stdout);
13863 624411d2 2023-07-08 jrick break;
13864 624411d2 2023-07-08 jrick default:
13865 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
13866 624411d2 2023-07-08 jrick break;
13867 624411d2 2023-07-08 jrick }
13868 624411d2 2023-07-08 jrick if (error)
13869 624411d2 2023-07-08 jrick break;
13870 624411d2 2023-07-08 jrick free(label);
13871 624411d2 2023-07-08 jrick label = NULL;
13872 624411d2 2023-07-08 jrick free(id);
13873 624411d2 2023-07-08 jrick id = NULL;
13874 624411d2 2023-07-08 jrick }
13875 624411d2 2023-07-08 jrick done:
13876 624411d2 2023-07-08 jrick free(label);
13877 624411d2 2023-07-08 jrick free(id);
13878 624411d2 2023-07-08 jrick free(commit_id);
13879 624411d2 2023-07-08 jrick if (commit)
13880 624411d2 2023-07-08 jrick got_object_commit_close(commit);
13881 624411d2 2023-07-08 jrick if (worktree)
13882 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13883 624411d2 2023-07-08 jrick if (repo) {
13884 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13885 624411d2 2023-07-08 jrick if (error == NULL)
13886 624411d2 2023-07-08 jrick error = close_err;
13887 624411d2 2023-07-08 jrick }
13888 624411d2 2023-07-08 jrick if (pack_fds) {
13889 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13890 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13891 624411d2 2023-07-08 jrick if (error == NULL)
13892 624411d2 2023-07-08 jrick error = pack_err;
13893 624411d2 2023-07-08 jrick }
13894 624411d2 2023-07-08 jrick
13895 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
13896 624411d2 2023-07-08 jrick return error;
13897 624411d2 2023-07-08 jrick }
13898 624411d2 2023-07-08 jrick
13899 624411d2 2023-07-08 jrick __dead static void
13900 624411d2 2023-07-08 jrick usage_info(void)
13901 624411d2 2023-07-08 jrick {
13902 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s info [path ...]\n",
13903 624411d2 2023-07-08 jrick getprogname());
13904 624411d2 2023-07-08 jrick exit(1);
13905 624411d2 2023-07-08 jrick }
13906 624411d2 2023-07-08 jrick
13907 624411d2 2023-07-08 jrick static const struct got_error *
13908 624411d2 2023-07-08 jrick print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
13909 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
13910 624411d2 2023-07-08 jrick struct got_object_id *commit_id)
13911 624411d2 2023-07-08 jrick {
13912 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
13913 624411d2 2023-07-08 jrick char *id_str = NULL;
13914 624411d2 2023-07-08 jrick char datebuf[128];
13915 624411d2 2023-07-08 jrick struct tm mytm, *tm;
13916 624411d2 2023-07-08 jrick struct got_pathlist_head *paths = arg;
13917 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
13918 624411d2 2023-07-08 jrick
13919 624411d2 2023-07-08 jrick /*
13920 624411d2 2023-07-08 jrick * Clear error indication from any of the path arguments which
13921 624411d2 2023-07-08 jrick * would cause this file index entry to be displayed.
13922 624411d2 2023-07-08 jrick */
13923 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, paths, entry) {
13924 624411d2 2023-07-08 jrick if (got_path_cmp(path, pe->path, strlen(path),
13925 624411d2 2023-07-08 jrick pe->path_len) == 0 ||
13926 624411d2 2023-07-08 jrick got_path_is_child(path, pe->path, pe->path_len))
13927 624411d2 2023-07-08 jrick pe->data = NULL; /* no error */
13928 624411d2 2023-07-08 jrick }
13929 624411d2 2023-07-08 jrick
13930 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
13931 624411d2 2023-07-08 jrick if (S_ISLNK(mode))
13932 624411d2 2023-07-08 jrick printf("symlink: %s\n", path);
13933 624411d2 2023-07-08 jrick else if (S_ISREG(mode)) {
13934 624411d2 2023-07-08 jrick printf("file: %s\n", path);
13935 624411d2 2023-07-08 jrick printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO));
13936 624411d2 2023-07-08 jrick } else if (S_ISDIR(mode))
13937 624411d2 2023-07-08 jrick printf("directory: %s\n", path);
13938 624411d2 2023-07-08 jrick else
13939 624411d2 2023-07-08 jrick printf("something: %s\n", path);
13940 624411d2 2023-07-08 jrick
13941 624411d2 2023-07-08 jrick tm = localtime_r(&mtime, &mytm);
13942 624411d2 2023-07-08 jrick if (tm == NULL)
13943 624411d2 2023-07-08 jrick return NULL;
13944 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0)
13945 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
13946 624411d2 2023-07-08 jrick printf("timestamp: %s\n", datebuf);
13947 624411d2 2023-07-08 jrick
13948 624411d2 2023-07-08 jrick if (blob_id) {
13949 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, blob_id);
13950 624411d2 2023-07-08 jrick if (err)
13951 624411d2 2023-07-08 jrick return err;
13952 624411d2 2023-07-08 jrick printf("based on blob: %s\n", id_str);
13953 624411d2 2023-07-08 jrick free(id_str);
13954 624411d2 2023-07-08 jrick }
13955 624411d2 2023-07-08 jrick
13956 624411d2 2023-07-08 jrick if (staged_blob_id) {
13957 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
13958 624411d2 2023-07-08 jrick if (err)
13959 624411d2 2023-07-08 jrick return err;
13960 624411d2 2023-07-08 jrick printf("based on staged blob: %s\n", id_str);
13961 624411d2 2023-07-08 jrick free(id_str);
13962 624411d2 2023-07-08 jrick }
13963 624411d2 2023-07-08 jrick
13964 624411d2 2023-07-08 jrick if (commit_id) {
13965 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, commit_id);
13966 624411d2 2023-07-08 jrick if (err)
13967 624411d2 2023-07-08 jrick return err;
13968 624411d2 2023-07-08 jrick printf("based on commit: %s\n", id_str);
13969 624411d2 2023-07-08 jrick free(id_str);
13970 624411d2 2023-07-08 jrick }
13971 624411d2 2023-07-08 jrick
13972 624411d2 2023-07-08 jrick return NULL;
13973 624411d2 2023-07-08 jrick }
13974 624411d2 2023-07-08 jrick
13975 624411d2 2023-07-08 jrick static const struct got_error *
13976 624411d2 2023-07-08 jrick cmd_info(int argc, char *argv[])
13977 624411d2 2023-07-08 jrick {
13978 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13979 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13980 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL;
13981 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13982 624411d2 2023-07-08 jrick char *uuidstr = NULL;
13983 624411d2 2023-07-08 jrick int ch, show_files = 0;
13984 624411d2 2023-07-08 jrick
13985 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13986 624411d2 2023-07-08 jrick
13987 624411d2 2023-07-08 jrick #ifndef PROFILE
13988 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
13989 624411d2 2023-07-08 jrick NULL) == -1)
13990 624411d2 2023-07-08 jrick err(1, "pledge");
13991 624411d2 2023-07-08 jrick #endif
13992 624411d2 2023-07-08 jrick
13993 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "")) != -1) {
13994 624411d2 2023-07-08 jrick switch (ch) {
13995 624411d2 2023-07-08 jrick default:
13996 624411d2 2023-07-08 jrick usage_info();
13997 624411d2 2023-07-08 jrick /* NOTREACHED */
13998 624411d2 2023-07-08 jrick }
13999 624411d2 2023-07-08 jrick }
14000 624411d2 2023-07-08 jrick
14001 624411d2 2023-07-08 jrick argc -= optind;
14002 624411d2 2023-07-08 jrick argv += optind;
14003 624411d2 2023-07-08 jrick
14004 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
14005 624411d2 2023-07-08 jrick if (cwd == NULL) {
14006 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
14007 624411d2 2023-07-08 jrick goto done;
14008 624411d2 2023-07-08 jrick }
14009 624411d2 2023-07-08 jrick
14010 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
14011 624411d2 2023-07-08 jrick if (error) {
14012 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
14013 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "info", cwd);
14014 624411d2 2023-07-08 jrick goto done;
14015 624411d2 2023-07-08 jrick }
14016 624411d2 2023-07-08 jrick
14017 624411d2 2023-07-08 jrick #ifndef PROFILE
14018 624411d2 2023-07-08 jrick /* Remove "wpath cpath proc exec sendfd" promises. */
14019 624411d2 2023-07-08 jrick if (pledge("stdio rpath flock unveil", NULL) == -1)
14020 624411d2 2023-07-08 jrick err(1, "pledge");
14021 624411d2 2023-07-08 jrick #endif
14022 624411d2 2023-07-08 jrick error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree));
14023 624411d2 2023-07-08 jrick if (error)
14024 624411d2 2023-07-08 jrick goto done;
14025 624411d2 2023-07-08 jrick
14026 624411d2 2023-07-08 jrick if (argc >= 1) {
14027 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv,
14028 624411d2 2023-07-08 jrick worktree);
14029 624411d2 2023-07-08 jrick if (error)
14030 624411d2 2023-07-08 jrick goto done;
14031 624411d2 2023-07-08 jrick show_files = 1;
14032 624411d2 2023-07-08 jrick }
14033 624411d2 2023-07-08 jrick
14034 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
14035 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
14036 624411d2 2023-07-08 jrick if (error)
14037 624411d2 2023-07-08 jrick goto done;
14038 624411d2 2023-07-08 jrick
14039 624411d2 2023-07-08 jrick error = got_worktree_get_uuid(&uuidstr, worktree);
14040 624411d2 2023-07-08 jrick if (error)
14041 624411d2 2023-07-08 jrick goto done;
14042 624411d2 2023-07-08 jrick
14043 624411d2 2023-07-08 jrick printf("work tree: %s\n", got_worktree_get_root_path(worktree));
14044 624411d2 2023-07-08 jrick printf("work tree base commit: %s\n", id_str);
14045 624411d2 2023-07-08 jrick printf("work tree path prefix: %s\n",
14046 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree));
14047 624411d2 2023-07-08 jrick printf("work tree branch reference: %s\n",
14048 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
14049 624411d2 2023-07-08 jrick printf("work tree UUID: %s\n", uuidstr);
14050 624411d2 2023-07-08 jrick printf("repository: %s\n", got_worktree_get_repo_path(worktree));
14051 624411d2 2023-07-08 jrick
14052 624411d2 2023-07-08 jrick if (show_files) {
14053 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
14054 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
14055 624411d2 2023-07-08 jrick if (pe->path_len == 0)
14056 624411d2 2023-07-08 jrick continue;
14057 624411d2 2023-07-08 jrick /*
14058 624411d2 2023-07-08 jrick * Assume this path will fail. This will be corrected
14059 624411d2 2023-07-08 jrick * in print_path_info() in case the path does suceeed.
14060 624411d2 2023-07-08 jrick */
14061 624411d2 2023-07-08 jrick pe->data = (void *)got_error(GOT_ERR_BAD_PATH);
14062 624411d2 2023-07-08 jrick }
14063 624411d2 2023-07-08 jrick error = got_worktree_path_info(worktree, &paths,
14064 624411d2 2023-07-08 jrick print_path_info, &paths, check_cancelled, NULL);
14065 624411d2 2023-07-08 jrick if (error)
14066 624411d2 2023-07-08 jrick goto done;
14067 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
14068 624411d2 2023-07-08 jrick if (pe->data != NULL) {
14069 624411d2 2023-07-08 jrick const struct got_error *perr;
14070 624411d2 2023-07-08 jrick
14071 624411d2 2023-07-08 jrick perr = pe->data;
14072 624411d2 2023-07-08 jrick error = got_error_fmt(perr->code, "%s",
14073 624411d2 2023-07-08 jrick pe->path);
14074 624411d2 2023-07-08 jrick break;
14075 624411d2 2023-07-08 jrick }
14076 624411d2 2023-07-08 jrick }
14077 624411d2 2023-07-08 jrick }
14078 624411d2 2023-07-08 jrick done:
14079 624411d2 2023-07-08 jrick if (worktree)
14080 624411d2 2023-07-08 jrick got_worktree_close(worktree);
14081 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
14082 624411d2 2023-07-08 jrick free(cwd);
14083 624411d2 2023-07-08 jrick free(id_str);
14084 624411d2 2023-07-08 jrick free(uuidstr);
14085 624411d2 2023-07-08 jrick return error;
14086 624411d2 2023-07-08 jrick }