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