Blame


1 24df9a28 2023-07-08 jrick /*
2 24df9a28 2023-07-08 jrick * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 24df9a28 2023-07-08 jrick * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 24df9a28 2023-07-08 jrick * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 24df9a28 2023-07-08 jrick * Copyright (C) 2023 Josh Rickmar <jrick@zettaport.com>
6 24df9a28 2023-07-08 jrick *
7 24df9a28 2023-07-08 jrick * Permission to use, copy, modify, and distribute this software for any
8 24df9a28 2023-07-08 jrick * purpose with or without fee is hereby granted, provided that the above
9 24df9a28 2023-07-08 jrick * copyright notice and this permission notice appear in all copies.
10 24df9a28 2023-07-08 jrick *
11 24df9a28 2023-07-08 jrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 24df9a28 2023-07-08 jrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 24df9a28 2023-07-08 jrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 24df9a28 2023-07-08 jrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 24df9a28 2023-07-08 jrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 24df9a28 2023-07-08 jrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 24df9a28 2023-07-08 jrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 24df9a28 2023-07-08 jrick */
19 24df9a28 2023-07-08 jrick
20 24df9a28 2023-07-08 jrick #include <sys/queue.h>
21 24df9a28 2023-07-08 jrick #include <sys/time.h>
22 24df9a28 2023-07-08 jrick #include <sys/types.h>
23 24df9a28 2023-07-08 jrick #include <sys/stat.h>
24 24df9a28 2023-07-08 jrick #include <sys/wait.h>
25 24df9a28 2023-07-08 jrick
26 24df9a28 2023-07-08 jrick #include <err.h>
27 24df9a28 2023-07-08 jrick #include <errno.h>
28 24df9a28 2023-07-08 jrick #include <fcntl.h>
29 24df9a28 2023-07-08 jrick #include <limits.h>
30 24df9a28 2023-07-08 jrick #include <locale.h>
31 24df9a28 2023-07-08 jrick #include <ctype.h>
32 24df9a28 2023-07-08 jrick #include <sha1.h>
33 24df9a28 2023-07-08 jrick #include <sha2.h>
34 24df9a28 2023-07-08 jrick #include <signal.h>
35 24df9a28 2023-07-08 jrick #include <stdio.h>
36 24df9a28 2023-07-08 jrick #include <stdlib.h>
37 24df9a28 2023-07-08 jrick #include <string.h>
38 24df9a28 2023-07-08 jrick #include <unistd.h>
39 24df9a28 2023-07-08 jrick #include <libgen.h>
40 24df9a28 2023-07-08 jrick #include <time.h>
41 24df9a28 2023-07-08 jrick #include <paths.h>
42 24df9a28 2023-07-08 jrick #include <regex.h>
43 24df9a28 2023-07-08 jrick #include <getopt.h>
44 24df9a28 2023-07-08 jrick #include <util.h>
45 24df9a28 2023-07-08 jrick
46 24df9a28 2023-07-08 jrick #include "got_version.h"
47 24df9a28 2023-07-08 jrick #include "got_error.h"
48 24df9a28 2023-07-08 jrick #include "got_object.h"
49 24df9a28 2023-07-08 jrick #include "got_reference.h"
50 24df9a28 2023-07-08 jrick #include "got_repository.h"
51 24df9a28 2023-07-08 jrick #include "got_path.h"
52 24df9a28 2023-07-08 jrick #include "got_cancel.h"
53 24df9a28 2023-07-08 jrick #include "got_worktree.h"
54 24df9a28 2023-07-08 jrick #include "got_worktree_cvg.h"
55 24df9a28 2023-07-08 jrick #include "got_diff.h"
56 24df9a28 2023-07-08 jrick #include "got_commit_graph.h"
57 24df9a28 2023-07-08 jrick #include "got_fetch.h"
58 24df9a28 2023-07-08 jrick #include "got_send.h"
59 24df9a28 2023-07-08 jrick #include "got_blame.h"
60 24df9a28 2023-07-08 jrick #include "got_privsep.h"
61 24df9a28 2023-07-08 jrick #include "got_opentemp.h"
62 24df9a28 2023-07-08 jrick #include "got_gotconfig.h"
63 24df9a28 2023-07-08 jrick #include "got_dial.h"
64 24df9a28 2023-07-08 jrick #include "got_patch.h"
65 24df9a28 2023-07-08 jrick #include "got_sigs.h"
66 24df9a28 2023-07-08 jrick #include "got_date.h"
67 24df9a28 2023-07-08 jrick
68 24df9a28 2023-07-08 jrick #ifndef nitems
69 24df9a28 2023-07-08 jrick #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
70 24df9a28 2023-07-08 jrick #endif
71 24df9a28 2023-07-08 jrick
72 24df9a28 2023-07-08 jrick static volatile sig_atomic_t sigint_received;
73 24df9a28 2023-07-08 jrick static volatile sig_atomic_t sigpipe_received;
74 24df9a28 2023-07-08 jrick
75 24df9a28 2023-07-08 jrick static void
76 24df9a28 2023-07-08 jrick catch_sigint(int signo)
77 24df9a28 2023-07-08 jrick {
78 24df9a28 2023-07-08 jrick sigint_received = 1;
79 24df9a28 2023-07-08 jrick }
80 24df9a28 2023-07-08 jrick
81 24df9a28 2023-07-08 jrick static void
82 24df9a28 2023-07-08 jrick catch_sigpipe(int signo)
83 24df9a28 2023-07-08 jrick {
84 24df9a28 2023-07-08 jrick sigpipe_received = 1;
85 24df9a28 2023-07-08 jrick }
86 24df9a28 2023-07-08 jrick
87 24df9a28 2023-07-08 jrick
88 24df9a28 2023-07-08 jrick struct got_cmd {
89 24df9a28 2023-07-08 jrick const char *cmd_name;
90 24df9a28 2023-07-08 jrick const struct got_error *(*cmd_main)(int, char *[]);
91 24df9a28 2023-07-08 jrick void (*cmd_usage)(void);
92 24df9a28 2023-07-08 jrick const char *cmd_alias;
93 24df9a28 2023-07-08 jrick };
94 24df9a28 2023-07-08 jrick
95 24df9a28 2023-07-08 jrick __dead static void usage(int, int);
96 24df9a28 2023-07-08 jrick __dead static void usage_import(void);
97 24df9a28 2023-07-08 jrick __dead static void usage_clone(void);
98 24df9a28 2023-07-08 jrick __dead static void usage_checkout(void);
99 24df9a28 2023-07-08 jrick __dead static void usage_update(void);
100 24df9a28 2023-07-08 jrick __dead static void usage_log(void);
101 24df9a28 2023-07-08 jrick __dead static void usage_diff(void);
102 24df9a28 2023-07-08 jrick __dead static void usage_blame(void);
103 24df9a28 2023-07-08 jrick __dead static void usage_tree(void);
104 24df9a28 2023-07-08 jrick __dead static void usage_status(void);
105 24df9a28 2023-07-08 jrick __dead static void usage_tag(void);
106 24df9a28 2023-07-08 jrick __dead static void usage_add(void);
107 24df9a28 2023-07-08 jrick __dead static void usage_remove(void);
108 24df9a28 2023-07-08 jrick __dead static void usage_patch(void);
109 24df9a28 2023-07-08 jrick __dead static void usage_revert(void);
110 24df9a28 2023-07-08 jrick __dead static void usage_commit(void);
111 24df9a28 2023-07-08 jrick __dead static void usage_cherrypick(void);
112 24df9a28 2023-07-08 jrick __dead static void usage_backout(void);
113 24df9a28 2023-07-08 jrick __dead static void usage_cat(void);
114 24df9a28 2023-07-08 jrick __dead static void usage_info(void);
115 24df9a28 2023-07-08 jrick
116 24df9a28 2023-07-08 jrick static const struct got_error* cmd_import(int, char *[]);
117 24df9a28 2023-07-08 jrick static const struct got_error* cmd_clone(int, char *[]);
118 24df9a28 2023-07-08 jrick static const struct got_error* cmd_checkout(int, char *[]);
119 24df9a28 2023-07-08 jrick static const struct got_error* cmd_update(int, char *[]);
120 24df9a28 2023-07-08 jrick static const struct got_error* cmd_log(int, char *[]);
121 24df9a28 2023-07-08 jrick static const struct got_error* cmd_diff(int, char *[]);
122 24df9a28 2023-07-08 jrick static const struct got_error* cmd_blame(int, char *[]);
123 24df9a28 2023-07-08 jrick static const struct got_error* cmd_tree(int, char *[]);
124 24df9a28 2023-07-08 jrick static const struct got_error* cmd_status(int, char *[]);
125 24df9a28 2023-07-08 jrick static const struct got_error* cmd_tag(int, char *[]);
126 24df9a28 2023-07-08 jrick static const struct got_error* cmd_add(int, char *[]);
127 24df9a28 2023-07-08 jrick static const struct got_error* cmd_remove(int, char *[]);
128 24df9a28 2023-07-08 jrick static const struct got_error* cmd_patch(int, char *[]);
129 24df9a28 2023-07-08 jrick static const struct got_error* cmd_revert(int, char *[]);
130 24df9a28 2023-07-08 jrick static const struct got_error* cmd_commit(int, char *[]);
131 24df9a28 2023-07-08 jrick static const struct got_error* cmd_cherrypick(int, char *[]);
132 24df9a28 2023-07-08 jrick static const struct got_error* cmd_backout(int, char *[]);
133 24df9a28 2023-07-08 jrick static const struct got_error* cmd_cat(int, char *[]);
134 24df9a28 2023-07-08 jrick static const struct got_error* cmd_info(int, char *[]);
135 24df9a28 2023-07-08 jrick
136 24df9a28 2023-07-08 jrick static const struct got_cmd got_commands[] = {
137 24df9a28 2023-07-08 jrick { "import", cmd_import, usage_import, "im" },
138 24df9a28 2023-07-08 jrick { "clone", cmd_clone, usage_clone, "cl" },
139 24df9a28 2023-07-08 jrick { "checkout", cmd_checkout, usage_checkout, "co" },
140 24df9a28 2023-07-08 jrick { "update", cmd_update, usage_update, "up" },
141 24df9a28 2023-07-08 jrick { "log", cmd_log, usage_log, "" },
142 24df9a28 2023-07-08 jrick { "diff", cmd_diff, usage_diff, "di" },
143 24df9a28 2023-07-08 jrick { "blame", cmd_blame, usage_blame, "bl" },
144 24df9a28 2023-07-08 jrick { "tree", cmd_tree, usage_tree, "tr" },
145 24df9a28 2023-07-08 jrick { "status", cmd_status, usage_status, "st" },
146 24df9a28 2023-07-08 jrick { "tag", cmd_tag, usage_tag, "" },
147 24df9a28 2023-07-08 jrick { "add", cmd_add, usage_add, "" },
148 24df9a28 2023-07-08 jrick { "remove", cmd_remove, usage_remove, "rm" },
149 24df9a28 2023-07-08 jrick { "patch", cmd_patch, usage_patch, "pa" },
150 24df9a28 2023-07-08 jrick { "revert", cmd_revert, usage_revert, "rv" },
151 24df9a28 2023-07-08 jrick { "commit", cmd_commit, usage_commit, "ci" },
152 24df9a28 2023-07-08 jrick { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
153 24df9a28 2023-07-08 jrick { "backout", cmd_backout, usage_backout, "bo" },
154 24df9a28 2023-07-08 jrick { "cat", cmd_cat, usage_cat, "" },
155 24df9a28 2023-07-08 jrick { "info", cmd_info, usage_info, "" },
156 24df9a28 2023-07-08 jrick };
157 24df9a28 2023-07-08 jrick
158 24df9a28 2023-07-08 jrick static void
159 24df9a28 2023-07-08 jrick list_commands(FILE *fp)
160 24df9a28 2023-07-08 jrick {
161 24df9a28 2023-07-08 jrick size_t i;
162 24df9a28 2023-07-08 jrick
163 24df9a28 2023-07-08 jrick fprintf(fp, "commands:");
164 24df9a28 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
165 24df9a28 2023-07-08 jrick const struct got_cmd *cmd = &got_commands[i];
166 24df9a28 2023-07-08 jrick fprintf(fp, " %s", cmd->cmd_name);
167 24df9a28 2023-07-08 jrick }
168 24df9a28 2023-07-08 jrick fputc('\n', fp);
169 24df9a28 2023-07-08 jrick }
170 24df9a28 2023-07-08 jrick
171 24df9a28 2023-07-08 jrick __dead static void
172 24df9a28 2023-07-08 jrick option_conflict(char a, char b)
173 24df9a28 2023-07-08 jrick {
174 24df9a28 2023-07-08 jrick errx(1, "-%c and -%c options are mutually exclusive", a, b);
175 24df9a28 2023-07-08 jrick }
176 24df9a28 2023-07-08 jrick
177 24df9a28 2023-07-08 jrick int
178 24df9a28 2023-07-08 jrick main(int argc, char *argv[])
179 24df9a28 2023-07-08 jrick {
180 24df9a28 2023-07-08 jrick const struct got_cmd *cmd;
181 24df9a28 2023-07-08 jrick size_t i;
182 24df9a28 2023-07-08 jrick int ch;
183 24df9a28 2023-07-08 jrick int hflag = 0, Vflag = 0;
184 24df9a28 2023-07-08 jrick static const struct option longopts[] = {
185 24df9a28 2023-07-08 jrick { "version", no_argument, NULL, 'V' },
186 24df9a28 2023-07-08 jrick { NULL, 0, NULL, 0 }
187 24df9a28 2023-07-08 jrick };
188 24df9a28 2023-07-08 jrick
189 24df9a28 2023-07-08 jrick setlocale(LC_CTYPE, "");
190 24df9a28 2023-07-08 jrick
191 24df9a28 2023-07-08 jrick while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
192 24df9a28 2023-07-08 jrick switch (ch) {
193 24df9a28 2023-07-08 jrick case 'h':
194 24df9a28 2023-07-08 jrick hflag = 1;
195 24df9a28 2023-07-08 jrick break;
196 24df9a28 2023-07-08 jrick case 'V':
197 24df9a28 2023-07-08 jrick Vflag = 1;
198 24df9a28 2023-07-08 jrick break;
199 24df9a28 2023-07-08 jrick default:
200 24df9a28 2023-07-08 jrick usage(hflag, 1);
201 24df9a28 2023-07-08 jrick /* NOTREACHED */
202 24df9a28 2023-07-08 jrick }
203 24df9a28 2023-07-08 jrick }
204 24df9a28 2023-07-08 jrick
205 24df9a28 2023-07-08 jrick argc -= optind;
206 24df9a28 2023-07-08 jrick argv += optind;
207 24df9a28 2023-07-08 jrick optind = 1;
208 24df9a28 2023-07-08 jrick optreset = 1;
209 24df9a28 2023-07-08 jrick
210 24df9a28 2023-07-08 jrick if (Vflag) {
211 24df9a28 2023-07-08 jrick got_version_print_str();
212 24df9a28 2023-07-08 jrick return 0;
213 24df9a28 2023-07-08 jrick }
214 24df9a28 2023-07-08 jrick
215 24df9a28 2023-07-08 jrick if (argc <= 0)
216 24df9a28 2023-07-08 jrick usage(hflag, hflag ? 0 : 1);
217 24df9a28 2023-07-08 jrick
218 24df9a28 2023-07-08 jrick signal(SIGINT, catch_sigint);
219 24df9a28 2023-07-08 jrick signal(SIGPIPE, catch_sigpipe);
220 24df9a28 2023-07-08 jrick
221 24df9a28 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
222 24df9a28 2023-07-08 jrick const struct got_error *error;
223 24df9a28 2023-07-08 jrick
224 24df9a28 2023-07-08 jrick cmd = &got_commands[i];
225 24df9a28 2023-07-08 jrick
226 24df9a28 2023-07-08 jrick if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
227 24df9a28 2023-07-08 jrick strcmp(cmd->cmd_alias, argv[0]) != 0)
228 24df9a28 2023-07-08 jrick continue;
229 24df9a28 2023-07-08 jrick
230 24df9a28 2023-07-08 jrick if (hflag)
231 24df9a28 2023-07-08 jrick cmd->cmd_usage();
232 24df9a28 2023-07-08 jrick
233 24df9a28 2023-07-08 jrick error = cmd->cmd_main(argc, argv);
234 24df9a28 2023-07-08 jrick if (error && error->code != GOT_ERR_CANCELLED &&
235 24df9a28 2023-07-08 jrick error->code != GOT_ERR_PRIVSEP_EXIT &&
236 24df9a28 2023-07-08 jrick !(sigpipe_received &&
237 24df9a28 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
238 24df9a28 2023-07-08 jrick !(sigint_received &&
239 24df9a28 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EINTR)) {
240 24df9a28 2023-07-08 jrick fflush(stdout);
241 24df9a28 2023-07-08 jrick fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
242 24df9a28 2023-07-08 jrick return 1;
243 24df9a28 2023-07-08 jrick }
244 24df9a28 2023-07-08 jrick
245 24df9a28 2023-07-08 jrick return 0;
246 24df9a28 2023-07-08 jrick }
247 24df9a28 2023-07-08 jrick
248 24df9a28 2023-07-08 jrick fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
249 24df9a28 2023-07-08 jrick list_commands(stderr);
250 24df9a28 2023-07-08 jrick return 1;
251 24df9a28 2023-07-08 jrick }
252 24df9a28 2023-07-08 jrick
253 24df9a28 2023-07-08 jrick __dead static void
254 24df9a28 2023-07-08 jrick usage(int hflag, int status)
255 24df9a28 2023-07-08 jrick {
256 24df9a28 2023-07-08 jrick FILE *fp = (status == 0) ? stdout : stderr;
257 24df9a28 2023-07-08 jrick
258 24df9a28 2023-07-08 jrick fprintf(fp, "usage: %s [-hV] command [arg ...]\n",
259 24df9a28 2023-07-08 jrick getprogname());
260 24df9a28 2023-07-08 jrick if (hflag)
261 24df9a28 2023-07-08 jrick list_commands(fp);
262 24df9a28 2023-07-08 jrick exit(status);
263 24df9a28 2023-07-08 jrick }
264 24df9a28 2023-07-08 jrick
265 24df9a28 2023-07-08 jrick static const struct got_error *
266 24df9a28 2023-07-08 jrick get_editor(char **abspath)
267 24df9a28 2023-07-08 jrick {
268 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
269 24df9a28 2023-07-08 jrick const char *editor;
270 24df9a28 2023-07-08 jrick
271 24df9a28 2023-07-08 jrick *abspath = NULL;
272 24df9a28 2023-07-08 jrick
273 24df9a28 2023-07-08 jrick editor = getenv("VISUAL");
274 24df9a28 2023-07-08 jrick if (editor == NULL)
275 24df9a28 2023-07-08 jrick editor = getenv("EDITOR");
276 24df9a28 2023-07-08 jrick
277 24df9a28 2023-07-08 jrick if (editor) {
278 24df9a28 2023-07-08 jrick err = got_path_find_prog(abspath, editor);
279 24df9a28 2023-07-08 jrick if (err)
280 24df9a28 2023-07-08 jrick return err;
281 24df9a28 2023-07-08 jrick }
282 24df9a28 2023-07-08 jrick
283 24df9a28 2023-07-08 jrick if (*abspath == NULL) {
284 24df9a28 2023-07-08 jrick *abspath = strdup("/usr/bin/vi");
285 24df9a28 2023-07-08 jrick if (*abspath == NULL)
286 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
287 24df9a28 2023-07-08 jrick }
288 24df9a28 2023-07-08 jrick
289 24df9a28 2023-07-08 jrick return NULL;
290 24df9a28 2023-07-08 jrick }
291 24df9a28 2023-07-08 jrick
292 24df9a28 2023-07-08 jrick static const struct got_error *
293 24df9a28 2023-07-08 jrick apply_unveil(const char *repo_path, int repo_read_only,
294 24df9a28 2023-07-08 jrick const char *worktree_path)
295 24df9a28 2023-07-08 jrick {
296 24df9a28 2023-07-08 jrick const struct got_error *err;
297 24df9a28 2023-07-08 jrick
298 24df9a28 2023-07-08 jrick #ifdef PROFILE
299 24df9a28 2023-07-08 jrick if (unveil("gmon.out", "rwc") != 0)
300 24df9a28 2023-07-08 jrick return got_error_from_errno2("unveil", "gmon.out");
301 24df9a28 2023-07-08 jrick #endif
302 24df9a28 2023-07-08 jrick if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
303 24df9a28 2023-07-08 jrick return got_error_from_errno2("unveil", repo_path);
304 24df9a28 2023-07-08 jrick
305 24df9a28 2023-07-08 jrick if (worktree_path && unveil(worktree_path, "rwc") != 0)
306 24df9a28 2023-07-08 jrick return got_error_from_errno2("unveil", worktree_path);
307 24df9a28 2023-07-08 jrick
308 24df9a28 2023-07-08 jrick if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
309 24df9a28 2023-07-08 jrick return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
310 24df9a28 2023-07-08 jrick
311 24df9a28 2023-07-08 jrick err = got_privsep_unveil_exec_helpers();
312 24df9a28 2023-07-08 jrick if (err != NULL)
313 24df9a28 2023-07-08 jrick return err;
314 24df9a28 2023-07-08 jrick
315 24df9a28 2023-07-08 jrick if (unveil(NULL, NULL) != 0)
316 24df9a28 2023-07-08 jrick return got_error_from_errno("unveil");
317 24df9a28 2023-07-08 jrick
318 24df9a28 2023-07-08 jrick return NULL;
319 24df9a28 2023-07-08 jrick }
320 24df9a28 2023-07-08 jrick
321 24df9a28 2023-07-08 jrick __dead static void
322 24df9a28 2023-07-08 jrick usage_import(void)
323 24df9a28 2023-07-08 jrick {
324 24df9a28 2023-07-08 jrick fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] "
325 24df9a28 2023-07-08 jrick "[-r repository-path] directory\n", getprogname());
326 24df9a28 2023-07-08 jrick exit(1);
327 24df9a28 2023-07-08 jrick }
328 24df9a28 2023-07-08 jrick
329 24df9a28 2023-07-08 jrick static int
330 24df9a28 2023-07-08 jrick spawn_editor(const char *editor, const char *file)
331 24df9a28 2023-07-08 jrick {
332 24df9a28 2023-07-08 jrick pid_t pid;
333 24df9a28 2023-07-08 jrick sig_t sighup, sigint, sigquit;
334 24df9a28 2023-07-08 jrick int st = -1;
335 24df9a28 2023-07-08 jrick
336 24df9a28 2023-07-08 jrick sighup = signal(SIGHUP, SIG_IGN);
337 24df9a28 2023-07-08 jrick sigint = signal(SIGINT, SIG_IGN);
338 24df9a28 2023-07-08 jrick sigquit = signal(SIGQUIT, SIG_IGN);
339 24df9a28 2023-07-08 jrick
340 24df9a28 2023-07-08 jrick switch (pid = fork()) {
341 24df9a28 2023-07-08 jrick case -1:
342 24df9a28 2023-07-08 jrick goto doneediting;
343 24df9a28 2023-07-08 jrick case 0:
344 24df9a28 2023-07-08 jrick execl(editor, editor, file, (char *)NULL);
345 24df9a28 2023-07-08 jrick _exit(127);
346 24df9a28 2023-07-08 jrick }
347 24df9a28 2023-07-08 jrick
348 24df9a28 2023-07-08 jrick while (waitpid(pid, &st, 0) == -1)
349 24df9a28 2023-07-08 jrick if (errno != EINTR)
350 24df9a28 2023-07-08 jrick break;
351 24df9a28 2023-07-08 jrick
352 24df9a28 2023-07-08 jrick doneediting:
353 24df9a28 2023-07-08 jrick (void)signal(SIGHUP, sighup);
354 24df9a28 2023-07-08 jrick (void)signal(SIGINT, sigint);
355 24df9a28 2023-07-08 jrick (void)signal(SIGQUIT, sigquit);
356 24df9a28 2023-07-08 jrick
357 24df9a28 2023-07-08 jrick if (!WIFEXITED(st)) {
358 24df9a28 2023-07-08 jrick errno = EINTR;
359 24df9a28 2023-07-08 jrick return -1;
360 24df9a28 2023-07-08 jrick }
361 24df9a28 2023-07-08 jrick
362 24df9a28 2023-07-08 jrick return WEXITSTATUS(st);
363 24df9a28 2023-07-08 jrick }
364 24df9a28 2023-07-08 jrick
365 24df9a28 2023-07-08 jrick static const struct got_error *
366 24df9a28 2023-07-08 jrick read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize)
367 24df9a28 2023-07-08 jrick {
368 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
369 24df9a28 2023-07-08 jrick char *line = NULL;
370 24df9a28 2023-07-08 jrick size_t linesize = 0;
371 24df9a28 2023-07-08 jrick
372 24df9a28 2023-07-08 jrick *logmsg = NULL;
373 24df9a28 2023-07-08 jrick *len = 0;
374 24df9a28 2023-07-08 jrick
375 24df9a28 2023-07-08 jrick if (fseeko(fp, 0L, SEEK_SET) == -1)
376 24df9a28 2023-07-08 jrick return got_error_from_errno("fseeko");
377 24df9a28 2023-07-08 jrick
378 24df9a28 2023-07-08 jrick *logmsg = malloc(filesize + 1);
379 24df9a28 2023-07-08 jrick if (*logmsg == NULL)
380 24df9a28 2023-07-08 jrick return got_error_from_errno("malloc");
381 24df9a28 2023-07-08 jrick (*logmsg)[0] = '\0';
382 24df9a28 2023-07-08 jrick
383 24df9a28 2023-07-08 jrick while (getline(&line, &linesize, fp) != -1) {
384 24df9a28 2023-07-08 jrick if (line[0] == '#' || (*len == 0 && line[0] == '\n'))
385 24df9a28 2023-07-08 jrick continue; /* remove comments and leading empty lines */
386 24df9a28 2023-07-08 jrick *len = strlcat(*logmsg, line, filesize + 1);
387 24df9a28 2023-07-08 jrick if (*len >= filesize + 1) {
388 24df9a28 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
389 24df9a28 2023-07-08 jrick goto done;
390 24df9a28 2023-07-08 jrick }
391 24df9a28 2023-07-08 jrick }
392 24df9a28 2023-07-08 jrick if (ferror(fp)) {
393 24df9a28 2023-07-08 jrick err = got_ferror(fp, GOT_ERR_IO);
394 24df9a28 2023-07-08 jrick goto done;
395 24df9a28 2023-07-08 jrick }
396 24df9a28 2023-07-08 jrick
397 24df9a28 2023-07-08 jrick while (*len > 0 && (*logmsg)[*len - 1] == '\n') {
398 24df9a28 2023-07-08 jrick (*logmsg)[*len - 1] = '\0';
399 24df9a28 2023-07-08 jrick (*len)--;
400 24df9a28 2023-07-08 jrick }
401 24df9a28 2023-07-08 jrick done:
402 24df9a28 2023-07-08 jrick free(line);
403 24df9a28 2023-07-08 jrick if (err) {
404 24df9a28 2023-07-08 jrick free(*logmsg);
405 24df9a28 2023-07-08 jrick *logmsg = NULL;
406 24df9a28 2023-07-08 jrick *len = 0;
407 24df9a28 2023-07-08 jrick }
408 24df9a28 2023-07-08 jrick return err;
409 24df9a28 2023-07-08 jrick }
410 24df9a28 2023-07-08 jrick
411 24df9a28 2023-07-08 jrick static const struct got_error *
412 24df9a28 2023-07-08 jrick edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
413 24df9a28 2023-07-08 jrick const char *initial_content, size_t initial_content_len,
414 24df9a28 2023-07-08 jrick int require_modification)
415 24df9a28 2023-07-08 jrick {
416 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
417 24df9a28 2023-07-08 jrick struct stat st, st2;
418 24df9a28 2023-07-08 jrick FILE *fp = NULL;
419 24df9a28 2023-07-08 jrick size_t logmsg_len;
420 24df9a28 2023-07-08 jrick
421 24df9a28 2023-07-08 jrick *logmsg = NULL;
422 24df9a28 2023-07-08 jrick
423 24df9a28 2023-07-08 jrick if (stat(logmsg_path, &st) == -1)
424 24df9a28 2023-07-08 jrick return got_error_from_errno2("stat", logmsg_path);
425 24df9a28 2023-07-08 jrick
426 24df9a28 2023-07-08 jrick if (spawn_editor(editor, logmsg_path) == -1)
427 24df9a28 2023-07-08 jrick return got_error_from_errno("failed spawning editor");
428 24df9a28 2023-07-08 jrick
429 24df9a28 2023-07-08 jrick if (require_modification) {
430 24df9a28 2023-07-08 jrick struct timespec timeout;
431 24df9a28 2023-07-08 jrick
432 24df9a28 2023-07-08 jrick timeout.tv_sec = 0;
433 24df9a28 2023-07-08 jrick timeout.tv_nsec = 1;
434 24df9a28 2023-07-08 jrick nanosleep(&timeout, NULL);
435 24df9a28 2023-07-08 jrick }
436 24df9a28 2023-07-08 jrick
437 24df9a28 2023-07-08 jrick if (stat(logmsg_path, &st2) == -1)
438 5a6c61ae 2023-07-15 naddy return got_error_from_errno2("stat", logmsg_path);
439 24df9a28 2023-07-08 jrick
440 24df9a28 2023-07-08 jrick if (require_modification && st.st_size == st2.st_size &&
441 24df9a28 2023-07-08 jrick timespeccmp(&st.st_mtim, &st2.st_mtim, ==))
442 24df9a28 2023-07-08 jrick return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
443 24df9a28 2023-07-08 jrick "no changes made to commit message, aborting");
444 24df9a28 2023-07-08 jrick
445 24df9a28 2023-07-08 jrick fp = fopen(logmsg_path, "re");
446 24df9a28 2023-07-08 jrick if (fp == NULL) {
447 24df9a28 2023-07-08 jrick err = got_error_from_errno("fopen");
448 24df9a28 2023-07-08 jrick goto done;
449 24df9a28 2023-07-08 jrick }
450 24df9a28 2023-07-08 jrick
451 24df9a28 2023-07-08 jrick /* strip comments and leading/trailing newlines */
452 24df9a28 2023-07-08 jrick err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size);
453 24df9a28 2023-07-08 jrick if (err)
454 24df9a28 2023-07-08 jrick goto done;
455 24df9a28 2023-07-08 jrick if (logmsg_len == 0) {
456 24df9a28 2023-07-08 jrick err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
457 24df9a28 2023-07-08 jrick "commit message cannot be empty, aborting");
458 24df9a28 2023-07-08 jrick goto done;
459 24df9a28 2023-07-08 jrick }
460 24df9a28 2023-07-08 jrick done:
461 24df9a28 2023-07-08 jrick if (fp && fclose(fp) == EOF && err == NULL)
462 24df9a28 2023-07-08 jrick err = got_error_from_errno("fclose");
463 24df9a28 2023-07-08 jrick if (err) {
464 24df9a28 2023-07-08 jrick free(*logmsg);
465 24df9a28 2023-07-08 jrick *logmsg = NULL;
466 24df9a28 2023-07-08 jrick }
467 24df9a28 2023-07-08 jrick return err;
468 24df9a28 2023-07-08 jrick }
469 24df9a28 2023-07-08 jrick
470 24df9a28 2023-07-08 jrick static const struct got_error *
471 24df9a28 2023-07-08 jrick collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
472 24df9a28 2023-07-08 jrick const char *path_dir, const char *branch_name)
473 24df9a28 2023-07-08 jrick {
474 24df9a28 2023-07-08 jrick char *initial_content = NULL;
475 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
476 24df9a28 2023-07-08 jrick int initial_content_len;
477 24df9a28 2023-07-08 jrick int fd = -1;
478 24df9a28 2023-07-08 jrick
479 24df9a28 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
480 24df9a28 2023-07-08 jrick "\n# %s to be imported to branch %s\n", path_dir,
481 24df9a28 2023-07-08 jrick branch_name);
482 24df9a28 2023-07-08 jrick if (initial_content_len == -1)
483 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
484 24df9a28 2023-07-08 jrick
485 24df9a28 2023-07-08 jrick err = got_opentemp_named_fd(logmsg_path, &fd,
486 24df9a28 2023-07-08 jrick GOT_TMPDIR_STR "/got-importmsg", "");
487 24df9a28 2023-07-08 jrick if (err)
488 24df9a28 2023-07-08 jrick goto done;
489 24df9a28 2023-07-08 jrick
490 24df9a28 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
491 24df9a28 2023-07-08 jrick err = got_error_from_errno2("write", *logmsg_path);
492 24df9a28 2023-07-08 jrick goto done;
493 24df9a28 2023-07-08 jrick }
494 24df9a28 2023-07-08 jrick if (close(fd) == -1) {
495 24df9a28 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
496 24df9a28 2023-07-08 jrick goto done;
497 24df9a28 2023-07-08 jrick }
498 24df9a28 2023-07-08 jrick fd = -1;
499 24df9a28 2023-07-08 jrick
500 24df9a28 2023-07-08 jrick err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
501 24df9a28 2023-07-08 jrick initial_content_len, 1);
502 24df9a28 2023-07-08 jrick done:
503 24df9a28 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
504 24df9a28 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
505 24df9a28 2023-07-08 jrick free(initial_content);
506 24df9a28 2023-07-08 jrick if (err) {
507 24df9a28 2023-07-08 jrick free(*logmsg_path);
508 24df9a28 2023-07-08 jrick *logmsg_path = NULL;
509 24df9a28 2023-07-08 jrick }
510 24df9a28 2023-07-08 jrick return err;
511 24df9a28 2023-07-08 jrick }
512 24df9a28 2023-07-08 jrick
513 24df9a28 2023-07-08 jrick static const struct got_error *
514 24df9a28 2023-07-08 jrick import_progress(void *arg, const char *path)
515 24df9a28 2023-07-08 jrick {
516 24df9a28 2023-07-08 jrick printf("A %s\n", path);
517 24df9a28 2023-07-08 jrick return NULL;
518 24df9a28 2023-07-08 jrick }
519 24df9a28 2023-07-08 jrick
520 24df9a28 2023-07-08 jrick static const struct got_error *
521 24df9a28 2023-07-08 jrick valid_author(const char *author)
522 24df9a28 2023-07-08 jrick {
523 24df9a28 2023-07-08 jrick const char *email = author;
524 24df9a28 2023-07-08 jrick
525 24df9a28 2023-07-08 jrick /*
526 24df9a28 2023-07-08 jrick * Git' expects the author (or committer) to be in the form
527 24df9a28 2023-07-08 jrick * "name <email>", which are mostly free form (see the
528 24df9a28 2023-07-08 jrick * "committer" description in git-fast-import(1)). We're only
529 24df9a28 2023-07-08 jrick * doing this to avoid git's object parser breaking on commits
530 24df9a28 2023-07-08 jrick * we create.
531 24df9a28 2023-07-08 jrick */
532 24df9a28 2023-07-08 jrick
533 24df9a28 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
534 24df9a28 2023-07-08 jrick author++;
535 24df9a28 2023-07-08 jrick if (author != email && *author == '<' && *(author - 1) != ' ')
536 24df9a28 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space "
537 24df9a28 2023-07-08 jrick "between author name and email required", email);
538 24df9a28 2023-07-08 jrick if (*author++ != '<')
539 24df9a28 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
540 24df9a28 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
541 24df9a28 2023-07-08 jrick author++;
542 24df9a28 2023-07-08 jrick if (strcmp(author, ">") != 0)
543 24df9a28 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
544 24df9a28 2023-07-08 jrick return NULL;
545 24df9a28 2023-07-08 jrick }
546 24df9a28 2023-07-08 jrick
547 24df9a28 2023-07-08 jrick static const struct got_error *
548 24df9a28 2023-07-08 jrick get_author(char **author, struct got_repository *repo,
549 24df9a28 2023-07-08 jrick struct got_worktree *worktree)
550 24df9a28 2023-07-08 jrick {
551 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
552 24df9a28 2023-07-08 jrick const char *got_author = NULL, *name, *email;
553 24df9a28 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
554 24df9a28 2023-07-08 jrick
555 24df9a28 2023-07-08 jrick *author = NULL;
556 24df9a28 2023-07-08 jrick
557 24df9a28 2023-07-08 jrick if (worktree)
558 24df9a28 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
559 24df9a28 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
560 24df9a28 2023-07-08 jrick
561 24df9a28 2023-07-08 jrick /*
562 24df9a28 2023-07-08 jrick * Priority of potential author information sources, from most
563 24df9a28 2023-07-08 jrick * significant to least significant:
564 24df9a28 2023-07-08 jrick * 1) work tree's .got/got.conf file
565 24df9a28 2023-07-08 jrick * 2) repository's got.conf file
566 24df9a28 2023-07-08 jrick * 3) repository's git config file
567 24df9a28 2023-07-08 jrick * 4) environment variables
568 24df9a28 2023-07-08 jrick * 5) global git config files (in user's home directory or /etc)
569 24df9a28 2023-07-08 jrick */
570 24df9a28 2023-07-08 jrick
571 24df9a28 2023-07-08 jrick if (worktree_conf)
572 24df9a28 2023-07-08 jrick got_author = got_gotconfig_get_author(worktree_conf);
573 24df9a28 2023-07-08 jrick if (got_author == NULL)
574 24df9a28 2023-07-08 jrick got_author = got_gotconfig_get_author(repo_conf);
575 24df9a28 2023-07-08 jrick if (got_author == NULL) {
576 24df9a28 2023-07-08 jrick name = got_repo_get_gitconfig_author_name(repo);
577 24df9a28 2023-07-08 jrick email = got_repo_get_gitconfig_author_email(repo);
578 24df9a28 2023-07-08 jrick if (name && email) {
579 24df9a28 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email) == -1)
580 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
581 24df9a28 2023-07-08 jrick return NULL;
582 24df9a28 2023-07-08 jrick }
583 24df9a28 2023-07-08 jrick
584 24df9a28 2023-07-08 jrick got_author = getenv("GOT_AUTHOR");
585 24df9a28 2023-07-08 jrick if (got_author == NULL) {
586 24df9a28 2023-07-08 jrick name = got_repo_get_global_gitconfig_author_name(repo);
587 24df9a28 2023-07-08 jrick email = got_repo_get_global_gitconfig_author_email(
588 24df9a28 2023-07-08 jrick repo);
589 24df9a28 2023-07-08 jrick if (name && email) {
590 24df9a28 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email)
591 24df9a28 2023-07-08 jrick == -1)
592 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
593 24df9a28 2023-07-08 jrick return NULL;
594 24df9a28 2023-07-08 jrick }
595 24df9a28 2023-07-08 jrick /* TODO: Look up user in password database? */
596 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
597 24df9a28 2023-07-08 jrick }
598 24df9a28 2023-07-08 jrick }
599 24df9a28 2023-07-08 jrick
600 24df9a28 2023-07-08 jrick *author = strdup(got_author);
601 24df9a28 2023-07-08 jrick if (*author == NULL)
602 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
603 24df9a28 2023-07-08 jrick
604 24df9a28 2023-07-08 jrick err = valid_author(*author);
605 24df9a28 2023-07-08 jrick if (err) {
606 24df9a28 2023-07-08 jrick free(*author);
607 24df9a28 2023-07-08 jrick *author = NULL;
608 24df9a28 2023-07-08 jrick }
609 24df9a28 2023-07-08 jrick return err;
610 24df9a28 2023-07-08 jrick }
611 24df9a28 2023-07-08 jrick
612 24df9a28 2023-07-08 jrick static const struct got_error *
613 24df9a28 2023-07-08 jrick get_allowed_signers(char **allowed_signers, struct got_repository *repo,
614 24df9a28 2023-07-08 jrick struct got_worktree *worktree)
615 24df9a28 2023-07-08 jrick {
616 24df9a28 2023-07-08 jrick const char *got_allowed_signers = NULL;
617 24df9a28 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
618 24df9a28 2023-07-08 jrick
619 24df9a28 2023-07-08 jrick *allowed_signers = NULL;
620 24df9a28 2023-07-08 jrick
621 24df9a28 2023-07-08 jrick if (worktree)
622 24df9a28 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
623 24df9a28 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
624 24df9a28 2023-07-08 jrick
625 24df9a28 2023-07-08 jrick /*
626 24df9a28 2023-07-08 jrick * Priority of potential author information sources, from most
627 24df9a28 2023-07-08 jrick * significant to least significant:
628 24df9a28 2023-07-08 jrick * 1) work tree's .got/got.conf file
629 24df9a28 2023-07-08 jrick * 2) repository's got.conf file
630 24df9a28 2023-07-08 jrick */
631 24df9a28 2023-07-08 jrick
632 24df9a28 2023-07-08 jrick if (worktree_conf)
633 24df9a28 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
634 24df9a28 2023-07-08 jrick worktree_conf);
635 24df9a28 2023-07-08 jrick if (got_allowed_signers == NULL)
636 24df9a28 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
637 24df9a28 2023-07-08 jrick repo_conf);
638 24df9a28 2023-07-08 jrick
639 24df9a28 2023-07-08 jrick if (got_allowed_signers) {
640 24df9a28 2023-07-08 jrick *allowed_signers = strdup(got_allowed_signers);
641 24df9a28 2023-07-08 jrick if (*allowed_signers == NULL)
642 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
643 24df9a28 2023-07-08 jrick }
644 24df9a28 2023-07-08 jrick return NULL;
645 24df9a28 2023-07-08 jrick }
646 24df9a28 2023-07-08 jrick
647 24df9a28 2023-07-08 jrick static const struct got_error *
648 24df9a28 2023-07-08 jrick get_revoked_signers(char **revoked_signers, struct got_repository *repo,
649 24df9a28 2023-07-08 jrick struct got_worktree *worktree)
650 24df9a28 2023-07-08 jrick {
651 24df9a28 2023-07-08 jrick const char *got_revoked_signers = NULL;
652 24df9a28 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
653 24df9a28 2023-07-08 jrick
654 24df9a28 2023-07-08 jrick *revoked_signers = NULL;
655 24df9a28 2023-07-08 jrick
656 24df9a28 2023-07-08 jrick if (worktree)
657 24df9a28 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
658 24df9a28 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
659 24df9a28 2023-07-08 jrick
660 24df9a28 2023-07-08 jrick /*
661 24df9a28 2023-07-08 jrick * Priority of potential author information sources, from most
662 24df9a28 2023-07-08 jrick * significant to least significant:
663 24df9a28 2023-07-08 jrick * 1) work tree's .got/got.conf file
664 24df9a28 2023-07-08 jrick * 2) repository's got.conf file
665 24df9a28 2023-07-08 jrick */
666 24df9a28 2023-07-08 jrick
667 24df9a28 2023-07-08 jrick if (worktree_conf)
668 24df9a28 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
669 24df9a28 2023-07-08 jrick worktree_conf);
670 24df9a28 2023-07-08 jrick if (got_revoked_signers == NULL)
671 24df9a28 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
672 24df9a28 2023-07-08 jrick repo_conf);
673 24df9a28 2023-07-08 jrick
674 24df9a28 2023-07-08 jrick if (got_revoked_signers) {
675 24df9a28 2023-07-08 jrick *revoked_signers = strdup(got_revoked_signers);
676 24df9a28 2023-07-08 jrick if (*revoked_signers == NULL)
677 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
678 24df9a28 2023-07-08 jrick }
679 24df9a28 2023-07-08 jrick return NULL;
680 24df9a28 2023-07-08 jrick }
681 24df9a28 2023-07-08 jrick
682 24df9a28 2023-07-08 jrick static const char *
683 24df9a28 2023-07-08 jrick get_signer_id(struct got_repository *repo, struct got_worktree *worktree)
684 24df9a28 2023-07-08 jrick {
685 24df9a28 2023-07-08 jrick const char *got_signer_id = NULL;
686 24df9a28 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
687 24df9a28 2023-07-08 jrick
688 24df9a28 2023-07-08 jrick if (worktree)
689 24df9a28 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
690 24df9a28 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
691 24df9a28 2023-07-08 jrick
692 24df9a28 2023-07-08 jrick /*
693 24df9a28 2023-07-08 jrick * Priority of potential author information sources, from most
694 24df9a28 2023-07-08 jrick * significant to least significant:
695 24df9a28 2023-07-08 jrick * 1) work tree's .got/got.conf file
696 24df9a28 2023-07-08 jrick * 2) repository's got.conf file
697 24df9a28 2023-07-08 jrick */
698 24df9a28 2023-07-08 jrick
699 24df9a28 2023-07-08 jrick if (worktree_conf)
700 24df9a28 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(worktree_conf);
701 24df9a28 2023-07-08 jrick if (got_signer_id == NULL)
702 24df9a28 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(repo_conf);
703 24df9a28 2023-07-08 jrick
704 24df9a28 2023-07-08 jrick return got_signer_id;
705 24df9a28 2023-07-08 jrick }
706 24df9a28 2023-07-08 jrick
707 24df9a28 2023-07-08 jrick static const struct got_error *
708 24df9a28 2023-07-08 jrick get_gitconfig_path(char **gitconfig_path)
709 24df9a28 2023-07-08 jrick {
710 24df9a28 2023-07-08 jrick const char *homedir = getenv("HOME");
711 24df9a28 2023-07-08 jrick
712 24df9a28 2023-07-08 jrick *gitconfig_path = NULL;
713 24df9a28 2023-07-08 jrick if (homedir) {
714 24df9a28 2023-07-08 jrick if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
715 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
716 24df9a28 2023-07-08 jrick
717 24df9a28 2023-07-08 jrick }
718 24df9a28 2023-07-08 jrick return NULL;
719 24df9a28 2023-07-08 jrick }
720 24df9a28 2023-07-08 jrick
721 24df9a28 2023-07-08 jrick static const struct got_error *
722 24df9a28 2023-07-08 jrick cmd_import(int argc, char *argv[])
723 24df9a28 2023-07-08 jrick {
724 24df9a28 2023-07-08 jrick const struct got_error *error = NULL;
725 24df9a28 2023-07-08 jrick char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
726 24df9a28 2023-07-08 jrick char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
727 24df9a28 2023-07-08 jrick const char *branch_name = NULL;
728 24df9a28 2023-07-08 jrick char *id_str = NULL, *logmsg_path = NULL;
729 24df9a28 2023-07-08 jrick char refname[PATH_MAX] = "refs/heads/";
730 24df9a28 2023-07-08 jrick struct got_repository *repo = NULL;
731 24df9a28 2023-07-08 jrick struct got_reference *branch_ref = NULL, *head_ref = NULL;
732 24df9a28 2023-07-08 jrick struct got_object_id *new_commit_id = NULL;
733 24df9a28 2023-07-08 jrick int ch, n = 0;
734 24df9a28 2023-07-08 jrick struct got_pathlist_head ignores;
735 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
736 24df9a28 2023-07-08 jrick int preserve_logmsg = 0;
737 24df9a28 2023-07-08 jrick int *pack_fds = NULL;
738 24df9a28 2023-07-08 jrick
739 24df9a28 2023-07-08 jrick TAILQ_INIT(&ignores);
740 24df9a28 2023-07-08 jrick
741 24df9a28 2023-07-08 jrick #ifndef PROFILE
742 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
743 24df9a28 2023-07-08 jrick "unveil",
744 24df9a28 2023-07-08 jrick NULL) == -1)
745 24df9a28 2023-07-08 jrick err(1, "pledge");
746 24df9a28 2023-07-08 jrick #endif
747 24df9a28 2023-07-08 jrick
748 24df9a28 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) {
749 24df9a28 2023-07-08 jrick switch (ch) {
750 24df9a28 2023-07-08 jrick case 'b':
751 24df9a28 2023-07-08 jrick branch_name = optarg;
752 24df9a28 2023-07-08 jrick break;
753 24df9a28 2023-07-08 jrick case 'I':
754 24df9a28 2023-07-08 jrick if (optarg[0] == '\0')
755 24df9a28 2023-07-08 jrick break;
756 24df9a28 2023-07-08 jrick error = got_pathlist_insert(&pe, &ignores, optarg,
757 24df9a28 2023-07-08 jrick NULL);
758 24df9a28 2023-07-08 jrick if (error)
759 24df9a28 2023-07-08 jrick goto done;
760 24df9a28 2023-07-08 jrick break;
761 24df9a28 2023-07-08 jrick case 'm':
762 24df9a28 2023-07-08 jrick logmsg = strdup(optarg);
763 24df9a28 2023-07-08 jrick if (logmsg == NULL) {
764 24df9a28 2023-07-08 jrick error = got_error_from_errno("strdup");
765 24df9a28 2023-07-08 jrick goto done;
766 24df9a28 2023-07-08 jrick }
767 24df9a28 2023-07-08 jrick break;
768 24df9a28 2023-07-08 jrick case 'r':
769 24df9a28 2023-07-08 jrick repo_path = realpath(optarg, NULL);
770 24df9a28 2023-07-08 jrick if (repo_path == NULL) {
771 24df9a28 2023-07-08 jrick error = got_error_from_errno2("realpath",
772 24df9a28 2023-07-08 jrick optarg);
773 24df9a28 2023-07-08 jrick goto done;
774 24df9a28 2023-07-08 jrick }
775 24df9a28 2023-07-08 jrick break;
776 24df9a28 2023-07-08 jrick default:
777 24df9a28 2023-07-08 jrick usage_import();
778 24df9a28 2023-07-08 jrick /* NOTREACHED */
779 24df9a28 2023-07-08 jrick }
780 24df9a28 2023-07-08 jrick }
781 24df9a28 2023-07-08 jrick
782 24df9a28 2023-07-08 jrick argc -= optind;
783 24df9a28 2023-07-08 jrick argv += optind;
784 24df9a28 2023-07-08 jrick
785 24df9a28 2023-07-08 jrick if (argc != 1)
786 24df9a28 2023-07-08 jrick usage_import();
787 24df9a28 2023-07-08 jrick
788 24df9a28 2023-07-08 jrick if (repo_path == NULL) {
789 24df9a28 2023-07-08 jrick repo_path = getcwd(NULL, 0);
790 24df9a28 2023-07-08 jrick if (repo_path == NULL)
791 24df9a28 2023-07-08 jrick return got_error_from_errno("getcwd");
792 24df9a28 2023-07-08 jrick }
793 24df9a28 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
794 24df9a28 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
795 24df9a28 2023-07-08 jrick if (error)
796 24df9a28 2023-07-08 jrick goto done;
797 24df9a28 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
798 24df9a28 2023-07-08 jrick if (error != NULL)
799 24df9a28 2023-07-08 jrick goto done;
800 24df9a28 2023-07-08 jrick error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds);
801 24df9a28 2023-07-08 jrick if (error)
802 24df9a28 2023-07-08 jrick goto done;
803 24df9a28 2023-07-08 jrick
804 24df9a28 2023-07-08 jrick error = get_author(&author, repo, NULL);
805 24df9a28 2023-07-08 jrick if (error)
806 24df9a28 2023-07-08 jrick return error;
807 24df9a28 2023-07-08 jrick
808 24df9a28 2023-07-08 jrick /*
809 24df9a28 2023-07-08 jrick * Don't let the user create a branch name with a leading '-'.
810 24df9a28 2023-07-08 jrick * While technically a valid reference name, this case is usually
811 24df9a28 2023-07-08 jrick * an unintended typo.
812 24df9a28 2023-07-08 jrick */
813 24df9a28 2023-07-08 jrick if (branch_name && branch_name[0] == '-')
814 24df9a28 2023-07-08 jrick return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
815 24df9a28 2023-07-08 jrick
816 24df9a28 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
817 24df9a28 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_REF)
818 24df9a28 2023-07-08 jrick goto done;
819 24df9a28 2023-07-08 jrick
820 24df9a28 2023-07-08 jrick if (branch_name)
821 24df9a28 2023-07-08 jrick n = strlcat(refname, branch_name, sizeof(refname));
822 24df9a28 2023-07-08 jrick else if (head_ref && got_ref_is_symbolic(head_ref))
823 24df9a28 2023-07-08 jrick n = strlcpy(refname, got_ref_get_symref_target(head_ref),
824 24df9a28 2023-07-08 jrick sizeof(refname));
825 24df9a28 2023-07-08 jrick else
826 24df9a28 2023-07-08 jrick n = strlcat(refname, "main", sizeof(refname));
827 24df9a28 2023-07-08 jrick if (n >= sizeof(refname)) {
828 24df9a28 2023-07-08 jrick error = got_error(GOT_ERR_NO_SPACE);
829 24df9a28 2023-07-08 jrick goto done;
830 24df9a28 2023-07-08 jrick }
831 24df9a28 2023-07-08 jrick
832 24df9a28 2023-07-08 jrick error = got_ref_open(&branch_ref, repo, refname, 0);
833 24df9a28 2023-07-08 jrick if (error) {
834 24df9a28 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
835 24df9a28 2023-07-08 jrick goto done;
836 24df9a28 2023-07-08 jrick } else {
837 24df9a28 2023-07-08 jrick error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
838 24df9a28 2023-07-08 jrick "import target branch already exists");
839 24df9a28 2023-07-08 jrick goto done;
840 24df9a28 2023-07-08 jrick }
841 24df9a28 2023-07-08 jrick
842 24df9a28 2023-07-08 jrick path_dir = realpath(argv[0], NULL);
843 24df9a28 2023-07-08 jrick if (path_dir == NULL) {
844 24df9a28 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
845 24df9a28 2023-07-08 jrick goto done;
846 24df9a28 2023-07-08 jrick }
847 24df9a28 2023-07-08 jrick got_path_strip_trailing_slashes(path_dir);
848 24df9a28 2023-07-08 jrick
849 24df9a28 2023-07-08 jrick /*
850 24df9a28 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have
851 24df9a28 2023-07-08 jrick * to apply unveil after the log message has been written.
852 24df9a28 2023-07-08 jrick */
853 24df9a28 2023-07-08 jrick if (logmsg == NULL || *logmsg == '\0') {
854 24df9a28 2023-07-08 jrick error = get_editor(&editor);
855 24df9a28 2023-07-08 jrick if (error)
856 24df9a28 2023-07-08 jrick goto done;
857 24df9a28 2023-07-08 jrick free(logmsg);
858 24df9a28 2023-07-08 jrick error = collect_import_msg(&logmsg, &logmsg_path, editor,
859 24df9a28 2023-07-08 jrick path_dir, refname);
860 24df9a28 2023-07-08 jrick if (error) {
861 24df9a28 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
862 24df9a28 2023-07-08 jrick logmsg_path != NULL)
863 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
864 24df9a28 2023-07-08 jrick goto done;
865 24df9a28 2023-07-08 jrick }
866 24df9a28 2023-07-08 jrick }
867 24df9a28 2023-07-08 jrick
868 24df9a28 2023-07-08 jrick if (unveil(path_dir, "r") != 0) {
869 24df9a28 2023-07-08 jrick error = got_error_from_errno2("unveil", path_dir);
870 24df9a28 2023-07-08 jrick if (logmsg_path)
871 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
872 24df9a28 2023-07-08 jrick goto done;
873 24df9a28 2023-07-08 jrick }
874 24df9a28 2023-07-08 jrick
875 24df9a28 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
876 24df9a28 2023-07-08 jrick if (error) {
877 24df9a28 2023-07-08 jrick if (logmsg_path)
878 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
879 24df9a28 2023-07-08 jrick goto done;
880 24df9a28 2023-07-08 jrick }
881 24df9a28 2023-07-08 jrick
882 24df9a28 2023-07-08 jrick error = got_repo_import(&new_commit_id, path_dir, logmsg,
883 24df9a28 2023-07-08 jrick author, &ignores, repo, import_progress, NULL);
884 24df9a28 2023-07-08 jrick if (error) {
885 24df9a28 2023-07-08 jrick if (logmsg_path)
886 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
887 24df9a28 2023-07-08 jrick goto done;
888 24df9a28 2023-07-08 jrick }
889 24df9a28 2023-07-08 jrick
890 24df9a28 2023-07-08 jrick error = got_ref_alloc(&branch_ref, refname, new_commit_id);
891 24df9a28 2023-07-08 jrick if (error) {
892 24df9a28 2023-07-08 jrick if (logmsg_path)
893 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
894 24df9a28 2023-07-08 jrick goto done;
895 24df9a28 2023-07-08 jrick }
896 24df9a28 2023-07-08 jrick
897 24df9a28 2023-07-08 jrick error = got_ref_write(branch_ref, repo);
898 24df9a28 2023-07-08 jrick if (error) {
899 24df9a28 2023-07-08 jrick if (logmsg_path)
900 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
901 24df9a28 2023-07-08 jrick goto done;
902 24df9a28 2023-07-08 jrick }
903 24df9a28 2023-07-08 jrick
904 24df9a28 2023-07-08 jrick error = got_object_id_str(&id_str, new_commit_id);
905 24df9a28 2023-07-08 jrick if (error) {
906 24df9a28 2023-07-08 jrick if (logmsg_path)
907 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
908 24df9a28 2023-07-08 jrick goto done;
909 24df9a28 2023-07-08 jrick }
910 24df9a28 2023-07-08 jrick
911 24df9a28 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
912 24df9a28 2023-07-08 jrick if (error) {
913 24df9a28 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF) {
914 24df9a28 2023-07-08 jrick if (logmsg_path)
915 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
916 24df9a28 2023-07-08 jrick goto done;
917 24df9a28 2023-07-08 jrick }
918 24df9a28 2023-07-08 jrick
919 24df9a28 2023-07-08 jrick error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
920 24df9a28 2023-07-08 jrick branch_ref);
921 24df9a28 2023-07-08 jrick if (error) {
922 24df9a28 2023-07-08 jrick if (logmsg_path)
923 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
924 24df9a28 2023-07-08 jrick goto done;
925 24df9a28 2023-07-08 jrick }
926 24df9a28 2023-07-08 jrick
927 24df9a28 2023-07-08 jrick error = got_ref_write(head_ref, repo);
928 24df9a28 2023-07-08 jrick if (error) {
929 24df9a28 2023-07-08 jrick if (logmsg_path)
930 24df9a28 2023-07-08 jrick preserve_logmsg = 1;
931 24df9a28 2023-07-08 jrick goto done;
932 24df9a28 2023-07-08 jrick }
933 24df9a28 2023-07-08 jrick }
934 24df9a28 2023-07-08 jrick
935 24df9a28 2023-07-08 jrick printf("Created branch %s with commit %s\n",
936 24df9a28 2023-07-08 jrick got_ref_get_name(branch_ref), id_str);
937 24df9a28 2023-07-08 jrick done:
938 24df9a28 2023-07-08 jrick if (pack_fds) {
939 24df9a28 2023-07-08 jrick const struct got_error *pack_err =
940 24df9a28 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
941 24df9a28 2023-07-08 jrick if (error == NULL)
942 24df9a28 2023-07-08 jrick error = pack_err;
943 24df9a28 2023-07-08 jrick }
944 24df9a28 2023-07-08 jrick if (repo) {
945 24df9a28 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
946 24df9a28 2023-07-08 jrick if (error == NULL)
947 24df9a28 2023-07-08 jrick error = close_err;
948 24df9a28 2023-07-08 jrick }
949 24df9a28 2023-07-08 jrick if (preserve_logmsg) {
950 24df9a28 2023-07-08 jrick fprintf(stderr, "%s: log message preserved in %s\n",
951 24df9a28 2023-07-08 jrick getprogname(), logmsg_path);
952 24df9a28 2023-07-08 jrick } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
953 24df9a28 2023-07-08 jrick error = got_error_from_errno2("unlink", logmsg_path);
954 24df9a28 2023-07-08 jrick free(logmsg);
955 24df9a28 2023-07-08 jrick free(logmsg_path);
956 24df9a28 2023-07-08 jrick free(repo_path);
957 24df9a28 2023-07-08 jrick free(editor);
958 24df9a28 2023-07-08 jrick free(new_commit_id);
959 24df9a28 2023-07-08 jrick free(id_str);
960 24df9a28 2023-07-08 jrick free(author);
961 24df9a28 2023-07-08 jrick free(gitconfig_path);
962 24df9a28 2023-07-08 jrick if (branch_ref)
963 24df9a28 2023-07-08 jrick got_ref_close(branch_ref);
964 24df9a28 2023-07-08 jrick if (head_ref)
965 24df9a28 2023-07-08 jrick got_ref_close(head_ref);
966 24df9a28 2023-07-08 jrick return error;
967 24df9a28 2023-07-08 jrick }
968 24df9a28 2023-07-08 jrick
969 24df9a28 2023-07-08 jrick __dead static void
970 24df9a28 2023-07-08 jrick usage_clone(void)
971 24df9a28 2023-07-08 jrick {
972 24df9a28 2023-07-08 jrick fprintf(stderr, "usage: %s clone [-almqv] [-b branch] [-R reference] "
973 24df9a28 2023-07-08 jrick "repository-URL [directory]\n", getprogname());
974 24df9a28 2023-07-08 jrick exit(1);
975 24df9a28 2023-07-08 jrick }
976 24df9a28 2023-07-08 jrick
977 24df9a28 2023-07-08 jrick struct got_fetch_progress_arg {
978 24df9a28 2023-07-08 jrick char last_scaled_size[FMT_SCALED_STRSIZE];
979 24df9a28 2023-07-08 jrick int last_p_indexed;
980 24df9a28 2023-07-08 jrick int last_p_resolved;
981 24df9a28 2023-07-08 jrick int verbosity;
982 24df9a28 2023-07-08 jrick
983 24df9a28 2023-07-08 jrick struct got_repository *repo;
984 24df9a28 2023-07-08 jrick
985 24df9a28 2023-07-08 jrick int create_configs;
986 24df9a28 2023-07-08 jrick int configs_created;
987 24df9a28 2023-07-08 jrick struct {
988 24df9a28 2023-07-08 jrick struct got_pathlist_head *symrefs;
989 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_branches;
990 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_refs;
991 24df9a28 2023-07-08 jrick const char *proto;
992 24df9a28 2023-07-08 jrick const char *host;
993 24df9a28 2023-07-08 jrick const char *port;
994 24df9a28 2023-07-08 jrick const char *remote_repo_path;
995 24df9a28 2023-07-08 jrick const char *git_url;
996 24df9a28 2023-07-08 jrick int fetch_all_branches;
997 24df9a28 2023-07-08 jrick int mirror_references;
998 24df9a28 2023-07-08 jrick } config_info;
999 24df9a28 2023-07-08 jrick };
1000 24df9a28 2023-07-08 jrick
1001 24df9a28 2023-07-08 jrick /* XXX forward declaration */
1002 24df9a28 2023-07-08 jrick static const struct got_error *
1003 24df9a28 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1004 24df9a28 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1005 24df9a28 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1006 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1007 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo);
1008 24df9a28 2023-07-08 jrick
1009 24df9a28 2023-07-08 jrick static const struct got_error *
1010 24df9a28 2023-07-08 jrick fetch_progress(void *arg, const char *message, off_t packfile_size,
1011 24df9a28 2023-07-08 jrick int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
1012 24df9a28 2023-07-08 jrick {
1013 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1014 24df9a28 2023-07-08 jrick struct got_fetch_progress_arg *a = arg;
1015 24df9a28 2023-07-08 jrick char scaled_size[FMT_SCALED_STRSIZE];
1016 24df9a28 2023-07-08 jrick int p_indexed, p_resolved;
1017 24df9a28 2023-07-08 jrick int print_size = 0, print_indexed = 0, print_resolved = 0;
1018 24df9a28 2023-07-08 jrick
1019 24df9a28 2023-07-08 jrick /*
1020 24df9a28 2023-07-08 jrick * In order to allow a failed clone to be resumed with 'got fetch'
1021 24df9a28 2023-07-08 jrick * we try to create configuration files as soon as possible.
1022 24df9a28 2023-07-08 jrick * Once the server has sent information about its default branch
1023 24df9a28 2023-07-08 jrick * we have all required information.
1024 24df9a28 2023-07-08 jrick */
1025 24df9a28 2023-07-08 jrick if (a->create_configs && !a->configs_created &&
1026 24df9a28 2023-07-08 jrick !TAILQ_EMPTY(a->config_info.symrefs)) {
1027 24df9a28 2023-07-08 jrick err = create_config_files(a->config_info.proto,
1028 24df9a28 2023-07-08 jrick a->config_info.host, a->config_info.port,
1029 24df9a28 2023-07-08 jrick a->config_info.remote_repo_path,
1030 24df9a28 2023-07-08 jrick a->config_info.git_url,
1031 24df9a28 2023-07-08 jrick a->config_info.fetch_all_branches,
1032 24df9a28 2023-07-08 jrick a->config_info.mirror_references,
1033 24df9a28 2023-07-08 jrick a->config_info.symrefs,
1034 24df9a28 2023-07-08 jrick a->config_info.wanted_branches,
1035 24df9a28 2023-07-08 jrick a->config_info.wanted_refs, a->repo);
1036 24df9a28 2023-07-08 jrick if (err)
1037 24df9a28 2023-07-08 jrick return err;
1038 24df9a28 2023-07-08 jrick a->configs_created = 1;
1039 24df9a28 2023-07-08 jrick }
1040 24df9a28 2023-07-08 jrick
1041 24df9a28 2023-07-08 jrick if (a->verbosity < 0)
1042 24df9a28 2023-07-08 jrick return NULL;
1043 24df9a28 2023-07-08 jrick
1044 24df9a28 2023-07-08 jrick if (message && message[0] != '\0') {
1045 24df9a28 2023-07-08 jrick printf("\rserver: %s", message);
1046 24df9a28 2023-07-08 jrick fflush(stdout);
1047 24df9a28 2023-07-08 jrick return NULL;
1048 24df9a28 2023-07-08 jrick }
1049 24df9a28 2023-07-08 jrick
1050 24df9a28 2023-07-08 jrick if (packfile_size > 0 || nobj_indexed > 0) {
1051 24df9a28 2023-07-08 jrick if (fmt_scaled(packfile_size, scaled_size) == 0 &&
1052 24df9a28 2023-07-08 jrick (a->last_scaled_size[0] == '\0' ||
1053 24df9a28 2023-07-08 jrick strcmp(scaled_size, a->last_scaled_size)) != 0) {
1054 24df9a28 2023-07-08 jrick print_size = 1;
1055 24df9a28 2023-07-08 jrick if (strlcpy(a->last_scaled_size, scaled_size,
1056 24df9a28 2023-07-08 jrick FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
1057 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
1058 24df9a28 2023-07-08 jrick }
1059 24df9a28 2023-07-08 jrick if (nobj_indexed > 0) {
1060 24df9a28 2023-07-08 jrick p_indexed = (nobj_indexed * 100) / nobj_total;
1061 24df9a28 2023-07-08 jrick if (p_indexed != a->last_p_indexed) {
1062 24df9a28 2023-07-08 jrick a->last_p_indexed = p_indexed;
1063 24df9a28 2023-07-08 jrick print_indexed = 1;
1064 24df9a28 2023-07-08 jrick print_size = 1;
1065 24df9a28 2023-07-08 jrick }
1066 24df9a28 2023-07-08 jrick }
1067 24df9a28 2023-07-08 jrick if (nobj_resolved > 0) {
1068 24df9a28 2023-07-08 jrick p_resolved = (nobj_resolved * 100) /
1069 24df9a28 2023-07-08 jrick (nobj_total - nobj_loose);
1070 24df9a28 2023-07-08 jrick if (p_resolved != a->last_p_resolved) {
1071 24df9a28 2023-07-08 jrick a->last_p_resolved = p_resolved;
1072 24df9a28 2023-07-08 jrick print_resolved = 1;
1073 24df9a28 2023-07-08 jrick print_indexed = 1;
1074 24df9a28 2023-07-08 jrick print_size = 1;
1075 24df9a28 2023-07-08 jrick }
1076 24df9a28 2023-07-08 jrick }
1077 24df9a28 2023-07-08 jrick
1078 24df9a28 2023-07-08 jrick }
1079 24df9a28 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1080 24df9a28 2023-07-08 jrick printf("\r");
1081 24df9a28 2023-07-08 jrick if (print_size)
1082 24df9a28 2023-07-08 jrick printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size);
1083 24df9a28 2023-07-08 jrick if (print_indexed)
1084 24df9a28 2023-07-08 jrick printf("; indexing %d%%", p_indexed);
1085 24df9a28 2023-07-08 jrick if (print_resolved)
1086 24df9a28 2023-07-08 jrick printf("; resolving deltas %d%%", p_resolved);
1087 24df9a28 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1088 24df9a28 2023-07-08 jrick fflush(stdout);
1089 24df9a28 2023-07-08 jrick
1090 24df9a28 2023-07-08 jrick return NULL;
1091 24df9a28 2023-07-08 jrick }
1092 24df9a28 2023-07-08 jrick
1093 24df9a28 2023-07-08 jrick static const struct got_error *
1094 24df9a28 2023-07-08 jrick create_symref(const char *refname, struct got_reference *target_ref,
1095 24df9a28 2023-07-08 jrick int verbosity, struct got_repository *repo)
1096 24df9a28 2023-07-08 jrick {
1097 24df9a28 2023-07-08 jrick const struct got_error *err;
1098 24df9a28 2023-07-08 jrick struct got_reference *head_symref;
1099 24df9a28 2023-07-08 jrick
1100 24df9a28 2023-07-08 jrick err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1101 24df9a28 2023-07-08 jrick if (err)
1102 24df9a28 2023-07-08 jrick return err;
1103 24df9a28 2023-07-08 jrick
1104 24df9a28 2023-07-08 jrick err = got_ref_write(head_symref, repo);
1105 24df9a28 2023-07-08 jrick if (err == NULL && verbosity > 0) {
1106 24df9a28 2023-07-08 jrick printf("Created reference %s: %s\n", GOT_REF_HEAD,
1107 24df9a28 2023-07-08 jrick got_ref_get_name(target_ref));
1108 24df9a28 2023-07-08 jrick }
1109 24df9a28 2023-07-08 jrick got_ref_close(head_symref);
1110 24df9a28 2023-07-08 jrick return err;
1111 24df9a28 2023-07-08 jrick }
1112 24df9a28 2023-07-08 jrick
1113 24df9a28 2023-07-08 jrick static const struct got_error *
1114 24df9a28 2023-07-08 jrick list_remote_refs(struct got_pathlist_head *symrefs,
1115 24df9a28 2023-07-08 jrick struct got_pathlist_head *refs)
1116 24df9a28 2023-07-08 jrick {
1117 24df9a28 2023-07-08 jrick const struct got_error *err;
1118 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1119 24df9a28 2023-07-08 jrick
1120 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1121 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1122 24df9a28 2023-07-08 jrick const char *targetref = pe->data;
1123 24df9a28 2023-07-08 jrick
1124 24df9a28 2023-07-08 jrick printf("%s: %s\n", refname, targetref);
1125 24df9a28 2023-07-08 jrick }
1126 24df9a28 2023-07-08 jrick
1127 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, refs, entry) {
1128 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1129 24df9a28 2023-07-08 jrick struct got_object_id *id = pe->data;
1130 24df9a28 2023-07-08 jrick char *id_str;
1131 24df9a28 2023-07-08 jrick
1132 24df9a28 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1133 24df9a28 2023-07-08 jrick if (err)
1134 24df9a28 2023-07-08 jrick return err;
1135 24df9a28 2023-07-08 jrick printf("%s: %s\n", refname, id_str);
1136 24df9a28 2023-07-08 jrick free(id_str);
1137 24df9a28 2023-07-08 jrick }
1138 24df9a28 2023-07-08 jrick
1139 24df9a28 2023-07-08 jrick return NULL;
1140 24df9a28 2023-07-08 jrick }
1141 24df9a28 2023-07-08 jrick
1142 24df9a28 2023-07-08 jrick static const struct got_error *
1143 24df9a28 2023-07-08 jrick create_ref(const char *refname, struct got_object_id *id,
1144 24df9a28 2023-07-08 jrick int verbosity, struct got_repository *repo)
1145 24df9a28 2023-07-08 jrick {
1146 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1147 24df9a28 2023-07-08 jrick struct got_reference *ref;
1148 24df9a28 2023-07-08 jrick char *id_str;
1149 24df9a28 2023-07-08 jrick
1150 24df9a28 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1151 24df9a28 2023-07-08 jrick if (err)
1152 24df9a28 2023-07-08 jrick return err;
1153 24df9a28 2023-07-08 jrick
1154 24df9a28 2023-07-08 jrick err = got_ref_alloc(&ref, refname, id);
1155 24df9a28 2023-07-08 jrick if (err)
1156 24df9a28 2023-07-08 jrick goto done;
1157 24df9a28 2023-07-08 jrick
1158 24df9a28 2023-07-08 jrick err = got_ref_write(ref, repo);
1159 24df9a28 2023-07-08 jrick got_ref_close(ref);
1160 24df9a28 2023-07-08 jrick
1161 24df9a28 2023-07-08 jrick if (err == NULL && verbosity >= 0)
1162 24df9a28 2023-07-08 jrick printf("Created reference %s: %s\n", refname, id_str);
1163 24df9a28 2023-07-08 jrick done:
1164 24df9a28 2023-07-08 jrick free(id_str);
1165 24df9a28 2023-07-08 jrick return err;
1166 24df9a28 2023-07-08 jrick }
1167 24df9a28 2023-07-08 jrick
1168 24df9a28 2023-07-08 jrick static int
1169 24df9a28 2023-07-08 jrick match_wanted_ref(const char *refname, const char *wanted_ref)
1170 24df9a28 2023-07-08 jrick {
1171 24df9a28 2023-07-08 jrick if (strncmp(refname, "refs/", 5) != 0)
1172 24df9a28 2023-07-08 jrick return 0;
1173 24df9a28 2023-07-08 jrick refname += 5;
1174 24df9a28 2023-07-08 jrick
1175 24df9a28 2023-07-08 jrick /*
1176 24df9a28 2023-07-08 jrick * Prevent fetching of references that won't make any
1177 24df9a28 2023-07-08 jrick * sense outside of the remote repository's context.
1178 24df9a28 2023-07-08 jrick */
1179 24df9a28 2023-07-08 jrick if (strncmp(refname, "got/", 4) == 0)
1180 24df9a28 2023-07-08 jrick return 0;
1181 24df9a28 2023-07-08 jrick if (strncmp(refname, "remotes/", 8) == 0)
1182 24df9a28 2023-07-08 jrick return 0;
1183 24df9a28 2023-07-08 jrick
1184 24df9a28 2023-07-08 jrick if (strncmp(wanted_ref, "refs/", 5) == 0)
1185 24df9a28 2023-07-08 jrick wanted_ref += 5;
1186 24df9a28 2023-07-08 jrick
1187 24df9a28 2023-07-08 jrick /* Allow prefix match. */
1188 24df9a28 2023-07-08 jrick if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1189 24df9a28 2023-07-08 jrick return 1;
1190 24df9a28 2023-07-08 jrick
1191 24df9a28 2023-07-08 jrick /* Allow exact match. */
1192 24df9a28 2023-07-08 jrick return (strcmp(refname, wanted_ref) == 0);
1193 24df9a28 2023-07-08 jrick }
1194 24df9a28 2023-07-08 jrick
1195 24df9a28 2023-07-08 jrick static int
1196 24df9a28 2023-07-08 jrick is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1197 24df9a28 2023-07-08 jrick {
1198 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1199 24df9a28 2023-07-08 jrick
1200 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1201 24df9a28 2023-07-08 jrick if (match_wanted_ref(refname, pe->path))
1202 24df9a28 2023-07-08 jrick return 1;
1203 24df9a28 2023-07-08 jrick }
1204 24df9a28 2023-07-08 jrick
1205 24df9a28 2023-07-08 jrick return 0;
1206 24df9a28 2023-07-08 jrick }
1207 24df9a28 2023-07-08 jrick
1208 24df9a28 2023-07-08 jrick static const struct got_error *
1209 24df9a28 2023-07-08 jrick create_wanted_ref(const char *refname, struct got_object_id *id,
1210 24df9a28 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
1211 24df9a28 2023-07-08 jrick {
1212 24df9a28 2023-07-08 jrick const struct got_error *err;
1213 24df9a28 2023-07-08 jrick char *remote_refname;
1214 24df9a28 2023-07-08 jrick
1215 24df9a28 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
1216 24df9a28 2023-07-08 jrick refname += 5;
1217 24df9a28 2023-07-08 jrick
1218 24df9a28 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1219 24df9a28 2023-07-08 jrick remote_repo_name, refname) == -1)
1220 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
1221 24df9a28 2023-07-08 jrick
1222 24df9a28 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
1223 24df9a28 2023-07-08 jrick free(remote_refname);
1224 24df9a28 2023-07-08 jrick return err;
1225 24df9a28 2023-07-08 jrick }
1226 24df9a28 2023-07-08 jrick
1227 24df9a28 2023-07-08 jrick static const struct got_error *
1228 24df9a28 2023-07-08 jrick create_gotconfig(const char *proto, const char *host, const char *port,
1229 24df9a28 2023-07-08 jrick const char *remote_repo_path, const char *default_branch,
1230 24df9a28 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1231 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1232 24df9a28 2023-07-08 jrick struct got_repository *repo)
1233 24df9a28 2023-07-08 jrick {
1234 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1235 24df9a28 2023-07-08 jrick char *gotconfig_path = NULL;
1236 24df9a28 2023-07-08 jrick char *gotconfig = NULL;
1237 24df9a28 2023-07-08 jrick FILE *gotconfig_file = NULL;
1238 24df9a28 2023-07-08 jrick const char *branchname = NULL;
1239 24df9a28 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1240 24df9a28 2023-07-08 jrick ssize_t n;
1241 24df9a28 2023-07-08 jrick
1242 24df9a28 2023-07-08 jrick if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
1243 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1244 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1245 24df9a28 2023-07-08 jrick char *s;
1246 24df9a28 2023-07-08 jrick branchname = pe->path;
1247 24df9a28 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1248 24df9a28 2023-07-08 jrick branchname += 11;
1249 24df9a28 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1250 24df9a28 2023-07-08 jrick branches ? branches : "", branchname) == -1) {
1251 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1252 24df9a28 2023-07-08 jrick goto done;
1253 24df9a28 2023-07-08 jrick }
1254 24df9a28 2023-07-08 jrick free(branches);
1255 24df9a28 2023-07-08 jrick branches = s;
1256 24df9a28 2023-07-08 jrick }
1257 24df9a28 2023-07-08 jrick } else if (!fetch_all_branches && default_branch) {
1258 24df9a28 2023-07-08 jrick branchname = default_branch;
1259 24df9a28 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1260 24df9a28 2023-07-08 jrick branchname += 11;
1261 24df9a28 2023-07-08 jrick if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1262 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1263 24df9a28 2023-07-08 jrick goto done;
1264 24df9a28 2023-07-08 jrick }
1265 24df9a28 2023-07-08 jrick }
1266 24df9a28 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1267 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1268 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1269 24df9a28 2023-07-08 jrick char *s;
1270 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1271 24df9a28 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1272 24df9a28 2023-07-08 jrick branchname += 5;
1273 24df9a28 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1274 24df9a28 2023-07-08 jrick refs ? refs : "", refname) == -1) {
1275 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1276 24df9a28 2023-07-08 jrick goto done;
1277 24df9a28 2023-07-08 jrick }
1278 24df9a28 2023-07-08 jrick free(refs);
1279 24df9a28 2023-07-08 jrick refs = s;
1280 24df9a28 2023-07-08 jrick }
1281 24df9a28 2023-07-08 jrick }
1282 24df9a28 2023-07-08 jrick
1283 24df9a28 2023-07-08 jrick /* Create got.conf(5). */
1284 24df9a28 2023-07-08 jrick gotconfig_path = got_repo_get_path_gotconfig(repo);
1285 24df9a28 2023-07-08 jrick if (gotconfig_path == NULL) {
1286 24df9a28 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gotconfig");
1287 24df9a28 2023-07-08 jrick goto done;
1288 24df9a28 2023-07-08 jrick }
1289 24df9a28 2023-07-08 jrick gotconfig_file = fopen(gotconfig_path, "ae");
1290 24df9a28 2023-07-08 jrick if (gotconfig_file == NULL) {
1291 24df9a28 2023-07-08 jrick err = got_error_from_errno2("fopen", gotconfig_path);
1292 24df9a28 2023-07-08 jrick goto done;
1293 24df9a28 2023-07-08 jrick }
1294 24df9a28 2023-07-08 jrick if (asprintf(&gotconfig,
1295 24df9a28 2023-07-08 jrick "remote \"%s\" {\n"
1296 24df9a28 2023-07-08 jrick "\tserver %s\n"
1297 24df9a28 2023-07-08 jrick "\tprotocol %s\n"
1298 24df9a28 2023-07-08 jrick "%s%s%s"
1299 24df9a28 2023-07-08 jrick "\trepository \"%s\"\n"
1300 24df9a28 2023-07-08 jrick "%s%s%s"
1301 24df9a28 2023-07-08 jrick "%s%s%s"
1302 24df9a28 2023-07-08 jrick "%s"
1303 24df9a28 2023-07-08 jrick "%s"
1304 24df9a28 2023-07-08 jrick "}\n",
1305 24df9a28 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
1306 24df9a28 2023-07-08 jrick port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1307 24df9a28 2023-07-08 jrick remote_repo_path, branches ? "\tbranch { " : "",
1308 24df9a28 2023-07-08 jrick branches ? branches : "", branches ? "}\n" : "",
1309 24df9a28 2023-07-08 jrick refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1310 24df9a28 2023-07-08 jrick mirror_references ? "\tmirror_references yes\n" : "",
1311 24df9a28 2023-07-08 jrick fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) {
1312 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1313 24df9a28 2023-07-08 jrick goto done;
1314 24df9a28 2023-07-08 jrick }
1315 24df9a28 2023-07-08 jrick n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1316 24df9a28 2023-07-08 jrick if (n != strlen(gotconfig)) {
1317 24df9a28 2023-07-08 jrick err = got_ferror(gotconfig_file, GOT_ERR_IO);
1318 24df9a28 2023-07-08 jrick goto done;
1319 24df9a28 2023-07-08 jrick }
1320 24df9a28 2023-07-08 jrick
1321 24df9a28 2023-07-08 jrick done:
1322 24df9a28 2023-07-08 jrick if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
1323 24df9a28 2023-07-08 jrick err = got_error_from_errno2("fclose", gotconfig_path);
1324 24df9a28 2023-07-08 jrick free(gotconfig_path);
1325 24df9a28 2023-07-08 jrick free(branches);
1326 24df9a28 2023-07-08 jrick return err;
1327 24df9a28 2023-07-08 jrick }
1328 24df9a28 2023-07-08 jrick
1329 24df9a28 2023-07-08 jrick static const struct got_error *
1330 24df9a28 2023-07-08 jrick create_gitconfig(const char *git_url, const char *default_branch,
1331 24df9a28 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1332 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1333 24df9a28 2023-07-08 jrick struct got_repository *repo)
1334 24df9a28 2023-07-08 jrick {
1335 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1336 24df9a28 2023-07-08 jrick char *gitconfig_path = NULL;
1337 24df9a28 2023-07-08 jrick char *gitconfig = NULL;
1338 24df9a28 2023-07-08 jrick FILE *gitconfig_file = NULL;
1339 24df9a28 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1340 24df9a28 2023-07-08 jrick const char *branchname;
1341 24df9a28 2023-07-08 jrick ssize_t n;
1342 24df9a28 2023-07-08 jrick
1343 24df9a28 2023-07-08 jrick /* Create a config file Git can understand. */
1344 24df9a28 2023-07-08 jrick gitconfig_path = got_repo_get_path_gitconfig(repo);
1345 24df9a28 2023-07-08 jrick if (gitconfig_path == NULL) {
1346 24df9a28 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gitconfig");
1347 24df9a28 2023-07-08 jrick goto done;
1348 24df9a28 2023-07-08 jrick }
1349 24df9a28 2023-07-08 jrick gitconfig_file = fopen(gitconfig_path, "ae");
1350 24df9a28 2023-07-08 jrick if (gitconfig_file == NULL) {
1351 24df9a28 2023-07-08 jrick err = got_error_from_errno2("fopen", gitconfig_path);
1352 24df9a28 2023-07-08 jrick goto done;
1353 24df9a28 2023-07-08 jrick }
1354 24df9a28 2023-07-08 jrick if (fetch_all_branches) {
1355 24df9a28 2023-07-08 jrick if (mirror_references) {
1356 24df9a28 2023-07-08 jrick if (asprintf(&branches,
1357 24df9a28 2023-07-08 jrick "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1358 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1359 24df9a28 2023-07-08 jrick goto done;
1360 24df9a28 2023-07-08 jrick }
1361 24df9a28 2023-07-08 jrick } else if (asprintf(&branches,
1362 24df9a28 2023-07-08 jrick "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1363 24df9a28 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1364 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1365 24df9a28 2023-07-08 jrick goto done;
1366 24df9a28 2023-07-08 jrick }
1367 24df9a28 2023-07-08 jrick } else if (!TAILQ_EMPTY(wanted_branches)) {
1368 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1369 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1370 24df9a28 2023-07-08 jrick char *s;
1371 24df9a28 2023-07-08 jrick branchname = pe->path;
1372 24df9a28 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1373 24df9a28 2023-07-08 jrick branchname += 11;
1374 24df9a28 2023-07-08 jrick if (mirror_references) {
1375 24df9a28 2023-07-08 jrick if (asprintf(&s,
1376 24df9a28 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1377 24df9a28 2023-07-08 jrick branches ? branches : "",
1378 24df9a28 2023-07-08 jrick branchname, branchname) == -1) {
1379 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1380 24df9a28 2023-07-08 jrick goto done;
1381 24df9a28 2023-07-08 jrick }
1382 24df9a28 2023-07-08 jrick } else if (asprintf(&s,
1383 24df9a28 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1384 24df9a28 2023-07-08 jrick branches ? branches : "",
1385 24df9a28 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1386 24df9a28 2023-07-08 jrick branchname) == -1) {
1387 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1388 24df9a28 2023-07-08 jrick goto done;
1389 24df9a28 2023-07-08 jrick }
1390 24df9a28 2023-07-08 jrick free(branches);
1391 24df9a28 2023-07-08 jrick branches = s;
1392 24df9a28 2023-07-08 jrick }
1393 24df9a28 2023-07-08 jrick } else {
1394 24df9a28 2023-07-08 jrick /*
1395 24df9a28 2023-07-08 jrick * If the server specified a default branch, use just that one.
1396 24df9a28 2023-07-08 jrick * Otherwise fall back to fetching all branches on next fetch.
1397 24df9a28 2023-07-08 jrick */
1398 24df9a28 2023-07-08 jrick if (default_branch) {
1399 24df9a28 2023-07-08 jrick branchname = default_branch;
1400 24df9a28 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1401 24df9a28 2023-07-08 jrick branchname += 11;
1402 24df9a28 2023-07-08 jrick } else
1403 24df9a28 2023-07-08 jrick branchname = "*"; /* fall back to all branches */
1404 24df9a28 2023-07-08 jrick if (mirror_references) {
1405 24df9a28 2023-07-08 jrick if (asprintf(&branches,
1406 24df9a28 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/heads/%s\n",
1407 24df9a28 2023-07-08 jrick branchname, branchname) == -1) {
1408 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1409 24df9a28 2023-07-08 jrick goto done;
1410 24df9a28 2023-07-08 jrick }
1411 24df9a28 2023-07-08 jrick } else if (asprintf(&branches,
1412 24df9a28 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1413 24df9a28 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1414 24df9a28 2023-07-08 jrick branchname) == -1) {
1415 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1416 24df9a28 2023-07-08 jrick goto done;
1417 24df9a28 2023-07-08 jrick }
1418 24df9a28 2023-07-08 jrick }
1419 24df9a28 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1420 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1421 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1422 24df9a28 2023-07-08 jrick char *s;
1423 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1424 24df9a28 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1425 24df9a28 2023-07-08 jrick refname += 5;
1426 24df9a28 2023-07-08 jrick if (mirror_references) {
1427 24df9a28 2023-07-08 jrick if (asprintf(&s,
1428 24df9a28 2023-07-08 jrick "%s\tfetch = refs/%s:refs/%s\n",
1429 24df9a28 2023-07-08 jrick refs ? refs : "", refname, refname) == -1) {
1430 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1431 24df9a28 2023-07-08 jrick goto done;
1432 24df9a28 2023-07-08 jrick }
1433 24df9a28 2023-07-08 jrick } else if (asprintf(&s,
1434 24df9a28 2023-07-08 jrick "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1435 24df9a28 2023-07-08 jrick refs ? refs : "",
1436 24df9a28 2023-07-08 jrick refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1437 24df9a28 2023-07-08 jrick refname) == -1) {
1438 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1439 24df9a28 2023-07-08 jrick goto done;
1440 24df9a28 2023-07-08 jrick }
1441 24df9a28 2023-07-08 jrick free(refs);
1442 24df9a28 2023-07-08 jrick refs = s;
1443 24df9a28 2023-07-08 jrick }
1444 24df9a28 2023-07-08 jrick }
1445 24df9a28 2023-07-08 jrick
1446 24df9a28 2023-07-08 jrick if (asprintf(&gitconfig,
1447 24df9a28 2023-07-08 jrick "[remote \"%s\"]\n"
1448 24df9a28 2023-07-08 jrick "\turl = %s\n"
1449 24df9a28 2023-07-08 jrick "%s"
1450 24df9a28 2023-07-08 jrick "%s"
1451 24df9a28 2023-07-08 jrick "\tfetch = refs/tags/*:refs/tags/*\n",
1452 24df9a28 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
1453 24df9a28 2023-07-08 jrick refs ? refs : "") == -1) {
1454 24df9a28 2023-07-08 jrick err = got_error_from_errno("asprintf");
1455 24df9a28 2023-07-08 jrick goto done;
1456 24df9a28 2023-07-08 jrick }
1457 24df9a28 2023-07-08 jrick n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1458 24df9a28 2023-07-08 jrick if (n != strlen(gitconfig)) {
1459 24df9a28 2023-07-08 jrick err = got_ferror(gitconfig_file, GOT_ERR_IO);
1460 24df9a28 2023-07-08 jrick goto done;
1461 24df9a28 2023-07-08 jrick }
1462 24df9a28 2023-07-08 jrick done:
1463 24df9a28 2023-07-08 jrick if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
1464 24df9a28 2023-07-08 jrick err = got_error_from_errno2("fclose", gitconfig_path);
1465 24df9a28 2023-07-08 jrick free(gitconfig_path);
1466 24df9a28 2023-07-08 jrick free(branches);
1467 24df9a28 2023-07-08 jrick return err;
1468 24df9a28 2023-07-08 jrick }
1469 24df9a28 2023-07-08 jrick
1470 24df9a28 2023-07-08 jrick static const struct got_error *
1471 24df9a28 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1472 24df9a28 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1473 24df9a28 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1474 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1475 24df9a28 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1476 24df9a28 2023-07-08 jrick {
1477 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1478 24df9a28 2023-07-08 jrick const char *default_branch = NULL;
1479 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1480 24df9a28 2023-07-08 jrick
1481 24df9a28 2023-07-08 jrick /*
1482 24df9a28 2023-07-08 jrick * If we asked for a set of wanted branches then use the first
1483 24df9a28 2023-07-08 jrick * one of those.
1484 24df9a28 2023-07-08 jrick */
1485 24df9a28 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_branches)) {
1486 24df9a28 2023-07-08 jrick pe = TAILQ_FIRST(wanted_branches);
1487 24df9a28 2023-07-08 jrick default_branch = pe->path;
1488 24df9a28 2023-07-08 jrick } else {
1489 24df9a28 2023-07-08 jrick /* First HEAD ref listed by server is the default branch. */
1490 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1491 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1492 24df9a28 2023-07-08 jrick const char *target = pe->data;
1493 24df9a28 2023-07-08 jrick
1494 24df9a28 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1495 24df9a28 2023-07-08 jrick continue;
1496 24df9a28 2023-07-08 jrick
1497 24df9a28 2023-07-08 jrick default_branch = target;
1498 24df9a28 2023-07-08 jrick break;
1499 24df9a28 2023-07-08 jrick }
1500 24df9a28 2023-07-08 jrick }
1501 24df9a28 2023-07-08 jrick
1502 24df9a28 2023-07-08 jrick /* Create got.conf(5). */
1503 24df9a28 2023-07-08 jrick err = create_gotconfig(proto, host, port, remote_repo_path,
1504 24df9a28 2023-07-08 jrick default_branch, fetch_all_branches, wanted_branches,
1505 24df9a28 2023-07-08 jrick wanted_refs, mirror_references, repo);
1506 24df9a28 2023-07-08 jrick if (err)
1507 24df9a28 2023-07-08 jrick return err;
1508 24df9a28 2023-07-08 jrick
1509 24df9a28 2023-07-08 jrick /* Create a config file Git can understand. */
1510 24df9a28 2023-07-08 jrick return create_gitconfig(git_url, default_branch, fetch_all_branches,
1511 24df9a28 2023-07-08 jrick wanted_branches, wanted_refs, mirror_references, repo);
1512 24df9a28 2023-07-08 jrick }
1513 24df9a28 2023-07-08 jrick
1514 24df9a28 2023-07-08 jrick static const struct got_error *
1515 24df9a28 2023-07-08 jrick cmd_clone(int argc, char *argv[])
1516 24df9a28 2023-07-08 jrick {
1517 24df9a28 2023-07-08 jrick const struct got_error *error = NULL;
1518 24df9a28 2023-07-08 jrick const char *uri, *dirname;
1519 24df9a28 2023-07-08 jrick char *proto, *host, *port, *repo_name, *server_path;
1520 24df9a28 2023-07-08 jrick char *default_destdir = NULL, *id_str = NULL;
1521 24df9a28 2023-07-08 jrick const char *repo_path;
1522 24df9a28 2023-07-08 jrick struct got_repository *repo = NULL;
1523 24df9a28 2023-07-08 jrick struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1524 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
1525 24df9a28 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
1526 24df9a28 2023-07-08 jrick int ch, fetchfd = -1, fetchstatus;
1527 24df9a28 2023-07-08 jrick pid_t fetchpid = -1;
1528 24df9a28 2023-07-08 jrick struct got_fetch_progress_arg fpa;
1529 24df9a28 2023-07-08 jrick char *git_url = NULL;
1530 24df9a28 2023-07-08 jrick int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1531 24df9a28 2023-07-08 jrick int bflag = 0, list_refs_only = 0;
1532 24df9a28 2023-07-08 jrick int *pack_fds = NULL;
1533 24df9a28 2023-07-08 jrick
1534 24df9a28 2023-07-08 jrick TAILQ_INIT(&refs);
1535 24df9a28 2023-07-08 jrick TAILQ_INIT(&symrefs);
1536 24df9a28 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
1537 24df9a28 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
1538 24df9a28 2023-07-08 jrick
1539 24df9a28 2023-07-08 jrick while ((ch = getopt(argc, argv, "ab:lmqR:v")) != -1) {
1540 24df9a28 2023-07-08 jrick switch (ch) {
1541 24df9a28 2023-07-08 jrick case 'a':
1542 24df9a28 2023-07-08 jrick fetch_all_branches = 1;
1543 24df9a28 2023-07-08 jrick break;
1544 24df9a28 2023-07-08 jrick case 'b':
1545 24df9a28 2023-07-08 jrick error = got_pathlist_append(&wanted_branches,
1546 24df9a28 2023-07-08 jrick optarg, NULL);
1547 24df9a28 2023-07-08 jrick if (error)
1548 24df9a28 2023-07-08 jrick return error;
1549 24df9a28 2023-07-08 jrick bflag = 1;
1550 24df9a28 2023-07-08 jrick break;
1551 24df9a28 2023-07-08 jrick case 'l':
1552 24df9a28 2023-07-08 jrick list_refs_only = 1;
1553 24df9a28 2023-07-08 jrick break;
1554 24df9a28 2023-07-08 jrick case 'm':
1555 24df9a28 2023-07-08 jrick mirror_references = 1;
1556 24df9a28 2023-07-08 jrick break;
1557 24df9a28 2023-07-08 jrick case 'q':
1558 24df9a28 2023-07-08 jrick verbosity = -1;
1559 24df9a28 2023-07-08 jrick break;
1560 24df9a28 2023-07-08 jrick case 'R':
1561 24df9a28 2023-07-08 jrick error = got_pathlist_append(&wanted_refs,
1562 24df9a28 2023-07-08 jrick optarg, NULL);
1563 24df9a28 2023-07-08 jrick if (error)
1564 24df9a28 2023-07-08 jrick return error;
1565 24df9a28 2023-07-08 jrick break;
1566 24df9a28 2023-07-08 jrick case 'v':
1567 24df9a28 2023-07-08 jrick if (verbosity < 0)
1568 24df9a28 2023-07-08 jrick verbosity = 0;
1569 24df9a28 2023-07-08 jrick else if (verbosity < 3)
1570 24df9a28 2023-07-08 jrick verbosity++;
1571 24df9a28 2023-07-08 jrick break;
1572 24df9a28 2023-07-08 jrick default:
1573 24df9a28 2023-07-08 jrick usage_clone();
1574 24df9a28 2023-07-08 jrick break;
1575 24df9a28 2023-07-08 jrick }
1576 24df9a28 2023-07-08 jrick }
1577 24df9a28 2023-07-08 jrick argc -= optind;
1578 24df9a28 2023-07-08 jrick argv += optind;
1579 24df9a28 2023-07-08 jrick
1580 24df9a28 2023-07-08 jrick if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1581 24df9a28 2023-07-08 jrick option_conflict('a', 'b');
1582 24df9a28 2023-07-08 jrick if (list_refs_only) {
1583 24df9a28 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_branches))
1584 24df9a28 2023-07-08 jrick option_conflict('l', 'b');
1585 24df9a28 2023-07-08 jrick if (fetch_all_branches)
1586 24df9a28 2023-07-08 jrick option_conflict('l', 'a');
1587 24df9a28 2023-07-08 jrick if (mirror_references)
1588 24df9a28 2023-07-08 jrick option_conflict('l', 'm');
1589 24df9a28 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_refs))
1590 24df9a28 2023-07-08 jrick option_conflict('l', 'R');
1591 24df9a28 2023-07-08 jrick }
1592 24df9a28 2023-07-08 jrick
1593 24df9a28 2023-07-08 jrick uri = argv[0];
1594 24df9a28 2023-07-08 jrick
1595 24df9a28 2023-07-08 jrick if (argc == 1)
1596 24df9a28 2023-07-08 jrick dirname = NULL;
1597 24df9a28 2023-07-08 jrick else if (argc == 2)
1598 24df9a28 2023-07-08 jrick dirname = argv[1];
1599 24df9a28 2023-07-08 jrick else
1600 24df9a28 2023-07-08 jrick usage_clone();
1601 24df9a28 2023-07-08 jrick
1602 24df9a28 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
1603 24df9a28 2023-07-08 jrick &repo_name, uri);
1604 24df9a28 2023-07-08 jrick if (error)
1605 24df9a28 2023-07-08 jrick goto done;
1606 24df9a28 2023-07-08 jrick
1607 24df9a28 2023-07-08 jrick if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1608 24df9a28 2023-07-08 jrick host, port ? ":" : "", port ? port : "",
1609 24df9a28 2023-07-08 jrick server_path[0] != '/' ? "/" : "", server_path) == -1) {
1610 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
1611 24df9a28 2023-07-08 jrick goto done;
1612 24df9a28 2023-07-08 jrick }
1613 24df9a28 2023-07-08 jrick
1614 24df9a28 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
1615 24df9a28 2023-07-08 jrick #ifndef PROFILE
1616 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1617 24df9a28 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
1618 24df9a28 2023-07-08 jrick err(1, "pledge");
1619 24df9a28 2023-07-08 jrick #endif
1620 24df9a28 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
1621 24df9a28 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
1622 24df9a28 2023-07-08 jrick #ifndef PROFILE
1623 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1624 24df9a28 2023-07-08 jrick "sendfd unveil", NULL) == -1)
1625 24df9a28 2023-07-08 jrick err(1, "pledge");
1626 24df9a28 2023-07-08 jrick #endif
1627 24df9a28 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
1628 24df9a28 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
1629 24df9a28 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1630 24df9a28 2023-07-08 jrick goto done;
1631 24df9a28 2023-07-08 jrick } else {
1632 24df9a28 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1633 24df9a28 2023-07-08 jrick goto done;
1634 24df9a28 2023-07-08 jrick }
1635 24df9a28 2023-07-08 jrick if (dirname == NULL) {
1636 24df9a28 2023-07-08 jrick if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1637 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
1638 24df9a28 2023-07-08 jrick goto done;
1639 24df9a28 2023-07-08 jrick }
1640 24df9a28 2023-07-08 jrick repo_path = default_destdir;
1641 24df9a28 2023-07-08 jrick } else
1642 24df9a28 2023-07-08 jrick repo_path = dirname;
1643 24df9a28 2023-07-08 jrick
1644 24df9a28 2023-07-08 jrick if (!list_refs_only) {
1645 24df9a28 2023-07-08 jrick error = got_path_mkdir(repo_path);
1646 24df9a28 2023-07-08 jrick if (error &&
1647 24df9a28 2023-07-08 jrick (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
1648 24df9a28 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST)))
1649 24df9a28 2023-07-08 jrick goto done;
1650 24df9a28 2023-07-08 jrick if (!got_path_dir_is_empty(repo_path)) {
1651 24df9a28 2023-07-08 jrick error = got_error_path(repo_path,
1652 24df9a28 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
1653 24df9a28 2023-07-08 jrick goto done;
1654 24df9a28 2023-07-08 jrick }
1655 24df9a28 2023-07-08 jrick }
1656 24df9a28 2023-07-08 jrick
1657 24df9a28 2023-07-08 jrick error = got_dial_apply_unveil(proto);
1658 24df9a28 2023-07-08 jrick if (error)
1659 24df9a28 2023-07-08 jrick goto done;
1660 24df9a28 2023-07-08 jrick
1661 24df9a28 2023-07-08 jrick error = apply_unveil(repo_path, 0, NULL);
1662 24df9a28 2023-07-08 jrick if (error)
1663 24df9a28 2023-07-08 jrick goto done;
1664 24df9a28 2023-07-08 jrick
1665 24df9a28 2023-07-08 jrick if (verbosity >= 0)
1666 24df9a28 2023-07-08 jrick printf("Connecting to %s\n", git_url);
1667 24df9a28 2023-07-08 jrick
1668 24df9a28 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1669 24df9a28 2023-07-08 jrick server_path, verbosity);
1670 24df9a28 2023-07-08 jrick if (error)
1671 24df9a28 2023-07-08 jrick goto done;
1672 24df9a28 2023-07-08 jrick
1673 24df9a28 2023-07-08 jrick if (!list_refs_only) {
1674 24df9a28 2023-07-08 jrick error = got_repo_init(repo_path, NULL);
1675 24df9a28 2023-07-08 jrick if (error)
1676 24df9a28 2023-07-08 jrick goto done;
1677 24df9a28 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
1678 24df9a28 2023-07-08 jrick if (error != NULL)
1679 24df9a28 2023-07-08 jrick goto done;
1680 24df9a28 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
1681 24df9a28 2023-07-08 jrick if (error)
1682 24df9a28 2023-07-08 jrick goto done;
1683 24df9a28 2023-07-08 jrick }
1684 24df9a28 2023-07-08 jrick
1685 24df9a28 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
1686 24df9a28 2023-07-08 jrick fpa.last_p_indexed = -1;
1687 24df9a28 2023-07-08 jrick fpa.last_p_resolved = -1;
1688 24df9a28 2023-07-08 jrick fpa.verbosity = verbosity;
1689 24df9a28 2023-07-08 jrick fpa.create_configs = 1;
1690 24df9a28 2023-07-08 jrick fpa.configs_created = 0;
1691 24df9a28 2023-07-08 jrick fpa.repo = repo;
1692 24df9a28 2023-07-08 jrick fpa.config_info.symrefs = &symrefs;
1693 24df9a28 2023-07-08 jrick fpa.config_info.wanted_branches = &wanted_branches;
1694 24df9a28 2023-07-08 jrick fpa.config_info.wanted_refs = &wanted_refs;
1695 24df9a28 2023-07-08 jrick fpa.config_info.proto = proto;
1696 24df9a28 2023-07-08 jrick fpa.config_info.host = host;
1697 24df9a28 2023-07-08 jrick fpa.config_info.port = port;
1698 24df9a28 2023-07-08 jrick fpa.config_info.remote_repo_path = server_path;
1699 24df9a28 2023-07-08 jrick fpa.config_info.git_url = git_url;
1700 24df9a28 2023-07-08 jrick fpa.config_info.fetch_all_branches = fetch_all_branches;
1701 24df9a28 2023-07-08 jrick fpa.config_info.mirror_references = mirror_references;
1702 24df9a28 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1703 24df9a28 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1704 24df9a28 2023-07-08 jrick fetch_all_branches, &wanted_branches, &wanted_refs,
1705 24df9a28 2023-07-08 jrick list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag,
1706 24df9a28 2023-07-08 jrick fetch_progress, &fpa);
1707 24df9a28 2023-07-08 jrick if (error)
1708 24df9a28 2023-07-08 jrick goto done;
1709 24df9a28 2023-07-08 jrick
1710 24df9a28 2023-07-08 jrick if (list_refs_only) {
1711 24df9a28 2023-07-08 jrick error = list_remote_refs(&symrefs, &refs);
1712 24df9a28 2023-07-08 jrick goto done;
1713 24df9a28 2023-07-08 jrick }
1714 24df9a28 2023-07-08 jrick
1715 24df9a28 2023-07-08 jrick if (pack_hash == NULL) {
1716 24df9a28 2023-07-08 jrick error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s",
1717 24df9a28 2023-07-08 jrick "server sent an empty pack file");
1718 24df9a28 2023-07-08 jrick goto done;
1719 24df9a28 2023-07-08 jrick }
1720 24df9a28 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
1721 24df9a28 2023-07-08 jrick if (error)
1722 24df9a28 2023-07-08 jrick goto done;
1723 24df9a28 2023-07-08 jrick if (verbosity >= 0)
1724 24df9a28 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
1725 24df9a28 2023-07-08 jrick free(id_str);
1726 24df9a28 2023-07-08 jrick
1727 24df9a28 2023-07-08 jrick /* Set up references provided with the pack file. */
1728 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
1729 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1730 24df9a28 2023-07-08 jrick struct got_object_id *id = pe->data;
1731 24df9a28 2023-07-08 jrick char *remote_refname;
1732 24df9a28 2023-07-08 jrick
1733 24df9a28 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname) &&
1734 24df9a28 2023-07-08 jrick !mirror_references) {
1735 24df9a28 2023-07-08 jrick error = create_wanted_ref(refname, id,
1736 24df9a28 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME,
1737 24df9a28 2023-07-08 jrick verbosity - 1, repo);
1738 24df9a28 2023-07-08 jrick if (error)
1739 24df9a28 2023-07-08 jrick goto done;
1740 24df9a28 2023-07-08 jrick continue;
1741 24df9a28 2023-07-08 jrick }
1742 24df9a28 2023-07-08 jrick
1743 24df9a28 2023-07-08 jrick error = create_ref(refname, id, verbosity - 1, repo);
1744 24df9a28 2023-07-08 jrick if (error)
1745 24df9a28 2023-07-08 jrick goto done;
1746 24df9a28 2023-07-08 jrick
1747 24df9a28 2023-07-08 jrick if (mirror_references)
1748 24df9a28 2023-07-08 jrick continue;
1749 24df9a28 2023-07-08 jrick
1750 24df9a28 2023-07-08 jrick if (strncmp("refs/heads/", refname, 11) != 0)
1751 24df9a28 2023-07-08 jrick continue;
1752 24df9a28 2023-07-08 jrick
1753 24df9a28 2023-07-08 jrick if (asprintf(&remote_refname,
1754 24df9a28 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1755 24df9a28 2023-07-08 jrick refname + 11) == -1) {
1756 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
1757 24df9a28 2023-07-08 jrick goto done;
1758 24df9a28 2023-07-08 jrick }
1759 24df9a28 2023-07-08 jrick error = create_ref(remote_refname, id, verbosity - 1, repo);
1760 24df9a28 2023-07-08 jrick free(remote_refname);
1761 24df9a28 2023-07-08 jrick if (error)
1762 24df9a28 2023-07-08 jrick goto done;
1763 24df9a28 2023-07-08 jrick }
1764 24df9a28 2023-07-08 jrick
1765 24df9a28 2023-07-08 jrick /* Set the HEAD reference if the server provided one. */
1766 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, &symrefs, entry) {
1767 24df9a28 2023-07-08 jrick struct got_reference *target_ref;
1768 24df9a28 2023-07-08 jrick const char *refname = pe->path;
1769 24df9a28 2023-07-08 jrick const char *target = pe->data;
1770 24df9a28 2023-07-08 jrick char *remote_refname = NULL, *remote_target = NULL;
1771 24df9a28 2023-07-08 jrick
1772 24df9a28 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1773 24df9a28 2023-07-08 jrick continue;
1774 24df9a28 2023-07-08 jrick
1775 24df9a28 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1776 24df9a28 2023-07-08 jrick if (error) {
1777 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1778 24df9a28 2023-07-08 jrick error = NULL;
1779 24df9a28 2023-07-08 jrick continue;
1780 24df9a28 2023-07-08 jrick }
1781 24df9a28 2023-07-08 jrick goto done;
1782 24df9a28 2023-07-08 jrick }
1783 24df9a28 2023-07-08 jrick
1784 24df9a28 2023-07-08 jrick error = create_symref(refname, target_ref, verbosity, repo);
1785 24df9a28 2023-07-08 jrick got_ref_close(target_ref);
1786 24df9a28 2023-07-08 jrick if (error)
1787 24df9a28 2023-07-08 jrick goto done;
1788 24df9a28 2023-07-08 jrick
1789 24df9a28 2023-07-08 jrick if (mirror_references)
1790 24df9a28 2023-07-08 jrick continue;
1791 24df9a28 2023-07-08 jrick
1792 24df9a28 2023-07-08 jrick if (strncmp("refs/heads/", target, 11) != 0)
1793 24df9a28 2023-07-08 jrick continue;
1794 24df9a28 2023-07-08 jrick
1795 24df9a28 2023-07-08 jrick if (asprintf(&remote_refname,
1796 24df9a28 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1797 24df9a28 2023-07-08 jrick refname) == -1) {
1798 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
1799 24df9a28 2023-07-08 jrick goto done;
1800 24df9a28 2023-07-08 jrick }
1801 24df9a28 2023-07-08 jrick if (asprintf(&remote_target,
1802 24df9a28 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1803 24df9a28 2023-07-08 jrick target + 11) == -1) {
1804 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
1805 24df9a28 2023-07-08 jrick free(remote_refname);
1806 24df9a28 2023-07-08 jrick goto done;
1807 24df9a28 2023-07-08 jrick }
1808 24df9a28 2023-07-08 jrick error = got_ref_open(&target_ref, repo, remote_target, 0);
1809 24df9a28 2023-07-08 jrick if (error) {
1810 24df9a28 2023-07-08 jrick free(remote_refname);
1811 24df9a28 2023-07-08 jrick free(remote_target);
1812 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1813 24df9a28 2023-07-08 jrick error = NULL;
1814 24df9a28 2023-07-08 jrick continue;
1815 24df9a28 2023-07-08 jrick }
1816 24df9a28 2023-07-08 jrick goto done;
1817 24df9a28 2023-07-08 jrick }
1818 24df9a28 2023-07-08 jrick error = create_symref(remote_refname, target_ref,
1819 24df9a28 2023-07-08 jrick verbosity - 1, repo);
1820 24df9a28 2023-07-08 jrick free(remote_refname);
1821 24df9a28 2023-07-08 jrick free(remote_target);
1822 24df9a28 2023-07-08 jrick got_ref_close(target_ref);
1823 24df9a28 2023-07-08 jrick if (error)
1824 24df9a28 2023-07-08 jrick goto done;
1825 24df9a28 2023-07-08 jrick }
1826 24df9a28 2023-07-08 jrick if (pe == NULL) {
1827 24df9a28 2023-07-08 jrick /*
1828 24df9a28 2023-07-08 jrick * We failed to set the HEAD reference. If we asked for
1829 24df9a28 2023-07-08 jrick * a set of wanted branches use the first of one of those
1830 24df9a28 2023-07-08 jrick * which could be fetched instead.
1831 24df9a28 2023-07-08 jrick */
1832 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, &wanted_branches, entry) {
1833 24df9a28 2023-07-08 jrick const char *target = pe->path;
1834 24df9a28 2023-07-08 jrick struct got_reference *target_ref;
1835 24df9a28 2023-07-08 jrick
1836 24df9a28 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1837 24df9a28 2023-07-08 jrick if (error) {
1838 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1839 24df9a28 2023-07-08 jrick error = NULL;
1840 24df9a28 2023-07-08 jrick continue;
1841 24df9a28 2023-07-08 jrick }
1842 24df9a28 2023-07-08 jrick goto done;
1843 24df9a28 2023-07-08 jrick }
1844 24df9a28 2023-07-08 jrick
1845 24df9a28 2023-07-08 jrick error = create_symref(GOT_REF_HEAD, target_ref,
1846 24df9a28 2023-07-08 jrick verbosity, repo);
1847 24df9a28 2023-07-08 jrick got_ref_close(target_ref);
1848 24df9a28 2023-07-08 jrick if (error)
1849 24df9a28 2023-07-08 jrick goto done;
1850 24df9a28 2023-07-08 jrick break;
1851 24df9a28 2023-07-08 jrick }
1852 24df9a28 2023-07-08 jrick
1853 24df9a28 2023-07-08 jrick if (!fpa.configs_created && pe != NULL) {
1854 24df9a28 2023-07-08 jrick error = create_config_files(fpa.config_info.proto,
1855 24df9a28 2023-07-08 jrick fpa.config_info.host, fpa.config_info.port,
1856 24df9a28 2023-07-08 jrick fpa.config_info.remote_repo_path,
1857 24df9a28 2023-07-08 jrick fpa.config_info.git_url,
1858 24df9a28 2023-07-08 jrick fpa.config_info.fetch_all_branches,
1859 24df9a28 2023-07-08 jrick fpa.config_info.mirror_references,
1860 24df9a28 2023-07-08 jrick fpa.config_info.symrefs,
1861 24df9a28 2023-07-08 jrick fpa.config_info.wanted_branches,
1862 24df9a28 2023-07-08 jrick fpa.config_info.wanted_refs, fpa.repo);
1863 24df9a28 2023-07-08 jrick if (error)
1864 24df9a28 2023-07-08 jrick goto done;
1865 24df9a28 2023-07-08 jrick }
1866 24df9a28 2023-07-08 jrick }
1867 24df9a28 2023-07-08 jrick
1868 24df9a28 2023-07-08 jrick if (verbosity >= 0)
1869 24df9a28 2023-07-08 jrick printf("Created %s repository '%s'\n",
1870 24df9a28 2023-07-08 jrick mirror_references ? "mirrored" : "cloned", repo_path);
1871 24df9a28 2023-07-08 jrick done:
1872 24df9a28 2023-07-08 jrick if (pack_fds) {
1873 24df9a28 2023-07-08 jrick const struct got_error *pack_err =
1874 24df9a28 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
1875 24df9a28 2023-07-08 jrick if (error == NULL)
1876 24df9a28 2023-07-08 jrick error = pack_err;
1877 24df9a28 2023-07-08 jrick }
1878 24df9a28 2023-07-08 jrick if (fetchpid > 0) {
1879 24df9a28 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
1880 24df9a28 2023-07-08 jrick error = got_error_from_errno("kill");
1881 24df9a28 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1882 24df9a28 2023-07-08 jrick error = got_error_from_errno("waitpid");
1883 24df9a28 2023-07-08 jrick }
1884 24df9a28 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1885 24df9a28 2023-07-08 jrick error = got_error_from_errno("close");
1886 24df9a28 2023-07-08 jrick if (repo) {
1887 24df9a28 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
1888 24df9a28 2023-07-08 jrick if (error == NULL)
1889 24df9a28 2023-07-08 jrick error = close_err;
1890 24df9a28 2023-07-08 jrick }
1891 24df9a28 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
1892 24df9a28 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
1893 24df9a28 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
1894 24df9a28 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
1895 24df9a28 2023-07-08 jrick free(pack_hash);
1896 24df9a28 2023-07-08 jrick free(proto);
1897 24df9a28 2023-07-08 jrick free(host);
1898 24df9a28 2023-07-08 jrick free(port);
1899 24df9a28 2023-07-08 jrick free(server_path);
1900 24df9a28 2023-07-08 jrick free(repo_name);
1901 24df9a28 2023-07-08 jrick free(default_destdir);
1902 24df9a28 2023-07-08 jrick free(git_url);
1903 24df9a28 2023-07-08 jrick return error;
1904 24df9a28 2023-07-08 jrick }
1905 24df9a28 2023-07-08 jrick
1906 24df9a28 2023-07-08 jrick static const struct got_error *
1907 24df9a28 2023-07-08 jrick update_ref(struct got_reference *ref, struct got_object_id *new_id,
1908 24df9a28 2023-07-08 jrick int replace_tags, int verbosity, struct got_repository *repo)
1909 24df9a28 2023-07-08 jrick {
1910 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
1911 24df9a28 2023-07-08 jrick char *new_id_str = NULL;
1912 24df9a28 2023-07-08 jrick struct got_object_id *old_id = NULL;
1913 24df9a28 2023-07-08 jrick
1914 24df9a28 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
1915 24df9a28 2023-07-08 jrick if (err)
1916 24df9a28 2023-07-08 jrick goto done;
1917 24df9a28 2023-07-08 jrick
1918 24df9a28 2023-07-08 jrick if (!replace_tags &&
1919 24df9a28 2023-07-08 jrick strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1920 24df9a28 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1921 24df9a28 2023-07-08 jrick if (err)
1922 24df9a28 2023-07-08 jrick goto done;
1923 24df9a28 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1924 24df9a28 2023-07-08 jrick goto done;
1925 24df9a28 2023-07-08 jrick if (verbosity >= 0) {
1926 24df9a28 2023-07-08 jrick printf("Rejecting update of existing tag %s: %s\n",
1927 24df9a28 2023-07-08 jrick got_ref_get_name(ref), new_id_str);
1928 24df9a28 2023-07-08 jrick }
1929 24df9a28 2023-07-08 jrick goto done;
1930 24df9a28 2023-07-08 jrick }
1931 24df9a28 2023-07-08 jrick
1932 24df9a28 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
1933 24df9a28 2023-07-08 jrick if (verbosity >= 0) {
1934 24df9a28 2023-07-08 jrick printf("Replacing reference %s: %s\n",
1935 24df9a28 2023-07-08 jrick got_ref_get_name(ref),
1936 24df9a28 2023-07-08 jrick got_ref_get_symref_target(ref));
1937 24df9a28 2023-07-08 jrick }
1938 24df9a28 2023-07-08 jrick err = got_ref_change_symref_to_ref(ref, new_id);
1939 24df9a28 2023-07-08 jrick if (err)
1940 24df9a28 2023-07-08 jrick goto done;
1941 24df9a28 2023-07-08 jrick err = got_ref_write(ref, repo);
1942 24df9a28 2023-07-08 jrick if (err)
1943 24df9a28 2023-07-08 jrick goto done;
1944 24df9a28 2023-07-08 jrick } else {
1945 24df9a28 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1946 24df9a28 2023-07-08 jrick if (err)
1947 24df9a28 2023-07-08 jrick goto done;
1948 24df9a28 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1949 24df9a28 2023-07-08 jrick goto done;
1950 24df9a28 2023-07-08 jrick
1951 24df9a28 2023-07-08 jrick err = got_ref_change_ref(ref, new_id);
1952 24df9a28 2023-07-08 jrick if (err)
1953 24df9a28 2023-07-08 jrick goto done;
1954 24df9a28 2023-07-08 jrick err = got_ref_write(ref, repo);
1955 24df9a28 2023-07-08 jrick if (err)
1956 24df9a28 2023-07-08 jrick goto done;
1957 24df9a28 2023-07-08 jrick }
1958 24df9a28 2023-07-08 jrick
1959 24df9a28 2023-07-08 jrick if (verbosity >= 0)
1960 24df9a28 2023-07-08 jrick printf("Updated %s: %s\n", got_ref_get_name(ref),
1961 24df9a28 2023-07-08 jrick new_id_str);
1962 24df9a28 2023-07-08 jrick done:
1963 24df9a28 2023-07-08 jrick free(old_id);
1964 24df9a28 2023-07-08 jrick free(new_id_str);
1965 24df9a28 2023-07-08 jrick return err;
1966 24df9a28 2023-07-08 jrick }
1967 24df9a28 2023-07-08 jrick
1968 24df9a28 2023-07-08 jrick static const struct got_error *
1969 24df9a28 2023-07-08 jrick update_wanted_ref(const char *refname, struct got_object_id *id,
1970 24df9a28 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
1971 24df9a28 2023-07-08 jrick {
1972 24df9a28 2023-07-08 jrick const struct got_error *err, *unlock_err;
1973 24df9a28 2023-07-08 jrick char *remote_refname;
1974 24df9a28 2023-07-08 jrick struct got_reference *ref;
1975 24df9a28 2023-07-08 jrick
1976 24df9a28 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
1977 24df9a28 2023-07-08 jrick refname += 5;
1978 24df9a28 2023-07-08 jrick
1979 24df9a28 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1980 24df9a28 2023-07-08 jrick remote_repo_name, refname) == -1)
1981 24df9a28 2023-07-08 jrick return got_error_from_errno("asprintf");
1982 24df9a28 2023-07-08 jrick
1983 24df9a28 2023-07-08 jrick err = got_ref_open(&ref, repo, remote_refname, 1);
1984 24df9a28 2023-07-08 jrick if (err) {
1985 24df9a28 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
1986 24df9a28 2023-07-08 jrick goto done;
1987 24df9a28 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
1988 24df9a28 2023-07-08 jrick } else {
1989 24df9a28 2023-07-08 jrick err = update_ref(ref, id, 0, verbosity, repo);
1990 24df9a28 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
1991 24df9a28 2023-07-08 jrick if (unlock_err && err == NULL)
1992 24df9a28 2023-07-08 jrick err = unlock_err;
1993 24df9a28 2023-07-08 jrick got_ref_close(ref);
1994 24df9a28 2023-07-08 jrick }
1995 24df9a28 2023-07-08 jrick done:
1996 24df9a28 2023-07-08 jrick free(remote_refname);
1997 24df9a28 2023-07-08 jrick return err;
1998 24df9a28 2023-07-08 jrick }
1999 24df9a28 2023-07-08 jrick
2000 24df9a28 2023-07-08 jrick __dead static void
2001 24df9a28 2023-07-08 jrick usage_checkout(void)
2002 24df9a28 2023-07-08 jrick {
2003 24df9a28 2023-07-08 jrick fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
2004 24df9a28 2023-07-08 jrick "[-p path-prefix] repository-path [work-tree-path]\n",
2005 24df9a28 2023-07-08 jrick getprogname());
2006 24df9a28 2023-07-08 jrick exit(1);
2007 24df9a28 2023-07-08 jrick }
2008 24df9a28 2023-07-08 jrick
2009 24df9a28 2023-07-08 jrick static void
2010 24df9a28 2023-07-08 jrick show_worktree_base_ref_warning(void)
2011 24df9a28 2023-07-08 jrick {
2012 24df9a28 2023-07-08 jrick fprintf(stderr, "%s: warning: could not create a reference "
2013 24df9a28 2023-07-08 jrick "to the work tree's base commit; the commit could be "
2014 24df9a28 2023-07-08 jrick "garbage-collected by Git or 'gotadmin cleanup'; making the "
2015 24df9a28 2023-07-08 jrick "repository writable and running 'got update' will prevent this\n",
2016 24df9a28 2023-07-08 jrick getprogname());
2017 24df9a28 2023-07-08 jrick }
2018 24df9a28 2023-07-08 jrick
2019 24df9a28 2023-07-08 jrick struct got_checkout_progress_arg {
2020 24df9a28 2023-07-08 jrick const char *worktree_path;
2021 24df9a28 2023-07-08 jrick int had_base_commit_ref_error;
2022 24df9a28 2023-07-08 jrick int verbosity;
2023 24df9a28 2023-07-08 jrick };
2024 24df9a28 2023-07-08 jrick
2025 24df9a28 2023-07-08 jrick static const struct got_error *
2026 24df9a28 2023-07-08 jrick checkout_progress(void *arg, unsigned char status, const char *path)
2027 24df9a28 2023-07-08 jrick {
2028 24df9a28 2023-07-08 jrick struct got_checkout_progress_arg *a = arg;
2029 24df9a28 2023-07-08 jrick
2030 24df9a28 2023-07-08 jrick /* Base commit bump happens silently. */
2031 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2032 24df9a28 2023-07-08 jrick return NULL;
2033 24df9a28 2023-07-08 jrick
2034 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_BASE_REF_ERR) {
2035 24df9a28 2023-07-08 jrick a->had_base_commit_ref_error = 1;
2036 24df9a28 2023-07-08 jrick return NULL;
2037 24df9a28 2023-07-08 jrick }
2038 24df9a28 2023-07-08 jrick
2039 24df9a28 2023-07-08 jrick while (path[0] == '/')
2040 24df9a28 2023-07-08 jrick path++;
2041 24df9a28 2023-07-08 jrick
2042 24df9a28 2023-07-08 jrick if (a->verbosity >= 0)
2043 24df9a28 2023-07-08 jrick printf("%c %s/%s\n", status, a->worktree_path, path);
2044 24df9a28 2023-07-08 jrick
2045 24df9a28 2023-07-08 jrick return NULL;
2046 24df9a28 2023-07-08 jrick }
2047 24df9a28 2023-07-08 jrick
2048 24df9a28 2023-07-08 jrick static const struct got_error *
2049 24df9a28 2023-07-08 jrick check_cancelled(void *arg)
2050 24df9a28 2023-07-08 jrick {
2051 24df9a28 2023-07-08 jrick if (sigint_received || sigpipe_received)
2052 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
2053 24df9a28 2023-07-08 jrick return NULL;
2054 24df9a28 2023-07-08 jrick }
2055 24df9a28 2023-07-08 jrick
2056 24df9a28 2023-07-08 jrick static const struct got_error *
2057 24df9a28 2023-07-08 jrick check_linear_ancestry(struct got_object_id *commit_id,
2058 24df9a28 2023-07-08 jrick struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2059 24df9a28 2023-07-08 jrick struct got_repository *repo)
2060 24df9a28 2023-07-08 jrick {
2061 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
2062 24df9a28 2023-07-08 jrick struct got_object_id *yca_id;
2063 24df9a28 2023-07-08 jrick
2064 24df9a28 2023-07-08 jrick err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2065 24df9a28 2023-07-08 jrick commit_id, base_commit_id, 1, repo, check_cancelled, NULL);
2066 24df9a28 2023-07-08 jrick if (err)
2067 24df9a28 2023-07-08 jrick return err;
2068 24df9a28 2023-07-08 jrick
2069 24df9a28 2023-07-08 jrick if (yca_id == NULL)
2070 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2071 24df9a28 2023-07-08 jrick
2072 24df9a28 2023-07-08 jrick /*
2073 24df9a28 2023-07-08 jrick * Require a straight line of history between the target commit
2074 24df9a28 2023-07-08 jrick * and the work tree's base commit.
2075 24df9a28 2023-07-08 jrick *
2076 24df9a28 2023-07-08 jrick * Non-linear situations such as this require a rebase:
2077 24df9a28 2023-07-08 jrick *
2078 24df9a28 2023-07-08 jrick * (commit) D F (base_commit)
2079 24df9a28 2023-07-08 jrick * \ /
2080 24df9a28 2023-07-08 jrick * C E
2081 24df9a28 2023-07-08 jrick * \ /
2082 24df9a28 2023-07-08 jrick * B (yca)
2083 24df9a28 2023-07-08 jrick * |
2084 24df9a28 2023-07-08 jrick * A
2085 24df9a28 2023-07-08 jrick *
2086 24df9a28 2023-07-08 jrick * 'got update' only handles linear cases:
2087 24df9a28 2023-07-08 jrick * Update forwards in time: A (base/yca) - B - C - D (commit)
2088 24df9a28 2023-07-08 jrick * Update backwards in time: D (base) - C - B - A (commit/yca)
2089 24df9a28 2023-07-08 jrick */
2090 24df9a28 2023-07-08 jrick if (allow_forwards_in_time_only) {
2091 24df9a28 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2092 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2093 24df9a28 2023-07-08 jrick } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2094 24df9a28 2023-07-08 jrick got_object_id_cmp(base_commit_id, yca_id) != 0)
2095 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2096 24df9a28 2023-07-08 jrick
2097 24df9a28 2023-07-08 jrick free(yca_id);
2098 24df9a28 2023-07-08 jrick return NULL;
2099 24df9a28 2023-07-08 jrick }
2100 24df9a28 2023-07-08 jrick
2101 24df9a28 2023-07-08 jrick static const struct got_error *
2102 24df9a28 2023-07-08 jrick check_same_branch(struct got_object_id *commit_id,
2103 24df9a28 2023-07-08 jrick struct got_reference *head_ref, struct got_repository *repo)
2104 24df9a28 2023-07-08 jrick {
2105 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
2106 24df9a28 2023-07-08 jrick struct got_commit_graph *graph = NULL;
2107 24df9a28 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
2108 24df9a28 2023-07-08 jrick
2109 24df9a28 2023-07-08 jrick err = got_ref_resolve(&head_commit_id, repo, head_ref);
2110 24df9a28 2023-07-08 jrick if (err)
2111 24df9a28 2023-07-08 jrick goto done;
2112 24df9a28 2023-07-08 jrick
2113 24df9a28 2023-07-08 jrick if (got_object_id_cmp(head_commit_id, commit_id) == 0)
2114 24df9a28 2023-07-08 jrick goto done;
2115 24df9a28 2023-07-08 jrick
2116 24df9a28 2023-07-08 jrick err = got_commit_graph_open(&graph, "/", 1);
2117 24df9a28 2023-07-08 jrick if (err)
2118 24df9a28 2023-07-08 jrick goto done;
2119 24df9a28 2023-07-08 jrick
2120 24df9a28 2023-07-08 jrick err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2121 24df9a28 2023-07-08 jrick check_cancelled, NULL);
2122 24df9a28 2023-07-08 jrick if (err)
2123 24df9a28 2023-07-08 jrick goto done;
2124 24df9a28 2023-07-08 jrick
2125 24df9a28 2023-07-08 jrick for (;;) {
2126 24df9a28 2023-07-08 jrick struct got_object_id id;
2127 24df9a28 2023-07-08 jrick
2128 24df9a28 2023-07-08 jrick err = got_commit_graph_iter_next(&id, graph, repo,
2129 24df9a28 2023-07-08 jrick check_cancelled, NULL);
2130 24df9a28 2023-07-08 jrick if (err) {
2131 24df9a28 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED)
2132 24df9a28 2023-07-08 jrick err = got_error(GOT_ERR_ANCESTRY);
2133 24df9a28 2023-07-08 jrick break;
2134 24df9a28 2023-07-08 jrick }
2135 24df9a28 2023-07-08 jrick
2136 24df9a28 2023-07-08 jrick if (got_object_id_cmp(&id, commit_id) == 0)
2137 24df9a28 2023-07-08 jrick break;
2138 24df9a28 2023-07-08 jrick }
2139 24df9a28 2023-07-08 jrick done:
2140 24df9a28 2023-07-08 jrick if (graph)
2141 24df9a28 2023-07-08 jrick got_commit_graph_close(graph);
2142 24df9a28 2023-07-08 jrick free(head_commit_id);
2143 24df9a28 2023-07-08 jrick return err;
2144 24df9a28 2023-07-08 jrick }
2145 24df9a28 2023-07-08 jrick
2146 24df9a28 2023-07-08 jrick static const struct got_error *
2147 24df9a28 2023-07-08 jrick checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2148 24df9a28 2023-07-08 jrick {
2149 24df9a28 2023-07-08 jrick static char msg[512];
2150 24df9a28 2023-07-08 jrick const char *branch_name;
2151 24df9a28 2023-07-08 jrick
2152 24df9a28 2023-07-08 jrick if (got_ref_is_symbolic(ref))
2153 24df9a28 2023-07-08 jrick branch_name = got_ref_get_symref_target(ref);
2154 24df9a28 2023-07-08 jrick else
2155 24df9a28 2023-07-08 jrick branch_name = got_ref_get_name(ref);
2156 24df9a28 2023-07-08 jrick
2157 24df9a28 2023-07-08 jrick if (strncmp("refs/heads/", branch_name, 11) == 0)
2158 24df9a28 2023-07-08 jrick branch_name += 11;
2159 24df9a28 2023-07-08 jrick
2160 24df9a28 2023-07-08 jrick snprintf(msg, sizeof(msg),
2161 24df9a28 2023-07-08 jrick "target commit is not contained in branch '%s'; "
2162 24df9a28 2023-07-08 jrick "the branch to use must be specified with -b; "
2163 24df9a28 2023-07-08 jrick "if necessary a new branch can be created for "
2164 24df9a28 2023-07-08 jrick "this commit with 'got branch -c %s BRANCH_NAME'",
2165 24df9a28 2023-07-08 jrick branch_name, commit_id_str);
2166 24df9a28 2023-07-08 jrick
2167 24df9a28 2023-07-08 jrick return got_error_msg(GOT_ERR_ANCESTRY, msg);
2168 24df9a28 2023-07-08 jrick }
2169 24df9a28 2023-07-08 jrick
2170 24df9a28 2023-07-08 jrick static const struct got_error *
2171 24df9a28 2023-07-08 jrick cmd_checkout(int argc, char *argv[])
2172 24df9a28 2023-07-08 jrick {
2173 24df9a28 2023-07-08 jrick const struct got_error *error = NULL;
2174 24df9a28 2023-07-08 jrick struct got_repository *repo = NULL;
2175 24df9a28 2023-07-08 jrick struct got_reference *head_ref = NULL, *ref = NULL;
2176 24df9a28 2023-07-08 jrick struct got_worktree *worktree = NULL;
2177 24df9a28 2023-07-08 jrick char *repo_path = NULL;
2178 24df9a28 2023-07-08 jrick char *worktree_path = NULL;
2179 24df9a28 2023-07-08 jrick const char *path_prefix = "";
2180 24df9a28 2023-07-08 jrick const char *branch_name = GOT_REF_HEAD, *refname = NULL;
2181 24df9a28 2023-07-08 jrick char *commit_id_str = NULL;
2182 24df9a28 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2183 24df9a28 2023-07-08 jrick char *cwd = NULL;
2184 24df9a28 2023-07-08 jrick int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0;
2185 24df9a28 2023-07-08 jrick struct got_pathlist_head paths;
2186 24df9a28 2023-07-08 jrick struct got_checkout_progress_arg cpa;
2187 24df9a28 2023-07-08 jrick int *pack_fds = NULL;
2188 24df9a28 2023-07-08 jrick
2189 24df9a28 2023-07-08 jrick TAILQ_INIT(&paths);
2190 24df9a28 2023-07-08 jrick
2191 24df9a28 2023-07-08 jrick #ifndef PROFILE
2192 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2193 24df9a28 2023-07-08 jrick "unveil", NULL) == -1)
2194 24df9a28 2023-07-08 jrick err(1, "pledge");
2195 24df9a28 2023-07-08 jrick #endif
2196 24df9a28 2023-07-08 jrick
2197 24df9a28 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) {
2198 24df9a28 2023-07-08 jrick switch (ch) {
2199 24df9a28 2023-07-08 jrick case 'b':
2200 24df9a28 2023-07-08 jrick branch_name = optarg;
2201 24df9a28 2023-07-08 jrick break;
2202 24df9a28 2023-07-08 jrick case 'c':
2203 24df9a28 2023-07-08 jrick commit_id_str = strdup(optarg);
2204 24df9a28 2023-07-08 jrick if (commit_id_str == NULL)
2205 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
2206 24df9a28 2023-07-08 jrick break;
2207 24df9a28 2023-07-08 jrick case 'E':
2208 24df9a28 2023-07-08 jrick allow_nonempty = 1;
2209 24df9a28 2023-07-08 jrick break;
2210 24df9a28 2023-07-08 jrick case 'p':
2211 24df9a28 2023-07-08 jrick path_prefix = optarg;
2212 24df9a28 2023-07-08 jrick break;
2213 24df9a28 2023-07-08 jrick case 'q':
2214 24df9a28 2023-07-08 jrick verbosity = -1;
2215 24df9a28 2023-07-08 jrick break;
2216 24df9a28 2023-07-08 jrick default:
2217 24df9a28 2023-07-08 jrick usage_checkout();
2218 24df9a28 2023-07-08 jrick /* NOTREACHED */
2219 24df9a28 2023-07-08 jrick }
2220 24df9a28 2023-07-08 jrick }
2221 24df9a28 2023-07-08 jrick
2222 24df9a28 2023-07-08 jrick argc -= optind;
2223 24df9a28 2023-07-08 jrick argv += optind;
2224 24df9a28 2023-07-08 jrick
2225 24df9a28 2023-07-08 jrick if (argc == 1) {
2226 24df9a28 2023-07-08 jrick char *base, *dotgit;
2227 24df9a28 2023-07-08 jrick const char *path;
2228 24df9a28 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2229 24df9a28 2023-07-08 jrick if (repo_path == NULL)
2230 24df9a28 2023-07-08 jrick return got_error_from_errno2("realpath", argv[0]);
2231 24df9a28 2023-07-08 jrick cwd = getcwd(NULL, 0);
2232 24df9a28 2023-07-08 jrick if (cwd == NULL) {
2233 24df9a28 2023-07-08 jrick error = got_error_from_errno("getcwd");
2234 24df9a28 2023-07-08 jrick goto done;
2235 24df9a28 2023-07-08 jrick }
2236 24df9a28 2023-07-08 jrick if (path_prefix[0])
2237 24df9a28 2023-07-08 jrick path = path_prefix;
2238 24df9a28 2023-07-08 jrick else
2239 24df9a28 2023-07-08 jrick path = repo_path;
2240 24df9a28 2023-07-08 jrick error = got_path_basename(&base, path);
2241 24df9a28 2023-07-08 jrick if (error)
2242 24df9a28 2023-07-08 jrick goto done;
2243 24df9a28 2023-07-08 jrick dotgit = strstr(base, ".git");
2244 24df9a28 2023-07-08 jrick if (dotgit)
2245 24df9a28 2023-07-08 jrick *dotgit = '\0';
2246 24df9a28 2023-07-08 jrick if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2247 24df9a28 2023-07-08 jrick error = got_error_from_errno("asprintf");
2248 24df9a28 2023-07-08 jrick free(base);
2249 24df9a28 2023-07-08 jrick goto done;
2250 24df9a28 2023-07-08 jrick }
2251 24df9a28 2023-07-08 jrick free(base);
2252 24df9a28 2023-07-08 jrick } else if (argc == 2) {
2253 24df9a28 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2254 24df9a28 2023-07-08 jrick if (repo_path == NULL) {
2255 24df9a28 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
2256 24df9a28 2023-07-08 jrick goto done;
2257 24df9a28 2023-07-08 jrick }
2258 24df9a28 2023-07-08 jrick worktree_path = realpath(argv[1], NULL);
2259 24df9a28 2023-07-08 jrick if (worktree_path == NULL) {
2260 24df9a28 2023-07-08 jrick if (errno != ENOENT) {
2261 24df9a28 2023-07-08 jrick error = got_error_from_errno2("realpath",
2262 24df9a28 2023-07-08 jrick argv[1]);
2263 24df9a28 2023-07-08 jrick goto done;
2264 24df9a28 2023-07-08 jrick }
2265 24df9a28 2023-07-08 jrick worktree_path = strdup(argv[1]);
2266 24df9a28 2023-07-08 jrick if (worktree_path == NULL) {
2267 24df9a28 2023-07-08 jrick error = got_error_from_errno("strdup");
2268 24df9a28 2023-07-08 jrick goto done;
2269 24df9a28 2023-07-08 jrick }
2270 24df9a28 2023-07-08 jrick }
2271 24df9a28 2023-07-08 jrick } else
2272 24df9a28 2023-07-08 jrick usage_checkout();
2273 24df9a28 2023-07-08 jrick
2274 24df9a28 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
2275 24df9a28 2023-07-08 jrick got_path_strip_trailing_slashes(worktree_path);
2276 24df9a28 2023-07-08 jrick
2277 24df9a28 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
2278 24df9a28 2023-07-08 jrick if (error != NULL)
2279 24df9a28 2023-07-08 jrick goto done;
2280 24df9a28 2023-07-08 jrick
2281 24df9a28 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
2282 24df9a28 2023-07-08 jrick if (error != NULL)
2283 24df9a28 2023-07-08 jrick goto done;
2284 24df9a28 2023-07-08 jrick
2285 24df9a28 2023-07-08 jrick /* Pre-create work tree path for unveil(2) */
2286 24df9a28 2023-07-08 jrick error = got_path_mkdir(worktree_path);
2287 24df9a28 2023-07-08 jrick if (error) {
2288 24df9a28 2023-07-08 jrick if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2289 24df9a28 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2290 24df9a28 2023-07-08 jrick goto done;
2291 24df9a28 2023-07-08 jrick if (!allow_nonempty &&
2292 24df9a28 2023-07-08 jrick !got_path_dir_is_empty(worktree_path)) {
2293 24df9a28 2023-07-08 jrick error = got_error_path(worktree_path,
2294 24df9a28 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
2295 24df9a28 2023-07-08 jrick goto done;
2296 24df9a28 2023-07-08 jrick }
2297 24df9a28 2023-07-08 jrick }
2298 24df9a28 2023-07-08 jrick
2299 24df9a28 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2300 24df9a28 2023-07-08 jrick if (error)
2301 24df9a28 2023-07-08 jrick goto done;
2302 24df9a28 2023-07-08 jrick
2303 24df9a28 2023-07-08 jrick error = got_ref_open(&head_ref, repo, branch_name, 0);
2304 24df9a28 2023-07-08 jrick if (error != NULL)
2305 24df9a28 2023-07-08 jrick goto done;
2306 24df9a28 2023-07-08 jrick
2307 df6221c7 2023-07-19 stsp error = got_worktree_init(worktree_path, head_ref, path_prefix,
2308 df6221c7 2023-07-19 stsp GOT_WORKTREE_CVG_DIR, repo);
2309 24df9a28 2023-07-08 jrick if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2310 24df9a28 2023-07-08 jrick goto done;
2311 24df9a28 2023-07-08 jrick
2312 df6221c7 2023-07-19 stsp error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR);
2313 24df9a28 2023-07-08 jrick if (error != NULL)
2314 24df9a28 2023-07-08 jrick goto done;
2315 24df9a28 2023-07-08 jrick
2316 24df9a28 2023-07-08 jrick error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2317 24df9a28 2023-07-08 jrick path_prefix);
2318 24df9a28 2023-07-08 jrick if (error != NULL)
2319 24df9a28 2023-07-08 jrick goto done;
2320 24df9a28 2023-07-08 jrick if (!same_path_prefix) {
2321 24df9a28 2023-07-08 jrick error = got_error(GOT_ERR_PATH_PREFIX);
2322 24df9a28 2023-07-08 jrick goto done;
2323 24df9a28 2023-07-08 jrick }
2324 24df9a28 2023-07-08 jrick
2325 24df9a28 2023-07-08 jrick if (commit_id_str) {
2326 24df9a28 2023-07-08 jrick struct got_reflist_head refs;
2327 24df9a28 2023-07-08 jrick TAILQ_INIT(&refs);
2328 24df9a28 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2329 24df9a28 2023-07-08 jrick NULL);
2330 24df9a28 2023-07-08 jrick if (error)
2331 24df9a28 2023-07-08 jrick goto done;
2332 24df9a28 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
2333 24df9a28 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2334 24df9a28 2023-07-08 jrick got_ref_list_free(&refs);
2335 24df9a28 2023-07-08 jrick if (error)
2336 24df9a28 2023-07-08 jrick goto done;
2337 24df9a28 2023-07-08 jrick error = check_linear_ancestry(commit_id,
2338 24df9a28 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2339 24df9a28 2023-07-08 jrick if (error != NULL) {
2340 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2341 24df9a28 2023-07-08 jrick error = checkout_ancestry_error(
2342 24df9a28 2023-07-08 jrick head_ref, commit_id_str);
2343 24df9a28 2023-07-08 jrick }
2344 24df9a28 2023-07-08 jrick goto done;
2345 24df9a28 2023-07-08 jrick }
2346 24df9a28 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
2347 24df9a28 2023-07-08 jrick if (error) {
2348 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2349 24df9a28 2023-07-08 jrick error = checkout_ancestry_error(
2350 24df9a28 2023-07-08 jrick head_ref, commit_id_str);
2351 24df9a28 2023-07-08 jrick }
2352 24df9a28 2023-07-08 jrick goto done;
2353 24df9a28 2023-07-08 jrick }
2354 24df9a28 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
2355 24df9a28 2023-07-08 jrick commit_id);
2356 24df9a28 2023-07-08 jrick if (error)
2357 24df9a28 2023-07-08 jrick goto done;
2358 24df9a28 2023-07-08 jrick /* Expand potentially abbreviated commit ID string. */
2359 24df9a28 2023-07-08 jrick free(commit_id_str);
2360 24df9a28 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2361 24df9a28 2023-07-08 jrick if (error)
2362 24df9a28 2023-07-08 jrick goto done;
2363 24df9a28 2023-07-08 jrick } else {
2364 24df9a28 2023-07-08 jrick commit_id = got_object_id_dup(
2365 24df9a28 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
2366 24df9a28 2023-07-08 jrick if (commit_id == NULL) {
2367 24df9a28 2023-07-08 jrick error = got_error_from_errno("got_object_id_dup");
2368 24df9a28 2023-07-08 jrick goto done;
2369 24df9a28 2023-07-08 jrick }
2370 24df9a28 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2371 24df9a28 2023-07-08 jrick if (error)
2372 24df9a28 2023-07-08 jrick goto done;
2373 24df9a28 2023-07-08 jrick }
2374 24df9a28 2023-07-08 jrick
2375 24df9a28 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
2376 24df9a28 2023-07-08 jrick if (error)
2377 24df9a28 2023-07-08 jrick goto done;
2378 24df9a28 2023-07-08 jrick cpa.worktree_path = worktree_path;
2379 24df9a28 2023-07-08 jrick cpa.had_base_commit_ref_error = 0;
2380 24df9a28 2023-07-08 jrick cpa.verbosity = verbosity;
2381 24df9a28 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
2382 24df9a28 2023-07-08 jrick checkout_progress, &cpa, check_cancelled, NULL);
2383 24df9a28 2023-07-08 jrick if (error != NULL)
2384 24df9a28 2023-07-08 jrick goto done;
2385 24df9a28 2023-07-08 jrick
2386 24df9a28 2023-07-08 jrick if (got_ref_is_symbolic(head_ref)) {
2387 24df9a28 2023-07-08 jrick error = got_ref_resolve_symbolic(&ref, repo, head_ref);
2388 24df9a28 2023-07-08 jrick if (error)
2389 24df9a28 2023-07-08 jrick goto done;
2390 24df9a28 2023-07-08 jrick refname = got_ref_get_name(ref);
2391 24df9a28 2023-07-08 jrick } else
2392 24df9a28 2023-07-08 jrick refname = got_ref_get_name(head_ref);
2393 24df9a28 2023-07-08 jrick printf("Checked out %s: %s\n", refname, commit_id_str);
2394 24df9a28 2023-07-08 jrick printf("Now shut up and hack\n");
2395 24df9a28 2023-07-08 jrick if (cpa.had_base_commit_ref_error)
2396 24df9a28 2023-07-08 jrick show_worktree_base_ref_warning();
2397 24df9a28 2023-07-08 jrick done:
2398 24df9a28 2023-07-08 jrick if (pack_fds) {
2399 24df9a28 2023-07-08 jrick const struct got_error *pack_err =
2400 24df9a28 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2401 24df9a28 2023-07-08 jrick if (error == NULL)
2402 24df9a28 2023-07-08 jrick error = pack_err;
2403 24df9a28 2023-07-08 jrick }
2404 24df9a28 2023-07-08 jrick if (head_ref)
2405 24df9a28 2023-07-08 jrick got_ref_close(head_ref);
2406 24df9a28 2023-07-08 jrick if (ref)
2407 24df9a28 2023-07-08 jrick got_ref_close(ref);
2408 24df9a28 2023-07-08 jrick if (repo) {
2409 24df9a28 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2410 24df9a28 2023-07-08 jrick if (error == NULL)
2411 24df9a28 2023-07-08 jrick error = close_err;
2412 24df9a28 2023-07-08 jrick }
2413 24df9a28 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
2414 24df9a28 2023-07-08 jrick free(commit_id_str);
2415 24df9a28 2023-07-08 jrick free(commit_id);
2416 24df9a28 2023-07-08 jrick free(repo_path);
2417 24df9a28 2023-07-08 jrick free(worktree_path);
2418 24df9a28 2023-07-08 jrick free(cwd);
2419 24df9a28 2023-07-08 jrick return error;
2420 24df9a28 2023-07-08 jrick }
2421 24df9a28 2023-07-08 jrick
2422 24df9a28 2023-07-08 jrick struct got_update_progress_arg {
2423 24df9a28 2023-07-08 jrick int did_something;
2424 24df9a28 2023-07-08 jrick int conflicts;
2425 24df9a28 2023-07-08 jrick int obstructed;
2426 24df9a28 2023-07-08 jrick int not_updated;
2427 24df9a28 2023-07-08 jrick int missing;
2428 24df9a28 2023-07-08 jrick int not_deleted;
2429 24df9a28 2023-07-08 jrick int unversioned;
2430 24df9a28 2023-07-08 jrick int verbosity;
2431 24df9a28 2023-07-08 jrick };
2432 24df9a28 2023-07-08 jrick
2433 24df9a28 2023-07-08 jrick static void
2434 24df9a28 2023-07-08 jrick print_update_progress_stats(struct got_update_progress_arg *upa)
2435 24df9a28 2023-07-08 jrick {
2436 24df9a28 2023-07-08 jrick if (!upa->did_something)
2437 24df9a28 2023-07-08 jrick return;
2438 24df9a28 2023-07-08 jrick
2439 24df9a28 2023-07-08 jrick if (upa->conflicts > 0)
2440 24df9a28 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2441 24df9a28 2023-07-08 jrick if (upa->obstructed > 0)
2442 24df9a28 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2443 24df9a28 2023-07-08 jrick upa->obstructed);
2444 24df9a28 2023-07-08 jrick if (upa->not_updated > 0)
2445 24df9a28 2023-07-08 jrick printf("Files not updated because of existing merge "
2446 24df9a28 2023-07-08 jrick "conflicts: %d\n", upa->not_updated);
2447 24df9a28 2023-07-08 jrick }
2448 24df9a28 2023-07-08 jrick
2449 24df9a28 2023-07-08 jrick /*
2450 24df9a28 2023-07-08 jrick * The meaning of some status codes differs between merge-style operations and
2451 24df9a28 2023-07-08 jrick * update operations. For example, the ! status code means "file was missing"
2452 24df9a28 2023-07-08 jrick * if changes were merged into the work tree, and "missing file was restored"
2453 24df9a28 2023-07-08 jrick * if the work tree was updated. This function should be used by any operation
2454 24df9a28 2023-07-08 jrick * which merges changes into the work tree without updating the work tree.
2455 24df9a28 2023-07-08 jrick */
2456 24df9a28 2023-07-08 jrick static void
2457 24df9a28 2023-07-08 jrick print_merge_progress_stats(struct got_update_progress_arg *upa)
2458 24df9a28 2023-07-08 jrick {
2459 24df9a28 2023-07-08 jrick if (!upa->did_something)
2460 24df9a28 2023-07-08 jrick return;
2461 24df9a28 2023-07-08 jrick
2462 24df9a28 2023-07-08 jrick if (upa->conflicts > 0)
2463 24df9a28 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2464 24df9a28 2023-07-08 jrick if (upa->obstructed > 0)
2465 24df9a28 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2466 24df9a28 2023-07-08 jrick upa->obstructed);
2467 24df9a28 2023-07-08 jrick if (upa->missing > 0)
2468 24df9a28 2023-07-08 jrick printf("Files which had incoming changes but could not be "
2469 24df9a28 2023-07-08 jrick "found in the work tree: %d\n", upa->missing);
2470 24df9a28 2023-07-08 jrick if (upa->not_deleted > 0)
2471 24df9a28 2023-07-08 jrick printf("Files not deleted due to differences in deleted "
2472 24df9a28 2023-07-08 jrick "content: %d\n", upa->not_deleted);
2473 24df9a28 2023-07-08 jrick if (upa->unversioned > 0)
2474 24df9a28 2023-07-08 jrick printf("Files not merged because an unversioned file was "
2475 24df9a28 2023-07-08 jrick "found in the work tree: %d\n", upa->unversioned);
2476 24df9a28 2023-07-08 jrick }
2477 24df9a28 2023-07-08 jrick
2478 24df9a28 2023-07-08 jrick __dead static void
2479 24df9a28 2023-07-08 jrick usage_update(void)
2480 24df9a28 2023-07-08 jrick {
2481 24df9a28 2023-07-08 jrick fprintf(stderr, "usage: %s update [-qtvX] [-c commit] [-r remote] "
2482 24df9a28 2023-07-08 jrick "[path ...]\n", getprogname());
2483 24df9a28 2023-07-08 jrick exit(1);
2484 24df9a28 2023-07-08 jrick }
2485 24df9a28 2023-07-08 jrick
2486 24df9a28 2023-07-08 jrick static const struct got_error *
2487 24df9a28 2023-07-08 jrick update_progress(void *arg, unsigned char status, const char *path)
2488 24df9a28 2023-07-08 jrick {
2489 24df9a28 2023-07-08 jrick struct got_update_progress_arg *upa = arg;
2490 24df9a28 2023-07-08 jrick
2491 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_EXISTS ||
2492 24df9a28 2023-07-08 jrick status == GOT_STATUS_BASE_REF_ERR)
2493 24df9a28 2023-07-08 jrick return NULL;
2494 24df9a28 2023-07-08 jrick
2495 24df9a28 2023-07-08 jrick upa->did_something = 1;
2496 24df9a28 2023-07-08 jrick
2497 24df9a28 2023-07-08 jrick /* Base commit bump happens silently. */
2498 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2499 24df9a28 2023-07-08 jrick return NULL;
2500 24df9a28 2023-07-08 jrick
2501 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_CONFLICT)
2502 24df9a28 2023-07-08 jrick upa->conflicts++;
2503 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_OBSTRUCTED)
2504 24df9a28 2023-07-08 jrick upa->obstructed++;
2505 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_UPDATE)
2506 24df9a28 2023-07-08 jrick upa->not_updated++;
2507 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_MISSING)
2508 24df9a28 2023-07-08 jrick upa->missing++;
2509 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_DELETE)
2510 24df9a28 2023-07-08 jrick upa->not_deleted++;
2511 24df9a28 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
2512 24df9a28 2023-07-08 jrick upa->unversioned++;
2513 24df9a28 2023-07-08 jrick
2514 24df9a28 2023-07-08 jrick while (path[0] == '/')
2515 24df9a28 2023-07-08 jrick path++;
2516 24df9a28 2023-07-08 jrick if (upa->verbosity >= 0)
2517 24df9a28 2023-07-08 jrick printf("%c %s\n", status, path);
2518 24df9a28 2023-07-08 jrick
2519 24df9a28 2023-07-08 jrick return NULL;
2520 24df9a28 2023-07-08 jrick }
2521 24df9a28 2023-07-08 jrick
2522 24df9a28 2023-07-08 jrick static const struct got_error *
2523 24df9a28 2023-07-08 jrick check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
2524 24df9a28 2023-07-08 jrick {
2525 24df9a28 2023-07-08 jrick const struct got_error *err;
2526 24df9a28 2023-07-08 jrick int in_progress;
2527 24df9a28 2023-07-08 jrick
2528 24df9a28 2023-07-08 jrick err = got_worktree_rebase_in_progress(&in_progress, worktree);
2529 24df9a28 2023-07-08 jrick if (err)
2530 24df9a28 2023-07-08 jrick return err;
2531 24df9a28 2023-07-08 jrick if (in_progress)
2532 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_REBASING);
2533 24df9a28 2023-07-08 jrick
2534 24df9a28 2023-07-08 jrick err = got_worktree_histedit_in_progress(&in_progress, worktree);
2535 24df9a28 2023-07-08 jrick if (err)
2536 24df9a28 2023-07-08 jrick return err;
2537 24df9a28 2023-07-08 jrick if (in_progress)
2538 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_HISTEDIT_BUSY);
2539 24df9a28 2023-07-08 jrick
2540 24df9a28 2023-07-08 jrick return NULL;
2541 24df9a28 2023-07-08 jrick }
2542 24df9a28 2023-07-08 jrick
2543 24df9a28 2023-07-08 jrick static const struct got_error *
2544 24df9a28 2023-07-08 jrick check_merge_in_progress(struct got_worktree *worktree,
2545 24df9a28 2023-07-08 jrick struct got_repository *repo)
2546 24df9a28 2023-07-08 jrick {
2547 24df9a28 2023-07-08 jrick const struct got_error *err;
2548 24df9a28 2023-07-08 jrick int in_progress;
2549 24df9a28 2023-07-08 jrick
2550 24df9a28 2023-07-08 jrick err = got_worktree_merge_in_progress(&in_progress, worktree, repo);
2551 24df9a28 2023-07-08 jrick if (err)
2552 24df9a28 2023-07-08 jrick return err;
2553 24df9a28 2023-07-08 jrick if (in_progress)
2554 24df9a28 2023-07-08 jrick return got_error(GOT_ERR_MERGE_BUSY);
2555 24df9a28 2023-07-08 jrick
2556 24df9a28 2023-07-08 jrick return NULL;
2557 24df9a28 2023-07-08 jrick }
2558 24df9a28 2023-07-08 jrick
2559 24df9a28 2023-07-08 jrick static const struct got_error *
2560 24df9a28 2023-07-08 jrick get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
2561 24df9a28 2023-07-08 jrick char *argv[], struct got_worktree *worktree)
2562 24df9a28 2023-07-08 jrick {
2563 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
2564 24df9a28 2023-07-08 jrick char *path;
2565 24df9a28 2023-07-08 jrick struct got_pathlist_entry *new;
2566 24df9a28 2023-07-08 jrick int i;
2567 24df9a28 2023-07-08 jrick
2568 24df9a28 2023-07-08 jrick if (argc == 0) {
2569 24df9a28 2023-07-08 jrick path = strdup("");
2570 24df9a28 2023-07-08 jrick if (path == NULL)
2571 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
2572 24df9a28 2023-07-08 jrick return got_pathlist_append(paths, path, NULL);
2573 24df9a28 2023-07-08 jrick }
2574 24df9a28 2023-07-08 jrick
2575 24df9a28 2023-07-08 jrick for (i = 0; i < argc; i++) {
2576 24df9a28 2023-07-08 jrick err = got_worktree_resolve_path(&path, worktree, argv[i]);
2577 24df9a28 2023-07-08 jrick if (err)
2578 24df9a28 2023-07-08 jrick break;
2579 24df9a28 2023-07-08 jrick err = got_pathlist_insert(&new, paths, path, NULL);
2580 24df9a28 2023-07-08 jrick if (err || new == NULL /* duplicate */) {
2581 24df9a28 2023-07-08 jrick free(path);
2582 24df9a28 2023-07-08 jrick if (err)
2583 24df9a28 2023-07-08 jrick break;
2584 24df9a28 2023-07-08 jrick }
2585 24df9a28 2023-07-08 jrick }
2586 24df9a28 2023-07-08 jrick
2587 24df9a28 2023-07-08 jrick return err;
2588 24df9a28 2023-07-08 jrick }
2589 24df9a28 2023-07-08 jrick
2590 24df9a28 2023-07-08 jrick static const struct got_error *
2591 24df9a28 2023-07-08 jrick wrap_not_worktree_error(const struct got_error *orig_err,
2592 24df9a28 2023-07-08 jrick const char *cmdname, const char *path)
2593 24df9a28 2023-07-08 jrick {
2594 24df9a28 2023-07-08 jrick const struct got_error *err;
2595 24df9a28 2023-07-08 jrick struct got_repository *repo;
2596 24df9a28 2023-07-08 jrick static char msg[512];
2597 24df9a28 2023-07-08 jrick int *pack_fds = NULL;
2598 24df9a28 2023-07-08 jrick
2599 24df9a28 2023-07-08 jrick err = got_repo_pack_fds_open(&pack_fds);
2600 24df9a28 2023-07-08 jrick if (err)
2601 24df9a28 2023-07-08 jrick return err;
2602 24df9a28 2023-07-08 jrick
2603 24df9a28 2023-07-08 jrick err = got_repo_open(&repo, path, NULL, pack_fds);
2604 24df9a28 2023-07-08 jrick if (err)
2605 24df9a28 2023-07-08 jrick return orig_err;
2606 24df9a28 2023-07-08 jrick
2607 24df9a28 2023-07-08 jrick snprintf(msg, sizeof(msg),
2608 24df9a28 2023-07-08 jrick "'got %s' needs a work tree in addition to a git repository\n"
2609 24df9a28 2023-07-08 jrick "Work trees can be checked out from this Git repository with "
2610 24df9a28 2023-07-08 jrick "'got checkout'.\n"
2611 24df9a28 2023-07-08 jrick "The got(1) manual page contains more information.", cmdname);
2612 24df9a28 2023-07-08 jrick err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
2613 24df9a28 2023-07-08 jrick if (repo) {
2614 24df9a28 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2615 24df9a28 2023-07-08 jrick if (err == NULL)
2616 24df9a28 2023-07-08 jrick err = close_err;
2617 24df9a28 2023-07-08 jrick }
2618 24df9a28 2023-07-08 jrick if (pack_fds) {
2619 24df9a28 2023-07-08 jrick const struct got_error *pack_err =
2620 24df9a28 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2621 24df9a28 2023-07-08 jrick if (err == NULL)
2622 24df9a28 2023-07-08 jrick err = pack_err;
2623 24df9a28 2023-07-08 jrick }
2624 24df9a28 2023-07-08 jrick return err;
2625 24df9a28 2023-07-08 jrick }
2626 24df9a28 2023-07-08 jrick
2627 24df9a28 2023-07-08 jrick static const struct got_error *
2628 24df9a28 2023-07-08 jrick cmd_update(int argc, char *argv[])
2629 24df9a28 2023-07-08 jrick {
2630 24df9a28 2023-07-08 jrick const struct got_error *error = NULL, *unlock_err;
2631 24df9a28 2023-07-08 jrick char *worktree_path = NULL;
2632 24df9a28 2023-07-08 jrick const char *repo_path = NULL;
2633 24df9a28 2023-07-08 jrick const char *remote_name = NULL;
2634 24df9a28 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
2635 24df9a28 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
2636 24df9a28 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
2637 24df9a28 2023-07-08 jrick int nremotes;
2638 24df9a28 2023-07-08 jrick char *id_str = NULL;
2639 24df9a28 2023-07-08 jrick struct got_repository *repo = NULL;
2640 24df9a28 2023-07-08 jrick struct got_worktree *worktree = NULL;
2641 24df9a28 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
2642 24df9a28 2023-07-08 jrick struct got_pathlist_head paths, refs, symrefs;
2643 24df9a28 2023-07-08 jrick struct got_pathlist_head wanted_branches, wanted_refs;
2644 24df9a28 2023-07-08 jrick struct got_pathlist_entry *pe;
2645 24df9a28 2023-07-08 jrick struct got_reflist_head remote_refs;
2646 24df9a28 2023-07-08 jrick struct got_reflist_entry *re;
2647 24df9a28 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
2648 24df9a28 2023-07-08 jrick int i, ch, fetchfd = -1, fetchstatus;
2649 24df9a28 2023-07-08 jrick pid_t fetchpid = -1;
2650 24df9a28 2023-07-08 jrick struct got_fetch_progress_arg fpa;
2651 24df9a28 2023-07-08 jrick struct got_update_progress_arg upa;
2652 24df9a28 2023-07-08 jrick int verbosity = 0;
2653 24df9a28 2023-07-08 jrick int delete_remote = 0;
2654 24df9a28 2023-07-08 jrick int replace_tags = 0;
2655 24df9a28 2023-07-08 jrick int *pack_fds = NULL;
2656 24df9a28 2023-07-08 jrick const char *remote_head = NULL, *worktree_branch = NULL;
2657 24df9a28 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2658 24df9a28 2023-07-08 jrick char *commit_id_str = NULL;
2659 24df9a28 2023-07-08 jrick const char *refname;
2660 24df9a28 2023-07-08 jrick struct got_reference *head_ref = NULL;
2661 24df9a28 2023-07-08 jrick
2662 24df9a28 2023-07-08 jrick TAILQ_INIT(&paths);
2663 24df9a28 2023-07-08 jrick TAILQ_INIT(&refs);
2664 24df9a28 2023-07-08 jrick TAILQ_INIT(&symrefs);
2665 24df9a28 2023-07-08 jrick TAILQ_INIT(&remote_refs);
2666 24df9a28 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
2667 24df9a28 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
2668 24df9a28 2023-07-08 jrick
2669 24df9a28 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:qr:vX")) != -1) {
2670 24df9a28 2023-07-08 jrick switch (ch) {
2671 24df9a28 2023-07-08 jrick case 'c':
2672 24df9a28 2023-07-08 jrick commit_id_str = strdup(optarg);
2673 24df9a28 2023-07-08 jrick if (commit_id_str == NULL)
2674 24df9a28 2023-07-08 jrick return got_error_from_errno("strdup");
2675 24df9a28 2023-07-08 jrick break;
2676 24df9a28 2023-07-08 jrick case 't':
2677 24df9a28 2023-07-08 jrick replace_tags = 1;
2678 24df9a28 2023-07-08 jrick break;
2679 24df9a28 2023-07-08 jrick case 'q':
2680 24df9a28 2023-07-08 jrick verbosity = -1;
2681 24df9a28 2023-07-08 jrick break;
2682 24df9a28 2023-07-08 jrick case 'r':
2683 24df9a28 2023-07-08 jrick remote_name = optarg;
2684 24df9a28 2023-07-08 jrick break;
2685 24df9a28 2023-07-08 jrick case 'v':
2686 24df9a28 2023-07-08 jrick if (verbosity < 0)
2687 24df9a28 2023-07-08 jrick verbosity = 0;
2688 24df9a28 2023-07-08 jrick else if (verbosity < 3)
2689 24df9a28 2023-07-08 jrick verbosity++;
2690 24df9a28 2023-07-08 jrick break;
2691 24df9a28 2023-07-08 jrick case 'X':
2692 24df9a28 2023-07-08 jrick delete_remote = 1;
2693 24df9a28 2023-07-08 jrick break;
2694 24df9a28 2023-07-08 jrick default:
2695 24df9a28 2023-07-08 jrick usage_update();
2696 24df9a28 2023-07-08 jrick break;
2697 24df9a28 2023-07-08 jrick }
2698 24df9a28 2023-07-08 jrick }
2699 24df9a28 2023-07-08 jrick argc -= optind;
2700 24df9a28 2023-07-08 jrick argv += optind;
2701 24df9a28 2023-07-08 jrick
2702 24df9a28 2023-07-08 jrick if (delete_remote) {
2703 24df9a28 2023-07-08 jrick if (replace_tags)
2704 24df9a28 2023-07-08 jrick option_conflict('X', 't');
2705 24df9a28 2023-07-08 jrick if (remote_name == NULL)
2706 24df9a28 2023-07-08 jrick errx(1, "-X option requires a remote name");
2707 24df9a28 2023-07-08 jrick }
2708 24df9a28 2023-07-08 jrick if (remote_name == NULL)
2709 24df9a28 2023-07-08 jrick remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
2710 24df9a28 2023-07-08 jrick
2711 24df9a28 2023-07-08 jrick worktree_path = getcwd(NULL, 0);
2712 24df9a28 2023-07-08 jrick if (worktree_path == NULL) {
2713 24df9a28 2023-07-08 jrick error = got_error_from_errno("getcwd");
2714 24df9a28 2023-07-08 jrick goto done;
2715 24df9a28 2023-07-08 jrick }
2716 df6221c7 2023-07-19 stsp error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR);
2717 24df9a28 2023-07-08 jrick if (error) {
2718 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
2719 24df9a28 2023-07-08 jrick error = wrap_not_worktree_error(error, "update",
2720 24df9a28 2023-07-08 jrick worktree_path);
2721 24df9a28 2023-07-08 jrick goto done;
2722 24df9a28 2023-07-08 jrick }
2723 24df9a28 2023-07-08 jrick repo_path = got_worktree_get_repo_path(worktree);
2724 24df9a28 2023-07-08 jrick
2725 24df9a28 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
2726 24df9a28 2023-07-08 jrick if (error != NULL)
2727 24df9a28 2023-07-08 jrick goto done;
2728 24df9a28 2023-07-08 jrick
2729 24df9a28 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
2730 24df9a28 2023-07-08 jrick if (error)
2731 24df9a28 2023-07-08 jrick goto done;
2732 24df9a28 2023-07-08 jrick
2733 24df9a28 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
2734 24df9a28 2023-07-08 jrick if (error)
2735 24df9a28 2023-07-08 jrick goto done;
2736 24df9a28 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
2737 24df9a28 2023-07-08 jrick if (error)
2738 24df9a28 2023-07-08 jrick goto done;
2739 24df9a28 2023-07-08 jrick
2740 24df9a28 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
2741 24df9a28 2023-07-08 jrick if (error)
2742 24df9a28 2023-07-08 jrick goto done;
2743 24df9a28 2023-07-08 jrick
2744 24df9a28 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
2745 24df9a28 2023-07-08 jrick if (worktree_conf) {
2746 24df9a28 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
2747 24df9a28 2023-07-08 jrick worktree_conf);
2748 24df9a28 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
2749 24df9a28 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
2750 24df9a28 2023-07-08 jrick remote = &remotes[i];
2751 24df9a28 2023-07-08 jrick break;
2752 24df9a28 2023-07-08 jrick }
2753 24df9a28 2023-07-08 jrick }
2754 24df9a28 2023-07-08 jrick }
2755 24df9a28 2023-07-08 jrick
2756 24df9a28 2023-07-08 jrick if (remote == NULL) {
2757 24df9a28 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
2758 24df9a28 2023-07-08 jrick if (repo_conf) {
2759 24df9a28 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
2760 24df9a28 2023-07-08 jrick repo_conf);
2761 24df9a28 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
2762 24df9a28 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
2763 24df9a28 2023-07-08 jrick remote = &remotes[i];
2764 24df9a28 2023-07-08 jrick break;
2765 24df9a28 2023-07-08 jrick }
2766 24df9a28 2023-07-08 jrick }
2767 24df9a28 2023-07-08 jrick }
2768 24df9a28 2023-07-08 jrick }
2769 24df9a28 2023-07-08 jrick if (remote == NULL) {
2770 24df9a28 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
2771 24df9a28 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
2772 24df9a28 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
2773 24df9a28 2023-07-08 jrick remote = &remotes[i];
2774 24df9a28 2023-07-08 jrick break;
2775 24df9a28 2023-07-08 jrick }
2776 24df9a28 2023-07-08 jrick }
2777 24df9a28 2023-07-08 jrick }
2778 24df9a28 2023-07-08 jrick if (remote == NULL) {
2779 24df9a28 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
2780 24df9a28 2023-07-08 jrick goto done;
2781 24df9a28 2023-07-08 jrick }
2782 24df9a28 2023-07-08 jrick
2783 24df9a28 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
2784 24df9a28 2023-07-08 jrick &repo_name, remote->fetch_url);
2785 24df9a28 2023-07-08 jrick if (error)
2786 24df9a28 2023-07-08 jrick goto done;
2787 24df9a28 2023-07-08 jrick
2788 24df9a28 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
2789 24df9a28 2023-07-08 jrick #ifndef PROFILE
2790 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2791 24df9a28 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
2792 24df9a28 2023-07-08 jrick err(1, "pledge");
2793 24df9a28 2023-07-08 jrick #endif
2794 24df9a28 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
2795 24df9a28 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
2796 24df9a28 2023-07-08 jrick #ifndef PROFILE
2797 24df9a28 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2798 24df9a28 2023-07-08 jrick "sendfd unveil", NULL) == -1)
2799 24df9a28 2023-07-08 jrick err(1, "pledge");
2800 24df9a28 2023-07-08 jrick #endif
2801 24df9a28 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
2802 24df9a28 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
2803 24df9a28 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
2804 24df9a28 2023-07-08 jrick goto done;
2805 24df9a28 2023-07-08 jrick } else {
2806 24df9a28 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
2807 24df9a28 2023-07-08 jrick goto done;
2808 24df9a28 2023-07-08 jrick }
2809 24df9a28 2023-07-08 jrick
2810 24df9a28 2023-07-08 jrick error = got_dial_apply_unveil(proto);
2811 24df9a28 2023-07-08 jrick if (error)
2812 24df9a28 2023-07-08 jrick goto done;
2813 24df9a28 2023-07-08 jrick
2814 24df9a28 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
2815 24df9a28 2023-07-08 jrick got_worktree_get_root_path(worktree));
2816 24df9a28 2023-07-08 jrick if (error)
2817 24df9a28 2023-07-08 jrick goto done;
2818 24df9a28 2023-07-08 jrick
2819 24df9a28 2023-07-08 jrick if (verbosity >= 0) {
2820 24df9a28 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
2821 24df9a28 2023-07-08 jrick remote->name, proto, host,
2822 24df9a28 2023-07-08 jrick port ? ":" : "", port ? port : "",
2823 24df9a28 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
2824 24df9a28 2023-07-08 jrick }
2825 24df9a28 2023-07-08 jrick
2826 24df9a28 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
2827 24df9a28 2023-07-08 jrick server_path, verbosity);
2828 24df9a28 2023-07-08 jrick if (error)
2829 24df9a28 2023-07-08 jrick goto done;
2830 24df9a28 2023-07-08 jrick
2831 24df9a28 2023-07-08 jrick /*
2832 24df9a28 2023-07-08 jrick * If set, get this remote's HEAD ref target so
2833 24df9a28 2023-07-08 jrick * if it has changed on the server we can fetch it.
2834 24df9a28 2023-07-08 jrick */
2835 24df9a28 2023-07-08 jrick error = got_ref_list(&remote_refs, repo, "refs/remotes",
2836 24df9a28 2023-07-08 jrick got_ref_cmp_by_name, repo);
2837 24df9a28 2023-07-08 jrick if (error)
2838 24df9a28 2023-07-08 jrick goto done;
2839 24df9a28 2023-07-08 jrick
2840 24df9a28 2023-07-08 jrick TAILQ_FOREACH(re, &remote_refs, entry) {
2841 24df9a28 2023-07-08 jrick const char *remote_refname, *remote_target;
2842 24df9a28 2023-07-08 jrick size_t remote_name_len;
2843 24df9a28 2023-07-08 jrick
2844 24df9a28 2023-07-08 jrick if (!got_ref_is_symbolic(re->ref))
2845 24df9a28 2023-07-08 jrick continue;
2846 24df9a28 2023-07-08 jrick
2847 24df9a28 2023-07-08 jrick remote_name_len = strlen(remote->name);
2848 24df9a28 2023-07-08 jrick remote_refname = got_ref_get_name(re->ref);
2849 24df9a28 2023-07-08 jrick
2850 24df9a28 2023-07-08 jrick /* we only want refs/remotes/$remote->name/HEAD */
2851 24df9a28 2023-07-08 jrick if (strncmp(remote_refname + 13, remote->name,
2852 24df9a28 2023-07-08 jrick remote_name_len) != 0)
2853 24df9a28 2023-07-08 jrick continue;
2854 24df9a28 2023-07-08 jrick
2855 24df9a28 2023-07-08 jrick if (strcmp(remote_refname + remote_name_len + 14,
2856 24df9a28 2023-07-08 jrick GOT_REF_HEAD) != 0)
2857 24df9a28 2023-07-08 jrick continue;
2858 24df9a28 2023-07-08 jrick
2859 24df9a28 2023-07-08 jrick /*
2860 24df9a28 2023-07-08 jrick * Take the name itself because we already
2861 24df9a28 2023-07-08 jrick * only match with refs/heads/ in fetch_pack().
2862 24df9a28 2023-07-08 jrick */
2863 24df9a28 2023-07-08 jrick remote_target = got_ref_get_symref_target(re->ref);
2864 24df9a28 2023-07-08 jrick remote_head = remote_target + remote_name_len + 14;
2865 24df9a28 2023-07-08 jrick break;
2866 24df9a28 2023-07-08 jrick }
2867 24df9a28 2023-07-08 jrick
2868 24df9a28 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
2869 24df9a28 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
2870 24df9a28 2023-07-08 jrick worktree_branch = refname;
2871 24df9a28 2023-07-08 jrick
2872 24df9a28 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
2873 24df9a28 2023-07-08 jrick fpa.last_p_indexed = -1;
2874 24df9a28 2023-07-08 jrick fpa.last_p_resolved = -1;
2875 24df9a28 2023-07-08 jrick fpa.verbosity = verbosity;
2876 24df9a28 2023-07-08 jrick fpa.repo = repo;
2877 24df9a28 2023-07-08 jrick fpa.create_configs = 0;
2878 24df9a28 2023-07-08 jrick fpa.configs_created = 0;
2879 24df9a28 2023-07-08 jrick memset(&fpa.config_info, 0, sizeof(fpa.config_info));
2880 24df9a28 2023-07-08 jrick
2881 24df9a28 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
2882 24df9a28 2023-07-08 jrick remote->mirror_references, 0, &wanted_branches, &wanted_refs,
2883 24df9a28 2023-07-08 jrick 0, verbosity, fetchfd, repo, worktree_branch, remote_head,
2884 24df9a28 2023-07-08 jrick 0, fetch_progress, &fpa);
2885 24df9a28 2023-07-08 jrick if (error)
2886 24df9a28 2023-07-08 jrick goto done;
2887 24df9a28 2023-07-08 jrick
2888 24df9a28 2023-07-08 jrick if (pack_hash != NULL && verbosity >= 0) {
2889 24df9a28 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
2890 24df9a28 2023-07-08 jrick if (error)
2891 24df9a28 2023-07-08 jrick goto done;
2892 24df9a28 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
2893 24df9a28 2023-07-08 jrick free(id_str);
2894 24df9a28 2023-07-08 jrick id_str = NULL;
2895 24df9a28 2023-07-08 jrick }
2896 24df9a28 2023-07-08 jrick
2897 24df9a28 2023-07-08 jrick /* Update references provided with the pack file. */
2898 24df9a28 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
2899 24df9a28 2023-07-08 jrick const char *refname = pe->path;
2900 24df9a28 2023-07-08 jrick struct got_object_id *id = pe->data;
2901 24df9a28 2023-07-08 jrick struct got_reference *ref;
2902 24df9a28 2023-07-08 jrick
2903 24df9a28 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname)) {
2904 24df9a28 2023-07-08 jrick error = update_wanted_ref(refname, id,
2905 24df9a28 2023-07-08 jrick remote->name, verbosity, repo);
2906 24df9a28 2023-07-08 jrick if (error)
2907 24df9a28 2023-07-08 jrick goto done;
2908 24df9a28 2023-07-08 jrick continue;
2909 24df9a28 2023-07-08 jrick }
2910 24df9a28 2023-07-08 jrick
2911 24df9a28 2023-07-08 jrick error = got_ref_open(&ref, repo, refname, 1);
2912 24df9a28 2023-07-08 jrick if (error) {
2913 24df9a28 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
2914 24df9a28 2023-07-08 jrick goto done;
2915 24df9a28 2023-07-08 jrick error = create_ref(refname, id, verbosity,
2916 24df9a28 2023-07-08 jrick repo);
2917 24df9a28 2023-07-08 jrick if (error)
2918 24df9a28 2023-07-08 jrick goto done;
2919 24df9a28 2023-07-08 jrick } else {
2920 24df9a28 2023-07-08 jrick error = update_ref(ref, id, replace_tags,
2921 24df9a28 2023-07-08 jrick verbosity-1, repo);
2922 24df9a28 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
2923 24df9a28 2023-07-08 jrick if (unlock_err && error == NULL)
2924 24df9a28 2023-07-08 jrick error = unlock_err;
2925 24df9a28 2023-07-08 jrick got_ref_close(ref);
2926 24df9a28 2023-07-08 jrick if (error)
2927 24df9a28 2023-07-08 jrick goto done;
2928 24df9a28 2023-07-08 jrick }
2929 24df9a28 2023-07-08 jrick }
2930 24df9a28 2023-07-08 jrick
2931 24df9a28 2023-07-08 jrick /* Update worktree */
2932 24df9a28 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
2933 24df9a28 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
2934 24df9a28 2023-07-08 jrick if (error != NULL)
2935 24df9a28 2023-07-08 jrick goto done;
2936 24df9a28 2023-07-08 jrick if (commit_id_str == NULL) {
2937 24df9a28 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
2938 24df9a28 2023-07-08 jrick if (error != NULL)
2939 24df9a28 2023-07-08 jrick goto done;
2940 24df9a28 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2941 24df9a28 2023-07-08 jrick if (error != NULL)
2942 24df9a28 2023-07-08 jrick goto done;
2943 24df9a28 2023-07-08 jrick } else {
2944 24df9a28 2023-07-08 jrick struct got_reflist_head refs;
2945 24df9a28 2023-07-08 jrick TAILQ_INIT(&refs);
2946 24df9a28 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2947 24df9a28 2023-07-08 jrick NULL);
2948 24df9a28 2023-07-08 jrick if (error)
2949 24df9a28 2023-07-08 jrick goto done;
2950 24df9a28 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
2951 24df9a28 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2952 24df9a28 2023-07-08 jrick got_ref_list_free(&refs);
2953 24df9a28 2023-07-08 jrick free(commit_id_str);
2954 24df9a28 2023-07-08 jrick commit_id_str = NULL;
2955 24df9a28 2023-07-08 jrick if (error)
2956 24df9a28 2023-07-08 jrick goto done;
2957 24df9a28 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2958 24df9a28 2023-07-08 jrick if (error)
2959 24df9a28 2023-07-08 jrick goto done;
2960 24df9a28 2023-07-08 jrick }
2961 24df9a28 2023-07-08 jrick
2962 24df9a28 2023-07-08 jrick
2963 24df9a28 2023-07-08 jrick error = check_linear_ancestry(commit_id,
2964 24df9a28 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2965 24df9a28 2023-07-08 jrick if (error != NULL) {
2966 24df9a28 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY)
2967 24df9a28 2023-07-08 jrick error = got_error(GOT_ERR_BRANCH_MOVED);
2968 24df9a28 2023-07-08 jrick goto done;
2969 24df9a28 2023-07-08 jrick }
2970 24df9a28 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
2971 24df9a28 2023-07-08 jrick if (error)
2972 24df9a28 2023-07-08 jrick goto done;
2973 24df9a28 2023-07-08 jrick
2974 24df9a28 2023-07-08 jrick if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
2975 24df9a28 2023-07-08 jrick commit_id) != 0) {
2976 24df9a28 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
2977 24df9a28 2023-07-08 jrick commit_id);
2978 24df9a28 2023-07-08 jrick if (error)
2979 24df9a28 2023-07-08 jrick goto done;
2980 24df9a28 2023-07-08 jrick }
2981 24df9a28 2023-07-08 jrick
2982 24df9a28 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
2983 24df9a28 2023-07-08 jrick upa.verbosity = verbosity;
2984 24df9a28 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
2985 24df9a28 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
2986 24df9a28 2023-07-08 jrick if (error != NULL)
2987 24df9a28 2023-07-08 jrick goto done;
2988 24df9a28 2023-07-08 jrick
2989 24df9a28 2023-07-08 jrick if (upa.did_something) {
2990 24df9a28 2023-07-08 jrick printf("Updated to %s: %s\n",
2991 24df9a28 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), commit_id_str);
2992 24df9a28 2023-07-08 jrick } else
2993 24df9a28 2023-07-08 jrick printf("Already up-to-date\n");
2994 24df9a28 2023-07-08 jrick
2995 24df9a28 2023-07-08 jrick print_update_progress_stats(&upa);
2996 24df9a28 2023-07-08 jrick done:
2997 24df9a28 2023-07-08 jrick if (fetchpid > 0) {
2998 24df9a28 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
2999 24df9a28 2023-07-08 jrick error = got_error_from_errno("kill");
3000 24df9a28 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
3001 24df9a28 2023-07-08 jrick error = got_error_from_errno("waitpid");
3002 24df9a28 2023-07-08 jrick }
3003 24df9a28 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
3004 24df9a28 2023-07-08 jrick error = got_error_from_errno("close");
3005 24df9a28 2023-07-08 jrick if (repo) {
3006 24df9a28 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
3007 24df9a28 2023-07-08 jrick if (error == NULL)
3008 24df9a28 2023-07-08 jrick error = close_err;
3009 24df9a28 2023-07-08 jrick }
3010 24df9a28 2023-07-08 jrick if (worktree)
3011 24df9a28 2023-07-08 jrick got_worktree_close(worktree);
3012 24df9a28 2023-07-08 jrick if (pack_fds) {
3013 24df9a28 2023-07-08 jrick const struct got_error *pack_err =
3014 24df9a28 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
3015 24df9a28 2023-07-08 jrick if (error == NULL)
3016 24df9a28 2023-07-08 jrick error = pack_err;
3017 24df9a28 2023-07-08 jrick }
3018 24df9a28 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
3019 24df9a28 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
3020 24df9a28 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
3021 24df9a28 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
3022 24df9a28 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
3023 24df9a28 2023-07-08 jrick got_ref_list_free(&remote_refs);
3024 24df9a28 2023-07-08 jrick free(id_str);
3025 24df9a28 2023-07-08 jrick free(worktree_path);
3026 24df9a28 2023-07-08 jrick free(pack_hash);
3027 24df9a28 2023-07-08 jrick free(proto);
3028 24df9a28 2023-07-08 jrick free(host);
3029 24df9a28 2023-07-08 jrick free(port);
3030 24df9a28 2023-07-08 jrick free(server_path);
3031 24df9a28 2023-07-08 jrick free(repo_name);
3032 24df9a28 2023-07-08 jrick free(commit_id);
3033 24df9a28 2023-07-08 jrick free(commit_id_str);
3034 24df9a28 2023-07-08 jrick return error;
3035 24df9a28 2023-07-08 jrick }
3036 24df9a28 2023-07-08 jrick
3037 24df9a28 2023-07-08 jrick static const struct got_error *
3038 24df9a28 2023-07-08 jrick diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3039 24df9a28 2023-07-08 jrick const char *path, int diff_context, int ignore_whitespace,
3040 24df9a28 2023-07-08 jrick int force_text_diff, struct got_diffstat_cb_arg *dsa,
3041 24df9a28 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3042 24df9a28 2023-07-08 jrick {
3043 24df9a28 2023-07-08 jrick const struct got_error *err = NULL;
3044 24df9a28 2023-07-08 jrick struct got_blob_object *blob1 = NULL, *blob2 = NULL;
3045 24df9a28 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3046 24df9a28 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3047 24df9a28 2023-07-08 jrick
3048 24df9a28 2023-07-08 jrick fd1 = got_opentempfd();
3049 24df9a28 2023-07-08 jrick if (fd1 == -1)
3050 24df9a28 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
3051 24df9a28 2023-07-08 jrick fd2 = got_opentempfd();
3052 24df9a28 2023-07-08 jrick if (fd2 == -1) {
3053 24df9a28 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3054 24df9a28 2023-07-08 jrick goto done;
3055 24df9a28 2023-07-08 jrick }
3056 24df9a28 2023-07-08 jrick
3057 24df9a28 2023-07-08 jrick if (blob_id1) {
3058 24df9a28 2023-07-08 jrick err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192,
3059 24df9a28 2023-07-08 jrick fd1);
3060 24df9a28 2023-07-08 jrick if (err)
3061 24df9a28 2023-07-08 jrick goto done;
3062 24df9a28 2023-07-08 jrick }
3063 24df9a28 2023-07-08 jrick
3064 24df9a28 2023-07-08 jrick err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2);
3065 24df9a28 2023-07-08 jrick if (err)
3066 24df9a28 2023-07-08 jrick goto done;
3067 24df9a28 2023-07-08 jrick
3068 24df9a28 2023-07-08 jrick f1 = got_opentemp();
3069 24df9a28 2023-07-08 jrick if (f1 == NULL) {
3070 24df9a28 2023-07-08 jrick err = got_error_from_errno("got_opentemp");