Blame


1 5c860e29 2018-03-12 stsp /*
2 f42b1b34 2018-03-12 stsp * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 5aa81393 2020-01-06 stsp * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 93658fb9 2020-03-18 stsp * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 5c860e29 2018-03-12 stsp *
6 5c860e29 2018-03-12 stsp * Permission to use, copy, modify, and distribute this software for any
7 5c860e29 2018-03-12 stsp * purpose with or without fee is hereby granted, provided that the above
8 5c860e29 2018-03-12 stsp * copyright notice and this permission notice appear in all copies.
9 5c860e29 2018-03-12 stsp *
10 5c860e29 2018-03-12 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 5c860e29 2018-03-12 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 5c860e29 2018-03-12 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 5c860e29 2018-03-12 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 5c860e29 2018-03-12 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 5c860e29 2018-03-12 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 5c860e29 2018-03-12 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 5c860e29 2018-03-12 stsp */
18 5c860e29 2018-03-12 stsp
19 f42b1b34 2018-03-12 stsp #include <sys/queue.h>
20 c0768b0f 2018-06-10 stsp #include <sys/types.h>
21 5de5890b 2018-10-18 stsp #include <sys/stat.h>
22 33ad4cbe 2019-05-12 jcs #include <sys/wait.h>
23 f42b1b34 2018-03-12 stsp
24 5c860e29 2018-03-12 stsp #include <err.h>
25 5c860e29 2018-03-12 stsp #include <errno.h>
26 12463d8b 2019-12-13 stsp #include <fcntl.h>
27 12ce7a6c 2019-08-12 stsp #include <limits.h>
28 5c860e29 2018-03-12 stsp #include <locale.h>
29 818c7501 2019-07-11 stsp #include <ctype.h>
30 d7b5a0e8 2022-04-20 stsp #include <sha1.h>
31 99437157 2018-11-11 stsp #include <signal.h>
32 5c860e29 2018-03-12 stsp #include <stdio.h>
33 5c860e29 2018-03-12 stsp #include <stdlib.h>
34 5c860e29 2018-03-12 stsp #include <string.h>
35 5c860e29 2018-03-12 stsp #include <unistd.h>
36 c09a553d 2018-03-12 stsp #include <libgen.h>
37 c0768b0f 2018-06-10 stsp #include <time.h>
38 33ad4cbe 2019-05-12 jcs #include <paths.h>
39 6841bf13 2019-11-29 kn #include <regex.h>
40 83cd27f8 2020-01-13 stsp #include <getopt.h>
41 d2cdc636 2020-03-18 stsp #include <util.h>
42 5c860e29 2018-03-12 stsp
43 53ccebc2 2019-07-30 stsp #include "got_version.h"
44 f42b1b34 2018-03-12 stsp #include "got_error.h"
45 f42b1b34 2018-03-12 stsp #include "got_object.h"
46 5261c201 2018-04-01 stsp #include "got_reference.h"
47 f42b1b34 2018-03-12 stsp #include "got_repository.h"
48 1dd54920 2019-05-11 stsp #include "got_path.h"
49 e6209546 2019-08-22 stsp #include "got_cancel.h"
50 c09a553d 2018-03-12 stsp #include "got_worktree.h"
51 79109fed 2018-03-27 stsp #include "got_diff.h"
52 372ccdbb 2018-06-10 stsp #include "got_commit_graph.h"
53 6f23baec 2020-03-18 stsp #include "got_fetch.h"
54 f8a36e22 2021-08-26 stsp #include "got_send.h"
55 404c43c4 2018-06-21 stsp #include "got_blame.h"
56 63219cd2 2019-01-04 stsp #include "got_privsep.h"
57 793c30b5 2019-05-13 stsp #include "got_opentemp.h"
58 50b0790e 2020-09-11 stsp #include "got_gotconfig.h"
59 d65a88a2 2021-09-05 stsp #include "got_dial.h"
60 e9ce266e 2022-03-07 op #include "got_patch.h"
61 5c860e29 2018-03-12 stsp
62 5c860e29 2018-03-12 stsp #ifndef nitems
63 5c860e29 2018-03-12 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
64 5c860e29 2018-03-12 stsp #endif
65 99437157 2018-11-11 stsp
66 99437157 2018-11-11 stsp static volatile sig_atomic_t sigint_received;
67 99437157 2018-11-11 stsp static volatile sig_atomic_t sigpipe_received;
68 99437157 2018-11-11 stsp
69 99437157 2018-11-11 stsp static void
70 99437157 2018-11-11 stsp catch_sigint(int signo)
71 99437157 2018-11-11 stsp {
72 99437157 2018-11-11 stsp sigint_received = 1;
73 99437157 2018-11-11 stsp }
74 99437157 2018-11-11 stsp
75 99437157 2018-11-11 stsp static void
76 99437157 2018-11-11 stsp catch_sigpipe(int signo)
77 99437157 2018-11-11 stsp {
78 99437157 2018-11-11 stsp sigpipe_received = 1;
79 99437157 2018-11-11 stsp }
80 5c860e29 2018-03-12 stsp
81 99437157 2018-11-11 stsp
82 8cfb4057 2019-07-09 stsp struct got_cmd {
83 820059fa 2020-09-25 stsp const char *cmd_name;
84 d7d4f210 2018-03-12 stsp const struct got_error *(*cmd_main)(int, char *[]);
85 1b6b95a8 2018-03-12 stsp void (*cmd_usage)(void);
86 97b3a7be 2019-07-09 stsp const char *cmd_alias;
87 5c860e29 2018-03-12 stsp };
88 5c860e29 2018-03-12 stsp
89 6879ba42 2020-10-01 naddy __dead static void usage(int, int);
90 2c7829a4 2019-06-17 stsp __dead static void usage_init(void);
91 3ce1b845 2019-07-15 stsp __dead static void usage_import(void);
92 93658fb9 2020-03-18 stsp __dead static void usage_clone(void);
93 7848a0e1 2020-03-19 stsp __dead static void usage_fetch(void);
94 2ab43947 2020-03-18 stsp __dead static void usage_checkout(void);
95 507dc3bb 2018-12-29 stsp __dead static void usage_update(void);
96 4ed7e80c 2018-05-20 stsp __dead static void usage_log(void);
97 4ed7e80c 2018-05-20 stsp __dead static void usage_diff(void);
98 404c43c4 2018-06-21 stsp __dead static void usage_blame(void);
99 5de5890b 2018-10-18 stsp __dead static void usage_tree(void);
100 6bad629b 2019-02-04 stsp __dead static void usage_status(void);
101 d0eebce4 2019-03-11 stsp __dead static void usage_ref(void);
102 4e759de4 2019-06-26 stsp __dead static void usage_branch(void);
103 8e7bd50a 2019-08-22 stsp __dead static void usage_tag(void);
104 d00136be 2019-03-26 stsp __dead static void usage_add(void);
105 648e4ef7 2019-07-09 stsp __dead static void usage_remove(void);
106 e9ce266e 2022-03-07 op __dead static void usage_patch(void);
107 a129376b 2019-03-28 stsp __dead static void usage_revert(void);
108 c4296144 2019-05-09 stsp __dead static void usage_commit(void);
109 f8a36e22 2021-08-26 stsp __dead static void usage_send(void);
110 234035bc 2019-06-01 stsp __dead static void usage_cherrypick(void);
111 5ef14e63 2019-06-02 stsp __dead static void usage_backout(void);
112 818c7501 2019-07-11 stsp __dead static void usage_rebase(void);
113 0ebf8283 2019-07-24 stsp __dead static void usage_histedit(void);
114 2822a352 2019-10-15 stsp __dead static void usage_integrate(void);
115 f259c4c1 2021-09-24 stsp __dead static void usage_merge(void);
116 715dc77e 2019-08-03 stsp __dead static void usage_stage(void);
117 ad493afc 2019-08-03 stsp __dead static void usage_unstage(void);
118 01073a5d 2019-08-22 stsp __dead static void usage_cat(void);
119 b2118c49 2020-07-28 stsp __dead static void usage_info(void);
120 5c860e29 2018-03-12 stsp
121 2c7829a4 2019-06-17 stsp static const struct got_error* cmd_init(int, char *[]);
122 3ce1b845 2019-07-15 stsp static const struct got_error* cmd_import(int, char *[]);
123 93658fb9 2020-03-18 stsp static const struct got_error* cmd_clone(int, char *[]);
124 7848a0e1 2020-03-19 stsp static const struct got_error* cmd_fetch(int, char *[]);
125 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_checkout(int, char *[]);
126 507dc3bb 2018-12-29 stsp static const struct got_error* cmd_update(int, char *[]);
127 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_log(int, char *[]);
128 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_diff(int, char *[]);
129 404c43c4 2018-06-21 stsp static const struct got_error* cmd_blame(int, char *[]);
130 5de5890b 2018-10-18 stsp static const struct got_error* cmd_tree(int, char *[]);
131 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_status(int, char *[]);
132 d0eebce4 2019-03-11 stsp static const struct got_error* cmd_ref(int, char *[]);
133 4e759de4 2019-06-26 stsp static const struct got_error* cmd_branch(int, char *[]);
134 8e7bd50a 2019-08-22 stsp static const struct got_error* cmd_tag(int, char *[]);
135 d00136be 2019-03-26 stsp static const struct got_error* cmd_add(int, char *[]);
136 648e4ef7 2019-07-09 stsp static const struct got_error* cmd_remove(int, char *[]);
137 e9ce266e 2022-03-07 op static const struct got_error* cmd_patch(int, char *[]);
138 a129376b 2019-03-28 stsp static const struct got_error* cmd_revert(int, char *[]);
139 c4296144 2019-05-09 stsp static const struct got_error* cmd_commit(int, char *[]);
140 f8a36e22 2021-08-26 stsp static const struct got_error* cmd_send(int, char *[]);
141 234035bc 2019-06-01 stsp static const struct got_error* cmd_cherrypick(int, char *[]);
142 5ef14e63 2019-06-02 stsp static const struct got_error* cmd_backout(int, char *[]);
143 818c7501 2019-07-11 stsp static const struct got_error* cmd_rebase(int, char *[]);
144 0ebf8283 2019-07-24 stsp static const struct got_error* cmd_histedit(int, char *[]);
145 2822a352 2019-10-15 stsp static const struct got_error* cmd_integrate(int, char *[]);
146 f259c4c1 2021-09-24 stsp static const struct got_error* cmd_merge(int, char *[]);
147 715dc77e 2019-08-03 stsp static const struct got_error* cmd_stage(int, char *[]);
148 ad493afc 2019-08-03 stsp static const struct got_error* cmd_unstage(int, char *[]);
149 01073a5d 2019-08-22 stsp static const struct got_error* cmd_cat(int, char *[]);
150 b2118c49 2020-07-28 stsp static const struct got_error* cmd_info(int, char *[]);
151 5c860e29 2018-03-12 stsp
152 3e166534 2022-02-16 naddy static const struct got_cmd got_commands[] = {
153 b2118c49 2020-07-28 stsp { "init", cmd_init, usage_init, "" },
154 bc26cce8 2019-08-04 stsp { "import", cmd_import, usage_import, "im" },
155 93658fb9 2020-03-18 stsp { "clone", cmd_clone, usage_clone, "cl" },
156 7848a0e1 2020-03-19 stsp { "fetch", cmd_fetch, usage_fetch, "fe" },
157 2ab43947 2020-03-18 stsp { "checkout", cmd_checkout, usage_checkout, "co" },
158 97b3a7be 2019-07-09 stsp { "update", cmd_update, usage_update, "up" },
159 97b3a7be 2019-07-09 stsp { "log", cmd_log, usage_log, "" },
160 bc26cce8 2019-08-04 stsp { "diff", cmd_diff, usage_diff, "di" },
161 bc26cce8 2019-08-04 stsp { "blame", cmd_blame, usage_blame, "bl" },
162 bc26cce8 2019-08-04 stsp { "tree", cmd_tree, usage_tree, "tr" },
163 97b3a7be 2019-07-09 stsp { "status", cmd_status, usage_status, "st" },
164 97b3a7be 2019-07-09 stsp { "ref", cmd_ref, usage_ref, "" },
165 97b3a7be 2019-07-09 stsp { "branch", cmd_branch, usage_branch, "br" },
166 8e7bd50a 2019-08-22 stsp { "tag", cmd_tag, usage_tag, "" },
167 97b3a7be 2019-07-09 stsp { "add", cmd_add, usage_add, "" },
168 648e4ef7 2019-07-09 stsp { "remove", cmd_remove, usage_remove, "rm" },
169 e9ce266e 2022-03-07 op { "patch", cmd_patch, usage_patch, "pa" },
170 97b3a7be 2019-07-09 stsp { "revert", cmd_revert, usage_revert, "rv" },
171 97b3a7be 2019-07-09 stsp { "commit", cmd_commit, usage_commit, "ci" },
172 f8a36e22 2021-08-26 stsp { "send", cmd_send, usage_send, "se" },
173 016477fd 2019-07-09 stsp { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
174 97b3a7be 2019-07-09 stsp { "backout", cmd_backout, usage_backout, "bo" },
175 818c7501 2019-07-11 stsp { "rebase", cmd_rebase, usage_rebase, "rb" },
176 0ebf8283 2019-07-24 stsp { "histedit", cmd_histedit, usage_histedit, "he" },
177 2822a352 2019-10-15 stsp { "integrate", cmd_integrate, usage_integrate,"ig" },
178 f259c4c1 2021-09-24 stsp { "merge", cmd_merge, usage_merge, "mg" },
179 715dc77e 2019-08-03 stsp { "stage", cmd_stage, usage_stage, "sg" },
180 ad493afc 2019-08-03 stsp { "unstage", cmd_unstage, usage_unstage, "ug" },
181 01073a5d 2019-08-22 stsp { "cat", cmd_cat, usage_cat, "" },
182 b2118c49 2020-07-28 stsp { "info", cmd_info, usage_info, "" },
183 5c860e29 2018-03-12 stsp };
184 ce5b7c56 2019-07-09 stsp
185 ce5b7c56 2019-07-09 stsp static void
186 6879ba42 2020-10-01 naddy list_commands(FILE *fp)
187 ce5b7c56 2019-07-09 stsp {
188 6059809a 2020-12-17 stsp size_t i;
189 ce5b7c56 2019-07-09 stsp
190 6879ba42 2020-10-01 naddy fprintf(fp, "commands:");
191 ce5b7c56 2019-07-09 stsp for (i = 0; i < nitems(got_commands); i++) {
192 3e166534 2022-02-16 naddy const struct got_cmd *cmd = &got_commands[i];
193 6879ba42 2020-10-01 naddy fprintf(fp, " %s", cmd->cmd_name);
194 ce5b7c56 2019-07-09 stsp }
195 6879ba42 2020-10-01 naddy fputc('\n', fp);
196 ce5b7c56 2019-07-09 stsp }
197 5c860e29 2018-03-12 stsp
198 ff69268e 2020-12-13 stsp __dead static void
199 ff69268e 2020-12-13 stsp option_conflict(char a, char b)
200 ff69268e 2020-12-13 stsp {
201 ff69268e 2020-12-13 stsp errx(1, "-%c and -%c options are mutually exclusive", a, b);
202 ff69268e 2020-12-13 stsp }
203 ff69268e 2020-12-13 stsp
204 5c860e29 2018-03-12 stsp int
205 5c860e29 2018-03-12 stsp main(int argc, char *argv[])
206 5c860e29 2018-03-12 stsp {
207 3e166534 2022-02-16 naddy const struct got_cmd *cmd;
208 6059809a 2020-12-17 stsp size_t i;
209 5c860e29 2018-03-12 stsp int ch;
210 53ccebc2 2019-07-30 stsp int hflag = 0, Vflag = 0;
211 3e166534 2022-02-16 naddy static const struct option longopts[] = {
212 62d463ca 2020-10-20 naddy { "version", no_argument, NULL, 'V' },
213 62d463ca 2020-10-20 naddy { NULL, 0, NULL, 0 }
214 83cd27f8 2020-01-13 stsp };
215 5c860e29 2018-03-12 stsp
216 289e3cbf 2019-02-04 stsp setlocale(LC_CTYPE, "");
217 5c860e29 2018-03-12 stsp
218 6586ea88 2020-01-13 stsp while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
219 5c860e29 2018-03-12 stsp switch (ch) {
220 1b6b95a8 2018-03-12 stsp case 'h':
221 1b6b95a8 2018-03-12 stsp hflag = 1;
222 53ccebc2 2019-07-30 stsp break;
223 53ccebc2 2019-07-30 stsp case 'V':
224 53ccebc2 2019-07-30 stsp Vflag = 1;
225 1b6b95a8 2018-03-12 stsp break;
226 5c860e29 2018-03-12 stsp default:
227 6879ba42 2020-10-01 naddy usage(hflag, 1);
228 5c860e29 2018-03-12 stsp /* NOTREACHED */
229 5c860e29 2018-03-12 stsp }
230 5c860e29 2018-03-12 stsp }
231 5c860e29 2018-03-12 stsp
232 5c860e29 2018-03-12 stsp argc -= optind;
233 5c860e29 2018-03-12 stsp argv += optind;
234 9814e6a3 2020-09-27 naddy optind = 1;
235 9814e6a3 2020-09-27 naddy optreset = 1;
236 53ccebc2 2019-07-30 stsp
237 53ccebc2 2019-07-30 stsp if (Vflag) {
238 53ccebc2 2019-07-30 stsp got_version_print_str();
239 6879ba42 2020-10-01 naddy return 0;
240 53ccebc2 2019-07-30 stsp }
241 5c860e29 2018-03-12 stsp
242 5c860e29 2018-03-12 stsp if (argc <= 0)
243 6879ba42 2020-10-01 naddy usage(hflag, hflag ? 0 : 1);
244 5c860e29 2018-03-12 stsp
245 99437157 2018-11-11 stsp signal(SIGINT, catch_sigint);
246 99437157 2018-11-11 stsp signal(SIGPIPE, catch_sigpipe);
247 99437157 2018-11-11 stsp
248 5c860e29 2018-03-12 stsp for (i = 0; i < nitems(got_commands); i++) {
249 d7d4f210 2018-03-12 stsp const struct got_error *error;
250 d7d4f210 2018-03-12 stsp
251 5c860e29 2018-03-12 stsp cmd = &got_commands[i];
252 5c860e29 2018-03-12 stsp
253 97b3a7be 2019-07-09 stsp if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
254 97b3a7be 2019-07-09 stsp strcmp(cmd->cmd_alias, argv[0]) != 0)
255 5c860e29 2018-03-12 stsp continue;
256 5c860e29 2018-03-12 stsp
257 1b6b95a8 2018-03-12 stsp if (hflag)
258 3e166534 2022-02-16 naddy cmd->cmd_usage();
259 1b6b95a8 2018-03-12 stsp
260 3e166534 2022-02-16 naddy error = cmd->cmd_main(argc, argv);
261 f8afbdc8 2019-11-08 stsp if (error && error->code != GOT_ERR_CANCELLED &&
262 f8afbdc8 2019-11-08 stsp error->code != GOT_ERR_PRIVSEP_EXIT &&
263 f8afbdc8 2019-11-08 stsp !(sigpipe_received &&
264 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
265 70015d7a 2019-11-08 stsp !(sigint_received &&
266 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EINTR)) {
267 d7d4f210 2018-03-12 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
268 d7d4f210 2018-03-12 stsp return 1;
269 d7d4f210 2018-03-12 stsp }
270 d7d4f210 2018-03-12 stsp
271 d7d4f210 2018-03-12 stsp return 0;
272 5c860e29 2018-03-12 stsp }
273 5c860e29 2018-03-12 stsp
274 20ecf764 2018-03-12 stsp fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
275 6879ba42 2020-10-01 naddy list_commands(stderr);
276 5c860e29 2018-03-12 stsp return 1;
277 5c860e29 2018-03-12 stsp }
278 5c860e29 2018-03-12 stsp
279 4ed7e80c 2018-05-20 stsp __dead static void
280 6879ba42 2020-10-01 naddy usage(int hflag, int status)
281 5c860e29 2018-03-12 stsp {
282 6879ba42 2020-10-01 naddy FILE *fp = (status == 0) ? stdout : stderr;
283 6879ba42 2020-10-01 naddy
284 6879ba42 2020-10-01 naddy fprintf(fp, "usage: %s [-h] [-V | --version] command [arg ...]\n",
285 53ccebc2 2019-07-30 stsp getprogname());
286 ce5b7c56 2019-07-09 stsp if (hflag)
287 6879ba42 2020-10-01 naddy list_commands(fp);
288 6879ba42 2020-10-01 naddy exit(status);
289 5c860e29 2018-03-12 stsp }
290 5c860e29 2018-03-12 stsp
291 0266afb7 2019-01-04 stsp static const struct got_error *
292 0ee7065d 2019-05-13 stsp get_editor(char **abspath)
293 e2ba3d07 2019-05-13 stsp {
294 0ee7065d 2019-05-13 stsp const struct got_error *err = NULL;
295 e2ba3d07 2019-05-13 stsp const char *editor;
296 8920fa04 2019-08-18 stsp
297 8920fa04 2019-08-18 stsp *abspath = NULL;
298 e2ba3d07 2019-05-13 stsp
299 e2ba3d07 2019-05-13 stsp editor = getenv("VISUAL");
300 e2ba3d07 2019-05-13 stsp if (editor == NULL)
301 e2ba3d07 2019-05-13 stsp editor = getenv("EDITOR");
302 e2ba3d07 2019-05-13 stsp
303 0ee7065d 2019-05-13 stsp if (editor) {
304 0ee7065d 2019-05-13 stsp err = got_path_find_prog(abspath, editor);
305 0ee7065d 2019-05-13 stsp if (err)
306 0ee7065d 2019-05-13 stsp return err;
307 0ee7065d 2019-05-13 stsp }
308 e2ba3d07 2019-05-13 stsp
309 0ee7065d 2019-05-13 stsp if (*abspath == NULL) {
310 0ee7065d 2019-05-13 stsp *abspath = strdup("/bin/ed");
311 0ee7065d 2019-05-13 stsp if (*abspath == NULL)
312 0ee7065d 2019-05-13 stsp return got_error_from_errno("strdup");
313 0ee7065d 2019-05-13 stsp }
314 0ee7065d 2019-05-13 stsp
315 e2ba3d07 2019-05-13 stsp return NULL;
316 e2ba3d07 2019-05-13 stsp }
317 e2ba3d07 2019-05-13 stsp
318 e2ba3d07 2019-05-13 stsp static const struct got_error *
319 d0eebce4 2019-03-11 stsp apply_unveil(const char *repo_path, int repo_read_only,
320 c530dc23 2019-07-23 stsp const char *worktree_path)
321 0266afb7 2019-01-04 stsp {
322 163ce85a 2019-05-13 stsp const struct got_error *err;
323 0266afb7 2019-01-04 stsp
324 37c06ea4 2019-07-15 stsp #ifdef PROFILE
325 37c06ea4 2019-07-15 stsp if (unveil("gmon.out", "rwc") != 0)
326 37c06ea4 2019-07-15 stsp return got_error_from_errno2("unveil", "gmon.out");
327 37c06ea4 2019-07-15 stsp #endif
328 d0eebce4 2019-03-11 stsp if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
329 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", repo_path);
330 0266afb7 2019-01-04 stsp
331 0266afb7 2019-01-04 stsp if (worktree_path && unveil(worktree_path, "rwc") != 0)
332 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", worktree_path);
333 0266afb7 2019-01-04 stsp
334 bb63914a 2020-02-17 stsp if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
335 bb63914a 2020-02-17 stsp return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
336 0266afb7 2019-01-04 stsp
337 163ce85a 2019-05-13 stsp err = got_privsep_unveil_exec_helpers();
338 163ce85a 2019-05-13 stsp if (err != NULL)
339 163ce85a 2019-05-13 stsp return err;
340 0266afb7 2019-01-04 stsp
341 0266afb7 2019-01-04 stsp if (unveil(NULL, NULL) != 0)
342 638f9024 2019-05-13 stsp return got_error_from_errno("unveil");
343 0266afb7 2019-01-04 stsp
344 0266afb7 2019-01-04 stsp return NULL;
345 2c7829a4 2019-06-17 stsp }
346 2c7829a4 2019-06-17 stsp
347 2c7829a4 2019-06-17 stsp __dead static void
348 2c7829a4 2019-06-17 stsp usage_init(void)
349 2c7829a4 2019-06-17 stsp {
350 09ea71ba 2019-07-27 stsp fprintf(stderr, "usage: %s init repository-path\n", getprogname());
351 2c7829a4 2019-06-17 stsp exit(1);
352 2c7829a4 2019-06-17 stsp }
353 2c7829a4 2019-06-17 stsp
354 2c7829a4 2019-06-17 stsp static const struct got_error *
355 2c7829a4 2019-06-17 stsp cmd_init(int argc, char *argv[])
356 2c7829a4 2019-06-17 stsp {
357 2c7829a4 2019-06-17 stsp const struct got_error *error = NULL;
358 2c7829a4 2019-06-17 stsp char *repo_path = NULL;
359 2c7829a4 2019-06-17 stsp int ch;
360 2c7829a4 2019-06-17 stsp
361 2c7829a4 2019-06-17 stsp while ((ch = getopt(argc, argv, "")) != -1) {
362 2c7829a4 2019-06-17 stsp switch (ch) {
363 2c7829a4 2019-06-17 stsp default:
364 2c7829a4 2019-06-17 stsp usage_init();
365 2c7829a4 2019-06-17 stsp /* NOTREACHED */
366 2c7829a4 2019-06-17 stsp }
367 2c7829a4 2019-06-17 stsp }
368 2c7829a4 2019-06-17 stsp
369 2c7829a4 2019-06-17 stsp argc -= optind;
370 2c7829a4 2019-06-17 stsp argv += optind;
371 2c7829a4 2019-06-17 stsp
372 2c7829a4 2019-06-17 stsp #ifndef PROFILE
373 2c7829a4 2019-06-17 stsp if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
374 2c7829a4 2019-06-17 stsp err(1, "pledge");
375 2c7829a4 2019-06-17 stsp #endif
376 2c7829a4 2019-06-17 stsp if (argc != 1)
377 bc20e173 2019-06-17 stsp usage_init();
378 2c7829a4 2019-06-17 stsp
379 2c7829a4 2019-06-17 stsp repo_path = strdup(argv[0]);
380 2c7829a4 2019-06-17 stsp if (repo_path == NULL)
381 2c7829a4 2019-06-17 stsp return got_error_from_errno("strdup");
382 2c7829a4 2019-06-17 stsp
383 2c7829a4 2019-06-17 stsp got_path_strip_trailing_slashes(repo_path);
384 2c7829a4 2019-06-17 stsp
385 2c7829a4 2019-06-17 stsp error = got_path_mkdir(repo_path);
386 2c7829a4 2019-06-17 stsp if (error &&
387 2c7829a4 2019-06-17 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
388 2c7829a4 2019-06-17 stsp goto done;
389 2c7829a4 2019-06-17 stsp
390 c530dc23 2019-07-23 stsp error = apply_unveil(repo_path, 0, NULL);
391 2c7829a4 2019-06-17 stsp if (error)
392 2c7829a4 2019-06-17 stsp goto done;
393 2c7829a4 2019-06-17 stsp
394 2c7829a4 2019-06-17 stsp error = got_repo_init(repo_path);
395 3ce1b845 2019-07-15 stsp done:
396 3ce1b845 2019-07-15 stsp free(repo_path);
397 3ce1b845 2019-07-15 stsp return error;
398 3ce1b845 2019-07-15 stsp }
399 3ce1b845 2019-07-15 stsp
400 3ce1b845 2019-07-15 stsp __dead static void
401 3ce1b845 2019-07-15 stsp usage_import(void)
402 3ce1b845 2019-07-15 stsp {
403 3ce1b845 2019-07-15 stsp fprintf(stderr, "usage: %s import [-b branch] [-m message] "
404 3ce1b845 2019-07-15 stsp "[-r repository-path] [-I pattern] path\n", getprogname());
405 3ce1b845 2019-07-15 stsp exit(1);
406 3ce1b845 2019-07-15 stsp }
407 3ce1b845 2019-07-15 stsp
408 3ce1b845 2019-07-15 stsp int
409 3ce1b845 2019-07-15 stsp spawn_editor(const char *editor, const char *file)
410 3ce1b845 2019-07-15 stsp {
411 3ce1b845 2019-07-15 stsp pid_t pid;
412 3ce1b845 2019-07-15 stsp sig_t sighup, sigint, sigquit;
413 3ce1b845 2019-07-15 stsp int st = -1;
414 3ce1b845 2019-07-15 stsp
415 3ce1b845 2019-07-15 stsp sighup = signal(SIGHUP, SIG_IGN);
416 3ce1b845 2019-07-15 stsp sigint = signal(SIGINT, SIG_IGN);
417 3ce1b845 2019-07-15 stsp sigquit = signal(SIGQUIT, SIG_IGN);
418 3ce1b845 2019-07-15 stsp
419 3ce1b845 2019-07-15 stsp switch (pid = fork()) {
420 3ce1b845 2019-07-15 stsp case -1:
421 3ce1b845 2019-07-15 stsp goto doneediting;
422 3ce1b845 2019-07-15 stsp case 0:
423 3ce1b845 2019-07-15 stsp execl(editor, editor, file, (char *)NULL);
424 3ce1b845 2019-07-15 stsp _exit(127);
425 3ce1b845 2019-07-15 stsp }
426 3ce1b845 2019-07-15 stsp
427 3ce1b845 2019-07-15 stsp while (waitpid(pid, &st, 0) == -1)
428 3ce1b845 2019-07-15 stsp if (errno != EINTR)
429 3ce1b845 2019-07-15 stsp break;
430 3ce1b845 2019-07-15 stsp
431 3ce1b845 2019-07-15 stsp doneediting:
432 3ce1b845 2019-07-15 stsp (void)signal(SIGHUP, sighup);
433 3ce1b845 2019-07-15 stsp (void)signal(SIGINT, sigint);
434 3ce1b845 2019-07-15 stsp (void)signal(SIGQUIT, sigquit);
435 3ce1b845 2019-07-15 stsp
436 3ce1b845 2019-07-15 stsp if (!WIFEXITED(st)) {
437 3ce1b845 2019-07-15 stsp errno = EINTR;
438 3ce1b845 2019-07-15 stsp return -1;
439 3ce1b845 2019-07-15 stsp }
440 3ce1b845 2019-07-15 stsp
441 3ce1b845 2019-07-15 stsp return WEXITSTATUS(st);
442 3ce1b845 2019-07-15 stsp }
443 3ce1b845 2019-07-15 stsp
444 3ce1b845 2019-07-15 stsp static const struct got_error *
445 3ce1b845 2019-07-15 stsp edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
446 28cf319f 2021-01-28 stsp const char *initial_content, size_t initial_content_len,
447 28cf319f 2021-01-28 stsp int require_modification)
448 3ce1b845 2019-07-15 stsp {
449 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
450 bfa12d5e 2020-09-26 stsp char *line = NULL;
451 bfa12d5e 2020-09-26 stsp size_t linesize = 0;
452 bfa12d5e 2020-09-26 stsp ssize_t linelen;
453 3ce1b845 2019-07-15 stsp struct stat st, st2;
454 bfa12d5e 2020-09-26 stsp FILE *fp = NULL;
455 bfa12d5e 2020-09-26 stsp size_t len, logmsg_len;
456 bfa12d5e 2020-09-26 stsp char *initial_content_stripped = NULL, *buf = NULL, *s;
457 3ce1b845 2019-07-15 stsp
458 3ce1b845 2019-07-15 stsp *logmsg = NULL;
459 3ce1b845 2019-07-15 stsp
460 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st) == -1)
461 3ce1b845 2019-07-15 stsp return got_error_from_errno2("stat", logmsg_path);
462 3ce1b845 2019-07-15 stsp
463 3ce1b845 2019-07-15 stsp if (spawn_editor(editor, logmsg_path) == -1)
464 3ce1b845 2019-07-15 stsp return got_error_from_errno("failed spawning editor");
465 3ce1b845 2019-07-15 stsp
466 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st2) == -1)
467 3ce1b845 2019-07-15 stsp return got_error_from_errno("stat");
468 3ce1b845 2019-07-15 stsp
469 28cf319f 2021-01-28 stsp if (require_modification &&
470 28cf319f 2021-01-28 stsp st.st_mtime == st2.st_mtime && st.st_size == st2.st_size)
471 3ce1b845 2019-07-15 stsp return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
472 3ce1b845 2019-07-15 stsp "no changes made to commit message, aborting");
473 3ce1b845 2019-07-15 stsp
474 bfa12d5e 2020-09-26 stsp /*
475 bfa12d5e 2020-09-26 stsp * Set up a stripped version of the initial content without comments
476 bfa12d5e 2020-09-26 stsp * and blank lines. We need this in order to check if the message
477 bfa12d5e 2020-09-26 stsp * has in fact been edited.
478 bfa12d5e 2020-09-26 stsp */
479 bfa12d5e 2020-09-26 stsp initial_content_stripped = malloc(initial_content_len + 1);
480 bfa12d5e 2020-09-26 stsp if (initial_content_stripped == NULL)
481 bfa12d5e 2020-09-26 stsp return got_error_from_errno("malloc");
482 bfa12d5e 2020-09-26 stsp initial_content_stripped[0] = '\0';
483 bfa12d5e 2020-09-26 stsp
484 bfa12d5e 2020-09-26 stsp buf = strdup(initial_content);
485 bfa12d5e 2020-09-26 stsp if (buf == NULL) {
486 bfa12d5e 2020-09-26 stsp err = got_error_from_errno("strdup");
487 bfa12d5e 2020-09-26 stsp goto done;
488 bfa12d5e 2020-09-26 stsp }
489 bfa12d5e 2020-09-26 stsp s = buf;
490 bfa12d5e 2020-09-26 stsp len = 0;
491 bfa12d5e 2020-09-26 stsp while ((line = strsep(&s, "\n")) != NULL) {
492 bfa12d5e 2020-09-26 stsp if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
493 bfa12d5e 2020-09-26 stsp continue; /* remove comments and leading empty lines */
494 bfa12d5e 2020-09-26 stsp len = strlcat(initial_content_stripped, line,
495 bfa12d5e 2020-09-26 stsp initial_content_len + 1);
496 bfa12d5e 2020-09-26 stsp if (len >= initial_content_len + 1) {
497 bfa12d5e 2020-09-26 stsp err = got_error(GOT_ERR_NO_SPACE);
498 bfa12d5e 2020-09-26 stsp goto done;
499 bfa12d5e 2020-09-26 stsp }
500 bfa12d5e 2020-09-26 stsp }
501 bfa12d5e 2020-09-26 stsp while (len > 0 && initial_content_stripped[len - 1] == '\n') {
502 bfa12d5e 2020-09-26 stsp initial_content_stripped[len - 1] = '\0';
503 bfa12d5e 2020-09-26 stsp len--;
504 bfa12d5e 2020-09-26 stsp }
505 bfa12d5e 2020-09-26 stsp
506 bfa12d5e 2020-09-26 stsp logmsg_len = st2.st_size;
507 bfa12d5e 2020-09-26 stsp *logmsg = malloc(logmsg_len + 1);
508 3ce1b845 2019-07-15 stsp if (*logmsg == NULL)
509 3ce1b845 2019-07-15 stsp return got_error_from_errno("malloc");
510 3ce1b845 2019-07-15 stsp (*logmsg)[0] = '\0';
511 3ce1b845 2019-07-15 stsp
512 00fe21f2 2021-12-31 stsp fp = fopen(logmsg_path, "re");
513 3ce1b845 2019-07-15 stsp if (fp == NULL) {
514 3ce1b845 2019-07-15 stsp err = got_error_from_errno("fopen");
515 3ce1b845 2019-07-15 stsp goto done;
516 3ce1b845 2019-07-15 stsp }
517 bfa12d5e 2020-09-26 stsp
518 bfa12d5e 2020-09-26 stsp len = 0;
519 bfa12d5e 2020-09-26 stsp while ((linelen = getline(&line, &linesize, fp)) != -1) {
520 bfa12d5e 2020-09-26 stsp if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
521 3ce1b845 2019-07-15 stsp continue; /* remove comments and leading empty lines */
522 bfa12d5e 2020-09-26 stsp len = strlcat(*logmsg, line, logmsg_len + 1);
523 bfa12d5e 2020-09-26 stsp if (len >= logmsg_len + 1) {
524 bfa12d5e 2020-09-26 stsp err = got_error(GOT_ERR_NO_SPACE);
525 bfa12d5e 2020-09-26 stsp goto done;
526 bfa12d5e 2020-09-26 stsp }
527 3ce1b845 2019-07-15 stsp }
528 bfa12d5e 2020-09-26 stsp free(line);
529 bfa12d5e 2020-09-26 stsp if (ferror(fp)) {
530 bfa12d5e 2020-09-26 stsp err = got_ferror(fp, GOT_ERR_IO);
531 bfa12d5e 2020-09-26 stsp goto done;
532 bfa12d5e 2020-09-26 stsp }
533 3ce1b845 2019-07-15 stsp while (len > 0 && (*logmsg)[len - 1] == '\n') {
534 3ce1b845 2019-07-15 stsp (*logmsg)[len - 1] = '\0';
535 3ce1b845 2019-07-15 stsp len--;
536 3ce1b845 2019-07-15 stsp }
537 3ce1b845 2019-07-15 stsp
538 bfa12d5e 2020-09-26 stsp if (len == 0) {
539 3ce1b845 2019-07-15 stsp err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
540 3ce1b845 2019-07-15 stsp "commit message cannot be empty, aborting");
541 bfa12d5e 2020-09-26 stsp goto done;
542 bfa12d5e 2020-09-26 stsp }
543 28cf319f 2021-01-28 stsp if (require_modification &&
544 28cf319f 2021-01-28 stsp strcmp(*logmsg, initial_content_stripped) == 0)
545 bfa12d5e 2020-09-26 stsp err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
546 bfa12d5e 2020-09-26 stsp "no changes made to commit message, aborting");
547 3ce1b845 2019-07-15 stsp done:
548 bfa12d5e 2020-09-26 stsp free(initial_content_stripped);
549 bfa12d5e 2020-09-26 stsp free(buf);
550 bfa12d5e 2020-09-26 stsp if (fp && fclose(fp) == EOF && err == NULL)
551 bfa12d5e 2020-09-26 stsp err = got_error_from_errno("fclose");
552 3ce1b845 2019-07-15 stsp if (err) {
553 3ce1b845 2019-07-15 stsp free(*logmsg);
554 3ce1b845 2019-07-15 stsp *logmsg = NULL;
555 3ce1b845 2019-07-15 stsp }
556 3ce1b845 2019-07-15 stsp return err;
557 3ce1b845 2019-07-15 stsp }
558 3ce1b845 2019-07-15 stsp
559 3ce1b845 2019-07-15 stsp static const struct got_error *
560 ef293bdd 2019-10-21 stsp collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
561 ef293bdd 2019-10-21 stsp const char *path_dir, const char *branch_name)
562 3ce1b845 2019-07-15 stsp {
563 ef293bdd 2019-10-21 stsp char *initial_content = NULL;
564 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
565 1601cb9f 2020-09-11 naddy int initial_content_len;
566 97972933 2020-09-11 stsp int fd = -1;
567 3ce1b845 2019-07-15 stsp
568 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
569 3ce1b845 2019-07-15 stsp "\n# %s to be imported to branch %s\n", path_dir,
570 1601cb9f 2020-09-11 naddy branch_name);
571 1601cb9f 2020-09-11 naddy if (initial_content_len == -1)
572 3ce1b845 2019-07-15 stsp return got_error_from_errno("asprintf");
573 3ce1b845 2019-07-15 stsp
574 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(logmsg_path, &fd,
575 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-importmsg");
576 3ce1b845 2019-07-15 stsp if (err)
577 3ce1b845 2019-07-15 stsp goto done;
578 3ce1b845 2019-07-15 stsp
579 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
580 97972933 2020-09-11 stsp err = got_error_from_errno2("write", *logmsg_path);
581 97972933 2020-09-11 stsp goto done;
582 97972933 2020-09-11 stsp }
583 3ce1b845 2019-07-15 stsp
584 bfa12d5e 2020-09-26 stsp err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
585 0d5bb276 2020-12-15 stsp initial_content_len, 1);
586 3ce1b845 2019-07-15 stsp done:
587 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
588 97972933 2020-09-11 stsp err = got_error_from_errno2("close", *logmsg_path);
589 3ce1b845 2019-07-15 stsp free(initial_content);
590 59f86c76 2020-09-11 stsp if (err) {
591 59f86c76 2020-09-11 stsp free(*logmsg_path);
592 59f86c76 2020-09-11 stsp *logmsg_path = NULL;
593 59f86c76 2020-09-11 stsp }
594 3ce1b845 2019-07-15 stsp return err;
595 3ce1b845 2019-07-15 stsp }
596 3ce1b845 2019-07-15 stsp
597 3ce1b845 2019-07-15 stsp static const struct got_error *
598 3ce1b845 2019-07-15 stsp import_progress(void *arg, const char *path)
599 3ce1b845 2019-07-15 stsp {
600 3ce1b845 2019-07-15 stsp printf("A %s\n", path);
601 3ce1b845 2019-07-15 stsp return NULL;
602 1d918cf9 2022-02-06 op }
603 1d918cf9 2022-02-06 op
604 1d918cf9 2022-02-06 op static int
605 1d918cf9 2022-02-06 op valid_author(const char *author)
606 1d918cf9 2022-02-06 op {
607 1d918cf9 2022-02-06 op /*
608 1d918cf9 2022-02-06 op * Really dumb email address check; we're only doing this to
609 1d918cf9 2022-02-06 op * avoid git's object parser breaking on commits we create.
610 1d918cf9 2022-02-06 op */
611 1d918cf9 2022-02-06 op while (*author && *author != '<')
612 1d918cf9 2022-02-06 op author++;
613 1d918cf9 2022-02-06 op if (*author != '<')
614 1d918cf9 2022-02-06 op return 0;
615 1d918cf9 2022-02-06 op while (*author && *author != '@')
616 1d918cf9 2022-02-06 op author++;
617 1d918cf9 2022-02-06 op if (*author != '@')
618 1d918cf9 2022-02-06 op return 0;
619 1d918cf9 2022-02-06 op while (*author && *author != '>')
620 1d918cf9 2022-02-06 op author++;
621 1d918cf9 2022-02-06 op return *author == '>';
622 3ce1b845 2019-07-15 stsp }
623 3ce1b845 2019-07-15 stsp
624 3ce1b845 2019-07-15 stsp static const struct got_error *
625 50b0790e 2020-09-11 stsp get_author(char **author, struct got_repository *repo,
626 50b0790e 2020-09-11 stsp struct got_worktree *worktree)
627 84792843 2019-08-09 stsp {
628 aba9c984 2019-09-08 stsp const struct got_error *err = NULL;
629 50b0790e 2020-09-11 stsp const char *got_author = NULL, *name, *email;
630 50b0790e 2020-09-11 stsp const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
631 84792843 2019-08-09 stsp
632 84792843 2019-08-09 stsp *author = NULL;
633 aba9c984 2019-09-08 stsp
634 50b0790e 2020-09-11 stsp if (worktree)
635 50b0790e 2020-09-11 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
636 50b0790e 2020-09-11 stsp repo_conf = got_repo_get_gotconfig(repo);
637 50b0790e 2020-09-11 stsp
638 50b0790e 2020-09-11 stsp /*
639 50b0790e 2020-09-11 stsp * Priority of potential author information sources, from most
640 50b0790e 2020-09-11 stsp * significant to least significant:
641 50b0790e 2020-09-11 stsp * 1) work tree's .got/got.conf file
642 50b0790e 2020-09-11 stsp * 2) repository's got.conf file
643 50b0790e 2020-09-11 stsp * 3) repository's git config file
644 50b0790e 2020-09-11 stsp * 4) environment variables
645 50b0790e 2020-09-11 stsp * 5) global git config files (in user's home directory or /etc)
646 50b0790e 2020-09-11 stsp */
647 50b0790e 2020-09-11 stsp
648 50b0790e 2020-09-11 stsp if (worktree_conf)
649 50b0790e 2020-09-11 stsp got_author = got_gotconfig_get_author(worktree_conf);
650 50b0790e 2020-09-11 stsp if (got_author == NULL)
651 50b0790e 2020-09-11 stsp got_author = got_gotconfig_get_author(repo_conf);
652 84792843 2019-08-09 stsp if (got_author == NULL) {
653 257add31 2020-09-09 stsp name = got_repo_get_gitconfig_author_name(repo);
654 257add31 2020-09-09 stsp email = got_repo_get_gitconfig_author_email(repo);
655 c9956ddf 2019-09-08 stsp if (name && email) {
656 c9956ddf 2019-09-08 stsp if (asprintf(author, "%s <%s>", name, email) == -1)
657 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
658 c9956ddf 2019-09-08 stsp return NULL;
659 c9956ddf 2019-09-08 stsp }
660 257add31 2020-09-09 stsp
661 257add31 2020-09-09 stsp got_author = getenv("GOT_AUTHOR");
662 257add31 2020-09-09 stsp if (got_author == NULL) {
663 257add31 2020-09-09 stsp name = got_repo_get_global_gitconfig_author_name(repo);
664 257add31 2020-09-09 stsp email = got_repo_get_global_gitconfig_author_email(
665 257add31 2020-09-09 stsp repo);
666 257add31 2020-09-09 stsp if (name && email) {
667 257add31 2020-09-09 stsp if (asprintf(author, "%s <%s>", name, email)
668 257add31 2020-09-09 stsp == -1)
669 257add31 2020-09-09 stsp return got_error_from_errno("asprintf");
670 257add31 2020-09-09 stsp return NULL;
671 257add31 2020-09-09 stsp }
672 257add31 2020-09-09 stsp /* TODO: Look up user in password database? */
673 257add31 2020-09-09 stsp return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
674 257add31 2020-09-09 stsp }
675 84792843 2019-08-09 stsp }
676 84792843 2019-08-09 stsp
677 aba9c984 2019-09-08 stsp *author = strdup(got_author);
678 aba9c984 2019-09-08 stsp if (*author == NULL)
679 aba9c984 2019-09-08 stsp return got_error_from_errno("strdup");
680 84792843 2019-08-09 stsp
681 1d918cf9 2022-02-06 op if (!valid_author(*author)) {
682 1d918cf9 2022-02-06 op err = got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", *author);
683 aba9c984 2019-09-08 stsp free(*author);
684 aba9c984 2019-09-08 stsp *author = NULL;
685 aba9c984 2019-09-08 stsp }
686 aba9c984 2019-09-08 stsp return err;
687 c9956ddf 2019-09-08 stsp }
688 c9956ddf 2019-09-08 stsp
689 c9956ddf 2019-09-08 stsp static const struct got_error *
690 c9956ddf 2019-09-08 stsp get_gitconfig_path(char **gitconfig_path)
691 c9956ddf 2019-09-08 stsp {
692 c9956ddf 2019-09-08 stsp const char *homedir = getenv("HOME");
693 c9956ddf 2019-09-08 stsp
694 c9956ddf 2019-09-08 stsp *gitconfig_path = NULL;
695 c9956ddf 2019-09-08 stsp if (homedir) {
696 c9956ddf 2019-09-08 stsp if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
697 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
698 c9956ddf 2019-09-08 stsp
699 c9956ddf 2019-09-08 stsp }
700 c9956ddf 2019-09-08 stsp return NULL;
701 84792843 2019-08-09 stsp }
702 84792843 2019-08-09 stsp
703 84792843 2019-08-09 stsp static const struct got_error *
704 3ce1b845 2019-07-15 stsp cmd_import(int argc, char *argv[])
705 3ce1b845 2019-07-15 stsp {
706 3ce1b845 2019-07-15 stsp const struct got_error *error = NULL;
707 3ce1b845 2019-07-15 stsp char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
708 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
709 5d67f40d 2019-11-08 stsp const char *branch_name = "main";
710 ef293bdd 2019-10-21 stsp char *refname = NULL, *id_str = NULL, *logmsg_path = NULL;
711 3ce1b845 2019-07-15 stsp struct got_repository *repo = NULL;
712 3ce1b845 2019-07-15 stsp struct got_reference *branch_ref = NULL, *head_ref = NULL;
713 3ce1b845 2019-07-15 stsp struct got_object_id *new_commit_id = NULL;
714 3ce1b845 2019-07-15 stsp int ch;
715 3ce1b845 2019-07-15 stsp struct got_pathlist_head ignores;
716 3ce1b845 2019-07-15 stsp struct got_pathlist_entry *pe;
717 ef293bdd 2019-10-21 stsp int preserve_logmsg = 0;
718 3ce1b845 2019-07-15 stsp
719 3ce1b845 2019-07-15 stsp TAILQ_INIT(&ignores);
720 3ce1b845 2019-07-15 stsp
721 3ce1b845 2019-07-15 stsp while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
722 3ce1b845 2019-07-15 stsp switch (ch) {
723 3ce1b845 2019-07-15 stsp case 'b':
724 3ce1b845 2019-07-15 stsp branch_name = optarg;
725 3ce1b845 2019-07-15 stsp break;
726 3ce1b845 2019-07-15 stsp case 'm':
727 3ce1b845 2019-07-15 stsp logmsg = strdup(optarg);
728 3ce1b845 2019-07-15 stsp if (logmsg == NULL) {
729 3ce1b845 2019-07-15 stsp error = got_error_from_errno("strdup");
730 3ce1b845 2019-07-15 stsp goto done;
731 3ce1b845 2019-07-15 stsp }
732 3ce1b845 2019-07-15 stsp break;
733 3ce1b845 2019-07-15 stsp case 'r':
734 3ce1b845 2019-07-15 stsp repo_path = realpath(optarg, NULL);
735 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
736 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath",
737 9ba1d308 2019-10-21 stsp optarg);
738 3ce1b845 2019-07-15 stsp goto done;
739 3ce1b845 2019-07-15 stsp }
740 3ce1b845 2019-07-15 stsp break;
741 3ce1b845 2019-07-15 stsp case 'I':
742 3ce1b845 2019-07-15 stsp if (optarg[0] == '\0')
743 3ce1b845 2019-07-15 stsp break;
744 3ce1b845 2019-07-15 stsp error = got_pathlist_insert(&pe, &ignores, optarg,
745 3ce1b845 2019-07-15 stsp NULL);
746 3ce1b845 2019-07-15 stsp if (error)
747 3ce1b845 2019-07-15 stsp goto done;
748 3ce1b845 2019-07-15 stsp break;
749 3ce1b845 2019-07-15 stsp default:
750 b2b65d18 2019-08-22 stsp usage_import();
751 3ce1b845 2019-07-15 stsp /* NOTREACHED */
752 3ce1b845 2019-07-15 stsp }
753 3ce1b845 2019-07-15 stsp }
754 3ce1b845 2019-07-15 stsp
755 3ce1b845 2019-07-15 stsp argc -= optind;
756 3ce1b845 2019-07-15 stsp argv += optind;
757 3ce1b845 2019-07-15 stsp
758 3ce1b845 2019-07-15 stsp #ifndef PROFILE
759 aba9c984 2019-09-08 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
760 aba9c984 2019-09-08 stsp "unveil",
761 3ce1b845 2019-07-15 stsp NULL) == -1)
762 3ce1b845 2019-07-15 stsp err(1, "pledge");
763 3ce1b845 2019-07-15 stsp #endif
764 3ce1b845 2019-07-15 stsp if (argc != 1)
765 3ce1b845 2019-07-15 stsp usage_import();
766 2c7829a4 2019-06-17 stsp
767 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
768 3ce1b845 2019-07-15 stsp repo_path = getcwd(NULL, 0);
769 3ce1b845 2019-07-15 stsp if (repo_path == NULL)
770 3ce1b845 2019-07-15 stsp return got_error_from_errno("getcwd");
771 3ce1b845 2019-07-15 stsp }
772 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(repo_path);
773 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
774 c9956ddf 2019-09-08 stsp if (error)
775 c9956ddf 2019-09-08 stsp goto done;
776 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
777 3ce1b845 2019-07-15 stsp if (error)
778 3ce1b845 2019-07-15 stsp goto done;
779 aba9c984 2019-09-08 stsp
780 50b0790e 2020-09-11 stsp error = get_author(&author, repo, NULL);
781 aba9c984 2019-09-08 stsp if (error)
782 aba9c984 2019-09-08 stsp return error;
783 e560b7e0 2019-11-28 stsp
784 e560b7e0 2019-11-28 stsp /*
785 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
786 e560b7e0 2019-11-28 stsp * While technically a valid reference name, this case is usually
787 e560b7e0 2019-11-28 stsp * an unintended typo.
788 e560b7e0 2019-11-28 stsp */
789 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
790 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
791 3ce1b845 2019-07-15 stsp
792 3ce1b845 2019-07-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
793 3ce1b845 2019-07-15 stsp error = got_error_from_errno("asprintf");
794 3ce1b845 2019-07-15 stsp goto done;
795 3ce1b845 2019-07-15 stsp }
796 3ce1b845 2019-07-15 stsp
797 3ce1b845 2019-07-15 stsp error = got_ref_open(&branch_ref, repo, refname, 0);
798 3ce1b845 2019-07-15 stsp if (error) {
799 3ce1b845 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
800 3ce1b845 2019-07-15 stsp goto done;
801 3ce1b845 2019-07-15 stsp } else {
802 3ce1b845 2019-07-15 stsp error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
803 3ce1b845 2019-07-15 stsp "import target branch already exists");
804 3ce1b845 2019-07-15 stsp goto done;
805 3ce1b845 2019-07-15 stsp }
806 3ce1b845 2019-07-15 stsp
807 3ce1b845 2019-07-15 stsp path_dir = realpath(argv[0], NULL);
808 3ce1b845 2019-07-15 stsp if (path_dir == NULL) {
809 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath", argv[0]);
810 3ce1b845 2019-07-15 stsp goto done;
811 3ce1b845 2019-07-15 stsp }
812 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(path_dir);
813 3ce1b845 2019-07-15 stsp
814 3ce1b845 2019-07-15 stsp /*
815 3ce1b845 2019-07-15 stsp * unveil(2) traverses exec(2); if an editor is used we have
816 3ce1b845 2019-07-15 stsp * to apply unveil after the log message has been written.
817 3ce1b845 2019-07-15 stsp */
818 3ce1b845 2019-07-15 stsp if (logmsg == NULL || strlen(logmsg) == 0) {
819 3ce1b845 2019-07-15 stsp error = get_editor(&editor);
820 3ce1b845 2019-07-15 stsp if (error)
821 3ce1b845 2019-07-15 stsp goto done;
822 8e158b01 2019-09-22 stsp free(logmsg);
823 ef293bdd 2019-10-21 stsp error = collect_import_msg(&logmsg, &logmsg_path, editor,
824 ef293bdd 2019-10-21 stsp path_dir, refname);
825 ef293bdd 2019-10-21 stsp if (error) {
826 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
827 ef293bdd 2019-10-21 stsp logmsg_path != NULL)
828 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
829 3ce1b845 2019-07-15 stsp goto done;
830 ef293bdd 2019-10-21 stsp }
831 3ce1b845 2019-07-15 stsp }
832 3ce1b845 2019-07-15 stsp
833 ef293bdd 2019-10-21 stsp if (unveil(path_dir, "r") != 0) {
834 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unveil", path_dir);
835 ef293bdd 2019-10-21 stsp if (logmsg_path)
836 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
837 3ce1b845 2019-07-15 stsp goto done;
838 ef293bdd 2019-10-21 stsp }
839 3ce1b845 2019-07-15 stsp
840 ef293bdd 2019-10-21 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
841 ef293bdd 2019-10-21 stsp if (error) {
842 ef293bdd 2019-10-21 stsp if (logmsg_path)
843 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
844 ef293bdd 2019-10-21 stsp goto done;
845 ef293bdd 2019-10-21 stsp }
846 ef293bdd 2019-10-21 stsp
847 3ce1b845 2019-07-15 stsp error = got_repo_import(&new_commit_id, path_dir, logmsg,
848 84792843 2019-08-09 stsp author, &ignores, repo, import_progress, NULL);
849 ef293bdd 2019-10-21 stsp if (error) {
850 ef293bdd 2019-10-21 stsp if (logmsg_path)
851 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
852 3ce1b845 2019-07-15 stsp goto done;
853 ef293bdd 2019-10-21 stsp }
854 3ce1b845 2019-07-15 stsp
855 3ce1b845 2019-07-15 stsp error = got_ref_alloc(&branch_ref, refname, new_commit_id);
856 ef293bdd 2019-10-21 stsp if (error) {
857 ef293bdd 2019-10-21 stsp if (logmsg_path)
858 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
859 3ce1b845 2019-07-15 stsp goto done;
860 ef293bdd 2019-10-21 stsp }
861 3ce1b845 2019-07-15 stsp
862 3ce1b845 2019-07-15 stsp error = got_ref_write(branch_ref, repo);
863 ef293bdd 2019-10-21 stsp if (error) {
864 ef293bdd 2019-10-21 stsp if (logmsg_path)
865 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
866 3ce1b845 2019-07-15 stsp goto done;
867 ef293bdd 2019-10-21 stsp }
868 3ce1b845 2019-07-15 stsp
869 3ce1b845 2019-07-15 stsp error = got_object_id_str(&id_str, new_commit_id);
870 ef293bdd 2019-10-21 stsp if (error) {
871 ef293bdd 2019-10-21 stsp if (logmsg_path)
872 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
873 3ce1b845 2019-07-15 stsp goto done;
874 ef293bdd 2019-10-21 stsp }
875 3ce1b845 2019-07-15 stsp
876 3ce1b845 2019-07-15 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
877 3ce1b845 2019-07-15 stsp if (error) {
878 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_NOT_REF) {
879 ef293bdd 2019-10-21 stsp if (logmsg_path)
880 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
881 3ce1b845 2019-07-15 stsp goto done;
882 ef293bdd 2019-10-21 stsp }
883 3ce1b845 2019-07-15 stsp
884 3ce1b845 2019-07-15 stsp error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
885 3ce1b845 2019-07-15 stsp branch_ref);
886 ef293bdd 2019-10-21 stsp if (error) {
887 ef293bdd 2019-10-21 stsp if (logmsg_path)
888 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
889 3ce1b845 2019-07-15 stsp goto done;
890 ef293bdd 2019-10-21 stsp }
891 3ce1b845 2019-07-15 stsp
892 3ce1b845 2019-07-15 stsp error = got_ref_write(head_ref, repo);
893 ef293bdd 2019-10-21 stsp if (error) {
894 ef293bdd 2019-10-21 stsp if (logmsg_path)
895 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
896 3ce1b845 2019-07-15 stsp goto done;
897 ef293bdd 2019-10-21 stsp }
898 3ce1b845 2019-07-15 stsp }
899 3ce1b845 2019-07-15 stsp
900 3ce1b845 2019-07-15 stsp printf("Created branch %s with commit %s\n",
901 3ce1b845 2019-07-15 stsp got_ref_get_name(branch_ref), id_str);
902 2c7829a4 2019-06-17 stsp done:
903 ef293bdd 2019-10-21 stsp if (preserve_logmsg) {
904 ef293bdd 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
905 ef293bdd 2019-10-21 stsp getprogname(), logmsg_path);
906 ef293bdd 2019-10-21 stsp } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
907 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unlink", logmsg_path);
908 8e158b01 2019-09-22 stsp free(logmsg);
909 ef293bdd 2019-10-21 stsp free(logmsg_path);
910 2c7829a4 2019-06-17 stsp free(repo_path);
911 3ce1b845 2019-07-15 stsp free(editor);
912 3ce1b845 2019-07-15 stsp free(refname);
913 3ce1b845 2019-07-15 stsp free(new_commit_id);
914 3ce1b845 2019-07-15 stsp free(id_str);
915 aba9c984 2019-09-08 stsp free(author);
916 c9956ddf 2019-09-08 stsp free(gitconfig_path);
917 3ce1b845 2019-07-15 stsp if (branch_ref)
918 3ce1b845 2019-07-15 stsp got_ref_close(branch_ref);
919 3ce1b845 2019-07-15 stsp if (head_ref)
920 3ce1b845 2019-07-15 stsp got_ref_close(head_ref);
921 2c7829a4 2019-06-17 stsp return error;
922 93658fb9 2020-03-18 stsp }
923 93658fb9 2020-03-18 stsp
924 93658fb9 2020-03-18 stsp __dead static void
925 93658fb9 2020-03-18 stsp usage_clone(void)
926 93658fb9 2020-03-18 stsp {
927 13f12b09 2020-03-21 stsp fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
928 0e4002ca 2020-03-21 stsp "[-R reference] repository-url [directory]\n", getprogname());
929 93658fb9 2020-03-18 stsp exit(1);
930 93658fb9 2020-03-18 stsp }
931 892ac3b6 2020-03-18 stsp
932 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg {
933 892ac3b6 2020-03-18 stsp char last_scaled_size[FMT_SCALED_STRSIZE];
934 892ac3b6 2020-03-18 stsp int last_p_indexed;
935 892ac3b6 2020-03-18 stsp int last_p_resolved;
936 68999b92 2020-03-18 stsp int verbosity;
937 04d9a9ec 2020-09-24 stsp
938 04d9a9ec 2020-09-24 stsp struct got_repository *repo;
939 04d9a9ec 2020-09-24 stsp
940 04d9a9ec 2020-09-24 stsp int create_configs;
941 04d9a9ec 2020-09-24 stsp int configs_created;
942 04d9a9ec 2020-09-24 stsp struct {
943 04d9a9ec 2020-09-24 stsp struct got_pathlist_head *symrefs;
944 04d9a9ec 2020-09-24 stsp struct got_pathlist_head *wanted_branches;
945 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs;
946 04d9a9ec 2020-09-24 stsp const char *proto;
947 04d9a9ec 2020-09-24 stsp const char *host;
948 04d9a9ec 2020-09-24 stsp const char *port;
949 04d9a9ec 2020-09-24 stsp const char *remote_repo_path;
950 04d9a9ec 2020-09-24 stsp const char *git_url;
951 04d9a9ec 2020-09-24 stsp int fetch_all_branches;
952 04d9a9ec 2020-09-24 stsp int mirror_references;
953 04d9a9ec 2020-09-24 stsp } config_info;
954 892ac3b6 2020-03-18 stsp };
955 93658fb9 2020-03-18 stsp
956 04d9a9ec 2020-09-24 stsp /* XXX forward declaration */
957 93658fb9 2020-03-18 stsp static const struct got_error *
958 04d9a9ec 2020-09-24 stsp create_config_files(const char *proto, const char *host, const char *port,
959 04d9a9ec 2020-09-24 stsp const char *remote_repo_path, const char *git_url, int fetch_all_branches,
960 04d9a9ec 2020-09-24 stsp int mirror_references, struct got_pathlist_head *symrefs,
961 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_branches,
962 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, struct got_repository *repo);
963 04d9a9ec 2020-09-24 stsp
964 04d9a9ec 2020-09-24 stsp static const struct got_error *
965 baa9fea0 2020-03-18 stsp fetch_progress(void *arg, const char *message, off_t packfile_size,
966 668a20f6 2020-03-18 stsp int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
967 531c3985 2020-03-18 stsp {
968 04d9a9ec 2020-09-24 stsp const struct got_error *err = NULL;
969 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg *a = arg;
970 892ac3b6 2020-03-18 stsp char scaled_size[FMT_SCALED_STRSIZE];
971 892ac3b6 2020-03-18 stsp int p_indexed, p_resolved;
972 892ac3b6 2020-03-18 stsp int print_size = 0, print_indexed = 0, print_resolved = 0;
973 04d9a9ec 2020-09-24 stsp
974 04d9a9ec 2020-09-24 stsp /*
975 04d9a9ec 2020-09-24 stsp * In order to allow a failed clone to be resumed with 'got fetch'
976 04d9a9ec 2020-09-24 stsp * we try to create configuration files as soon as possible.
977 04d9a9ec 2020-09-24 stsp * Once the server has sent information about its default branch
978 04d9a9ec 2020-09-24 stsp * we have all required information.
979 04d9a9ec 2020-09-24 stsp */
980 04d9a9ec 2020-09-24 stsp if (a->create_configs && !a->configs_created &&
981 04d9a9ec 2020-09-24 stsp !TAILQ_EMPTY(a->config_info.symrefs)) {
982 04d9a9ec 2020-09-24 stsp err = create_config_files(a->config_info.proto,
983 62d463ca 2020-10-20 naddy a->config_info.host, a->config_info.port,
984 62d463ca 2020-10-20 naddy a->config_info.remote_repo_path,
985 62d463ca 2020-10-20 naddy a->config_info.git_url,
986 62d463ca 2020-10-20 naddy a->config_info.fetch_all_branches,
987 62d463ca 2020-10-20 naddy a->config_info.mirror_references,
988 62d463ca 2020-10-20 naddy a->config_info.symrefs,
989 99495ddb 2021-01-10 stsp a->config_info.wanted_branches,
990 99495ddb 2021-01-10 stsp a->config_info.wanted_refs, a->repo);
991 04d9a9ec 2020-09-24 stsp if (err)
992 04d9a9ec 2020-09-24 stsp return err;
993 04d9a9ec 2020-09-24 stsp a->configs_created = 1;
994 04d9a9ec 2020-09-24 stsp }
995 b2409d58 2020-03-18 stsp
996 68999b92 2020-03-18 stsp if (a->verbosity < 0)
997 68999b92 2020-03-18 stsp return NULL;
998 68999b92 2020-03-18 stsp
999 fd843b58 2020-03-18 stsp if (message && message[0] != '\0') {
1000 d2cdc636 2020-03-18 stsp printf("\rserver: %s", message);
1001 892ac3b6 2020-03-18 stsp fflush(stdout);
1002 12d1281e 2020-03-19 stsp return NULL;
1003 b2409d58 2020-03-18 stsp }
1004 b2409d58 2020-03-18 stsp
1005 b2409d58 2020-03-18 stsp if (packfile_size > 0 || nobj_indexed > 0) {
1006 892ac3b6 2020-03-18 stsp if (fmt_scaled(packfile_size, scaled_size) == 0 &&
1007 892ac3b6 2020-03-18 stsp (a->last_scaled_size[0] == '\0' ||
1008 892ac3b6 2020-03-18 stsp strcmp(scaled_size, a->last_scaled_size)) != 0) {
1009 892ac3b6 2020-03-18 stsp print_size = 1;
1010 892ac3b6 2020-03-18 stsp if (strlcpy(a->last_scaled_size, scaled_size,
1011 892ac3b6 2020-03-18 stsp FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
1012 892ac3b6 2020-03-18 stsp return got_error(GOT_ERR_NO_SPACE);
1013 892ac3b6 2020-03-18 stsp }
1014 61cc1a7a 2020-03-18 stsp if (nobj_indexed > 0) {
1015 892ac3b6 2020-03-18 stsp p_indexed = (nobj_indexed * 100) / nobj_total;
1016 892ac3b6 2020-03-18 stsp if (p_indexed != a->last_p_indexed) {
1017 892ac3b6 2020-03-18 stsp a->last_p_indexed = p_indexed;
1018 892ac3b6 2020-03-18 stsp print_indexed = 1;
1019 892ac3b6 2020-03-18 stsp print_size = 1;
1020 892ac3b6 2020-03-18 stsp }
1021 61cc1a7a 2020-03-18 stsp }
1022 61cc1a7a 2020-03-18 stsp if (nobj_resolved > 0) {
1023 892ac3b6 2020-03-18 stsp p_resolved = (nobj_resolved * 100) /
1024 892ac3b6 2020-03-18 stsp (nobj_total - nobj_loose);
1025 892ac3b6 2020-03-18 stsp if (p_resolved != a->last_p_resolved) {
1026 892ac3b6 2020-03-18 stsp a->last_p_resolved = p_resolved;
1027 892ac3b6 2020-03-18 stsp print_resolved = 1;
1028 892ac3b6 2020-03-18 stsp print_indexed = 1;
1029 892ac3b6 2020-03-18 stsp print_size = 1;
1030 892ac3b6 2020-03-18 stsp }
1031 61cc1a7a 2020-03-18 stsp }
1032 3168e5da 2020-09-10 stsp
1033 d2cdc636 2020-03-18 stsp }
1034 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
1035 892ac3b6 2020-03-18 stsp printf("\r");
1036 892ac3b6 2020-03-18 stsp if (print_size)
1037 b5934965 2022-02-12 naddy printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size);
1038 d715f13e 2020-03-19 stsp if (print_indexed)
1039 892ac3b6 2020-03-18 stsp printf("; indexing %d%%", p_indexed);
1040 d715f13e 2020-03-19 stsp if (print_resolved)
1041 892ac3b6 2020-03-18 stsp printf("; resolving deltas %d%%", p_resolved);
1042 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
1043 892ac3b6 2020-03-18 stsp fflush(stdout);
1044 892ac3b6 2020-03-18 stsp
1045 531c3985 2020-03-18 stsp return NULL;
1046 531c3985 2020-03-18 stsp }
1047 531c3985 2020-03-18 stsp
1048 531c3985 2020-03-18 stsp static const struct got_error *
1049 04d9a9ec 2020-09-24 stsp create_symref(const char *refname, struct got_reference *target_ref,
1050 04d9a9ec 2020-09-24 stsp int verbosity, struct got_repository *repo)
1051 4ba14133 2020-03-20 stsp {
1052 4ba14133 2020-03-20 stsp const struct got_error *err;
1053 04d9a9ec 2020-09-24 stsp struct got_reference *head_symref;
1054 4ba14133 2020-03-20 stsp
1055 04d9a9ec 2020-09-24 stsp err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1056 4ba14133 2020-03-20 stsp if (err)
1057 4ba14133 2020-03-20 stsp return err;
1058 4ba14133 2020-03-20 stsp
1059 04d9a9ec 2020-09-24 stsp err = got_ref_write(head_symref, repo);
1060 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity > 0) {
1061 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", GOT_REF_HEAD,
1062 6338a6a1 2020-03-21 stsp got_ref_get_name(target_ref));
1063 6338a6a1 2020-03-21 stsp }
1064 04d9a9ec 2020-09-24 stsp got_ref_close(head_symref);
1065 4ba14133 2020-03-20 stsp return err;
1066 4ba14133 2020-03-20 stsp }
1067 4ba14133 2020-03-20 stsp
1068 4ba14133 2020-03-20 stsp static const struct got_error *
1069 41b0de12 2020-03-21 stsp list_remote_refs(struct got_pathlist_head *symrefs,
1070 41b0de12 2020-03-21 stsp struct got_pathlist_head *refs)
1071 41b0de12 2020-03-21 stsp {
1072 41b0de12 2020-03-21 stsp const struct got_error *err;
1073 41b0de12 2020-03-21 stsp struct got_pathlist_entry *pe;
1074 41b0de12 2020-03-21 stsp
1075 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, symrefs, entry) {
1076 41b0de12 2020-03-21 stsp const char *refname = pe->path;
1077 41b0de12 2020-03-21 stsp const char *targetref = pe->data;
1078 41b0de12 2020-03-21 stsp
1079 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, targetref);
1080 41b0de12 2020-03-21 stsp }
1081 41b0de12 2020-03-21 stsp
1082 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, refs, entry) {
1083 41b0de12 2020-03-21 stsp const char *refname = pe->path;
1084 41b0de12 2020-03-21 stsp struct got_object_id *id = pe->data;
1085 41b0de12 2020-03-21 stsp char *id_str;
1086 41b0de12 2020-03-21 stsp
1087 41b0de12 2020-03-21 stsp err = got_object_id_str(&id_str, id);
1088 41b0de12 2020-03-21 stsp if (err)
1089 41b0de12 2020-03-21 stsp return err;
1090 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, id_str);
1091 41b0de12 2020-03-21 stsp free(id_str);
1092 41b0de12 2020-03-21 stsp }
1093 41b0de12 2020-03-21 stsp
1094 41b0de12 2020-03-21 stsp return NULL;
1095 6338a6a1 2020-03-21 stsp }
1096 6338a6a1 2020-03-21 stsp
1097 6338a6a1 2020-03-21 stsp static const struct got_error *
1098 6338a6a1 2020-03-21 stsp create_ref(const char *refname, struct got_object_id *id,
1099 6338a6a1 2020-03-21 stsp int verbosity, struct got_repository *repo)
1100 6338a6a1 2020-03-21 stsp {
1101 6338a6a1 2020-03-21 stsp const struct got_error *err = NULL;
1102 6338a6a1 2020-03-21 stsp struct got_reference *ref;
1103 6338a6a1 2020-03-21 stsp char *id_str;
1104 6338a6a1 2020-03-21 stsp
1105 6338a6a1 2020-03-21 stsp err = got_object_id_str(&id_str, id);
1106 6338a6a1 2020-03-21 stsp if (err)
1107 6338a6a1 2020-03-21 stsp return err;
1108 6338a6a1 2020-03-21 stsp
1109 6338a6a1 2020-03-21 stsp err = got_ref_alloc(&ref, refname, id);
1110 6338a6a1 2020-03-21 stsp if (err)
1111 6338a6a1 2020-03-21 stsp goto done;
1112 6338a6a1 2020-03-21 stsp
1113 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
1114 6338a6a1 2020-03-21 stsp got_ref_close(ref);
1115 6338a6a1 2020-03-21 stsp
1116 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity >= 0)
1117 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", refname, id_str);
1118 6338a6a1 2020-03-21 stsp done:
1119 6338a6a1 2020-03-21 stsp free(id_str);
1120 6338a6a1 2020-03-21 stsp return err;
1121 0e4002ca 2020-03-21 stsp }
1122 0e4002ca 2020-03-21 stsp
1123 0e4002ca 2020-03-21 stsp static int
1124 0e4002ca 2020-03-21 stsp match_wanted_ref(const char *refname, const char *wanted_ref)
1125 0e4002ca 2020-03-21 stsp {
1126 0e4002ca 2020-03-21 stsp if (strncmp(refname, "refs/", 5) != 0)
1127 0e4002ca 2020-03-21 stsp return 0;
1128 0e4002ca 2020-03-21 stsp refname += 5;
1129 0e4002ca 2020-03-21 stsp
1130 0e4002ca 2020-03-21 stsp /*
1131 0e4002ca 2020-03-21 stsp * Prevent fetching of references that won't make any
1132 0e4002ca 2020-03-21 stsp * sense outside of the remote repository's context.
1133 0e4002ca 2020-03-21 stsp */
1134 0e4002ca 2020-03-21 stsp if (strncmp(refname, "got/", 4) == 0)
1135 0e4002ca 2020-03-21 stsp return 0;
1136 0e4002ca 2020-03-21 stsp if (strncmp(refname, "remotes/", 8) == 0)
1137 0e4002ca 2020-03-21 stsp return 0;
1138 0e4002ca 2020-03-21 stsp
1139 0e4002ca 2020-03-21 stsp if (strncmp(wanted_ref, "refs/", 5) == 0)
1140 0e4002ca 2020-03-21 stsp wanted_ref += 5;
1141 0e4002ca 2020-03-21 stsp
1142 0e4002ca 2020-03-21 stsp /* Allow prefix match. */
1143 0e4002ca 2020-03-21 stsp if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1144 0e4002ca 2020-03-21 stsp return 1;
1145 0e4002ca 2020-03-21 stsp
1146 0e4002ca 2020-03-21 stsp /* Allow exact match. */
1147 0e4002ca 2020-03-21 stsp return (strcmp(refname, wanted_ref) == 0);
1148 41b0de12 2020-03-21 stsp }
1149 41b0de12 2020-03-21 stsp
1150 0e4002ca 2020-03-21 stsp static int
1151 0e4002ca 2020-03-21 stsp is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1152 0e4002ca 2020-03-21 stsp {
1153 0e4002ca 2020-03-21 stsp struct got_pathlist_entry *pe;
1154 0e4002ca 2020-03-21 stsp
1155 0e4002ca 2020-03-21 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1156 0e4002ca 2020-03-21 stsp if (match_wanted_ref(refname, pe->path))
1157 0e4002ca 2020-03-21 stsp return 1;
1158 0e4002ca 2020-03-21 stsp }
1159 0e4002ca 2020-03-21 stsp
1160 0e4002ca 2020-03-21 stsp return 0;
1161 0e4002ca 2020-03-21 stsp }
1162 0e4002ca 2020-03-21 stsp
1163 41b0de12 2020-03-21 stsp static const struct got_error *
1164 0e4002ca 2020-03-21 stsp create_wanted_ref(const char *refname, struct got_object_id *id,
1165 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
1166 0e4002ca 2020-03-21 stsp {
1167 0e4002ca 2020-03-21 stsp const struct got_error *err;
1168 0e4002ca 2020-03-21 stsp char *remote_refname;
1169 0e4002ca 2020-03-21 stsp
1170 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
1171 0e4002ca 2020-03-21 stsp refname += 5;
1172 0e4002ca 2020-03-21 stsp
1173 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1174 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
1175 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
1176 0e4002ca 2020-03-21 stsp
1177 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
1178 0e4002ca 2020-03-21 stsp free(remote_refname);
1179 7c0b7f42 2020-09-24 stsp return err;
1180 7c0b7f42 2020-09-24 stsp }
1181 7c0b7f42 2020-09-24 stsp
1182 7c0b7f42 2020-09-24 stsp static const struct got_error *
1183 7c0b7f42 2020-09-24 stsp create_gotconfig(const char *proto, const char *host, const char *port,
1184 15d3c221 2021-01-05 stsp const char *remote_repo_path, const char *default_branch,
1185 0c8b29c5 2021-01-05 stsp int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1186 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, int mirror_references,
1187 99495ddb 2021-01-10 stsp struct got_repository *repo)
1188 7c0b7f42 2020-09-24 stsp {
1189 7c0b7f42 2020-09-24 stsp const struct got_error *err = NULL;
1190 7c0b7f42 2020-09-24 stsp char *gotconfig_path = NULL;
1191 7c0b7f42 2020-09-24 stsp char *gotconfig = NULL;
1192 7c0b7f42 2020-09-24 stsp FILE *gotconfig_file = NULL;
1193 15d3c221 2021-01-05 stsp const char *branchname = NULL;
1194 99495ddb 2021-01-10 stsp char *branches = NULL, *refs = NULL;
1195 7c0b7f42 2020-09-24 stsp ssize_t n;
1196 7c0b7f42 2020-09-24 stsp
1197 0c8b29c5 2021-01-05 stsp if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
1198 132af4a5 2021-01-05 stsp struct got_pathlist_entry *pe;
1199 132af4a5 2021-01-05 stsp TAILQ_FOREACH(pe, wanted_branches, entry) {
1200 132af4a5 2021-01-05 stsp char *s;
1201 132af4a5 2021-01-05 stsp branchname = pe->path;
1202 132af4a5 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1203 132af4a5 2021-01-05 stsp branchname += 11;
1204 132af4a5 2021-01-05 stsp if (asprintf(&s, "%s\"%s\" ",
1205 132af4a5 2021-01-05 stsp branches ? branches : "", branchname) == -1) {
1206 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1207 132af4a5 2021-01-05 stsp goto done;
1208 132af4a5 2021-01-05 stsp }
1209 132af4a5 2021-01-05 stsp free(branches);
1210 132af4a5 2021-01-05 stsp branches = s;
1211 132af4a5 2021-01-05 stsp }
1212 0c8b29c5 2021-01-05 stsp } else if (!fetch_all_branches && default_branch) {
1213 15d3c221 2021-01-05 stsp branchname = default_branch;
1214 15d3c221 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1215 15d3c221 2021-01-05 stsp branchname += 11;
1216 132af4a5 2021-01-05 stsp if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1217 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1218 132af4a5 2021-01-05 stsp goto done;
1219 99495ddb 2021-01-10 stsp }
1220 99495ddb 2021-01-10 stsp }
1221 99495ddb 2021-01-10 stsp if (!TAILQ_EMPTY(wanted_refs)) {
1222 99495ddb 2021-01-10 stsp struct got_pathlist_entry *pe;
1223 99495ddb 2021-01-10 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1224 99495ddb 2021-01-10 stsp char *s;
1225 99495ddb 2021-01-10 stsp const char *refname = pe->path;
1226 99495ddb 2021-01-10 stsp if (strncmp(refname, "refs/", 5) == 0)
1227 99495ddb 2021-01-10 stsp branchname += 5;
1228 99495ddb 2021-01-10 stsp if (asprintf(&s, "%s\"%s\" ",
1229 99495ddb 2021-01-10 stsp refs ? refs : "", refname) == -1) {
1230 99495ddb 2021-01-10 stsp err = got_error_from_errno("asprintf");
1231 99495ddb 2021-01-10 stsp goto done;
1232 99495ddb 2021-01-10 stsp }
1233 99495ddb 2021-01-10 stsp free(refs);
1234 99495ddb 2021-01-10 stsp refs = s;
1235 132af4a5 2021-01-05 stsp }
1236 15d3c221 2021-01-05 stsp }
1237 15d3c221 2021-01-05 stsp
1238 7c0b7f42 2020-09-24 stsp /* Create got.conf(5). */
1239 7c0b7f42 2020-09-24 stsp gotconfig_path = got_repo_get_path_gotconfig(repo);
1240 7c0b7f42 2020-09-24 stsp if (gotconfig_path == NULL) {
1241 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("got_repo_get_path_gotconfig");
1242 7c0b7f42 2020-09-24 stsp goto done;
1243 7c0b7f42 2020-09-24 stsp }
1244 00fe21f2 2021-12-31 stsp gotconfig_file = fopen(gotconfig_path, "ae");
1245 7c0b7f42 2020-09-24 stsp if (gotconfig_file == NULL) {
1246 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fopen", gotconfig_path);
1247 7c0b7f42 2020-09-24 stsp goto done;
1248 7c0b7f42 2020-09-24 stsp }
1249 7c0b7f42 2020-09-24 stsp if (asprintf(&gotconfig,
1250 7c0b7f42 2020-09-24 stsp "remote \"%s\" {\n"
1251 7c0b7f42 2020-09-24 stsp "\tserver %s\n"
1252 7c0b7f42 2020-09-24 stsp "\tprotocol %s\n"
1253 7c0b7f42 2020-09-24 stsp "%s%s%s"
1254 7c0b7f42 2020-09-24 stsp "\trepository \"%s\"\n"
1255 15d3c221 2021-01-05 stsp "%s%s%s"
1256 99495ddb 2021-01-10 stsp "%s%s%s"
1257 7c0b7f42 2020-09-24 stsp "%s"
1258 0c8b29c5 2021-01-05 stsp "%s"
1259 7c0b7f42 2020-09-24 stsp "}\n",
1260 7c0b7f42 2020-09-24 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
1261 7c0b7f42 2020-09-24 stsp port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1262 132af4a5 2021-01-05 stsp remote_repo_path, branches ? "\tbranch { " : "",
1263 132af4a5 2021-01-05 stsp branches ? branches : "", branches ? "}\n" : "",
1264 99495ddb 2021-01-10 stsp refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1265 0c8b29c5 2021-01-05 stsp mirror_references ? "\tmirror-references yes\n" : "",
1266 0c8b29c5 2021-01-05 stsp fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) {
1267 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1268 7c0b7f42 2020-09-24 stsp goto done;
1269 7c0b7f42 2020-09-24 stsp }
1270 7c0b7f42 2020-09-24 stsp n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1271 7c0b7f42 2020-09-24 stsp if (n != strlen(gotconfig)) {
1272 7c0b7f42 2020-09-24 stsp err = got_ferror(gotconfig_file, GOT_ERR_IO);
1273 7c0b7f42 2020-09-24 stsp goto done;
1274 7c0b7f42 2020-09-24 stsp }
1275 7c0b7f42 2020-09-24 stsp
1276 7c0b7f42 2020-09-24 stsp done:
1277 7c0b7f42 2020-09-24 stsp if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
1278 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fclose", gotconfig_path);
1279 7c0b7f42 2020-09-24 stsp free(gotconfig_path);
1280 132af4a5 2021-01-05 stsp free(branches);
1281 7c0b7f42 2020-09-24 stsp return err;
1282 7c0b7f42 2020-09-24 stsp }
1283 7c0b7f42 2020-09-24 stsp
1284 7c0b7f42 2020-09-24 stsp static const struct got_error *
1285 04d9a9ec 2020-09-24 stsp create_gitconfig(const char *git_url, const char *default_branch,
1286 132af4a5 2021-01-05 stsp int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1287 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, int mirror_references,
1288 99495ddb 2021-01-10 stsp struct got_repository *repo)
1289 7c0b7f42 2020-09-24 stsp {
1290 7c0b7f42 2020-09-24 stsp const struct got_error *err = NULL;
1291 7c0b7f42 2020-09-24 stsp char *gitconfig_path = NULL;
1292 7c0b7f42 2020-09-24 stsp char *gitconfig = NULL;
1293 7c0b7f42 2020-09-24 stsp FILE *gitconfig_file = NULL;
1294 99495ddb 2021-01-10 stsp char *branches = NULL, *refs = NULL;
1295 56d0a753 2021-01-20 stsp const char *branchname;
1296 7c0b7f42 2020-09-24 stsp ssize_t n;
1297 7c0b7f42 2020-09-24 stsp
1298 7c0b7f42 2020-09-24 stsp /* Create a config file Git can understand. */
1299 7c0b7f42 2020-09-24 stsp gitconfig_path = got_repo_get_path_gitconfig(repo);
1300 7c0b7f42 2020-09-24 stsp if (gitconfig_path == NULL) {
1301 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("got_repo_get_path_gitconfig");
1302 7c0b7f42 2020-09-24 stsp goto done;
1303 7c0b7f42 2020-09-24 stsp }
1304 00fe21f2 2021-12-31 stsp gitconfig_file = fopen(gitconfig_path, "ae");
1305 7c0b7f42 2020-09-24 stsp if (gitconfig_file == NULL) {
1306 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fopen", gitconfig_path);
1307 7c0b7f42 2020-09-24 stsp goto done;
1308 7c0b7f42 2020-09-24 stsp }
1309 56d0a753 2021-01-20 stsp if (fetch_all_branches) {
1310 56d0a753 2021-01-20 stsp if (mirror_references) {
1311 56d0a753 2021-01-20 stsp if (asprintf(&branches,
1312 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1313 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1314 56d0a753 2021-01-20 stsp goto done;
1315 56d0a753 2021-01-20 stsp }
1316 56d0a753 2021-01-20 stsp } else if (asprintf(&branches,
1317 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1318 7c0b7f42 2020-09-24 stsp GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1319 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1320 7c0b7f42 2020-09-24 stsp goto done;
1321 132af4a5 2021-01-05 stsp }
1322 132af4a5 2021-01-05 stsp } else if (!TAILQ_EMPTY(wanted_branches)) {
1323 132af4a5 2021-01-05 stsp struct got_pathlist_entry *pe;
1324 132af4a5 2021-01-05 stsp TAILQ_FOREACH(pe, wanted_branches, entry) {
1325 132af4a5 2021-01-05 stsp char *s;
1326 132af4a5 2021-01-05 stsp branchname = pe->path;
1327 132af4a5 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1328 132af4a5 2021-01-05 stsp branchname += 11;
1329 56d0a753 2021-01-20 stsp if (mirror_references) {
1330 56d0a753 2021-01-20 stsp if (asprintf(&s,
1331 56d0a753 2021-01-20 stsp "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1332 56d0a753 2021-01-20 stsp branches ? branches : "",
1333 56d0a753 2021-01-20 stsp branchname, branchname) == -1) {
1334 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1335 56d0a753 2021-01-20 stsp goto done;
1336 56d0a753 2021-01-20 stsp }
1337 56d0a753 2021-01-20 stsp } else if (asprintf(&s,
1338 56d0a753 2021-01-20 stsp "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1339 132af4a5 2021-01-05 stsp branches ? branches : "",
1340 132af4a5 2021-01-05 stsp branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1341 132af4a5 2021-01-05 stsp branchname) == -1) {
1342 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1343 132af4a5 2021-01-05 stsp goto done;
1344 132af4a5 2021-01-05 stsp }
1345 132af4a5 2021-01-05 stsp free(branches);
1346 132af4a5 2021-01-05 stsp branches = s;
1347 7c0b7f42 2020-09-24 stsp }
1348 7c0b7f42 2020-09-24 stsp } else {
1349 7c0b7f42 2020-09-24 stsp /*
1350 7c0b7f42 2020-09-24 stsp * If the server specified a default branch, use just that one.
1351 7c0b7f42 2020-09-24 stsp * Otherwise fall back to fetching all branches on next fetch.
1352 7c0b7f42 2020-09-24 stsp */
1353 04d9a9ec 2020-09-24 stsp if (default_branch) {
1354 04d9a9ec 2020-09-24 stsp branchname = default_branch;
1355 7c0b7f42 2020-09-24 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1356 7c0b7f42 2020-09-24 stsp branchname += 11;
1357 7c0b7f42 2020-09-24 stsp } else
1358 7c0b7f42 2020-09-24 stsp branchname = "*"; /* fall back to all branches */
1359 56d0a753 2021-01-20 stsp if (mirror_references) {
1360 56d0a753 2021-01-20 stsp if (asprintf(&branches,
1361 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/%s:refs/heads/%s\n",
1362 56d0a753 2021-01-20 stsp branchname, branchname) == -1) {
1363 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1364 56d0a753 2021-01-20 stsp goto done;
1365 56d0a753 2021-01-20 stsp }
1366 56d0a753 2021-01-20 stsp } else if (asprintf(&branches,
1367 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1368 7c0b7f42 2020-09-24 stsp branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1369 7c0b7f42 2020-09-24 stsp branchname) == -1) {
1370 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1371 7c0b7f42 2020-09-24 stsp goto done;
1372 99495ddb 2021-01-10 stsp }
1373 99495ddb 2021-01-10 stsp }
1374 56d0a753 2021-01-20 stsp if (!TAILQ_EMPTY(wanted_refs)) {
1375 99495ddb 2021-01-10 stsp struct got_pathlist_entry *pe;
1376 99495ddb 2021-01-10 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1377 99495ddb 2021-01-10 stsp char *s;
1378 99495ddb 2021-01-10 stsp const char *refname = pe->path;
1379 99495ddb 2021-01-10 stsp if (strncmp(refname, "refs/", 5) == 0)
1380 99495ddb 2021-01-10 stsp refname += 5;
1381 56d0a753 2021-01-20 stsp if (mirror_references) {
1382 56d0a753 2021-01-20 stsp if (asprintf(&s,
1383 56d0a753 2021-01-20 stsp "%s\tfetch = refs/%s:refs/%s\n",
1384 56d0a753 2021-01-20 stsp refs ? refs : "", refname, refname) == -1) {
1385 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1386 56d0a753 2021-01-20 stsp goto done;
1387 56d0a753 2021-01-20 stsp }
1388 56d0a753 2021-01-20 stsp } else if (asprintf(&s,
1389 56d0a753 2021-01-20 stsp "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1390 99495ddb 2021-01-10 stsp refs ? refs : "",
1391 99495ddb 2021-01-10 stsp refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1392 99495ddb 2021-01-10 stsp refname) == -1) {
1393 99495ddb 2021-01-10 stsp err = got_error_from_errno("asprintf");
1394 99495ddb 2021-01-10 stsp goto done;
1395 99495ddb 2021-01-10 stsp }
1396 99495ddb 2021-01-10 stsp free(refs);
1397 99495ddb 2021-01-10 stsp refs = s;
1398 7c0b7f42 2020-09-24 stsp }
1399 132af4a5 2021-01-05 stsp }
1400 99495ddb 2021-01-10 stsp
1401 132af4a5 2021-01-05 stsp if (asprintf(&gitconfig,
1402 132af4a5 2021-01-05 stsp "[remote \"%s\"]\n"
1403 132af4a5 2021-01-05 stsp "\turl = %s\n"
1404 132af4a5 2021-01-05 stsp "%s"
1405 99495ddb 2021-01-10 stsp "%s"
1406 56d0a753 2021-01-20 stsp "\tfetch = refs/tags/*:refs/tags/*\n",
1407 132af4a5 2021-01-05 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
1408 56d0a753 2021-01-20 stsp refs ? refs : "") == -1) {
1409 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1410 132af4a5 2021-01-05 stsp goto done;
1411 7c0b7f42 2020-09-24 stsp }
1412 7c0b7f42 2020-09-24 stsp n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1413 7c0b7f42 2020-09-24 stsp if (n != strlen(gitconfig)) {
1414 7c0b7f42 2020-09-24 stsp err = got_ferror(gitconfig_file, GOT_ERR_IO);
1415 7c0b7f42 2020-09-24 stsp goto done;
1416 7c0b7f42 2020-09-24 stsp }
1417 7c0b7f42 2020-09-24 stsp done:
1418 7c0b7f42 2020-09-24 stsp if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
1419 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fclose", gitconfig_path);
1420 7c0b7f42 2020-09-24 stsp free(gitconfig_path);
1421 132af4a5 2021-01-05 stsp free(branches);
1422 0e4002ca 2020-03-21 stsp return err;
1423 0e4002ca 2020-03-21 stsp }
1424 0e4002ca 2020-03-21 stsp
1425 0e4002ca 2020-03-21 stsp static const struct got_error *
1426 04d9a9ec 2020-09-24 stsp create_config_files(const char *proto, const char *host, const char *port,
1427 04d9a9ec 2020-09-24 stsp const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1428 04d9a9ec 2020-09-24 stsp int mirror_references, struct got_pathlist_head *symrefs,
1429 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_branches,
1430 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1431 04d9a9ec 2020-09-24 stsp {
1432 04d9a9ec 2020-09-24 stsp const struct got_error *err = NULL;
1433 04d9a9ec 2020-09-24 stsp const char *default_branch = NULL;
1434 04d9a9ec 2020-09-24 stsp struct got_pathlist_entry *pe;
1435 04d9a9ec 2020-09-24 stsp
1436 04d9a9ec 2020-09-24 stsp /*
1437 04d9a9ec 2020-09-24 stsp * If we asked for a set of wanted branches then use the first
1438 04d9a9ec 2020-09-24 stsp * one of those.
1439 04d9a9ec 2020-09-24 stsp */
1440 62d463ca 2020-10-20 naddy if (!TAILQ_EMPTY(wanted_branches)) {
1441 04d9a9ec 2020-09-24 stsp pe = TAILQ_FIRST(wanted_branches);
1442 04d9a9ec 2020-09-24 stsp default_branch = pe->path;
1443 04d9a9ec 2020-09-24 stsp } else {
1444 04d9a9ec 2020-09-24 stsp /* First HEAD ref listed by server is the default branch. */
1445 04d9a9ec 2020-09-24 stsp TAILQ_FOREACH(pe, symrefs, entry) {
1446 04d9a9ec 2020-09-24 stsp const char *refname = pe->path;
1447 04d9a9ec 2020-09-24 stsp const char *target = pe->data;
1448 04d9a9ec 2020-09-24 stsp
1449 04d9a9ec 2020-09-24 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
1450 04d9a9ec 2020-09-24 stsp continue;
1451 04d9a9ec 2020-09-24 stsp
1452 04d9a9ec 2020-09-24 stsp default_branch = target;
1453 04d9a9ec 2020-09-24 stsp break;
1454 04d9a9ec 2020-09-24 stsp }
1455 04d9a9ec 2020-09-24 stsp }
1456 04d9a9ec 2020-09-24 stsp
1457 04d9a9ec 2020-09-24 stsp /* Create got.conf(5). */
1458 04d9a9ec 2020-09-24 stsp err = create_gotconfig(proto, host, port, remote_repo_path,
1459 0c8b29c5 2021-01-05 stsp default_branch, fetch_all_branches, wanted_branches,
1460 99495ddb 2021-01-10 stsp wanted_refs, mirror_references, repo);
1461 04d9a9ec 2020-09-24 stsp if (err)
1462 04d9a9ec 2020-09-24 stsp return err;
1463 04d9a9ec 2020-09-24 stsp
1464 04d9a9ec 2020-09-24 stsp /* Create a config file Git can understand. */
1465 04d9a9ec 2020-09-24 stsp return create_gitconfig(git_url, default_branch, fetch_all_branches,
1466 99495ddb 2021-01-10 stsp wanted_branches, wanted_refs, mirror_references, repo);
1467 04d9a9ec 2020-09-24 stsp }
1468 04d9a9ec 2020-09-24 stsp
1469 04d9a9ec 2020-09-24 stsp static const struct got_error *
1470 93658fb9 2020-03-18 stsp cmd_clone(int argc, char *argv[])
1471 93658fb9 2020-03-18 stsp {
1472 39c64a6a 2020-03-18 stsp const struct got_error *error = NULL;
1473 9df6f38b 2020-03-18 stsp const char *uri, *dirname;
1474 09838ffc 2020-03-18 stsp char *proto, *host, *port, *repo_name, *server_path;
1475 d9b4d0c0 2020-03-18 stsp char *default_destdir = NULL, *id_str = NULL;
1476 a9c2d4c2 2020-09-24 stsp const char *repo_path;
1477 bb64b798 2020-03-18 stsp struct got_repository *repo = NULL;
1478 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1479 d9b4d0c0 2020-03-18 stsp struct got_pathlist_entry *pe;
1480 d9b4d0c0 2020-03-18 stsp struct got_object_id *pack_hash = NULL;
1481 9c52365f 2020-03-21 stsp int ch, fetchfd = -1, fetchstatus;
1482 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
1483 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg fpa;
1484 b46f3e71 2020-03-18 stsp char *git_url = NULL;
1485 659e7fbd 2020-03-20 stsp int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1486 41b0de12 2020-03-21 stsp int list_refs_only = 0;
1487 93658fb9 2020-03-18 stsp
1488 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&refs);
1489 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&symrefs);
1490 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
1491 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
1492 d9b4d0c0 2020-03-18 stsp
1493 0e4002ca 2020-03-21 stsp while ((ch = getopt(argc, argv, "ab:lmvqR:")) != -1) {
1494 93658fb9 2020-03-18 stsp switch (ch) {
1495 659e7fbd 2020-03-20 stsp case 'a':
1496 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
1497 4ba14133 2020-03-20 stsp break;
1498 4ba14133 2020-03-20 stsp case 'b':
1499 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
1500 4ba14133 2020-03-20 stsp optarg, NULL);
1501 4ba14133 2020-03-20 stsp if (error)
1502 4ba14133 2020-03-20 stsp return error;
1503 659e7fbd 2020-03-20 stsp break;
1504 41b0de12 2020-03-21 stsp case 'l':
1505 41b0de12 2020-03-21 stsp list_refs_only = 1;
1506 41b0de12 2020-03-21 stsp break;
1507 469dd726 2020-03-20 stsp case 'm':
1508 469dd726 2020-03-20 stsp mirror_references = 1;
1509 469dd726 2020-03-20 stsp break;
1510 68999b92 2020-03-18 stsp case 'v':
1511 68999b92 2020-03-18 stsp if (verbosity < 0)
1512 68999b92 2020-03-18 stsp verbosity = 0;
1513 68999b92 2020-03-18 stsp else if (verbosity < 3)
1514 68999b92 2020-03-18 stsp verbosity++;
1515 68999b92 2020-03-18 stsp break;
1516 68999b92 2020-03-18 stsp case 'q':
1517 68999b92 2020-03-18 stsp verbosity = -1;
1518 68999b92 2020-03-18 stsp break;
1519 0e4002ca 2020-03-21 stsp case 'R':
1520 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
1521 0e4002ca 2020-03-21 stsp optarg, NULL);
1522 0e4002ca 2020-03-21 stsp if (error)
1523 0e4002ca 2020-03-21 stsp return error;
1524 0e4002ca 2020-03-21 stsp break;
1525 93658fb9 2020-03-18 stsp default:
1526 93658fb9 2020-03-18 stsp usage_clone();
1527 93658fb9 2020-03-18 stsp break;
1528 93658fb9 2020-03-18 stsp }
1529 93658fb9 2020-03-18 stsp }
1530 93658fb9 2020-03-18 stsp argc -= optind;
1531 93658fb9 2020-03-18 stsp argv += optind;
1532 39c64a6a 2020-03-18 stsp
1533 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1534 ff69268e 2020-12-13 stsp option_conflict('a', 'b');
1535 41b0de12 2020-03-21 stsp if (list_refs_only) {
1536 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
1537 ff69268e 2020-12-13 stsp option_conflict('l', 'b');
1538 41b0de12 2020-03-21 stsp if (fetch_all_branches)
1539 ff69268e 2020-12-13 stsp option_conflict('l', 'a');
1540 41b0de12 2020-03-21 stsp if (mirror_references)
1541 ff69268e 2020-12-13 stsp option_conflict('l', 'm');
1542 0e4002ca 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_refs))
1543 ff69268e 2020-12-13 stsp option_conflict('l', 'R');
1544 41b0de12 2020-03-21 stsp }
1545 4ba14133 2020-03-20 stsp
1546 93658fb9 2020-03-18 stsp uri = argv[0];
1547 9df6f38b 2020-03-18 stsp
1548 9df6f38b 2020-03-18 stsp if (argc == 1)
1549 93658fb9 2020-03-18 stsp dirname = NULL;
1550 9df6f38b 2020-03-18 stsp else if (argc == 2)
1551 93658fb9 2020-03-18 stsp dirname = argv[1];
1552 93658fb9 2020-03-18 stsp else
1553 93658fb9 2020-03-18 stsp usage_clone();
1554 09838ffc 2020-03-18 stsp
1555 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
1556 4dbec0a8 2020-08-27 stsp &repo_name, uri);
1557 39c64a6a 2020-03-18 stsp if (error)
1558 09f63084 2020-03-20 stsp goto done;
1559 09f63084 2020-03-20 stsp
1560 09f63084 2020-03-20 stsp if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1561 09f63084 2020-03-20 stsp host, port ? ":" : "", port ? port : "",
1562 09f63084 2020-03-20 stsp server_path[0] != '/' ? "/" : "", server_path) == -1) {
1563 09f63084 2020-03-20 stsp error = got_error_from_errno("asprintf");
1564 09838ffc 2020-03-18 stsp goto done;
1565 09f63084 2020-03-20 stsp }
1566 09838ffc 2020-03-18 stsp
1567 39c64a6a 2020-03-18 stsp if (strcmp(proto, "git") == 0) {
1568 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1569 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1570 39c64a6a 2020-03-18 stsp "sendfd dns inet unveil", NULL) == -1)
1571 39c64a6a 2020-03-18 stsp err(1, "pledge");
1572 b46f3e71 2020-03-18 stsp #endif
1573 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
1574 39c64a6a 2020-03-18 stsp strcmp(proto, "ssh") == 0) {
1575 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1576 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1577 39c64a6a 2020-03-18 stsp "sendfd unveil", NULL) == -1)
1578 39c64a6a 2020-03-18 stsp err(1, "pledge");
1579 b46f3e71 2020-03-18 stsp #endif
1580 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "http") == 0 ||
1581 39c64a6a 2020-03-18 stsp strcmp(proto, "git+http") == 0) {
1582 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1583 39c64a6a 2020-03-18 stsp goto done;
1584 39c64a6a 2020-03-18 stsp } else {
1585 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1586 39c64a6a 2020-03-18 stsp goto done;
1587 39c64a6a 2020-03-18 stsp }
1588 bb64b798 2020-03-18 stsp if (dirname == NULL) {
1589 bb64b798 2020-03-18 stsp if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1590 39c64a6a 2020-03-18 stsp error = got_error_from_errno("asprintf");
1591 bb64b798 2020-03-18 stsp goto done;
1592 bb64b798 2020-03-18 stsp }
1593 bb64b798 2020-03-18 stsp repo_path = default_destdir;
1594 bb64b798 2020-03-18 stsp } else
1595 bb64b798 2020-03-18 stsp repo_path = dirname;
1596 bb64b798 2020-03-18 stsp
1597 41b0de12 2020-03-21 stsp if (!list_refs_only) {
1598 41b0de12 2020-03-21 stsp error = got_path_mkdir(repo_path);
1599 2751fe64 2020-09-24 stsp if (error &&
1600 2751fe64 2020-09-24 stsp (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
1601 2751fe64 2020-09-24 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST)))
1602 41b0de12 2020-03-21 stsp goto done;
1603 2751fe64 2020-09-24 stsp if (!got_path_dir_is_empty(repo_path)) {
1604 2751fe64 2020-09-24 stsp error = got_error_path(repo_path,
1605 2751fe64 2020-09-24 stsp GOT_ERR_DIR_NOT_EMPTY);
1606 41b0de12 2020-03-21 stsp goto done;
1607 2751fe64 2020-09-24 stsp }
1608 41b0de12 2020-03-21 stsp }
1609 bb64b798 2020-03-18 stsp
1610 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
1611 d65a88a2 2021-09-05 stsp if (error)
1612 d65a88a2 2021-09-05 stsp goto done;
1613 d65a88a2 2021-09-05 stsp
1614 f535bcd4 2020-09-30 stsp error = apply_unveil(repo_path, 0, NULL);
1615 ee448f5f 2020-03-18 stsp if (error)
1616 ee448f5f 2020-03-18 stsp goto done;
1617 f79e6490 2020-04-19 stsp
1618 f79e6490 2020-04-19 stsp if (verbosity >= 0)
1619 f79e6490 2020-04-19 stsp printf("Connecting to %s%s%s\n", host,
1620 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
1621 ee448f5f 2020-03-18 stsp
1622 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1623 9c52365f 2020-03-21 stsp server_path, verbosity);
1624 39c64a6a 2020-03-18 stsp if (error)
1625 bb64b798 2020-03-18 stsp goto done;
1626 bb64b798 2020-03-18 stsp
1627 2751fe64 2020-09-24 stsp if (!list_refs_only) {
1628 2751fe64 2020-09-24 stsp error = got_repo_init(repo_path);
1629 2751fe64 2020-09-24 stsp if (error)
1630 2751fe64 2020-09-24 stsp goto done;
1631 2751fe64 2020-09-24 stsp error = got_repo_open(&repo, repo_path, NULL);
1632 2751fe64 2020-09-24 stsp if (error)
1633 2751fe64 2020-09-24 stsp goto done;
1634 2751fe64 2020-09-24 stsp }
1635 2751fe64 2020-09-24 stsp
1636 892ac3b6 2020-03-18 stsp fpa.last_scaled_size[0] = '\0';
1637 892ac3b6 2020-03-18 stsp fpa.last_p_indexed = -1;
1638 892ac3b6 2020-03-18 stsp fpa.last_p_resolved = -1;
1639 68999b92 2020-03-18 stsp fpa.verbosity = verbosity;
1640 04d9a9ec 2020-09-24 stsp fpa.create_configs = 1;
1641 04d9a9ec 2020-09-24 stsp fpa.configs_created = 0;
1642 04d9a9ec 2020-09-24 stsp fpa.repo = repo;
1643 04d9a9ec 2020-09-24 stsp fpa.config_info.symrefs = &symrefs;
1644 04d9a9ec 2020-09-24 stsp fpa.config_info.wanted_branches = &wanted_branches;
1645 99495ddb 2021-01-10 stsp fpa.config_info.wanted_refs = &wanted_refs;
1646 04d9a9ec 2020-09-24 stsp fpa.config_info.proto = proto;
1647 04d9a9ec 2020-09-24 stsp fpa.config_info.host = host;
1648 04d9a9ec 2020-09-24 stsp fpa.config_info.port = port;
1649 04d9a9ec 2020-09-24 stsp fpa.config_info.remote_repo_path = server_path;
1650 04d9a9ec 2020-09-24 stsp fpa.config_info.git_url = git_url;
1651 04d9a9ec 2020-09-24 stsp fpa.config_info.fetch_all_branches = fetch_all_branches;
1652 04d9a9ec 2020-09-24 stsp fpa.config_info.mirror_references = mirror_references;
1653 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1654 469dd726 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1655 0e4002ca 2020-03-21 stsp fetch_all_branches, &wanted_branches, &wanted_refs,
1656 0e4002ca 2020-03-21 stsp list_refs_only, verbosity, fetchfd, repo,
1657 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
1658 39c64a6a 2020-03-18 stsp if (error)
1659 d9b4d0c0 2020-03-18 stsp goto done;
1660 d9b4d0c0 2020-03-18 stsp
1661 41b0de12 2020-03-21 stsp if (list_refs_only) {
1662 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
1663 41b0de12 2020-03-21 stsp goto done;
1664 41b0de12 2020-03-21 stsp }
1665 41b0de12 2020-03-21 stsp
1666 8a4f8535 2021-12-27 stsp if (pack_hash == NULL) {
1667 8a4f8535 2021-12-27 stsp error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s",
1668 8a4f8535 2021-12-27 stsp "server sent an empty pack file");
1669 8a4f8535 2021-12-27 stsp goto done;
1670 8a4f8535 2021-12-27 stsp }
1671 39c64a6a 2020-03-18 stsp error = got_object_id_str(&id_str, pack_hash);
1672 39c64a6a 2020-03-18 stsp if (error)
1673 d9b4d0c0 2020-03-18 stsp goto done;
1674 68999b92 2020-03-18 stsp if (verbosity >= 0)
1675 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
1676 d9b4d0c0 2020-03-18 stsp free(id_str);
1677 d9b4d0c0 2020-03-18 stsp
1678 d9b4d0c0 2020-03-18 stsp /* Set up references provided with the pack file. */
1679 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1680 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1681 d9b4d0c0 2020-03-18 stsp struct got_object_id *id = pe->data;
1682 7ebc0570 2020-03-18 stsp char *remote_refname;
1683 0e4002ca 2020-03-21 stsp
1684 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
1685 0e4002ca 2020-03-21 stsp !mirror_references) {
1686 0e4002ca 2020-03-21 stsp error = create_wanted_ref(refname, id,
1687 0e4002ca 2020-03-21 stsp GOT_FETCH_DEFAULT_REMOTE_NAME,
1688 0e4002ca 2020-03-21 stsp verbosity - 1, repo);
1689 0e4002ca 2020-03-21 stsp if (error)
1690 0e4002ca 2020-03-21 stsp goto done;
1691 0e4002ca 2020-03-21 stsp continue;
1692 0e4002ca 2020-03-21 stsp }
1693 668a20f6 2020-03-18 stsp
1694 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity - 1, repo);
1695 39c64a6a 2020-03-18 stsp if (error)
1696 d9b4d0c0 2020-03-18 stsp goto done;
1697 d9b4d0c0 2020-03-18 stsp
1698 469dd726 2020-03-20 stsp if (mirror_references)
1699 469dd726 2020-03-20 stsp continue;
1700 469dd726 2020-03-20 stsp
1701 7ebc0570 2020-03-18 stsp if (strncmp("refs/heads/", refname, 11) != 0)
1702 7ebc0570 2020-03-18 stsp continue;
1703 7ebc0570 2020-03-18 stsp
1704 7ebc0570 2020-03-18 stsp if (asprintf(&remote_refname,
1705 7ebc0570 2020-03-18 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1706 7ebc0570 2020-03-18 stsp refname + 11) == -1) {
1707 7ebc0570 2020-03-18 stsp error = got_error_from_errno("asprintf");
1708 7ebc0570 2020-03-18 stsp goto done;
1709 7ebc0570 2020-03-18 stsp }
1710 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id, verbosity - 1, repo);
1711 f298ae0f 2020-03-25 stsp free(remote_refname);
1712 39c64a6a 2020-03-18 stsp if (error)
1713 d9b4d0c0 2020-03-18 stsp goto done;
1714 d9b4d0c0 2020-03-18 stsp }
1715 d9b4d0c0 2020-03-18 stsp
1716 d9b4d0c0 2020-03-18 stsp /* Set the HEAD reference if the server provided one. */
1717 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1718 659e7fbd 2020-03-20 stsp struct got_reference *target_ref;
1719 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1720 d9b4d0c0 2020-03-18 stsp const char *target = pe->data;
1721 f298ae0f 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
1722 d9b4d0c0 2020-03-18 stsp
1723 d9b4d0c0 2020-03-18 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
1724 d9b4d0c0 2020-03-18 stsp continue;
1725 d9b4d0c0 2020-03-18 stsp
1726 39c64a6a 2020-03-18 stsp error = got_ref_open(&target_ref, repo, target, 0);
1727 39c64a6a 2020-03-18 stsp if (error) {
1728 55330abe 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1729 55330abe 2020-03-20 stsp error = NULL;
1730 d9b4d0c0 2020-03-18 stsp continue;
1731 55330abe 2020-03-20 stsp }
1732 d9b4d0c0 2020-03-18 stsp goto done;
1733 d9b4d0c0 2020-03-18 stsp }
1734 d9b4d0c0 2020-03-18 stsp
1735 04d9a9ec 2020-09-24 stsp error = create_symref(refname, target_ref, verbosity, repo);
1736 f298ae0f 2020-03-25 stsp got_ref_close(target_ref);
1737 f298ae0f 2020-03-25 stsp if (error)
1738 f298ae0f 2020-03-25 stsp goto done;
1739 f298ae0f 2020-03-25 stsp
1740 f298ae0f 2020-03-25 stsp if (mirror_references)
1741 f298ae0f 2020-03-25 stsp continue;
1742 f298ae0f 2020-03-25 stsp
1743 f298ae0f 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
1744 f298ae0f 2020-03-25 stsp continue;
1745 f298ae0f 2020-03-25 stsp
1746 f298ae0f 2020-03-25 stsp if (asprintf(&remote_refname,
1747 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1748 f298ae0f 2020-03-25 stsp refname) == -1) {
1749 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1750 f298ae0f 2020-03-25 stsp goto done;
1751 f298ae0f 2020-03-25 stsp }
1752 f298ae0f 2020-03-25 stsp if (asprintf(&remote_target,
1753 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1754 f298ae0f 2020-03-25 stsp target + 11) == -1) {
1755 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1756 f298ae0f 2020-03-25 stsp free(remote_refname);
1757 f298ae0f 2020-03-25 stsp goto done;
1758 f298ae0f 2020-03-25 stsp }
1759 f298ae0f 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target, 0);
1760 f298ae0f 2020-03-25 stsp if (error) {
1761 f298ae0f 2020-03-25 stsp free(remote_refname);
1762 f298ae0f 2020-03-25 stsp free(remote_target);
1763 f298ae0f 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
1764 f298ae0f 2020-03-25 stsp error = NULL;
1765 f298ae0f 2020-03-25 stsp continue;
1766 f298ae0f 2020-03-25 stsp }
1767 f298ae0f 2020-03-25 stsp goto done;
1768 f298ae0f 2020-03-25 stsp }
1769 04d9a9ec 2020-09-24 stsp error = create_symref(remote_refname, target_ref,
1770 04d9a9ec 2020-09-24 stsp verbosity - 1, repo);
1771 f298ae0f 2020-03-25 stsp free(remote_refname);
1772 f298ae0f 2020-03-25 stsp free(remote_target);
1773 d9b4d0c0 2020-03-18 stsp got_ref_close(target_ref);
1774 39c64a6a 2020-03-18 stsp if (error)
1775 d9b4d0c0 2020-03-18 stsp goto done;
1776 4ba14133 2020-03-20 stsp }
1777 4ba14133 2020-03-20 stsp if (pe == NULL) {
1778 4ba14133 2020-03-20 stsp /*
1779 4ba14133 2020-03-20 stsp * We failed to set the HEAD reference. If we asked for
1780 4ba14133 2020-03-20 stsp * a set of wanted branches use the first of one of those
1781 4ba14133 2020-03-20 stsp * which could be fetched instead.
1782 4ba14133 2020-03-20 stsp */
1783 62d463ca 2020-10-20 naddy TAILQ_FOREACH(pe, &wanted_branches, entry) {
1784 4ba14133 2020-03-20 stsp const char *target = pe->path;
1785 4ba14133 2020-03-20 stsp struct got_reference *target_ref;
1786 d9b4d0c0 2020-03-18 stsp
1787 4ba14133 2020-03-20 stsp error = got_ref_open(&target_ref, repo, target, 0);
1788 4ba14133 2020-03-20 stsp if (error) {
1789 4ba14133 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1790 4ba14133 2020-03-20 stsp error = NULL;
1791 4ba14133 2020-03-20 stsp continue;
1792 4ba14133 2020-03-20 stsp }
1793 4ba14133 2020-03-20 stsp goto done;
1794 4ba14133 2020-03-20 stsp }
1795 4ba14133 2020-03-20 stsp
1796 04d9a9ec 2020-09-24 stsp error = create_symref(GOT_REF_HEAD, target_ref,
1797 04d9a9ec 2020-09-24 stsp verbosity, repo);
1798 4ba14133 2020-03-20 stsp got_ref_close(target_ref);
1799 4ba14133 2020-03-20 stsp if (error)
1800 4ba14133 2020-03-20 stsp goto done;
1801 4ba14133 2020-03-20 stsp break;
1802 4ba14133 2020-03-20 stsp }
1803 659e7fbd 2020-03-20 stsp }
1804 659e7fbd 2020-03-20 stsp
1805 d715f13e 2020-03-19 stsp if (verbosity >= 0)
1806 469dd726 2020-03-20 stsp printf("Created %s repository '%s'\n",
1807 469dd726 2020-03-20 stsp mirror_references ? "mirrored" : "cloned", repo_path);
1808 09838ffc 2020-03-18 stsp done:
1809 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
1810 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
1811 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
1812 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1813 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
1814 9c52365f 2020-03-21 stsp }
1815 39c64a6a 2020-03-18 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1816 39c64a6a 2020-03-18 stsp error = got_error_from_errno("close");
1817 1d0f4054 2021-06-17 stsp if (repo) {
1818 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
1819 1d0f4054 2021-06-17 stsp if (error == NULL)
1820 1d0f4054 2021-06-17 stsp error = close_err;
1821 1d0f4054 2021-06-17 stsp }
1822 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1823 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1824 d9b4d0c0 2020-03-18 stsp free(pe->data);
1825 d9b4d0c0 2020-03-18 stsp }
1826 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&refs);
1827 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1828 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1829 d9b4d0c0 2020-03-18 stsp free(pe->data);
1830 d9b4d0c0 2020-03-18 stsp }
1831 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&symrefs);
1832 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
1833 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
1834 d9b4d0c0 2020-03-18 stsp free(pack_hash);
1835 09838ffc 2020-03-18 stsp free(proto);
1836 09838ffc 2020-03-18 stsp free(host);
1837 09838ffc 2020-03-18 stsp free(port);
1838 09838ffc 2020-03-18 stsp free(server_path);
1839 09838ffc 2020-03-18 stsp free(repo_name);
1840 bb64b798 2020-03-18 stsp free(default_destdir);
1841 b46f3e71 2020-03-18 stsp free(git_url);
1842 39c64a6a 2020-03-18 stsp return error;
1843 7848a0e1 2020-03-19 stsp }
1844 7848a0e1 2020-03-19 stsp
1845 7848a0e1 2020-03-19 stsp static const struct got_error *
1846 7848a0e1 2020-03-19 stsp update_ref(struct got_reference *ref, struct got_object_id *new_id,
1847 db6d8ad8 2020-03-21 stsp int replace_tags, int verbosity, struct got_repository *repo)
1848 7848a0e1 2020-03-19 stsp {
1849 7848a0e1 2020-03-19 stsp const struct got_error *err = NULL;
1850 7848a0e1 2020-03-19 stsp char *new_id_str = NULL;
1851 7848a0e1 2020-03-19 stsp struct got_object_id *old_id = NULL;
1852 7848a0e1 2020-03-19 stsp
1853 7848a0e1 2020-03-19 stsp err = got_object_id_str(&new_id_str, new_id);
1854 7848a0e1 2020-03-19 stsp if (err)
1855 7848a0e1 2020-03-19 stsp goto done;
1856 7848a0e1 2020-03-19 stsp
1857 db6d8ad8 2020-03-21 stsp if (!replace_tags &&
1858 db6d8ad8 2020-03-21 stsp strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1859 88609724 2020-03-21 stsp err = got_ref_resolve(&old_id, repo, ref);
1860 88609724 2020-03-21 stsp if (err)
1861 88609724 2020-03-21 stsp goto done;
1862 88609724 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1863 88609724 2020-03-21 stsp goto done;
1864 db6d8ad8 2020-03-21 stsp if (verbosity >= 0) {
1865 db6d8ad8 2020-03-21 stsp printf("Rejecting update of existing tag %s: %s\n",
1866 db6d8ad8 2020-03-21 stsp got_ref_get_name(ref), new_id_str);
1867 db6d8ad8 2020-03-21 stsp }
1868 db6d8ad8 2020-03-21 stsp goto done;
1869 db6d8ad8 2020-03-21 stsp }
1870 db6d8ad8 2020-03-21 stsp
1871 7848a0e1 2020-03-19 stsp if (got_ref_is_symbolic(ref)) {
1872 688f11b3 2020-03-21 stsp if (verbosity >= 0) {
1873 e8a967e0 2020-03-21 stsp printf("Replacing reference %s: %s\n",
1874 6338a6a1 2020-03-21 stsp got_ref_get_name(ref),
1875 6338a6a1 2020-03-21 stsp got_ref_get_symref_target(ref));
1876 688f11b3 2020-03-21 stsp }
1877 e8a967e0 2020-03-21 stsp err = got_ref_change_symref_to_ref(ref, new_id);
1878 7848a0e1 2020-03-19 stsp if (err)
1879 7848a0e1 2020-03-19 stsp goto done;
1880 e8a967e0 2020-03-21 stsp err = got_ref_write(ref, repo);
1881 e8a967e0 2020-03-21 stsp if (err)
1882 e8a967e0 2020-03-21 stsp goto done;
1883 7848a0e1 2020-03-19 stsp } else {
1884 7848a0e1 2020-03-19 stsp err = got_ref_resolve(&old_id, repo, ref);
1885 7848a0e1 2020-03-19 stsp if (err)
1886 7848a0e1 2020-03-19 stsp goto done;
1887 6338a6a1 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1888 6338a6a1 2020-03-21 stsp goto done;
1889 6338a6a1 2020-03-21 stsp
1890 6338a6a1 2020-03-21 stsp err = got_ref_change_ref(ref, new_id);
1891 6338a6a1 2020-03-21 stsp if (err)
1892 6338a6a1 2020-03-21 stsp goto done;
1893 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
1894 6338a6a1 2020-03-21 stsp if (err)
1895 6338a6a1 2020-03-21 stsp goto done;
1896 7848a0e1 2020-03-19 stsp }
1897 6338a6a1 2020-03-21 stsp
1898 6338a6a1 2020-03-21 stsp if (verbosity >= 0)
1899 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(ref),
1900 6338a6a1 2020-03-21 stsp new_id_str);
1901 7848a0e1 2020-03-19 stsp done:
1902 7848a0e1 2020-03-19 stsp free(old_id);
1903 7848a0e1 2020-03-19 stsp free(new_id_str);
1904 7848a0e1 2020-03-19 stsp return err;
1905 2ab43947 2020-03-18 stsp }
1906 f1bcca34 2020-03-25 stsp
1907 f1bcca34 2020-03-25 stsp static const struct got_error *
1908 f1bcca34 2020-03-25 stsp update_symref(const char *refname, struct got_reference *target_ref,
1909 f1bcca34 2020-03-25 stsp int verbosity, struct got_repository *repo)
1910 f1bcca34 2020-03-25 stsp {
1911 f1bcca34 2020-03-25 stsp const struct got_error *err = NULL, *unlock_err;
1912 f1bcca34 2020-03-25 stsp struct got_reference *symref;
1913 bcf34b0e 2020-03-26 stsp int symref_is_locked = 0;
1914 f1bcca34 2020-03-25 stsp
1915 f1bcca34 2020-03-25 stsp err = got_ref_open(&symref, repo, refname, 1);
1916 bcf34b0e 2020-03-26 stsp if (err) {
1917 bcf34b0e 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
1918 bcf34b0e 2020-03-26 stsp return err;
1919 bcf34b0e 2020-03-26 stsp err = got_ref_alloc_symref(&symref, refname, target_ref);
1920 bcf34b0e 2020-03-26 stsp if (err)
1921 bcf34b0e 2020-03-26 stsp goto done;
1922 2ab43947 2020-03-18 stsp
1923 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1924 bcf34b0e 2020-03-26 stsp if (err)
1925 bcf34b0e 2020-03-26 stsp goto done;
1926 f1bcca34 2020-03-25 stsp
1927 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1928 bcf34b0e 2020-03-26 stsp printf("Created reference %s: %s\n",
1929 bcf34b0e 2020-03-26 stsp got_ref_get_name(symref),
1930 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1931 bcf34b0e 2020-03-26 stsp } else {
1932 bcf34b0e 2020-03-26 stsp symref_is_locked = 1;
1933 f1bcca34 2020-03-25 stsp
1934 bcf34b0e 2020-03-26 stsp if (strcmp(got_ref_get_symref_target(symref),
1935 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref)) == 0)
1936 bcf34b0e 2020-03-26 stsp goto done;
1937 bcf34b0e 2020-03-26 stsp
1938 bcf34b0e 2020-03-26 stsp err = got_ref_change_symref(symref,
1939 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref));
1940 bcf34b0e 2020-03-26 stsp if (err)
1941 bcf34b0e 2020-03-26 stsp goto done;
1942 bcf34b0e 2020-03-26 stsp
1943 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1944 bcf34b0e 2020-03-26 stsp if (err)
1945 bcf34b0e 2020-03-26 stsp goto done;
1946 bcf34b0e 2020-03-26 stsp
1947 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1948 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(symref),
1949 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1950 bcf34b0e 2020-03-26 stsp
1951 bcf34b0e 2020-03-26 stsp }
1952 f1bcca34 2020-03-25 stsp done:
1953 bcf34b0e 2020-03-26 stsp if (symref_is_locked) {
1954 bcf34b0e 2020-03-26 stsp unlock_err = got_ref_unlock(symref);
1955 bcf34b0e 2020-03-26 stsp if (unlock_err && err == NULL)
1956 bcf34b0e 2020-03-26 stsp err = unlock_err;
1957 bcf34b0e 2020-03-26 stsp }
1958 f1bcca34 2020-03-25 stsp got_ref_close(symref);
1959 f1bcca34 2020-03-25 stsp return err;
1960 f1bcca34 2020-03-25 stsp }
1961 f1bcca34 2020-03-25 stsp
1962 2ab43947 2020-03-18 stsp __dead static void
1963 7848a0e1 2020-03-19 stsp usage_fetch(void)
1964 7848a0e1 2020-03-19 stsp {
1965 f21ec2f0 2020-03-21 stsp fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
1966 161728eb 2021-07-24 stsp "[-r repository-path] [-t] [-q] [-v] [-R reference] [-X] "
1967 0e4002ca 2020-03-21 stsp "[remote-repository-name]\n",
1968 13f12b09 2020-03-21 stsp getprogname());
1969 7848a0e1 2020-03-19 stsp exit(1);
1970 7848a0e1 2020-03-19 stsp }
1971 7848a0e1 2020-03-19 stsp
1972 7848a0e1 2020-03-19 stsp static const struct got_error *
1973 3789fd73 2020-03-26 stsp delete_missing_ref(struct got_reference *ref,
1974 688f11b3 2020-03-21 stsp int verbosity, struct got_repository *repo)
1975 f21ec2f0 2020-03-21 stsp {
1976 f21ec2f0 2020-03-21 stsp const struct got_error *err = NULL;
1977 3789fd73 2020-03-26 stsp struct got_object_id *id = NULL;
1978 3789fd73 2020-03-26 stsp char *id_str = NULL;
1979 3789fd73 2020-03-26 stsp
1980 3789fd73 2020-03-26 stsp if (got_ref_is_symbolic(ref)) {
1981 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1982 3789fd73 2020-03-26 stsp if (err)
1983 3789fd73 2020-03-26 stsp return err;
1984 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
1985 f9d54ee6 2021-07-16 stsp printf("Deleted %s: %s\n",
1986 3789fd73 2020-03-26 stsp got_ref_get_name(ref),
1987 3789fd73 2020-03-26 stsp got_ref_get_symref_target(ref));
1988 3789fd73 2020-03-26 stsp }
1989 3789fd73 2020-03-26 stsp } else {
1990 3789fd73 2020-03-26 stsp err = got_ref_resolve(&id, repo, ref);
1991 3789fd73 2020-03-26 stsp if (err)
1992 3789fd73 2020-03-26 stsp return err;
1993 3789fd73 2020-03-26 stsp err = got_object_id_str(&id_str, id);
1994 3789fd73 2020-03-26 stsp if (err)
1995 3789fd73 2020-03-26 stsp goto done;
1996 3168e5da 2020-09-10 stsp
1997 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1998 3789fd73 2020-03-26 stsp if (err)
1999 3789fd73 2020-03-26 stsp goto done;
2000 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
2001 f9d54ee6 2021-07-16 stsp printf("Deleted %s: %s\n",
2002 3789fd73 2020-03-26 stsp got_ref_get_name(ref), id_str);
2003 3789fd73 2020-03-26 stsp }
2004 3789fd73 2020-03-26 stsp }
2005 3789fd73 2020-03-26 stsp done:
2006 3789fd73 2020-03-26 stsp free(id);
2007 3789fd73 2020-03-26 stsp free(id_str);
2008 3789fd73 2020-03-26 stsp return NULL;
2009 3789fd73 2020-03-26 stsp }
2010 3789fd73 2020-03-26 stsp
2011 3789fd73 2020-03-26 stsp static const struct got_error *
2012 3789fd73 2020-03-26 stsp delete_missing_refs(struct got_pathlist_head *their_refs,
2013 50b0790e 2020-09-11 stsp struct got_pathlist_head *their_symrefs,
2014 50b0790e 2020-09-11 stsp const struct got_remote_repo *remote,
2015 3789fd73 2020-03-26 stsp int verbosity, struct got_repository *repo)
2016 3789fd73 2020-03-26 stsp {
2017 3789fd73 2020-03-26 stsp const struct got_error *err = NULL, *unlock_err;
2018 f21ec2f0 2020-03-21 stsp struct got_reflist_head my_refs;
2019 f21ec2f0 2020-03-21 stsp struct got_reflist_entry *re;
2020 f21ec2f0 2020-03-21 stsp struct got_pathlist_entry *pe;
2021 3789fd73 2020-03-26 stsp char *remote_namespace = NULL;
2022 3789fd73 2020-03-26 stsp char *local_refname = NULL;
2023 f21ec2f0 2020-03-21 stsp
2024 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&my_refs);
2025 f21ec2f0 2020-03-21 stsp
2026 3789fd73 2020-03-26 stsp if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
2027 3789fd73 2020-03-26 stsp == -1)
2028 3789fd73 2020-03-26 stsp return got_error_from_errno("asprintf");
2029 3789fd73 2020-03-26 stsp
2030 f21ec2f0 2020-03-21 stsp err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
2031 f21ec2f0 2020-03-21 stsp if (err)
2032 3789fd73 2020-03-26 stsp goto done;
2033 f21ec2f0 2020-03-21 stsp
2034 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &my_refs, entry) {
2035 f21ec2f0 2020-03-21 stsp const char *refname = got_ref_get_name(re->ref);
2036 1b796c3f 2021-09-11 stsp const char *their_refname;
2037 f21ec2f0 2020-03-21 stsp
2038 1b796c3f 2021-09-11 stsp if (remote->mirror_references) {
2039 1b796c3f 2021-09-11 stsp their_refname = refname;
2040 1b796c3f 2021-09-11 stsp } else {
2041 3789fd73 2020-03-26 stsp if (strncmp(refname, remote_namespace,
2042 3789fd73 2020-03-26 stsp strlen(remote_namespace)) == 0) {
2043 3789fd73 2020-03-26 stsp if (strcmp(refname + strlen(remote_namespace),
2044 3789fd73 2020-03-26 stsp GOT_REF_HEAD) == 0)
2045 3789fd73 2020-03-26 stsp continue;
2046 3789fd73 2020-03-26 stsp if (asprintf(&local_refname, "refs/heads/%s",
2047 3789fd73 2020-03-26 stsp refname + strlen(remote_namespace)) == -1) {
2048 3789fd73 2020-03-26 stsp err = got_error_from_errno("asprintf");
2049 3789fd73 2020-03-26 stsp goto done;
2050 3789fd73 2020-03-26 stsp }
2051 3789fd73 2020-03-26 stsp } else if (strncmp(refname, "refs/tags/", 10) != 0)
2052 3789fd73 2020-03-26 stsp continue;
2053 f21ec2f0 2020-03-21 stsp
2054 1b796c3f 2021-09-11 stsp their_refname = local_refname;
2055 1b796c3f 2021-09-11 stsp }
2056 1b796c3f 2021-09-11 stsp
2057 f21ec2f0 2020-03-21 stsp TAILQ_FOREACH(pe, their_refs, entry) {
2058 1b796c3f 2021-09-11 stsp if (strcmp(their_refname, pe->path) == 0)
2059 f21ec2f0 2020-03-21 stsp break;
2060 f21ec2f0 2020-03-21 stsp }
2061 f21ec2f0 2020-03-21 stsp if (pe != NULL)
2062 f21ec2f0 2020-03-21 stsp continue;
2063 f21ec2f0 2020-03-21 stsp
2064 3789fd73 2020-03-26 stsp TAILQ_FOREACH(pe, their_symrefs, entry) {
2065 1b796c3f 2021-09-11 stsp if (strcmp(their_refname, pe->path) == 0)
2066 3789fd73 2020-03-26 stsp break;
2067 3789fd73 2020-03-26 stsp }
2068 3789fd73 2020-03-26 stsp if (pe != NULL)
2069 3789fd73 2020-03-26 stsp continue;
2070 f21ec2f0 2020-03-21 stsp
2071 3789fd73 2020-03-26 stsp err = delete_missing_ref(re->ref, verbosity, repo);
2072 f21ec2f0 2020-03-21 stsp if (err)
2073 f21ec2f0 2020-03-21 stsp break;
2074 3789fd73 2020-03-26 stsp
2075 3789fd73 2020-03-26 stsp if (local_refname) {
2076 3789fd73 2020-03-26 stsp struct got_reference *ref;
2077 3789fd73 2020-03-26 stsp err = got_ref_open(&ref, repo, local_refname, 1);
2078 3789fd73 2020-03-26 stsp if (err) {
2079 3789fd73 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
2080 3789fd73 2020-03-26 stsp break;
2081 3789fd73 2020-03-26 stsp free(local_refname);
2082 3789fd73 2020-03-26 stsp local_refname = NULL;
2083 3789fd73 2020-03-26 stsp continue;
2084 3789fd73 2020-03-26 stsp }
2085 3789fd73 2020-03-26 stsp err = delete_missing_ref(ref, verbosity, repo);
2086 3789fd73 2020-03-26 stsp if (err)
2087 3789fd73 2020-03-26 stsp break;
2088 3789fd73 2020-03-26 stsp unlock_err = got_ref_unlock(ref);
2089 3789fd73 2020-03-26 stsp got_ref_close(ref);
2090 3789fd73 2020-03-26 stsp if (unlock_err && err == NULL) {
2091 3789fd73 2020-03-26 stsp err = unlock_err;
2092 3789fd73 2020-03-26 stsp break;
2093 3789fd73 2020-03-26 stsp }
2094 3789fd73 2020-03-26 stsp
2095 3789fd73 2020-03-26 stsp free(local_refname);
2096 3789fd73 2020-03-26 stsp local_refname = NULL;
2097 6338a6a1 2020-03-21 stsp }
2098 f21ec2f0 2020-03-21 stsp }
2099 3789fd73 2020-03-26 stsp done:
2100 3789fd73 2020-03-26 stsp free(remote_namespace);
2101 3789fd73 2020-03-26 stsp free(local_refname);
2102 0e4002ca 2020-03-21 stsp return err;
2103 0e4002ca 2020-03-21 stsp }
2104 0e4002ca 2020-03-21 stsp
2105 0e4002ca 2020-03-21 stsp static const struct got_error *
2106 0e4002ca 2020-03-21 stsp update_wanted_ref(const char *refname, struct got_object_id *id,
2107 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
2108 0e4002ca 2020-03-21 stsp {
2109 9f142382 2020-03-21 stsp const struct got_error *err, *unlock_err;
2110 0e4002ca 2020-03-21 stsp char *remote_refname;
2111 0e4002ca 2020-03-21 stsp struct got_reference *ref;
2112 0e4002ca 2020-03-21 stsp
2113 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
2114 0e4002ca 2020-03-21 stsp refname += 5;
2115 0e4002ca 2020-03-21 stsp
2116 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2117 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
2118 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
2119 f21ec2f0 2020-03-21 stsp
2120 9f142382 2020-03-21 stsp err = got_ref_open(&ref, repo, remote_refname, 1);
2121 0e4002ca 2020-03-21 stsp if (err) {
2122 0e4002ca 2020-03-21 stsp if (err->code != GOT_ERR_NOT_REF)
2123 0e4002ca 2020-03-21 stsp goto done;
2124 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
2125 0e4002ca 2020-03-21 stsp } else {
2126 0e4002ca 2020-03-21 stsp err = update_ref(ref, id, 0, verbosity, repo);
2127 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2128 9f142382 2020-03-21 stsp if (unlock_err && err == NULL)
2129 9f142382 2020-03-21 stsp err = unlock_err;
2130 0e4002ca 2020-03-21 stsp got_ref_close(ref);
2131 0e4002ca 2020-03-21 stsp }
2132 0e4002ca 2020-03-21 stsp done:
2133 0e4002ca 2020-03-21 stsp free(remote_refname);
2134 161728eb 2021-07-24 stsp return err;
2135 161728eb 2021-07-24 stsp }
2136 161728eb 2021-07-24 stsp
2137 161728eb 2021-07-24 stsp static const struct got_error *
2138 161728eb 2021-07-24 stsp delete_ref(struct got_repository *repo, struct got_reference *ref)
2139 161728eb 2021-07-24 stsp {
2140 161728eb 2021-07-24 stsp const struct got_error *err = NULL;
2141 161728eb 2021-07-24 stsp struct got_object_id *id = NULL;
2142 161728eb 2021-07-24 stsp char *id_str = NULL;
2143 161728eb 2021-07-24 stsp const char *target;
2144 161728eb 2021-07-24 stsp
2145 161728eb 2021-07-24 stsp if (got_ref_is_symbolic(ref)) {
2146 161728eb 2021-07-24 stsp target = got_ref_get_symref_target(ref);
2147 161728eb 2021-07-24 stsp } else {
2148 161728eb 2021-07-24 stsp err = got_ref_resolve(&id, repo, ref);
2149 161728eb 2021-07-24 stsp if (err)
2150 161728eb 2021-07-24 stsp goto done;
2151 161728eb 2021-07-24 stsp err = got_object_id_str(&id_str, id);
2152 161728eb 2021-07-24 stsp if (err)
2153 161728eb 2021-07-24 stsp goto done;
2154 161728eb 2021-07-24 stsp target = id_str;
2155 161728eb 2021-07-24 stsp }
2156 161728eb 2021-07-24 stsp
2157 161728eb 2021-07-24 stsp err = got_ref_delete(ref, repo);
2158 161728eb 2021-07-24 stsp if (err)
2159 161728eb 2021-07-24 stsp goto done;
2160 161728eb 2021-07-24 stsp
2161 161728eb 2021-07-24 stsp printf("Deleted %s: %s\n", got_ref_get_name(ref), target);
2162 161728eb 2021-07-24 stsp done:
2163 161728eb 2021-07-24 stsp free(id);
2164 161728eb 2021-07-24 stsp free(id_str);
2165 f21ec2f0 2020-03-21 stsp return err;
2166 f21ec2f0 2020-03-21 stsp }
2167 f21ec2f0 2020-03-21 stsp
2168 f21ec2f0 2020-03-21 stsp static const struct got_error *
2169 161728eb 2021-07-24 stsp delete_refs_for_remote(struct got_repository *repo, const char *remote_name)
2170 161728eb 2021-07-24 stsp {
2171 161728eb 2021-07-24 stsp const struct got_error *err = NULL;
2172 161728eb 2021-07-24 stsp struct got_reflist_head refs;
2173 161728eb 2021-07-24 stsp struct got_reflist_entry *re;
2174 161728eb 2021-07-24 stsp char *prefix;
2175 161728eb 2021-07-24 stsp
2176 161728eb 2021-07-24 stsp TAILQ_INIT(&refs);
2177 161728eb 2021-07-24 stsp
2178 161728eb 2021-07-24 stsp if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) {
2179 161728eb 2021-07-24 stsp err = got_error_from_errno("asprintf");
2180 161728eb 2021-07-24 stsp goto done;
2181 161728eb 2021-07-24 stsp }
2182 161728eb 2021-07-24 stsp err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL);
2183 161728eb 2021-07-24 stsp if (err)
2184 161728eb 2021-07-24 stsp goto done;
2185 161728eb 2021-07-24 stsp
2186 161728eb 2021-07-24 stsp TAILQ_FOREACH(re, &refs, entry)
2187 161728eb 2021-07-24 stsp delete_ref(repo, re->ref);
2188 161728eb 2021-07-24 stsp done:
2189 161728eb 2021-07-24 stsp got_ref_list_free(&refs);
2190 161728eb 2021-07-24 stsp return err;
2191 161728eb 2021-07-24 stsp }
2192 161728eb 2021-07-24 stsp
2193 161728eb 2021-07-24 stsp static const struct got_error *
2194 7848a0e1 2020-03-19 stsp cmd_fetch(int argc, char *argv[])
2195 7848a0e1 2020-03-19 stsp {
2196 9f142382 2020-03-21 stsp const struct got_error *error = NULL, *unlock_err;
2197 7848a0e1 2020-03-19 stsp char *cwd = NULL, *repo_path = NULL;
2198 7848a0e1 2020-03-19 stsp const char *remote_name;
2199 7848a0e1 2020-03-19 stsp char *proto = NULL, *host = NULL, *port = NULL;
2200 7848a0e1 2020-03-19 stsp char *repo_name = NULL, *server_path = NULL;
2201 50b0790e 2020-09-11 stsp const struct got_remote_repo *remotes, *remote = NULL;
2202 7848a0e1 2020-03-19 stsp int nremotes;
2203 7848a0e1 2020-03-19 stsp char *id_str = NULL;
2204 7848a0e1 2020-03-19 stsp struct got_repository *repo = NULL;
2205 7848a0e1 2020-03-19 stsp struct got_worktree *worktree = NULL;
2206 50b0790e 2020-09-11 stsp const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
2207 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
2208 7848a0e1 2020-03-19 stsp struct got_pathlist_entry *pe;
2209 7848a0e1 2020-03-19 stsp struct got_object_id *pack_hash = NULL;
2210 9c52365f 2020-03-21 stsp int i, ch, fetchfd = -1, fetchstatus;
2211 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
2212 7848a0e1 2020-03-19 stsp struct got_fetch_progress_arg fpa;
2213 41b0de12 2020-03-21 stsp int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
2214 161728eb 2021-07-24 stsp int delete_refs = 0, replace_tags = 0, delete_remote = 0;
2215 7848a0e1 2020-03-19 stsp
2216 7848a0e1 2020-03-19 stsp TAILQ_INIT(&refs);
2217 7848a0e1 2020-03-19 stsp TAILQ_INIT(&symrefs);
2218 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
2219 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
2220 7848a0e1 2020-03-19 stsp
2221 161728eb 2021-07-24 stsp while ((ch = getopt(argc, argv, "ab:dlr:tvqR:X")) != -1) {
2222 7848a0e1 2020-03-19 stsp switch (ch) {
2223 659e7fbd 2020-03-20 stsp case 'a':
2224 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
2225 4ba14133 2020-03-20 stsp break;
2226 4ba14133 2020-03-20 stsp case 'b':
2227 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
2228 4ba14133 2020-03-20 stsp optarg, NULL);
2229 4ba14133 2020-03-20 stsp if (error)
2230 4ba14133 2020-03-20 stsp return error;
2231 41b0de12 2020-03-21 stsp break;
2232 f21ec2f0 2020-03-21 stsp case 'd':
2233 f21ec2f0 2020-03-21 stsp delete_refs = 1;
2234 f21ec2f0 2020-03-21 stsp break;
2235 41b0de12 2020-03-21 stsp case 'l':
2236 41b0de12 2020-03-21 stsp list_refs_only = 1;
2237 659e7fbd 2020-03-20 stsp break;
2238 7848a0e1 2020-03-19 stsp case 'r':
2239 7848a0e1 2020-03-19 stsp repo_path = realpath(optarg, NULL);
2240 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
2241 7848a0e1 2020-03-19 stsp return got_error_from_errno2("realpath",
2242 7848a0e1 2020-03-19 stsp optarg);
2243 7848a0e1 2020-03-19 stsp got_path_strip_trailing_slashes(repo_path);
2244 7848a0e1 2020-03-19 stsp break;
2245 db6d8ad8 2020-03-21 stsp case 't':
2246 db6d8ad8 2020-03-21 stsp replace_tags = 1;
2247 db6d8ad8 2020-03-21 stsp break;
2248 7848a0e1 2020-03-19 stsp case 'v':
2249 7848a0e1 2020-03-19 stsp if (verbosity < 0)
2250 7848a0e1 2020-03-19 stsp verbosity = 0;
2251 7848a0e1 2020-03-19 stsp else if (verbosity < 3)
2252 7848a0e1 2020-03-19 stsp verbosity++;
2253 7848a0e1 2020-03-19 stsp break;
2254 7848a0e1 2020-03-19 stsp case 'q':
2255 7848a0e1 2020-03-19 stsp verbosity = -1;
2256 7848a0e1 2020-03-19 stsp break;
2257 0e4002ca 2020-03-21 stsp case 'R':
2258 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
2259 0e4002ca 2020-03-21 stsp optarg, NULL);
2260 0e4002ca 2020-03-21 stsp if (error)
2261 0e4002ca 2020-03-21 stsp return error;
2262 0e4002ca 2020-03-21 stsp break;
2263 161728eb 2021-07-24 stsp case 'X':
2264 161728eb 2021-07-24 stsp delete_remote = 1;
2265 161728eb 2021-07-24 stsp break;
2266 7848a0e1 2020-03-19 stsp default:
2267 7848a0e1 2020-03-19 stsp usage_fetch();
2268 7848a0e1 2020-03-19 stsp break;
2269 7848a0e1 2020-03-19 stsp }
2270 7848a0e1 2020-03-19 stsp }
2271 7848a0e1 2020-03-19 stsp argc -= optind;
2272 7848a0e1 2020-03-19 stsp argv += optind;
2273 7848a0e1 2020-03-19 stsp
2274 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
2275 ff69268e 2020-12-13 stsp option_conflict('a', 'b');
2276 41b0de12 2020-03-21 stsp if (list_refs_only) {
2277 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
2278 ff69268e 2020-12-13 stsp option_conflict('l', 'b');
2279 ff69268e 2020-12-13 stsp if (fetch_all_branches)
2280 ff69268e 2020-12-13 stsp option_conflict('l', 'a');
2281 f21ec2f0 2020-03-21 stsp if (delete_refs)
2282 ff69268e 2020-12-13 stsp option_conflict('l', 'd');
2283 161728eb 2021-07-24 stsp if (delete_remote)
2284 161728eb 2021-07-24 stsp option_conflict('l', 'X');
2285 41b0de12 2020-03-21 stsp }
2286 161728eb 2021-07-24 stsp if (delete_remote) {
2287 161728eb 2021-07-24 stsp if (fetch_all_branches)
2288 161728eb 2021-07-24 stsp option_conflict('X', 'a');
2289 161728eb 2021-07-24 stsp if (!TAILQ_EMPTY(&wanted_branches))
2290 161728eb 2021-07-24 stsp option_conflict('X', 'b');
2291 161728eb 2021-07-24 stsp if (delete_refs)
2292 161728eb 2021-07-24 stsp option_conflict('X', 'd');
2293 161728eb 2021-07-24 stsp if (replace_tags)
2294 161728eb 2021-07-24 stsp option_conflict('X', 't');
2295 161728eb 2021-07-24 stsp if (!TAILQ_EMPTY(&wanted_refs))
2296 161728eb 2021-07-24 stsp option_conflict('X', 'R');
2297 161728eb 2021-07-24 stsp }
2298 161728eb 2021-07-24 stsp
2299 161728eb 2021-07-24 stsp if (argc == 0) {
2300 161728eb 2021-07-24 stsp if (delete_remote)
2301 161728eb 2021-07-24 stsp errx(1, "-X option requires a remote name");
2302 7848a0e1 2020-03-19 stsp remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
2303 161728eb 2021-07-24 stsp } else if (argc == 1)
2304 7848a0e1 2020-03-19 stsp remote_name = argv[0];
2305 7848a0e1 2020-03-19 stsp else
2306 7848a0e1 2020-03-19 stsp usage_fetch();
2307 7848a0e1 2020-03-19 stsp
2308 7848a0e1 2020-03-19 stsp cwd = getcwd(NULL, 0);
2309 7848a0e1 2020-03-19 stsp if (cwd == NULL) {
2310 7848a0e1 2020-03-19 stsp error = got_error_from_errno("getcwd");
2311 7848a0e1 2020-03-19 stsp goto done;
2312 7848a0e1 2020-03-19 stsp }
2313 7848a0e1 2020-03-19 stsp
2314 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
2315 7848a0e1 2020-03-19 stsp error = got_worktree_open(&worktree, cwd);
2316 7848a0e1 2020-03-19 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
2317 7848a0e1 2020-03-19 stsp goto done;
2318 7848a0e1 2020-03-19 stsp else
2319 7848a0e1 2020-03-19 stsp error = NULL;
2320 7848a0e1 2020-03-19 stsp if (worktree) {
2321 7848a0e1 2020-03-19 stsp repo_path =
2322 7848a0e1 2020-03-19 stsp strdup(got_worktree_get_repo_path(worktree));
2323 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
2324 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
2325 7848a0e1 2020-03-19 stsp if (error)
2326 7848a0e1 2020-03-19 stsp goto done;
2327 7848a0e1 2020-03-19 stsp } else {
2328 7848a0e1 2020-03-19 stsp repo_path = strdup(cwd);
2329 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
2330 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
2331 7848a0e1 2020-03-19 stsp goto done;
2332 7848a0e1 2020-03-19 stsp }
2333 7848a0e1 2020-03-19 stsp }
2334 7848a0e1 2020-03-19 stsp }
2335 7848a0e1 2020-03-19 stsp
2336 7848a0e1 2020-03-19 stsp error = got_repo_open(&repo, repo_path, NULL);
2337 7848a0e1 2020-03-19 stsp if (error)
2338 7848a0e1 2020-03-19 stsp goto done;
2339 7848a0e1 2020-03-19 stsp
2340 161728eb 2021-07-24 stsp if (delete_remote) {
2341 161728eb 2021-07-24 stsp error = delete_refs_for_remote(repo, remote_name);
2342 161728eb 2021-07-24 stsp goto done; /* nothing else to do */
2343 161728eb 2021-07-24 stsp }
2344 161728eb 2021-07-24 stsp
2345 50b0790e 2020-09-11 stsp if (worktree) {
2346 50b0790e 2020-09-11 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
2347 50b0790e 2020-09-11 stsp if (worktree_conf) {
2348 50b0790e 2020-09-11 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
2349 50b0790e 2020-09-11 stsp worktree_conf);
2350 50b0790e 2020-09-11 stsp for (i = 0; i < nremotes; i++) {
2351 54eb00d5 2020-10-20 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
2352 54eb00d5 2020-10-20 stsp remote = &remotes[i];
2353 50b0790e 2020-09-11 stsp break;
2354 54eb00d5 2020-10-20 stsp }
2355 50b0790e 2020-09-11 stsp }
2356 50b0790e 2020-09-11 stsp }
2357 7848a0e1 2020-03-19 stsp }
2358 50b0790e 2020-09-11 stsp if (remote == NULL) {
2359 50b0790e 2020-09-11 stsp repo_conf = got_repo_get_gotconfig(repo);
2360 50b0790e 2020-09-11 stsp if (repo_conf) {
2361 50b0790e 2020-09-11 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
2362 50b0790e 2020-09-11 stsp repo_conf);
2363 50b0790e 2020-09-11 stsp for (i = 0; i < nremotes; i++) {
2364 54eb00d5 2020-10-20 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
2365 54eb00d5 2020-10-20 stsp remote = &remotes[i];
2366 50b0790e 2020-09-11 stsp break;
2367 54eb00d5 2020-10-20 stsp }
2368 50b0790e 2020-09-11 stsp }
2369 50b0790e 2020-09-11 stsp }
2370 50b0790e 2020-09-11 stsp }
2371 50b0790e 2020-09-11 stsp if (remote == NULL) {
2372 257add31 2020-09-09 stsp got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
2373 257add31 2020-09-09 stsp for (i = 0; i < nremotes; i++) {
2374 54eb00d5 2020-10-20 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
2375 54eb00d5 2020-10-20 stsp remote = &remotes[i];
2376 257add31 2020-09-09 stsp break;
2377 54eb00d5 2020-10-20 stsp }
2378 257add31 2020-09-09 stsp }
2379 7848a0e1 2020-03-19 stsp }
2380 50b0790e 2020-09-11 stsp if (remote == NULL) {
2381 50b0790e 2020-09-11 stsp error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
2382 50b0790e 2020-09-11 stsp goto done;
2383 b8adfa55 2020-09-25 stsp }
2384 b8adfa55 2020-09-25 stsp
2385 0c8b29c5 2021-01-05 stsp if (TAILQ_EMPTY(&wanted_branches)) {
2386 0c8b29c5 2021-01-05 stsp if (!fetch_all_branches)
2387 0c8b29c5 2021-01-05 stsp fetch_all_branches = remote->fetch_all_branches;
2388 6480c871 2021-08-30 stsp for (i = 0; i < remote->nfetch_branches; i++) {
2389 b8adfa55 2020-09-25 stsp got_pathlist_append(&wanted_branches,
2390 6480c871 2021-08-30 stsp remote->fetch_branches[i], NULL);
2391 99495ddb 2021-01-10 stsp }
2392 99495ddb 2021-01-10 stsp }
2393 99495ddb 2021-01-10 stsp if (TAILQ_EMPTY(&wanted_refs)) {
2394 6480c871 2021-08-30 stsp for (i = 0; i < remote->nfetch_refs; i++) {
2395 99495ddb 2021-01-10 stsp got_pathlist_append(&wanted_refs,
2396 6480c871 2021-08-30 stsp remote->fetch_refs[i], NULL);
2397 b8adfa55 2020-09-25 stsp }
2398 50b0790e 2020-09-11 stsp }
2399 7848a0e1 2020-03-19 stsp
2400 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
2401 6480c871 2021-08-30 stsp &repo_name, remote->fetch_url);
2402 7848a0e1 2020-03-19 stsp if (error)
2403 7848a0e1 2020-03-19 stsp goto done;
2404 7848a0e1 2020-03-19 stsp
2405 7848a0e1 2020-03-19 stsp if (strcmp(proto, "git") == 0) {
2406 7848a0e1 2020-03-19 stsp #ifndef PROFILE
2407 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2408 7848a0e1 2020-03-19 stsp "sendfd dns inet unveil", NULL) == -1)
2409 7848a0e1 2020-03-19 stsp err(1, "pledge");
2410 7848a0e1 2020-03-19 stsp #endif
2411 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
2412 7848a0e1 2020-03-19 stsp strcmp(proto, "ssh") == 0) {
2413 7848a0e1 2020-03-19 stsp #ifndef PROFILE
2414 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2415 7848a0e1 2020-03-19 stsp "sendfd unveil", NULL) == -1)
2416 7848a0e1 2020-03-19 stsp err(1, "pledge");
2417 7848a0e1 2020-03-19 stsp #endif
2418 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "http") == 0 ||
2419 7848a0e1 2020-03-19 stsp strcmp(proto, "git+http") == 0) {
2420 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
2421 7848a0e1 2020-03-19 stsp goto done;
2422 7848a0e1 2020-03-19 stsp } else {
2423 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
2424 7848a0e1 2020-03-19 stsp goto done;
2425 7848a0e1 2020-03-19 stsp }
2426 7848a0e1 2020-03-19 stsp
2427 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
2428 d65a88a2 2021-09-05 stsp if (error)
2429 d65a88a2 2021-09-05 stsp goto done;
2430 d65a88a2 2021-09-05 stsp
2431 7848a0e1 2020-03-19 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
2432 7848a0e1 2020-03-19 stsp if (error)
2433 7848a0e1 2020-03-19 stsp goto done;
2434 f79e6490 2020-04-19 stsp
2435 f79e6490 2020-04-19 stsp if (verbosity >= 0)
2436 f79e6490 2020-04-19 stsp printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
2437 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
2438 7848a0e1 2020-03-19 stsp
2439 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
2440 9c52365f 2020-03-21 stsp server_path, verbosity);
2441 7848a0e1 2020-03-19 stsp if (error)
2442 7848a0e1 2020-03-19 stsp goto done;
2443 7848a0e1 2020-03-19 stsp
2444 7848a0e1 2020-03-19 stsp fpa.last_scaled_size[0] = '\0';
2445 7848a0e1 2020-03-19 stsp fpa.last_p_indexed = -1;
2446 7848a0e1 2020-03-19 stsp fpa.last_p_resolved = -1;
2447 7848a0e1 2020-03-19 stsp fpa.verbosity = verbosity;
2448 04d9a9ec 2020-09-24 stsp fpa.repo = repo;
2449 04d9a9ec 2020-09-24 stsp fpa.create_configs = 0;
2450 04d9a9ec 2020-09-24 stsp fpa.configs_created = 0;
2451 04d9a9ec 2020-09-24 stsp memset(&fpa.config_info, 0, sizeof(fpa.config_info));
2452 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
2453 4ba14133 2020-03-20 stsp remote->mirror_references, fetch_all_branches, &wanted_branches,
2454 0e4002ca 2020-03-21 stsp &wanted_refs, list_refs_only, verbosity, fetchfd, repo,
2455 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
2456 7848a0e1 2020-03-19 stsp if (error)
2457 7848a0e1 2020-03-19 stsp goto done;
2458 7848a0e1 2020-03-19 stsp
2459 41b0de12 2020-03-21 stsp if (list_refs_only) {
2460 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
2461 41b0de12 2020-03-21 stsp goto done;
2462 41b0de12 2020-03-21 stsp }
2463 41b0de12 2020-03-21 stsp
2464 7848a0e1 2020-03-19 stsp if (pack_hash == NULL) {
2465 7848a0e1 2020-03-19 stsp if (verbosity >= 0)
2466 7848a0e1 2020-03-19 stsp printf("Already up-to-date\n");
2467 bcf34b0e 2020-03-26 stsp } else if (verbosity >= 0) {
2468 984065c8 2020-03-19 stsp error = got_object_id_str(&id_str, pack_hash);
2469 984065c8 2020-03-19 stsp if (error)
2470 984065c8 2020-03-19 stsp goto done;
2471 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
2472 984065c8 2020-03-19 stsp free(id_str);
2473 984065c8 2020-03-19 stsp id_str = NULL;
2474 984065c8 2020-03-19 stsp }
2475 7848a0e1 2020-03-19 stsp
2476 7848a0e1 2020-03-19 stsp /* Update references provided with the pack file. */
2477 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
2478 7848a0e1 2020-03-19 stsp const char *refname = pe->path;
2479 7848a0e1 2020-03-19 stsp struct got_object_id *id = pe->data;
2480 7848a0e1 2020-03-19 stsp struct got_reference *ref;
2481 7848a0e1 2020-03-19 stsp char *remote_refname;
2482 7848a0e1 2020-03-19 stsp
2483 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
2484 0e4002ca 2020-03-21 stsp !remote->mirror_references) {
2485 0e4002ca 2020-03-21 stsp error = update_wanted_ref(refname, id,
2486 0e4002ca 2020-03-21 stsp remote->name, verbosity, repo);
2487 0e4002ca 2020-03-21 stsp if (error)
2488 0e4002ca 2020-03-21 stsp goto done;
2489 0e4002ca 2020-03-21 stsp continue;
2490 0e4002ca 2020-03-21 stsp }
2491 0e4002ca 2020-03-21 stsp
2492 1510c839 2020-03-20 stsp if (remote->mirror_references ||
2493 1510c839 2020-03-20 stsp strncmp("refs/tags/", refname, 10) == 0) {
2494 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
2495 7848a0e1 2020-03-19 stsp if (error) {
2496 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
2497 7848a0e1 2020-03-19 stsp goto done;
2498 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
2499 6338a6a1 2020-03-21 stsp repo);
2500 7848a0e1 2020-03-19 stsp if (error)
2501 7848a0e1 2020-03-19 stsp goto done;
2502 7848a0e1 2020-03-19 stsp } else {
2503 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
2504 db6d8ad8 2020-03-21 stsp verbosity, repo);
2505 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2506 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2507 9f142382 2020-03-21 stsp error = unlock_err;
2508 7848a0e1 2020-03-19 stsp got_ref_close(ref);
2509 7848a0e1 2020-03-19 stsp if (error)
2510 7848a0e1 2020-03-19 stsp goto done;
2511 7848a0e1 2020-03-19 stsp }
2512 7848a0e1 2020-03-19 stsp } else if (strncmp("refs/heads/", refname, 11) == 0) {
2513 7848a0e1 2020-03-19 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2514 7848a0e1 2020-03-19 stsp remote_name, refname + 11) == -1) {
2515 7848a0e1 2020-03-19 stsp error = got_error_from_errno("asprintf");
2516 7848a0e1 2020-03-19 stsp goto done;
2517 7848a0e1 2020-03-19 stsp }
2518 7848a0e1 2020-03-19 stsp
2519 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, remote_refname, 1);
2520 7848a0e1 2020-03-19 stsp if (error) {
2521 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
2522 7848a0e1 2020-03-19 stsp goto done;
2523 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id,
2524 688f11b3 2020-03-21 stsp verbosity, repo);
2525 7848a0e1 2020-03-19 stsp if (error)
2526 7848a0e1 2020-03-19 stsp goto done;
2527 7848a0e1 2020-03-19 stsp } else {
2528 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
2529 db6d8ad8 2020-03-21 stsp verbosity, repo);
2530 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2531 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2532 9f142382 2020-03-21 stsp error = unlock_err;
2533 7848a0e1 2020-03-19 stsp got_ref_close(ref);
2534 7848a0e1 2020-03-19 stsp if (error)
2535 7848a0e1 2020-03-19 stsp goto done;
2536 7848a0e1 2020-03-19 stsp }
2537 2ec30c80 2020-03-20 stsp
2538 2ec30c80 2020-03-20 stsp /* Also create a local branch if none exists yet. */
2539 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
2540 2ec30c80 2020-03-20 stsp if (error) {
2541 2ec30c80 2020-03-20 stsp if (error->code != GOT_ERR_NOT_REF)
2542 2ec30c80 2020-03-20 stsp goto done;
2543 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
2544 6338a6a1 2020-03-21 stsp repo);
2545 2ec30c80 2020-03-20 stsp if (error)
2546 2ec30c80 2020-03-20 stsp goto done;
2547 9f142382 2020-03-21 stsp } else {
2548 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2549 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2550 9f142382 2020-03-21 stsp error = unlock_err;
2551 2ec30c80 2020-03-20 stsp got_ref_close(ref);
2552 9f142382 2020-03-21 stsp }
2553 7848a0e1 2020-03-19 stsp }
2554 7848a0e1 2020-03-19 stsp }
2555 f1bcca34 2020-03-25 stsp if (delete_refs) {
2556 3789fd73 2020-03-26 stsp error = delete_missing_refs(&refs, &symrefs, remote,
2557 3789fd73 2020-03-26 stsp verbosity, repo);
2558 f1bcca34 2020-03-25 stsp if (error)
2559 f1bcca34 2020-03-25 stsp goto done;
2560 f1bcca34 2020-03-25 stsp }
2561 f1bcca34 2020-03-25 stsp
2562 f1bcca34 2020-03-25 stsp if (!remote->mirror_references) {
2563 f1bcca34 2020-03-25 stsp /* Update remote HEAD reference if the server provided one. */
2564 f1bcca34 2020-03-25 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2565 f1bcca34 2020-03-25 stsp struct got_reference *target_ref;
2566 f1bcca34 2020-03-25 stsp const char *refname = pe->path;
2567 f1bcca34 2020-03-25 stsp const char *target = pe->data;
2568 f1bcca34 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
2569 f1bcca34 2020-03-25 stsp
2570 f1bcca34 2020-03-25 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
2571 f1bcca34 2020-03-25 stsp continue;
2572 f1bcca34 2020-03-25 stsp
2573 f1bcca34 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
2574 f1bcca34 2020-03-25 stsp continue;
2575 f1bcca34 2020-03-25 stsp
2576 f1bcca34 2020-03-25 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2577 f1bcca34 2020-03-25 stsp remote->name, refname) == -1) {
2578 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2579 f1bcca34 2020-03-25 stsp goto done;
2580 f1bcca34 2020-03-25 stsp }
2581 f1bcca34 2020-03-25 stsp if (asprintf(&remote_target, "refs/remotes/%s/%s",
2582 f1bcca34 2020-03-25 stsp remote->name, target + 11) == -1) {
2583 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2584 f1bcca34 2020-03-25 stsp free(remote_refname);
2585 f1bcca34 2020-03-25 stsp goto done;
2586 f1bcca34 2020-03-25 stsp }
2587 f1bcca34 2020-03-25 stsp
2588 f1bcca34 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target,
2589 f1bcca34 2020-03-25 stsp 0);
2590 f1bcca34 2020-03-25 stsp if (error) {
2591 f1bcca34 2020-03-25 stsp free(remote_refname);
2592 f1bcca34 2020-03-25 stsp free(remote_target);
2593 f1bcca34 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
2594 f1bcca34 2020-03-25 stsp error = NULL;
2595 f1bcca34 2020-03-25 stsp continue;
2596 f1bcca34 2020-03-25 stsp }
2597 f1bcca34 2020-03-25 stsp goto done;
2598 f1bcca34 2020-03-25 stsp }
2599 f1bcca34 2020-03-25 stsp error = update_symref(remote_refname, target_ref,
2600 f1bcca34 2020-03-25 stsp verbosity, repo);
2601 f1bcca34 2020-03-25 stsp free(remote_refname);
2602 f1bcca34 2020-03-25 stsp free(remote_target);
2603 f1bcca34 2020-03-25 stsp got_ref_close(target_ref);
2604 f1bcca34 2020-03-25 stsp if (error)
2605 f1bcca34 2020-03-25 stsp goto done;
2606 f1bcca34 2020-03-25 stsp }
2607 f1bcca34 2020-03-25 stsp }
2608 7848a0e1 2020-03-19 stsp done:
2609 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
2610 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
2611 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
2612 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
2613 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
2614 9c52365f 2020-03-21 stsp }
2615 7848a0e1 2020-03-19 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
2616 7848a0e1 2020-03-19 stsp error = got_error_from_errno("close");
2617 1d0f4054 2021-06-17 stsp if (repo) {
2618 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
2619 1d0f4054 2021-06-17 stsp if (error == NULL)
2620 1d0f4054 2021-06-17 stsp error = close_err;
2621 1d0f4054 2021-06-17 stsp }
2622 7848a0e1 2020-03-19 stsp if (worktree)
2623 7848a0e1 2020-03-19 stsp got_worktree_close(worktree);
2624 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
2625 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2626 7848a0e1 2020-03-19 stsp free(pe->data);
2627 7848a0e1 2020-03-19 stsp }
2628 7848a0e1 2020-03-19 stsp got_pathlist_free(&refs);
2629 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2630 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2631 7848a0e1 2020-03-19 stsp free(pe->data);
2632 7848a0e1 2020-03-19 stsp }
2633 7848a0e1 2020-03-19 stsp got_pathlist_free(&symrefs);
2634 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
2635 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
2636 7848a0e1 2020-03-19 stsp free(id_str);
2637 7848a0e1 2020-03-19 stsp free(cwd);
2638 7848a0e1 2020-03-19 stsp free(repo_path);
2639 7848a0e1 2020-03-19 stsp free(pack_hash);
2640 7848a0e1 2020-03-19 stsp free(proto);
2641 7848a0e1 2020-03-19 stsp free(host);
2642 7848a0e1 2020-03-19 stsp free(port);
2643 7848a0e1 2020-03-19 stsp free(server_path);
2644 7848a0e1 2020-03-19 stsp free(repo_name);
2645 7848a0e1 2020-03-19 stsp return error;
2646 7848a0e1 2020-03-19 stsp }
2647 7848a0e1 2020-03-19 stsp
2648 7848a0e1 2020-03-19 stsp
2649 7848a0e1 2020-03-19 stsp __dead static void
2650 2ab43947 2020-03-18 stsp usage_checkout(void)
2651 2ab43947 2020-03-18 stsp {
2652 2ab43947 2020-03-18 stsp fprintf(stderr, "usage: %s checkout [-E] [-b branch] [-c commit] "
2653 4ad4a1ec 2021-09-13 tracey "[-p prefix] [-q] repository-path [worktree-path]\n",
2654 4ad4a1ec 2021-09-13 tracey getprogname());
2655 2ab43947 2020-03-18 stsp exit(1);
2656 2ab43947 2020-03-18 stsp }
2657 2ab43947 2020-03-18 stsp
2658 2ab43947 2020-03-18 stsp static void
2659 2ab43947 2020-03-18 stsp show_worktree_base_ref_warning(void)
2660 2ab43947 2020-03-18 stsp {
2661 2ab43947 2020-03-18 stsp fprintf(stderr, "%s: warning: could not create a reference "
2662 2ab43947 2020-03-18 stsp "to the work tree's base commit; the commit could be "
2663 e6786710 2021-07-03 stsp "garbage-collected by Git or 'gotadmin cleanup'; making the "
2664 e6786710 2021-07-03 stsp "repository writable and running 'got update' will prevent this\n",
2665 2ab43947 2020-03-18 stsp getprogname());
2666 2ab43947 2020-03-18 stsp }
2667 2ab43947 2020-03-18 stsp
2668 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg {
2669 2ab43947 2020-03-18 stsp const char *worktree_path;
2670 2ab43947 2020-03-18 stsp int had_base_commit_ref_error;
2671 4ad4a1ec 2021-09-13 tracey int verbosity;
2672 2ab43947 2020-03-18 stsp };
2673 2ab43947 2020-03-18 stsp
2674 2ab43947 2020-03-18 stsp static const struct got_error *
2675 2ab43947 2020-03-18 stsp checkout_progress(void *arg, unsigned char status, const char *path)
2676 2ab43947 2020-03-18 stsp {
2677 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg *a = arg;
2678 2ab43947 2020-03-18 stsp
2679 2ab43947 2020-03-18 stsp /* Base commit bump happens silently. */
2680 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BUMP_BASE)
2681 2ab43947 2020-03-18 stsp return NULL;
2682 2ab43947 2020-03-18 stsp
2683 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BASE_REF_ERR) {
2684 2ab43947 2020-03-18 stsp a->had_base_commit_ref_error = 1;
2685 2ab43947 2020-03-18 stsp return NULL;
2686 2ab43947 2020-03-18 stsp }
2687 2ab43947 2020-03-18 stsp
2688 2ab43947 2020-03-18 stsp while (path[0] == '/')
2689 2ab43947 2020-03-18 stsp path++;
2690 2ab43947 2020-03-18 stsp
2691 4ad4a1ec 2021-09-13 tracey if (a->verbosity >= 0)
2692 4ad4a1ec 2021-09-13 tracey printf("%c %s/%s\n", status, a->worktree_path, path);
2693 4ad4a1ec 2021-09-13 tracey
2694 2ab43947 2020-03-18 stsp return NULL;
2695 2ab43947 2020-03-18 stsp }
2696 2ab43947 2020-03-18 stsp
2697 2ab43947 2020-03-18 stsp static const struct got_error *
2698 2ab43947 2020-03-18 stsp check_cancelled(void *arg)
2699 2ab43947 2020-03-18 stsp {
2700 2ab43947 2020-03-18 stsp if (sigint_received || sigpipe_received)
2701 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_CANCELLED);
2702 2ab43947 2020-03-18 stsp return NULL;
2703 2ab43947 2020-03-18 stsp }
2704 2ab43947 2020-03-18 stsp
2705 2ab43947 2020-03-18 stsp static const struct got_error *
2706 2ab43947 2020-03-18 stsp check_linear_ancestry(struct got_object_id *commit_id,
2707 2ab43947 2020-03-18 stsp struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2708 2ab43947 2020-03-18 stsp struct got_repository *repo)
2709 2ab43947 2020-03-18 stsp {
2710 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2711 2ab43947 2020-03-18 stsp struct got_object_id *yca_id;
2712 2ab43947 2020-03-18 stsp
2713 2ab43947 2020-03-18 stsp err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2714 4e91ef15 2021-09-26 stsp commit_id, base_commit_id, 1, repo, check_cancelled, NULL);
2715 2ab43947 2020-03-18 stsp if (err)
2716 2ab43947 2020-03-18 stsp return err;
2717 2ab43947 2020-03-18 stsp
2718 2ab43947 2020-03-18 stsp if (yca_id == NULL)
2719 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2720 2ab43947 2020-03-18 stsp
2721 2ab43947 2020-03-18 stsp /*
2722 2ab43947 2020-03-18 stsp * Require a straight line of history between the target commit
2723 2ab43947 2020-03-18 stsp * and the work tree's base commit.
2724 2ab43947 2020-03-18 stsp *
2725 2ab43947 2020-03-18 stsp * Non-linear situations such as this require a rebase:
2726 2ab43947 2020-03-18 stsp *
2727 2ab43947 2020-03-18 stsp * (commit) D F (base_commit)
2728 2ab43947 2020-03-18 stsp * \ /
2729 2ab43947 2020-03-18 stsp * C E
2730 2ab43947 2020-03-18 stsp * \ /
2731 2ab43947 2020-03-18 stsp * B (yca)
2732 2ab43947 2020-03-18 stsp * |
2733 2ab43947 2020-03-18 stsp * A
2734 2ab43947 2020-03-18 stsp *
2735 2ab43947 2020-03-18 stsp * 'got update' only handles linear cases:
2736 2ab43947 2020-03-18 stsp * Update forwards in time: A (base/yca) - B - C - D (commit)
2737 2ab43947 2020-03-18 stsp * Update backwards in time: D (base) - C - B - A (commit/yca)
2738 2ab43947 2020-03-18 stsp */
2739 2ab43947 2020-03-18 stsp if (allow_forwards_in_time_only) {
2740 2ab43947 2020-03-18 stsp if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2741 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2742 2ab43947 2020-03-18 stsp } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2743 2ab43947 2020-03-18 stsp got_object_id_cmp(base_commit_id, yca_id) != 0)
2744 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2745 2ab43947 2020-03-18 stsp
2746 2ab43947 2020-03-18 stsp free(yca_id);
2747 2ab43947 2020-03-18 stsp return NULL;
2748 2ab43947 2020-03-18 stsp }
2749 2ab43947 2020-03-18 stsp
2750 2ab43947 2020-03-18 stsp static const struct got_error *
2751 2ab43947 2020-03-18 stsp check_same_branch(struct got_object_id *commit_id,
2752 2ab43947 2020-03-18 stsp struct got_reference *head_ref, struct got_object_id *yca_id,
2753 2ab43947 2020-03-18 stsp struct got_repository *repo)
2754 2ab43947 2020-03-18 stsp {
2755 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2756 2ab43947 2020-03-18 stsp struct got_commit_graph *graph = NULL;
2757 2ab43947 2020-03-18 stsp struct got_object_id *head_commit_id = NULL;
2758 2ab43947 2020-03-18 stsp int is_same_branch = 0;
2759 2ab43947 2020-03-18 stsp
2760 2ab43947 2020-03-18 stsp err = got_ref_resolve(&head_commit_id, repo, head_ref);
2761 2ab43947 2020-03-18 stsp if (err)
2762 2ab43947 2020-03-18 stsp goto done;
2763 2ab43947 2020-03-18 stsp
2764 2ab43947 2020-03-18 stsp if (got_object_id_cmp(head_commit_id, commit_id) == 0) {
2765 2ab43947 2020-03-18 stsp is_same_branch = 1;
2766 2ab43947 2020-03-18 stsp goto done;
2767 2ab43947 2020-03-18 stsp }
2768 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(commit_id, yca_id) == 0) {
2769 2ab43947 2020-03-18 stsp is_same_branch = 1;
2770 2ab43947 2020-03-18 stsp goto done;
2771 2ab43947 2020-03-18 stsp }
2772 2ab43947 2020-03-18 stsp
2773 2ab43947 2020-03-18 stsp err = got_commit_graph_open(&graph, "/", 1);
2774 2ab43947 2020-03-18 stsp if (err)
2775 2ab43947 2020-03-18 stsp goto done;
2776 2ab43947 2020-03-18 stsp
2777 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2778 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2779 2ab43947 2020-03-18 stsp if (err)
2780 2ab43947 2020-03-18 stsp goto done;
2781 2ab43947 2020-03-18 stsp
2782 2ab43947 2020-03-18 stsp for (;;) {
2783 2ab43947 2020-03-18 stsp struct got_object_id *id;
2784 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_next(&id, graph, repo,
2785 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2786 2ab43947 2020-03-18 stsp if (err) {
2787 2ab43947 2020-03-18 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
2788 2ab43947 2020-03-18 stsp err = NULL;
2789 2ab43947 2020-03-18 stsp break;
2790 2ab43947 2020-03-18 stsp }
2791 2ab43947 2020-03-18 stsp
2792 2ab43947 2020-03-18 stsp if (id) {
2793 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(id, yca_id) == 0)
2794 2ab43947 2020-03-18 stsp break;
2795 2ab43947 2020-03-18 stsp if (got_object_id_cmp(id, commit_id) == 0) {
2796 2ab43947 2020-03-18 stsp is_same_branch = 1;
2797 2ab43947 2020-03-18 stsp break;
2798 2ab43947 2020-03-18 stsp }
2799 2ab43947 2020-03-18 stsp }
2800 2ab43947 2020-03-18 stsp }
2801 2ab43947 2020-03-18 stsp done:
2802 2ab43947 2020-03-18 stsp if (graph)
2803 2ab43947 2020-03-18 stsp got_commit_graph_close(graph);
2804 2ab43947 2020-03-18 stsp free(head_commit_id);
2805 2ab43947 2020-03-18 stsp if (!err && !is_same_branch)
2806 2ab43947 2020-03-18 stsp err = got_error(GOT_ERR_ANCESTRY);
2807 2ab43947 2020-03-18 stsp return err;
2808 a367ff0f 2019-05-14 stsp }
2809 8069f636 2019-01-12 stsp
2810 4ed7e80c 2018-05-20 stsp static const struct got_error *
2811 4b6c9460 2020-03-05 stsp checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2812 4b6c9460 2020-03-05 stsp {
2813 4b6c9460 2020-03-05 stsp static char msg[512];
2814 4b6c9460 2020-03-05 stsp const char *branch_name;
2815 4b6c9460 2020-03-05 stsp
2816 4b6c9460 2020-03-05 stsp if (got_ref_is_symbolic(ref))
2817 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_symref_target(ref);
2818 4b6c9460 2020-03-05 stsp else
2819 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_name(ref);
2820 4b6c9460 2020-03-05 stsp
2821 4b6c9460 2020-03-05 stsp if (strncmp("refs/heads/", branch_name, 11) == 0)
2822 4b6c9460 2020-03-05 stsp branch_name += 11;
2823 4b6c9460 2020-03-05 stsp
2824 4b6c9460 2020-03-05 stsp snprintf(msg, sizeof(msg),
2825 4b6c9460 2020-03-05 stsp "target commit is not contained in branch '%s'; "
2826 4b6c9460 2020-03-05 stsp "the branch to use must be specified with -b; "
2827 4b6c9460 2020-03-05 stsp "if necessary a new branch can be created for "
2828 4b6c9460 2020-03-05 stsp "this commit with 'got branch -c %s BRANCH_NAME'",
2829 4b6c9460 2020-03-05 stsp branch_name, commit_id_str);
2830 4b6c9460 2020-03-05 stsp
2831 4b6c9460 2020-03-05 stsp return got_error_msg(GOT_ERR_ANCESTRY, msg);
2832 4b6c9460 2020-03-05 stsp }
2833 4b6c9460 2020-03-05 stsp
2834 4b6c9460 2020-03-05 stsp static const struct got_error *
2835 c09a553d 2018-03-12 stsp cmd_checkout(int argc, char *argv[])
2836 c09a553d 2018-03-12 stsp {
2837 c09a553d 2018-03-12 stsp const struct got_error *error = NULL;
2838 c09a553d 2018-03-12 stsp struct got_repository *repo = NULL;
2839 08e5873e 2021-09-14 stsp struct got_reference *head_ref = NULL, *ref = NULL;
2840 c09a553d 2018-03-12 stsp struct got_worktree *worktree = NULL;
2841 c09a553d 2018-03-12 stsp char *repo_path = NULL;
2842 c09a553d 2018-03-12 stsp char *worktree_path = NULL;
2843 0bb8a95e 2018-03-12 stsp const char *path_prefix = "";
2844 08e5873e 2021-09-14 stsp const char *branch_name = GOT_REF_HEAD, *refname = NULL;
2845 8069f636 2019-01-12 stsp char *commit_id_str = NULL;
2846 08e5873e 2021-09-14 stsp struct got_object_id *commit_id = NULL;
2847 f0207f6a 2020-10-19 stsp char *cwd = NULL;
2848 4ad4a1ec 2021-09-13 tracey int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0;
2849 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
2850 7f47418f 2019-12-20 stsp struct got_checkout_progress_arg cpa;
2851 f2ea84fa 2019-07-27 stsp
2852 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
2853 c09a553d 2018-03-12 stsp
2854 4ad4a1ec 2021-09-13 tracey while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) {
2855 0bb8a95e 2018-03-12 stsp switch (ch) {
2856 08573d5b 2019-05-14 stsp case 'b':
2857 08573d5b 2019-05-14 stsp branch_name = optarg;
2858 08573d5b 2019-05-14 stsp break;
2859 8069f636 2019-01-12 stsp case 'c':
2860 8069f636 2019-01-12 stsp commit_id_str = strdup(optarg);
2861 8069f636 2019-01-12 stsp if (commit_id_str == NULL)
2862 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
2863 bb51a5b4 2020-01-13 stsp break;
2864 bb51a5b4 2020-01-13 stsp case 'E':
2865 bb51a5b4 2020-01-13 stsp allow_nonempty = 1;
2866 8069f636 2019-01-12 stsp break;
2867 0bb8a95e 2018-03-12 stsp case 'p':
2868 0bb8a95e 2018-03-12 stsp path_prefix = optarg;
2869 0bb8a95e 2018-03-12 stsp break;
2870 4ad4a1ec 2021-09-13 tracey case 'q':
2871 4ad4a1ec 2021-09-13 tracey verbosity = -1;
2872 4ad4a1ec 2021-09-13 tracey break;
2873 0bb8a95e 2018-03-12 stsp default:
2874 2deda0b9 2019-03-07 stsp usage_checkout();
2875 0bb8a95e 2018-03-12 stsp /* NOTREACHED */
2876 0bb8a95e 2018-03-12 stsp }
2877 0bb8a95e 2018-03-12 stsp }
2878 0bb8a95e 2018-03-12 stsp
2879 0bb8a95e 2018-03-12 stsp argc -= optind;
2880 0bb8a95e 2018-03-12 stsp argv += optind;
2881 0bb8a95e 2018-03-12 stsp
2882 6715a751 2018-03-16 stsp #ifndef PROFILE
2883 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2884 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
2885 c09a553d 2018-03-12 stsp err(1, "pledge");
2886 6715a751 2018-03-16 stsp #endif
2887 0bb8a95e 2018-03-12 stsp if (argc == 1) {
2888 c47340da 2020-09-20 stsp char *base, *dotgit;
2889 f0207f6a 2020-10-19 stsp const char *path;
2890 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2891 76089277 2018-04-01 stsp if (repo_path == NULL)
2892 638f9024 2019-05-13 stsp return got_error_from_errno2("realpath", argv[0]);
2893 c09a553d 2018-03-12 stsp cwd = getcwd(NULL, 0);
2894 76089277 2018-04-01 stsp if (cwd == NULL) {
2895 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
2896 76089277 2018-04-01 stsp goto done;
2897 76089277 2018-04-01 stsp }
2898 c47340da 2020-09-20 stsp if (path_prefix[0])
2899 f0207f6a 2020-10-19 stsp path = path_prefix;
2900 c47340da 2020-09-20 stsp else
2901 f0207f6a 2020-10-19 stsp path = repo_path;
2902 f0207f6a 2020-10-19 stsp error = got_path_basename(&base, path);
2903 f0207f6a 2020-10-19 stsp if (error)
2904 c47340da 2020-09-20 stsp goto done;
2905 c09a553d 2018-03-12 stsp dotgit = strstr(base, ".git");
2906 c09a553d 2018-03-12 stsp if (dotgit)
2907 c09a553d 2018-03-12 stsp *dotgit = '\0';
2908 c09a553d 2018-03-12 stsp if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2909 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
2910 f0207f6a 2020-10-19 stsp free(base);
2911 76089277 2018-04-01 stsp goto done;
2912 c09a553d 2018-03-12 stsp }
2913 f0207f6a 2020-10-19 stsp free(base);
2914 0bb8a95e 2018-03-12 stsp } else if (argc == 2) {
2915 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2916 76089277 2018-04-01 stsp if (repo_path == NULL) {
2917 638f9024 2019-05-13 stsp error = got_error_from_errno2("realpath", argv[0]);
2918 76089277 2018-04-01 stsp goto done;
2919 76089277 2018-04-01 stsp }
2920 f7b38925 2018-04-01 stsp worktree_path = realpath(argv[1], NULL);
2921 76089277 2018-04-01 stsp if (worktree_path == NULL) {
2922 b4b3a7dd 2019-07-22 stsp if (errno != ENOENT) {
2923 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno2("realpath",
2924 b4b3a7dd 2019-07-22 stsp argv[1]);
2925 b4b3a7dd 2019-07-22 stsp goto done;
2926 b4b3a7dd 2019-07-22 stsp }
2927 b4b3a7dd 2019-07-22 stsp worktree_path = strdup(argv[1]);
2928 b4b3a7dd 2019-07-22 stsp if (worktree_path == NULL) {
2929 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno("strdup");
2930 b4b3a7dd 2019-07-22 stsp goto done;
2931 b4b3a7dd 2019-07-22 stsp }
2932 76089277 2018-04-01 stsp }
2933 c09a553d 2018-03-12 stsp } else
2934 c09a553d 2018-03-12 stsp usage_checkout();
2935 c09a553d 2018-03-12 stsp
2936 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
2937 72151b04 2019-05-11 stsp got_path_strip_trailing_slashes(worktree_path);
2938 13bfb272 2019-05-10 jcs
2939 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
2940 c09a553d 2018-03-12 stsp if (error != NULL)
2941 c02c541e 2019-03-29 stsp goto done;
2942 c02c541e 2019-03-29 stsp
2943 c530dc23 2019-07-23 stsp /* Pre-create work tree path for unveil(2) */
2944 c530dc23 2019-07-23 stsp error = got_path_mkdir(worktree_path);
2945 c530dc23 2019-07-23 stsp if (error) {
2946 80c1b583 2019-08-07 stsp if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2947 80c1b583 2019-08-07 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2948 c530dc23 2019-07-23 stsp goto done;
2949 bb51a5b4 2020-01-13 stsp if (!allow_nonempty &&
2950 bb51a5b4 2020-01-13 stsp !got_path_dir_is_empty(worktree_path)) {
2951 c530dc23 2019-07-23 stsp error = got_error_path(worktree_path,
2952 c530dc23 2019-07-23 stsp GOT_ERR_DIR_NOT_EMPTY);
2953 c530dc23 2019-07-23 stsp goto done;
2954 c530dc23 2019-07-23 stsp }
2955 c530dc23 2019-07-23 stsp }
2956 c530dc23 2019-07-23 stsp
2957 c530dc23 2019-07-23 stsp error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2958 c02c541e 2019-03-29 stsp if (error)
2959 c09a553d 2018-03-12 stsp goto done;
2960 8069f636 2019-01-12 stsp
2961 08573d5b 2019-05-14 stsp error = got_ref_open(&head_ref, repo, branch_name, 0);
2962 c09a553d 2018-03-12 stsp if (error != NULL)
2963 c09a553d 2018-03-12 stsp goto done;
2964 c09a553d 2018-03-12 stsp
2965 0bb8a95e 2018-03-12 stsp error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2966 d70b8e30 2018-12-27 stsp if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2967 c09a553d 2018-03-12 stsp goto done;
2968 c09a553d 2018-03-12 stsp
2969 c09a553d 2018-03-12 stsp error = got_worktree_open(&worktree, worktree_path);
2970 c09a553d 2018-03-12 stsp if (error != NULL)
2971 c09a553d 2018-03-12 stsp goto done;
2972 c09a553d 2018-03-12 stsp
2973 e5dc7198 2018-12-29 stsp error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2974 e5dc7198 2018-12-29 stsp path_prefix);
2975 e5dc7198 2018-12-29 stsp if (error != NULL)
2976 e5dc7198 2018-12-29 stsp goto done;
2977 e5dc7198 2018-12-29 stsp if (!same_path_prefix) {
2978 49520a32 2018-12-29 stsp error = got_error(GOT_ERR_PATH_PREFIX);
2979 49520a32 2018-12-29 stsp goto done;
2980 49520a32 2018-12-29 stsp }
2981 49520a32 2018-12-29 stsp
2982 8069f636 2019-01-12 stsp if (commit_id_str) {
2983 84de9106 2020-12-26 stsp struct got_reflist_head refs;
2984 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
2985 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2986 84de9106 2020-12-26 stsp NULL);
2987 84de9106 2020-12-26 stsp if (error)
2988 84de9106 2020-12-26 stsp goto done;
2989 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
2990 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2991 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
2992 30837e32 2019-07-25 stsp if (error)
2993 8069f636 2019-01-12 stsp goto done;
2994 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
2995 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
2996 8069f636 2019-01-12 stsp if (error != NULL) {
2997 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
2998 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
2999 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
3000 4b6c9460 2020-03-05 stsp }
3001 8069f636 2019-01-12 stsp goto done;
3002 8069f636 2019-01-12 stsp }
3003 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
3004 4b6c9460 2020-03-05 stsp if (error) {
3005 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
3006 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
3007 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
3008 4b6c9460 2020-03-05 stsp }
3009 45d344f6 2019-05-14 stsp goto done;
3010 4b6c9460 2020-03-05 stsp }
3011 8069f636 2019-01-12 stsp error = got_worktree_set_base_commit_id(worktree, repo,
3012 8069f636 2019-01-12 stsp commit_id);
3013 8069f636 2019-01-12 stsp if (error)
3014 8069f636 2019-01-12 stsp goto done;
3015 08e5873e 2021-09-14 stsp /* Expand potentially abbreviated commit ID string. */
3016 08e5873e 2021-09-14 stsp free(commit_id_str);
3017 08e5873e 2021-09-14 stsp error = got_object_id_str(&commit_id_str, commit_id);
3018 08e5873e 2021-09-14 stsp if (error)
3019 08e5873e 2021-09-14 stsp goto done;
3020 08e5873e 2021-09-14 stsp } else {
3021 08e5873e 2021-09-14 stsp commit_id = got_object_id_dup(
3022 08e5873e 2021-09-14 stsp got_worktree_get_base_commit_id(worktree));
3023 08e5873e 2021-09-14 stsp if (commit_id == NULL) {
3024 08e5873e 2021-09-14 stsp error = got_error_from_errno("got_object_id_dup");
3025 08e5873e 2021-09-14 stsp goto done;
3026 08e5873e 2021-09-14 stsp }
3027 08e5873e 2021-09-14 stsp error = got_object_id_str(&commit_id_str, commit_id);
3028 08e5873e 2021-09-14 stsp if (error)
3029 08e5873e 2021-09-14 stsp goto done;
3030 8069f636 2019-01-12 stsp }
3031 8069f636 2019-01-12 stsp
3032 adc19d55 2019-07-28 stsp error = got_pathlist_append(&paths, "", NULL);
3033 f2ea84fa 2019-07-27 stsp if (error)
3034 f2ea84fa 2019-07-27 stsp goto done;
3035 7f47418f 2019-12-20 stsp cpa.worktree_path = worktree_path;
3036 7f47418f 2019-12-20 stsp cpa.had_base_commit_ref_error = 0;
3037 4ad4a1ec 2021-09-13 tracey cpa.verbosity = verbosity;
3038 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
3039 7f47418f 2019-12-20 stsp checkout_progress, &cpa, check_cancelled, NULL);
3040 c09a553d 2018-03-12 stsp if (error != NULL)
3041 c09a553d 2018-03-12 stsp goto done;
3042 c09a553d 2018-03-12 stsp
3043 08e5873e 2021-09-14 stsp if (got_ref_is_symbolic(head_ref)) {
3044 08e5873e 2021-09-14 stsp error = got_ref_resolve_symbolic(&ref, repo, head_ref);
3045 08e5873e 2021-09-14 stsp if (error)
3046 08e5873e 2021-09-14 stsp goto done;
3047 08e5873e 2021-09-14 stsp refname = got_ref_get_name(ref);
3048 08e5873e 2021-09-14 stsp } else
3049 08e5873e 2021-09-14 stsp refname = got_ref_get_name(head_ref);
3050 08e5873e 2021-09-14 stsp printf("Checked out %s: %s\n", refname, commit_id_str);
3051 b65ae19a 2018-04-24 stsp printf("Now shut up and hack\n");
3052 7f47418f 2019-12-20 stsp if (cpa.had_base_commit_ref_error)
3053 7f47418f 2019-12-20 stsp show_worktree_base_ref_warning();
3054 c09a553d 2018-03-12 stsp done:
3055 08e5873e 2021-09-14 stsp if (head_ref)
3056 08e5873e 2021-09-14 stsp got_ref_close(head_ref);
3057 08e5873e 2021-09-14 stsp if (ref)
3058 08e5873e 2021-09-14 stsp got_ref_close(ref);
3059 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
3060 8069f636 2019-01-12 stsp free(commit_id_str);
3061 08e5873e 2021-09-14 stsp free(commit_id);
3062 76089277 2018-04-01 stsp free(repo_path);
3063 507dc3bb 2018-12-29 stsp free(worktree_path);
3064 c47340da 2020-09-20 stsp free(cwd);
3065 507dc3bb 2018-12-29 stsp return error;
3066 9627c110 2020-04-18 stsp }
3067 9627c110 2020-04-18 stsp
3068 9627c110 2020-04-18 stsp struct got_update_progress_arg {
3069 9627c110 2020-04-18 stsp int did_something;
3070 9627c110 2020-04-18 stsp int conflicts;
3071 9627c110 2020-04-18 stsp int obstructed;
3072 9627c110 2020-04-18 stsp int not_updated;
3073 f259c4c1 2021-09-24 stsp int missing;
3074 35ca1db7 2021-09-28 stsp int not_deleted;
3075 35ca1db7 2021-09-28 stsp int unversioned;
3076 4ad4a1ec 2021-09-13 tracey int verbosity;
3077 9627c110 2020-04-18 stsp };
3078 9627c110 2020-04-18 stsp
3079 9627c110 2020-04-18 stsp void
3080 9627c110 2020-04-18 stsp print_update_progress_stats(struct got_update_progress_arg *upa)
3081 9627c110 2020-04-18 stsp {
3082 9627c110 2020-04-18 stsp if (!upa->did_something)
3083 9627c110 2020-04-18 stsp return;
3084 9627c110 2020-04-18 stsp
3085 9627c110 2020-04-18 stsp if (upa->conflicts > 0)
3086 9627c110 2020-04-18 stsp printf("Files with new merge conflicts: %d\n", upa->conflicts);
3087 9627c110 2020-04-18 stsp if (upa->obstructed > 0)
3088 9627c110 2020-04-18 stsp printf("File paths obstructed by a non-regular file: %d\n",
3089 9627c110 2020-04-18 stsp upa->obstructed);
3090 9627c110 2020-04-18 stsp if (upa->not_updated > 0)
3091 9627c110 2020-04-18 stsp printf("Files not updated because of existing merge "
3092 9627c110 2020-04-18 stsp "conflicts: %d\n", upa->not_updated);
3093 507dc3bb 2018-12-29 stsp }
3094 507dc3bb 2018-12-29 stsp
3095 35ca1db7 2021-09-28 stsp /*
3096 35ca1db7 2021-09-28 stsp * The meaning of some status codes differs between merge-style operations and
3097 35ca1db7 2021-09-28 stsp * update operations. For example, the ! status code means "file was missing"
3098 35ca1db7 2021-09-28 stsp * if changes were merged into the work tree, and "missing file was restored"
3099 35ca1db7 2021-09-28 stsp * if the work tree was updated. This function should be used by any operation
3100 35ca1db7 2021-09-28 stsp * which merges changes into the work tree without updating the work tree.
3101 35ca1db7 2021-09-28 stsp */
3102 35ca1db7 2021-09-28 stsp void
3103 35ca1db7 2021-09-28 stsp print_merge_progress_stats(struct got_update_progress_arg *upa)
3104 35ca1db7 2021-09-28 stsp {
3105 35ca1db7 2021-09-28 stsp if (!upa->did_something)
3106 35ca1db7 2021-09-28 stsp return;
3107 35ca1db7 2021-09-28 stsp
3108 35ca1db7 2021-09-28 stsp if (upa->conflicts > 0)
3109 35ca1db7 2021-09-28 stsp printf("Files with new merge conflicts: %d\n", upa->conflicts);
3110 35ca1db7 2021-09-28 stsp if (upa->obstructed > 0)
3111 35ca1db7 2021-09-28 stsp printf("File paths obstructed by a non-regular file: %d\n",
3112 35ca1db7 2021-09-28 stsp upa->obstructed);
3113 35ca1db7 2021-09-28 stsp if (upa->missing > 0)
3114 35ca1db7 2021-09-28 stsp printf("Files which had incoming changes but could not be "
3115 35ca1db7 2021-09-28 stsp "found in the work tree: %d\n", upa->missing);
3116 35ca1db7 2021-09-28 stsp if (upa->not_deleted > 0)
3117 35ca1db7 2021-09-28 stsp printf("Files not deleted due to differences in deleted "
3118 35ca1db7 2021-09-28 stsp "content: %d\n", upa->not_deleted);
3119 35ca1db7 2021-09-28 stsp if (upa->unversioned > 0)
3120 35ca1db7 2021-09-28 stsp printf("Files not merged because an unversioned file was "
3121 35ca1db7 2021-09-28 stsp "found in the work tree: %d\n", upa->unversioned);
3122 35ca1db7 2021-09-28 stsp }
3123 35ca1db7 2021-09-28 stsp
3124 507dc3bb 2018-12-29 stsp __dead static void
3125 507dc3bb 2018-12-29 stsp usage_update(void)
3126 507dc3bb 2018-12-29 stsp {
3127 4ad4a1ec 2021-09-13 tracey fprintf(stderr, "usage: %s update [-b branch] [-c commit] [-q] "
3128 4ad4a1ec 2021-09-13 tracey "[path ...]\n",
3129 507dc3bb 2018-12-29 stsp getprogname());
3130 507dc3bb 2018-12-29 stsp exit(1);
3131 507dc3bb 2018-12-29 stsp }
3132 507dc3bb 2018-12-29 stsp
3133 1ee397ad 2019-07-12 stsp static const struct got_error *
3134 507dc3bb 2018-12-29 stsp update_progress(void *arg, unsigned char status, const char *path)
3135 507dc3bb 2018-12-29 stsp {
3136 9627c110 2020-04-18 stsp struct got_update_progress_arg *upa = arg;
3137 784955db 2019-01-12 stsp
3138 7f47418f 2019-12-20 stsp if (status == GOT_STATUS_EXISTS ||
3139 7f47418f 2019-12-20 stsp status == GOT_STATUS_BASE_REF_ERR)
3140 1ee397ad 2019-07-12 stsp return NULL;
3141 507dc3bb 2018-12-29 stsp
3142 9627c110 2020-04-18 stsp upa->did_something = 1;
3143 a484d721 2019-06-10 stsp
3144 a484d721 2019-06-10 stsp /* Base commit bump happens silently. */
3145 a484d721 2019-06-10 stsp if (status == GOT_STATUS_BUMP_BASE)
3146 1ee397ad 2019-07-12 stsp return NULL;
3147 a484d721 2019-06-10 stsp
3148 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CONFLICT)
3149 9627c110 2020-04-18 stsp upa->conflicts++;
3150 9627c110 2020-04-18 stsp if (status == GOT_STATUS_OBSTRUCTED)
3151 9627c110 2020-04-18 stsp upa->obstructed++;
3152 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CANNOT_UPDATE)
3153 9627c110 2020-04-18 stsp upa->not_updated++;
3154 f259c4c1 2021-09-24 stsp if (status == GOT_STATUS_MISSING)
3155 f259c4c1 2021-09-24 stsp upa->missing++;
3156 35ca1db7 2021-09-28 stsp if (status == GOT_STATUS_CANNOT_DELETE)
3157 35ca1db7 2021-09-28 stsp upa->not_deleted++;
3158 35ca1db7 2021-09-28 stsp if (status == GOT_STATUS_UNVERSIONED)
3159 35ca1db7 2021-09-28 stsp upa->unversioned++;
3160 9627c110 2020-04-18 stsp
3161 507dc3bb 2018-12-29 stsp while (path[0] == '/')
3162 507dc3bb 2018-12-29 stsp path++;
3163 4ad4a1ec 2021-09-13 tracey if (upa->verbosity >= 0)
3164 4ad4a1ec 2021-09-13 tracey printf("%c %s\n", status, path);
3165 4ad4a1ec 2021-09-13 tracey
3166 1ee397ad 2019-07-12 stsp return NULL;
3167 be7061eb 2018-12-30 stsp }
3168 be7061eb 2018-12-30 stsp
3169 be7061eb 2018-12-30 stsp static const struct got_error *
3170 a1fb16d8 2019-05-24 stsp switch_head_ref(struct got_reference *head_ref,
3171 a1fb16d8 2019-05-24 stsp struct got_object_id *commit_id, struct got_worktree *worktree,
3172 a1fb16d8 2019-05-24 stsp struct got_repository *repo)
3173 a1fb16d8 2019-05-24 stsp {
3174 a1fb16d8 2019-05-24 stsp const struct got_error *err = NULL;
3175 a1fb16d8 2019-05-24 stsp char *base_id_str;
3176 a1fb16d8 2019-05-24 stsp int ref_has_moved = 0;
3177 a1fb16d8 2019-05-24 stsp
3178 a1fb16d8 2019-05-24 stsp /* Trivial case: switching between two different references. */
3179 a1fb16d8 2019-05-24 stsp if (strcmp(got_ref_get_name(head_ref),
3180 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree)) != 0) {
3181 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n",
3182 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree),
3183 a1fb16d8 2019-05-24 stsp got_ref_get_name(head_ref));
3184 a1fb16d8 2019-05-24 stsp return got_worktree_set_head_ref(worktree, head_ref);
3185 a1fb16d8 2019-05-24 stsp }
3186 a1fb16d8 2019-05-24 stsp
3187 a1fb16d8 2019-05-24 stsp err = check_linear_ancestry(commit_id,
3188 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
3189 a1fb16d8 2019-05-24 stsp if (err) {
3190 a1fb16d8 2019-05-24 stsp if (err->code != GOT_ERR_ANCESTRY)
3191 a1fb16d8 2019-05-24 stsp return err;
3192 a1fb16d8 2019-05-24 stsp ref_has_moved = 1;
3193 a1fb16d8 2019-05-24 stsp }
3194 a1fb16d8 2019-05-24 stsp if (!ref_has_moved)
3195 a1fb16d8 2019-05-24 stsp return NULL;
3196 a1fb16d8 2019-05-24 stsp
3197 a1fb16d8 2019-05-24 stsp /* Switching to a rebased branch with the same reference name. */
3198 a1fb16d8 2019-05-24 stsp err = got_object_id_str(&base_id_str,
3199 a1fb16d8 2019-05-24 stsp got_worktree_get_base_commit_id(worktree));
3200 a1fb16d8 2019-05-24 stsp if (err)
3201 a1fb16d8 2019-05-24 stsp return err;
3202 a1fb16d8 2019-05-24 stsp printf("Reference %s now points at a different branch\n",
3203 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
3204 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n", base_id_str,
3205 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
3206 0ebf8283 2019-07-24 stsp return NULL;
3207 0ebf8283 2019-07-24 stsp }
3208 0ebf8283 2019-07-24 stsp
3209 0ebf8283 2019-07-24 stsp static const struct got_error *
3210 0ebf8283 2019-07-24 stsp check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
3211 0ebf8283 2019-07-24 stsp {
3212 0ebf8283 2019-07-24 stsp const struct got_error *err;
3213 0ebf8283 2019-07-24 stsp int in_progress;
3214 0ebf8283 2019-07-24 stsp
3215 0ebf8283 2019-07-24 stsp err = got_worktree_rebase_in_progress(&in_progress, worktree);
3216 0ebf8283 2019-07-24 stsp if (err)
3217 0ebf8283 2019-07-24 stsp return err;
3218 0ebf8283 2019-07-24 stsp if (in_progress)
3219 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_REBASING);
3220 0ebf8283 2019-07-24 stsp
3221 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_in_progress(&in_progress, worktree);
3222 0ebf8283 2019-07-24 stsp if (err)
3223 0ebf8283 2019-07-24 stsp return err;
3224 0ebf8283 2019-07-24 stsp if (in_progress)
3225 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_BUSY);
3226 f259c4c1 2021-09-24 stsp
3227 f259c4c1 2021-09-24 stsp return NULL;
3228 f259c4c1 2021-09-24 stsp }
3229 f259c4c1 2021-09-24 stsp
3230 f259c4c1 2021-09-24 stsp static const struct got_error *
3231 f259c4c1 2021-09-24 stsp check_merge_in_progress(struct got_worktree *worktree,
3232 f259c4c1 2021-09-24 stsp struct got_repository *repo)
3233 f259c4c1 2021-09-24 stsp {
3234 f259c4c1 2021-09-24 stsp const struct got_error *err;
3235 f259c4c1 2021-09-24 stsp int in_progress;
3236 f259c4c1 2021-09-24 stsp
3237 f259c4c1 2021-09-24 stsp err = got_worktree_merge_in_progress(&in_progress, worktree, repo);
3238 f259c4c1 2021-09-24 stsp if (err)
3239 f259c4c1 2021-09-24 stsp return err;
3240 f259c4c1 2021-09-24 stsp if (in_progress)
3241 f259c4c1 2021-09-24 stsp return got_error(GOT_ERR_MERGE_BUSY);
3242 0ebf8283 2019-07-24 stsp
3243 a1fb16d8 2019-05-24 stsp return NULL;
3244 a5edda0a 2019-07-27 stsp }
3245 a5edda0a 2019-07-27 stsp
3246 a5edda0a 2019-07-27 stsp static const struct got_error *
3247 a5edda0a 2019-07-27 stsp get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
3248 a5edda0a 2019-07-27 stsp char *argv[], struct got_worktree *worktree)
3249 a5edda0a 2019-07-27 stsp {
3250 a0de39f3 2019-08-09 stsp const struct got_error *err = NULL;
3251 a5edda0a 2019-07-27 stsp char *path;
3252 10a623df 2021-10-11 stsp struct got_pathlist_entry *new;
3253 a5edda0a 2019-07-27 stsp int i;
3254 a5edda0a 2019-07-27 stsp
3255 a5edda0a 2019-07-27 stsp if (argc == 0) {
3256 a5edda0a 2019-07-27 stsp path = strdup("");
3257 a5edda0a 2019-07-27 stsp if (path == NULL)
3258 a5edda0a 2019-07-27 stsp return got_error_from_errno("strdup");
3259 adc19d55 2019-07-28 stsp return got_pathlist_append(paths, path, NULL);
3260 a5edda0a 2019-07-27 stsp }
3261 a5edda0a 2019-07-27 stsp
3262 a5edda0a 2019-07-27 stsp for (i = 0; i < argc; i++) {
3263 a5edda0a 2019-07-27 stsp err = got_worktree_resolve_path(&path, worktree, argv[i]);
3264 a5edda0a 2019-07-27 stsp if (err)
3265 a5edda0a 2019-07-27 stsp break;
3266 10a623df 2021-10-11 stsp err = got_pathlist_insert(&new, paths, path, NULL);
3267 10a623df 2021-10-11 stsp if (err || new == NULL /* duplicate */) {
3268 a5edda0a 2019-07-27 stsp free(path);
3269 10a623df 2021-10-11 stsp if (err)
3270 10a623df 2021-10-11 stsp break;
3271 a5edda0a 2019-07-27 stsp }
3272 a5edda0a 2019-07-27 stsp }
3273 a5edda0a 2019-07-27 stsp
3274 a5edda0a 2019-07-27 stsp return err;
3275 a1fb16d8 2019-05-24 stsp }
3276 a1fb16d8 2019-05-24 stsp
3277 a1fb16d8 2019-05-24 stsp static const struct got_error *
3278 fa51e947 2020-03-27 stsp wrap_not_worktree_error(const struct got_error *orig_err,
3279 fa51e947 2020-03-27 stsp const char *cmdname, const char *path)
3280 fa51e947 2020-03-27 stsp {
3281 fa51e947 2020-03-27 stsp const struct got_error *err;
3282 fa51e947 2020-03-27 stsp struct got_repository *repo;
3283 fa51e947 2020-03-27 stsp static char msg[512];
3284 fa51e947 2020-03-27 stsp
3285 fa51e947 2020-03-27 stsp err = got_repo_open(&repo, path, NULL);
3286 fa51e947 2020-03-27 stsp if (err)
3287 fa51e947 2020-03-27 stsp return orig_err;
3288 fa51e947 2020-03-27 stsp
3289 fa51e947 2020-03-27 stsp snprintf(msg, sizeof(msg),
3290 fa51e947 2020-03-27 stsp "'got %s' needs a work tree in addition to a git repository\n"
3291 fa51e947 2020-03-27 stsp "Work trees can be checked out from this Git repository with "
3292 fa51e947 2020-03-27 stsp "'got checkout'.\n"
3293 fa51e947 2020-03-27 stsp "The got(1) manual page contains more information.", cmdname);
3294 fa51e947 2020-03-27 stsp err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
3295 fa51e947 2020-03-27 stsp got_repo_close(repo);
3296 fa51e947 2020-03-27 stsp return err;
3297 fa51e947 2020-03-27 stsp }
3298 fa51e947 2020-03-27 stsp
3299 fa51e947 2020-03-27 stsp static const struct got_error *
3300 507dc3bb 2018-12-29 stsp cmd_update(int argc, char *argv[])
3301 507dc3bb 2018-12-29 stsp {
3302 507dc3bb 2018-12-29 stsp const struct got_error *error = NULL;
3303 507dc3bb 2018-12-29 stsp struct got_repository *repo = NULL;
3304 507dc3bb 2018-12-29 stsp struct got_worktree *worktree = NULL;
3305 f2ea84fa 2019-07-27 stsp char *worktree_path = NULL;
3306 507dc3bb 2018-12-29 stsp struct got_object_id *commit_id = NULL;
3307 9c4b8182 2019-01-02 stsp char *commit_id_str = NULL;
3308 024e9686 2019-05-14 stsp const char *branch_name = NULL;
3309 024e9686 2019-05-14 stsp struct got_reference *head_ref = NULL;
3310 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
3311 f2ea84fa 2019-07-27 stsp struct got_pathlist_entry *pe;
3312 4ad4a1ec 2021-09-13 tracey int ch, verbosity = 0;
3313 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
3314 507dc3bb 2018-12-29 stsp
3315 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
3316 f2ea84fa 2019-07-27 stsp
3317 4ad4a1ec 2021-09-13 tracey while ((ch = getopt(argc, argv, "b:c:q")) != -1) {
3318 507dc3bb 2018-12-29 stsp switch (ch) {
3319 024e9686 2019-05-14 stsp case 'b':
3320 024e9686 2019-05-14 stsp branch_name = optarg;
3321 024e9686 2019-05-14 stsp break;
3322 507dc3bb 2018-12-29 stsp case 'c':
3323 9c4b8182 2019-01-02 stsp commit_id_str = strdup(optarg);
3324 9c4b8182 2019-01-02 stsp if (commit_id_str == NULL)
3325 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
3326 4ad4a1ec 2021-09-13 tracey break;
3327 4ad4a1ec 2021-09-13 tracey case 'q':
3328 4ad4a1ec 2021-09-13 tracey verbosity = -1;
3329 507dc3bb 2018-12-29 stsp break;
3330 507dc3bb 2018-12-29 stsp default:
3331 2deda0b9 2019-03-07 stsp usage_update();
3332 507dc3bb 2018-12-29 stsp /* NOTREACHED */
3333 507dc3bb 2018-12-29 stsp }
3334 507dc3bb 2018-12-29 stsp }
3335 507dc3bb 2018-12-29 stsp
3336 507dc3bb 2018-12-29 stsp argc -= optind;
3337 507dc3bb 2018-12-29 stsp argv += optind;
3338 507dc3bb 2018-12-29 stsp
3339 507dc3bb 2018-12-29 stsp #ifndef PROFILE
3340 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3341 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
3342 507dc3bb 2018-12-29 stsp err(1, "pledge");
3343 507dc3bb 2018-12-29 stsp #endif
3344 c4cdcb68 2019-04-03 stsp worktree_path = getcwd(NULL, 0);
3345 c4cdcb68 2019-04-03 stsp if (worktree_path == NULL) {
3346 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
3347 c4cdcb68 2019-04-03 stsp goto done;
3348 c4cdcb68 2019-04-03 stsp }
3349 c4cdcb68 2019-04-03 stsp error = got_worktree_open(&worktree, worktree_path);
3350 fa51e947 2020-03-27 stsp if (error) {
3351 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
3352 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "update",
3353 fa51e947 2020-03-27 stsp worktree_path);
3354 7d5807f4 2019-07-11 stsp goto done;
3355 fa51e947 2020-03-27 stsp }
3356 7d5807f4 2019-07-11 stsp
3357 0ebf8283 2019-07-24 stsp error = check_rebase_or_histedit_in_progress(worktree);
3358 f2ea84fa 2019-07-27 stsp if (error)
3359 f2ea84fa 2019-07-27 stsp goto done;
3360 507dc3bb 2018-12-29 stsp
3361 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
3362 c9956ddf 2019-09-08 stsp NULL);
3363 507dc3bb 2018-12-29 stsp if (error != NULL)
3364 507dc3bb 2018-12-29 stsp goto done;
3365 507dc3bb 2018-12-29 stsp
3366 97430839 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
3367 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
3368 087fb88c 2019-08-04 stsp if (error)
3369 087fb88c 2019-08-04 stsp goto done;
3370 087fb88c 2019-08-04 stsp
3371 f259c4c1 2021-09-24 stsp error = check_merge_in_progress(worktree, repo);
3372 f259c4c1 2021-09-24 stsp if (error)
3373 f259c4c1 2021-09-24 stsp goto done;
3374 f259c4c1 2021-09-24 stsp
3375 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
3376 0266afb7 2019-01-04 stsp if (error)
3377 0266afb7 2019-01-04 stsp goto done;
3378 0266afb7 2019-01-04 stsp
3379 a1fb16d8 2019-05-24 stsp error = got_ref_open(&head_ref, repo, branch_name ? branch_name :
3380 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree), 0);
3381 024e9686 2019-05-14 stsp if (error != NULL)
3382 024e9686 2019-05-14 stsp goto done;
3383 507dc3bb 2018-12-29 stsp if (commit_id_str == NULL) {
3384 507dc3bb 2018-12-29 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
3385 9c4b8182 2019-01-02 stsp if (error != NULL)
3386 9c4b8182 2019-01-02 stsp goto done;
3387 9c4b8182 2019-01-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
3388 507dc3bb 2018-12-29 stsp if (error != NULL)
3389 507dc3bb 2018-12-29 stsp goto done;
3390 507dc3bb 2018-12-29 stsp } else {
3391 84de9106 2020-12-26 stsp struct got_reflist_head refs;
3392 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
3393 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
3394 84de9106 2020-12-26 stsp NULL);
3395 84de9106 2020-12-26 stsp if (error)
3396 84de9106 2020-12-26 stsp goto done;
3397 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
3398 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
3399 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
3400 04f57cb3 2019-07-25 stsp free(commit_id_str);
3401 bb787f09 2019-07-25 stsp commit_id_str = NULL;
3402 30837e32 2019-07-25 stsp if (error)
3403 a297e751 2019-07-11 stsp goto done;
3404 a297e751 2019-07-11 stsp error = got_object_id_str(&commit_id_str, commit_id);
3405 a297e751 2019-07-11 stsp if (error)
3406 507dc3bb 2018-12-29 stsp goto done;
3407 507dc3bb 2018-12-29 stsp }
3408 35c965b2 2018-12-29 stsp
3409 a1fb16d8 2019-05-24 stsp if (branch_name) {
3410 024e9686 2019-05-14 stsp struct got_object_id *head_commit_id;
3411 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry) {
3412 f2b16ada 2019-08-02 stsp if (pe->path_len == 0)
3413 f2ea84fa 2019-07-27 stsp continue;
3414 f2ea84fa 2019-07-27 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
3415 f2ea84fa 2019-07-27 stsp "switching between branches requires that "
3416 f2ea84fa 2019-07-27 stsp "the entire work tree gets updated");
3417 024e9686 2019-05-14 stsp goto done;
3418 024e9686 2019-05-14 stsp }
3419 024e9686 2019-05-14 stsp error = got_ref_resolve(&head_commit_id, repo, head_ref);
3420 024e9686 2019-05-14 stsp if (error)
3421 024e9686 2019-05-14 stsp goto done;
3422 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, head_commit_id, 0,
3423 3aef623b 2019-10-15 stsp repo);
3424 a367ff0f 2019-05-14 stsp free(head_commit_id);
3425 024e9686 2019-05-14 stsp if (error != NULL)
3426 024e9686 2019-05-14 stsp goto done;
3427 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
3428 a367ff0f 2019-05-14 stsp if (error)
3429 a367ff0f 2019-05-14 stsp goto done;
3430 a1fb16d8 2019-05-24 stsp error = switch_head_ref(head_ref, commit_id, worktree, repo);
3431 024e9686 2019-05-14 stsp if (error)
3432 024e9686 2019-05-14 stsp goto done;
3433 024e9686 2019-05-14 stsp } else {
3434 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
3435 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
3436 a367ff0f 2019-05-14 stsp if (error != NULL) {
3437 a367ff0f 2019-05-14 stsp if (error->code == GOT_ERR_ANCESTRY)
3438 a367ff0f 2019-05-14 stsp error = got_error(GOT_ERR_BRANCH_MOVED);
3439 024e9686 2019-05-14 stsp goto done;
3440 a367ff0f 2019-05-14 stsp }
3441 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
3442 a367ff0f 2019-05-14 stsp if (error)
3443 a367ff0f 2019-05-14 stsp goto done;
3444 024e9686 2019-05-14 stsp }
3445 507dc3bb 2018-12-29 stsp
3446 507dc3bb 2018-12-29 stsp if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
3447 507dc3bb 2018-12-29 stsp commit_id) != 0) {
3448 507dc3bb 2018-12-29 stsp error = got_worktree_set_base_commit_id(worktree, repo,
3449 507dc3bb 2018-12-29 stsp commit_id);
3450 507dc3bb 2018-12-29 stsp if (error)
3451 507dc3bb 2018-12-29 stsp goto done;
3452 507dc3bb 2018-12-29 stsp }
3453 507dc3bb 2018-12-29 stsp
3454 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
3455 4ad4a1ec 2021-09-13 tracey upa.verbosity = verbosity;
3456 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
3457 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
3458 507dc3bb 2018-12-29 stsp if (error != NULL)
3459 507dc3bb 2018-12-29 stsp goto done;
3460 9c4b8182 2019-01-02 stsp
3461 4f3c844b 2021-09-14 stsp if (upa.did_something) {
3462 4f3c844b 2021-09-14 stsp printf("Updated to %s: %s\n",
3463 4f3c844b 2021-09-14 stsp got_worktree_get_head_ref_name(worktree), commit_id_str);
3464 4f3c844b 2021-09-14 stsp } else
3465 784955db 2019-01-12 stsp printf("Already up-to-date\n");
3466 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
3467 507dc3bb 2018-12-29 stsp done:
3468 c09a553d 2018-03-12 stsp free(worktree_path);
3469 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
3470 f2ea84fa 2019-07-27 stsp free((char *)pe->path);
3471 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
3472 507dc3bb 2018-12-29 stsp free(commit_id);
3473 9c4b8182 2019-01-02 stsp free(commit_id_str);
3474 c09a553d 2018-03-12 stsp return error;
3475 c09a553d 2018-03-12 stsp }
3476 c09a553d 2018-03-12 stsp
3477 f42b1b34 2018-03-12 stsp static const struct got_error *
3478 44392932 2019-08-25 stsp diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3479 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
3480 64453f7e 2020-11-21 stsp int force_text_diff, struct got_repository *repo)
3481 5c860e29 2018-03-12 stsp {
3482 f42b1b34 2018-03-12 stsp const struct got_error *err = NULL;
3483 44392932 2019-08-25 stsp struct got_blob_object *blob1 = NULL, *blob2 = NULL;
3484 79109fed 2018-03-27 stsp
3485 44392932 2019-08-25 stsp if (blob_id1) {
3486 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192);
3487 44392932 2019-08-25 stsp if (err)
3488 44392932 2019-08-25 stsp goto done;
3489 44392932 2019-08-25 stsp }
3490 79109fed 2018-03-27 stsp
3491 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192);
3492 44392932 2019-08-25 stsp if (err)
3493 44392932 2019-08-25 stsp goto done;
3494 79109fed 2018-03-27 stsp
3495 44392932 2019-08-25 stsp while (path[0] == '/')
3496 44392932 2019-08-25 stsp path++;
3497 fe621944 2020-11-10 stsp err = got_diff_blob(NULL, NULL, blob1, blob2, path, path,
3498 64453f7e 2020-11-21 stsp diff_context, ignore_whitespace, force_text_diff, stdout);
3499 44392932 2019-08-25 stsp done:
3500 44392932 2019-08-25 stsp if (blob1)
3501 44392932 2019-08-25 stsp got_object_blob_close(blob1);
3502 44392932 2019-08-25 stsp got_object_blob_close(blob2);
3503 44392932 2019-08-25 stsp return err;
3504 44392932 2019-08-25 stsp }
3505 44392932 2019-08-25 stsp
3506 44392932 2019-08-25 stsp static const struct got_error *
3507 44392932 2019-08-25 stsp diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
3508 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
3509 64453f7e 2020-11-21 stsp int force_text_diff, struct got_repository *repo)
3510 44392932 2019-08-25 stsp {
3511 44392932 2019-08-25 stsp const struct got_error *err = NULL;
3512 44392932 2019-08-25 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3513 44392932 2019-08-25 stsp struct got_diff_blob_output_unidiff_arg arg;
3514 44392932 2019-08-25 stsp
3515 44392932 2019-08-25 stsp if (tree_id1) {
3516 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
3517 79109fed 2018-03-27 stsp if (err)
3518 44392932 2019-08-25 stsp goto done;
3519 79109fed 2018-03-27 stsp }
3520 79109fed 2018-03-27 stsp
3521 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
3522 0f2b3dca 2018-12-22 stsp if (err)
3523 0f2b3dca 2018-12-22 stsp goto done;
3524 0f2b3dca 2018-12-22 stsp
3525 aaa13589 2019-06-01 stsp arg.diff_context = diff_context;
3526 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
3527 64453f7e 2020-11-21 stsp arg.force_text_diff = force_text_diff;
3528 aaa13589 2019-06-01 stsp arg.outfile = stdout;
3529 fe621944 2020-11-10 stsp arg.line_offsets = NULL;
3530 fe621944 2020-11-10 stsp arg.nlines = 0;
3531 44392932 2019-08-25 stsp while (path[0] == '/')
3532 44392932 2019-08-25 stsp path++;
3533 44392932 2019-08-25 stsp err = got_diff_tree(tree1, tree2, path, path, repo,
3534 31b4484f 2019-07-27 stsp got_diff_blob_output_unidiff, &arg, 1);
3535 0f2b3dca 2018-12-22 stsp done:
3536 79109fed 2018-03-27 stsp if (tree1)
3537 79109fed 2018-03-27 stsp got_object_tree_close(tree1);
3538 366e0a5f 2019-10-10 stsp if (tree2)
3539 366e0a5f 2019-10-10 stsp got_object_tree_close(tree2);
3540 44392932 2019-08-25 stsp return err;
3541 44392932 2019-08-25 stsp }
3542 44392932 2019-08-25 stsp
3543 44392932 2019-08-25 stsp static const struct got_error *
3544 0208f208 2020-05-05 stsp get_changed_paths(struct got_pathlist_head *paths,
3545 0208f208 2020-05-05 stsp struct got_commit_object *commit, struct got_repository *repo)
3546 0208f208 2020-05-05 stsp {
3547 0208f208 2020-05-05 stsp const struct got_error *err = NULL;
3548 0208f208 2020-05-05 stsp struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3549 0208f208 2020-05-05 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3550 0208f208 2020-05-05 stsp struct got_object_qid *qid;
3551 0208f208 2020-05-05 stsp
3552 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3553 0208f208 2020-05-05 stsp if (qid != NULL) {
3554 0208f208 2020-05-05 stsp struct got_commit_object *pcommit;
3555 0208f208 2020-05-05 stsp err = got_object_open_as_commit(&pcommit, repo,
3556 d7b5a0e8 2022-04-20 stsp &qid->id);
3557 0208f208 2020-05-05 stsp if (err)
3558 0208f208 2020-05-05 stsp return err;
3559 0208f208 2020-05-05 stsp
3560 aa8b5dd0 2021-08-01 stsp tree_id1 = got_object_id_dup(
3561 aa8b5dd0 2021-08-01 stsp got_object_commit_get_tree_id(pcommit));
3562 aa8b5dd0 2021-08-01 stsp if (tree_id1 == NULL) {
3563 aa8b5dd0 2021-08-01 stsp got_object_commit_close(pcommit);
3564 aa8b5dd0 2021-08-01 stsp return got_error_from_errno("got_object_id_dup");
3565 aa8b5dd0 2021-08-01 stsp }
3566 0208f208 2020-05-05 stsp got_object_commit_close(pcommit);
3567 0208f208 2020-05-05 stsp
3568 0208f208 2020-05-05 stsp }
3569 0208f208 2020-05-05 stsp
3570 0208f208 2020-05-05 stsp if (tree_id1) {
3571 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
3572 0208f208 2020-05-05 stsp if (err)
3573 0208f208 2020-05-05 stsp goto done;
3574 0208f208 2020-05-05 stsp }
3575 0208f208 2020-05-05 stsp
3576 0208f208 2020-05-05 stsp tree_id2 = got_object_commit_get_tree_id(commit);
3577 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
3578 0208f208 2020-05-05 stsp if (err)
3579 0208f208 2020-05-05 stsp goto done;
3580 0208f208 2020-05-05 stsp
3581 0208f208 2020-05-05 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
3582 0208f208 2020-05-05 stsp got_diff_tree_collect_changed_paths, paths, 0);
3583 0208f208 2020-05-05 stsp done:
3584 0208f208 2020-05-05 stsp if (tree1)
3585 0208f208 2020-05-05 stsp got_object_tree_close(tree1);
3586 0208f208 2020-05-05 stsp if (tree2)
3587 0208f208 2020-05-05 stsp got_object_tree_close(tree2);
3588 aa8b5dd0 2021-08-01 stsp free(tree_id1);
3589 0208f208 2020-05-05 stsp return err;
3590 0208f208 2020-05-05 stsp }
3591 0208f208 2020-05-05 stsp
3592 0208f208 2020-05-05 stsp static const struct got_error *
3593 44392932 2019-08-25 stsp print_patch(struct got_commit_object *commit, struct got_object_id *id,
3594 44392932 2019-08-25 stsp const char *path, int diff_context, struct got_repository *repo)
3595 44392932 2019-08-25 stsp {
3596 44392932 2019-08-25 stsp const struct got_error *err = NULL;
3597 44392932 2019-08-25 stsp struct got_commit_object *pcommit = NULL;
3598 44392932 2019-08-25 stsp char *id_str1 = NULL, *id_str2 = NULL;
3599 44392932 2019-08-25 stsp struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL;
3600 44392932 2019-08-25 stsp struct got_object_qid *qid;
3601 44392932 2019-08-25 stsp
3602 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3603 44392932 2019-08-25 stsp if (qid != NULL) {
3604 44392932 2019-08-25 stsp err = got_object_open_as_commit(&pcommit, repo,
3605 d7b5a0e8 2022-04-20 stsp &qid->id);
3606 44392932 2019-08-25 stsp if (err)
3607 44392932 2019-08-25 stsp return err;
3608 44392932 2019-08-25 stsp }
3609 44392932 2019-08-25 stsp
3610 44392932 2019-08-25 stsp if (path && path[0] != '\0') {
3611 44392932 2019-08-25 stsp int obj_type;
3612 a44927cc 2022-04-07 stsp err = got_object_id_by_path(&obj_id2, repo, commit, path);
3613 44392932 2019-08-25 stsp if (err)
3614 44392932 2019-08-25 stsp goto done;
3615 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
3616 44392932 2019-08-25 stsp if (err) {
3617 44392932 2019-08-25 stsp free(obj_id2);
3618 44392932 2019-08-25 stsp goto done;
3619 44392932 2019-08-25 stsp }
3620 44392932 2019-08-25 stsp if (pcommit) {
3621 44392932 2019-08-25 stsp err = got_object_id_by_path(&obj_id1, repo,
3622 a44927cc 2022-04-07 stsp pcommit, path);
3623 44392932 2019-08-25 stsp if (err) {
3624 2e8c69d1 2020-05-04 stsp if (err->code != GOT_ERR_NO_TREE_ENTRY) {
3625 2e8c69d1 2020-05-04 stsp free(obj_id2);
3626 2e8c69d1 2020-05-04 stsp goto done;
3627 2e8c69d1 2020-05-04 stsp }
3628 2e8c69d1 2020-05-04 stsp } else {
3629 2e8c69d1 2020-05-04 stsp err = got_object_id_str(&id_str1, obj_id1);
3630 2e8c69d1 2020-05-04 stsp if (err) {
3631 2e8c69d1 2020-05-04 stsp free(obj_id2);
3632 2e8c69d1 2020-05-04 stsp goto done;
3633 2e8c69d1 2020-05-04 stsp }
3634 44392932 2019-08-25 stsp }
3635 44392932 2019-08-25 stsp }
3636 44392932 2019-08-25 stsp err = got_object_get_type(&obj_type, repo, obj_id2);
3637 44392932 2019-08-25 stsp if (err) {
3638 44392932 2019-08-25 stsp free(obj_id2);
3639 44392932 2019-08-25 stsp goto done;
3640 44392932 2019-08-25 stsp }
3641 44392932 2019-08-25 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3642 44392932 2019-08-25 stsp switch (obj_type) {
3643 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_BLOB:
3644 44392932 2019-08-25 stsp err = diff_blobs(obj_id1, obj_id2, path, diff_context,
3645 64453f7e 2020-11-21 stsp 0, 0, repo);
3646 44392932 2019-08-25 stsp break;
3647 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_TREE:
3648 44392932 2019-08-25 stsp err = diff_trees(obj_id1, obj_id2, path, diff_context,
3649 64453f7e 2020-11-21 stsp 0, 0, repo);
3650 44392932 2019-08-25 stsp break;
3651 44392932 2019-08-25 stsp default:
3652 44392932 2019-08-25 stsp err = got_error(GOT_ERR_OBJ_TYPE);
3653 44392932 2019-08-25 stsp break;
3654 44392932 2019-08-25 stsp }
3655 44392932 2019-08-25 stsp free(obj_id1);
3656 44392932 2019-08-25 stsp free(obj_id2);
3657 44392932 2019-08-25 stsp } else {
3658 44392932 2019-08-25 stsp obj_id2 = got_object_commit_get_tree_id(commit);
3659 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
3660 44392932 2019-08-25 stsp if (err)
3661 44392932 2019-08-25 stsp goto done;
3662 579bd556 2020-10-24 stsp if (pcommit) {
3663 579bd556 2020-10-24 stsp obj_id1 = got_object_commit_get_tree_id(pcommit);
3664 579bd556 2020-10-24 stsp err = got_object_id_str(&id_str1, obj_id1);
3665 579bd556 2020-10-24 stsp if (err)
3666 579bd556 2020-10-24 stsp goto done;
3667 579bd556 2020-10-24 stsp }
3668 64453f7e 2020-11-21 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null",
3669 64453f7e 2020-11-21 stsp id_str2);
3670 64453f7e 2020-11-21 stsp err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
3671 64453f7e 2020-11-21 stsp repo);
3672 44392932 2019-08-25 stsp }
3673 44392932 2019-08-25 stsp done:
3674 0f2b3dca 2018-12-22 stsp free(id_str1);
3675 0f2b3dca 2018-12-22 stsp free(id_str2);
3676 44392932 2019-08-25 stsp if (pcommit)
3677 44392932 2019-08-25 stsp got_object_commit_close(pcommit);
3678 79109fed 2018-03-27 stsp return err;
3679 79109fed 2018-03-27 stsp }
3680 79109fed 2018-03-27 stsp
3681 4bb494d5 2018-06-16 stsp static char *
3682 6c281f94 2018-06-11 stsp get_datestr(time_t *time, char *datebuf)
3683 6c281f94 2018-06-11 stsp {
3684 09867e48 2019-08-13 stsp struct tm mytm, *tm;
3685 09867e48 2019-08-13 stsp char *p, *s;
3686 09867e48 2019-08-13 stsp
3687 09867e48 2019-08-13 stsp tm = gmtime_r(time, &mytm);
3688 09867e48 2019-08-13 stsp if (tm == NULL)
3689 09867e48 2019-08-13 stsp return NULL;
3690 09867e48 2019-08-13 stsp s = asctime_r(tm, datebuf);
3691 09867e48 2019-08-13 stsp if (s == NULL)
3692 09867e48 2019-08-13 stsp return NULL;
3693 6c281f94 2018-06-11 stsp p = strchr(s, '\n');
3694 6c281f94 2018-06-11 stsp if (p)
3695 6c281f94 2018-06-11 stsp *p = '\0';
3696 6c281f94 2018-06-11 stsp return s;
3697 6c281f94 2018-06-11 stsp }
3698 dc424a06 2019-08-07 stsp
3699 6841bf13 2019-11-29 kn static const struct got_error *
3700 6841bf13 2019-11-29 kn match_logmsg(int *have_match, struct got_object_id *id,
3701 6841bf13 2019-11-29 kn struct got_commit_object *commit, regex_t *regex)
3702 6841bf13 2019-11-29 kn {
3703 6841bf13 2019-11-29 kn const struct got_error *err = NULL;
3704 6841bf13 2019-11-29 kn regmatch_t regmatch;
3705 6841bf13 2019-11-29 kn char *id_str = NULL, *logmsg = NULL;
3706 6841bf13 2019-11-29 kn
3707 6841bf13 2019-11-29 kn *have_match = 0;
3708 6841bf13 2019-11-29 kn
3709 6841bf13 2019-11-29 kn err = got_object_id_str(&id_str, id);
3710 6841bf13 2019-11-29 kn if (err)
3711 6841bf13 2019-11-29 kn return err;
3712 6841bf13 2019-11-29 kn
3713 6841bf13 2019-11-29 kn err = got_object_commit_get_logmsg(&logmsg, commit);
3714 6841bf13 2019-11-29 kn if (err)
3715 6841bf13 2019-11-29 kn goto done;
3716 6841bf13 2019-11-29 kn
3717 6841bf13 2019-11-29 kn if (regexec(regex, logmsg, 1, &regmatch, 0) == 0)
3718 6841bf13 2019-11-29 kn *have_match = 1;
3719 6841bf13 2019-11-29 kn done:
3720 6841bf13 2019-11-29 kn free(id_str);
3721 6841bf13 2019-11-29 kn free(logmsg);
3722 6841bf13 2019-11-29 kn return err;
3723 6841bf13 2019-11-29 kn }
3724 6841bf13 2019-11-29 kn
3725 0208f208 2020-05-05 stsp static void
3726 0208f208 2020-05-05 stsp match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3727 0208f208 2020-05-05 stsp regex_t *regex)
3728 0208f208 2020-05-05 stsp {
3729 0208f208 2020-05-05 stsp regmatch_t regmatch;
3730 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3731 0208f208 2020-05-05 stsp
3732 0208f208 2020-05-05 stsp *have_match = 0;
3733 0208f208 2020-05-05 stsp
3734 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3735 0208f208 2020-05-05 stsp if (regexec(regex, pe->path, 1, &regmatch, 0) == 0) {
3736 0208f208 2020-05-05 stsp *have_match = 1;
3737 0208f208 2020-05-05 stsp break;
3738 0208f208 2020-05-05 stsp }
3739 0208f208 2020-05-05 stsp }
3740 0208f208 2020-05-05 stsp }
3741 0208f208 2020-05-05 stsp
3742 dc424a06 2019-08-07 stsp #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3743 6c281f94 2018-06-11 stsp
3744 888b7d99 2020-12-26 stsp static const struct got_error*
3745 888b7d99 2020-12-26 stsp build_refs_str(char **refs_str, struct got_reflist_head *refs,
3746 888b7d99 2020-12-26 stsp struct got_object_id *id, struct got_repository *repo)
3747 888b7d99 2020-12-26 stsp {
3748 888b7d99 2020-12-26 stsp static const struct got_error *err = NULL;
3749 199a4027 2019-02-02 stsp struct got_reflist_entry *re;
3750 888b7d99 2020-12-26 stsp char *s;
3751 888b7d99 2020-12-26 stsp const char *name;
3752 5c860e29 2018-03-12 stsp
3753 888b7d99 2020-12-26 stsp *refs_str = NULL;
3754 888b7d99 2020-12-26 stsp
3755 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, refs, entry) {
3756 a436ad14 2019-08-13 stsp struct got_tag_object *tag = NULL;
3757 48cae60d 2020-09-22 stsp struct got_object_id *ref_id;
3758 a436ad14 2019-08-13 stsp int cmp;
3759 a436ad14 2019-08-13 stsp
3760 199a4027 2019-02-02 stsp name = got_ref_get_name(re->ref);
3761 d9498b20 2019-02-05 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
3762 d9498b20 2019-02-05 stsp continue;
3763 199a4027 2019-02-02 stsp if (strncmp(name, "refs/", 5) == 0)
3764 199a4027 2019-02-02 stsp name += 5;
3765 7143d404 2019-03-12 stsp if (strncmp(name, "got/", 4) == 0)
3766 7143d404 2019-03-12 stsp continue;
3767 e34f9ed6 2019-02-02 stsp if (strncmp(name, "heads/", 6) == 0)
3768 e34f9ed6 2019-02-02 stsp name += 6;
3769 4343a07f 2020-04-24 stsp if (strncmp(name, "remotes/", 8) == 0) {
3770 141c2bff 2019-02-04 stsp name += 8;
3771 4343a07f 2020-04-24 stsp s = strstr(name, "/" GOT_REF_HEAD);
3772 4343a07f 2020-04-24 stsp if (s != NULL && s[strlen(s)] == '\0')
3773 4343a07f 2020-04-24 stsp continue;
3774 4343a07f 2020-04-24 stsp }
3775 48cae60d 2020-09-22 stsp err = got_ref_resolve(&ref_id, repo, re->ref);
3776 48cae60d 2020-09-22 stsp if (err)
3777 888b7d99 2020-12-26 stsp break;
3778 a436ad14 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
3779 48cae60d 2020-09-22 stsp err = got_object_open_as_tag(&tag, repo, ref_id);
3780 5d844a1e 2019-08-13 stsp if (err) {
3781 48cae60d 2020-09-22 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
3782 48cae60d 2020-09-22 stsp free(ref_id);
3783 888b7d99 2020-12-26 stsp break;
3784 48cae60d 2020-09-22 stsp }
3785 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
3786 5d844a1e 2019-08-13 stsp err = NULL;
3787 5d844a1e 2019-08-13 stsp tag = NULL;
3788 5d844a1e 2019-08-13 stsp }
3789 a436ad14 2019-08-13 stsp }
3790 a436ad14 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
3791 48cae60d 2020-09-22 stsp got_object_tag_get_object_id(tag) : ref_id, id);
3792 48cae60d 2020-09-22 stsp free(ref_id);
3793 a436ad14 2019-08-13 stsp if (tag)
3794 a436ad14 2019-08-13 stsp got_object_tag_close(tag);
3795 a436ad14 2019-08-13 stsp if (cmp != 0)
3796 a436ad14 2019-08-13 stsp continue;
3797 888b7d99 2020-12-26 stsp s = *refs_str;
3798 888b7d99 2020-12-26 stsp if (asprintf(refs_str, "%s%s%s", s ? s : "",
3799 888b7d99 2020-12-26 stsp s ? ", " : "", name) == -1) {
3800 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
3801 199a4027 2019-02-02 stsp free(s);
3802 888b7d99 2020-12-26 stsp *refs_str = NULL;
3803 888b7d99 2020-12-26 stsp break;
3804 199a4027 2019-02-02 stsp }
3805 199a4027 2019-02-02 stsp free(s);
3806 199a4027 2019-02-02 stsp }
3807 888b7d99 2020-12-26 stsp
3808 888b7d99 2020-12-26 stsp return err;
3809 888b7d99 2020-12-26 stsp }
3810 888b7d99 2020-12-26 stsp
3811 888b7d99 2020-12-26 stsp static const struct got_error *
3812 888b7d99 2020-12-26 stsp print_commit(struct got_commit_object *commit, struct got_object_id *id,
3813 888b7d99 2020-12-26 stsp struct got_repository *repo, const char *path,
3814 888b7d99 2020-12-26 stsp struct got_pathlist_head *changed_paths, int show_patch,
3815 e600f124 2021-03-21 stsp int diff_context, struct got_reflist_object_id_map *refs_idmap,
3816 e600f124 2021-03-21 stsp const char *custom_refs_str)
3817 888b7d99 2020-12-26 stsp {
3818 888b7d99 2020-12-26 stsp const struct got_error *err = NULL;
3819 888b7d99 2020-12-26 stsp char *id_str, *datestr, *logmsg0, *logmsg, *line;
3820 888b7d99 2020-12-26 stsp char datebuf[26];
3821 888b7d99 2020-12-26 stsp time_t committer_time;
3822 888b7d99 2020-12-26 stsp const char *author, *committer;
3823 888b7d99 2020-12-26 stsp char *refs_str = NULL;
3824 888b7d99 2020-12-26 stsp
3825 832c249c 2018-06-10 stsp err = got_object_id_str(&id_str, id);
3826 8bf5b3c9 2018-03-17 stsp if (err)
3827 8bf5b3c9 2018-03-17 stsp return err;
3828 788c352e 2018-06-16 stsp
3829 e600f124 2021-03-21 stsp if (custom_refs_str == NULL) {
3830 e600f124 2021-03-21 stsp struct got_reflist_head *refs;
3831 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3832 e600f124 2021-03-21 stsp if (refs) {
3833 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, id, repo);
3834 e600f124 2021-03-21 stsp if (err)
3835 e600f124 2021-03-21 stsp goto done;
3836 e600f124 2021-03-21 stsp }
3837 888b7d99 2020-12-26 stsp }
3838 888b7d99 2020-12-26 stsp
3839 dc424a06 2019-08-07 stsp printf(GOT_COMMIT_SEP_STR);
3840 e600f124 2021-03-21 stsp if (custom_refs_str)
3841 e600f124 2021-03-21 stsp printf("commit %s (%s)\n", id_str, custom_refs_str);
3842 e600f124 2021-03-21 stsp else
3843 e600f124 2021-03-21 stsp printf("commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
3844 e600f124 2021-03-21 stsp refs_str ? refs_str : "", refs_str ? ")" : "");
3845 832c249c 2018-06-10 stsp free(id_str);
3846 d3d493d7 2019-02-21 stsp id_str = NULL;
3847 d3d493d7 2019-02-21 stsp free(refs_str);
3848 d3d493d7 2019-02-21 stsp refs_str = NULL;
3849 45d799e2 2018-12-23 stsp printf("from: %s\n", got_object_commit_get_author(commit));
3850 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
3851 45d799e2 2018-12-23 stsp datestr = get_datestr(&committer_time, datebuf);
3852 09867e48 2019-08-13 stsp if (datestr)
3853 09867e48 2019-08-13 stsp printf("date: %s UTC\n", datestr);
3854 45d799e2 2018-12-23 stsp author = got_object_commit_get_author(commit);
3855 45d799e2 2018-12-23 stsp committer = got_object_commit_get_committer(commit);
3856 45d799e2 2018-12-23 stsp if (strcmp(author, committer) != 0)
3857 45d799e2 2018-12-23 stsp printf("via: %s\n", committer);
3858 45d799e2 2018-12-23 stsp if (got_object_commit_get_nparents(commit) > 1) {
3859 45d799e2 2018-12-23 stsp const struct got_object_id_queue *parent_ids;
3860 79f35eb3 2018-06-11 stsp struct got_object_qid *qid;
3861 3fe1abad 2018-06-10 stsp int n = 1;
3862 45d799e2 2018-12-23 stsp parent_ids = got_object_commit_get_parent_ids(commit);
3863 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, parent_ids, entry) {
3864 d7b5a0e8 2022-04-20 stsp err = got_object_id_str(&id_str, &qid->id);
3865 a0603db2 2018-06-10 stsp if (err)
3866 888b7d99 2020-12-26 stsp goto done;
3867 3fe1abad 2018-06-10 stsp printf("parent %d: %s\n", n++, id_str);
3868 a0603db2 2018-06-10 stsp free(id_str);
3869 888b7d99 2020-12-26 stsp id_str = NULL;
3870 a0603db2 2018-06-10 stsp }
3871 a0603db2 2018-06-10 stsp }
3872 832c249c 2018-06-10 stsp
3873 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
3874 5943eee2 2019-08-13 stsp if (err)
3875 888b7d99 2020-12-26 stsp goto done;
3876 8bf5b3c9 2018-03-17 stsp
3877 621015ac 2018-07-23 stsp logmsg = logmsg0;
3878 832c249c 2018-06-10 stsp do {
3879 832c249c 2018-06-10 stsp line = strsep(&logmsg, "\n");
3880 832c249c 2018-06-10 stsp if (line)
3881 832c249c 2018-06-10 stsp printf(" %s\n", line);
3882 832c249c 2018-06-10 stsp } while (line);
3883 621015ac 2018-07-23 stsp free(logmsg0);
3884 832c249c 2018-06-10 stsp
3885 0208f208 2020-05-05 stsp if (changed_paths) {
3886 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3887 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3888 0208f208 2020-05-05 stsp struct got_diff_changed_path *cp = pe->data;
3889 0208f208 2020-05-05 stsp printf(" %c %s\n", cp->status, pe->path);
3890 0208f208 2020-05-05 stsp }
3891 0208f208 2020-05-05 stsp printf("\n");
3892 0208f208 2020-05-05 stsp }
3893 971751ac 2018-03-27 stsp if (show_patch) {
3894 44392932 2019-08-25 stsp err = print_patch(commit, id, path, diff_context, repo);
3895 971751ac 2018-03-27 stsp if (err == 0)
3896 971751ac 2018-03-27 stsp printf("\n");
3897 971751ac 2018-03-27 stsp }
3898 07862c20 2018-09-15 stsp
3899 cbe7f848 2019-02-11 stsp if (fflush(stdout) != 0 && err == NULL)
3900 638f9024 2019-05-13 stsp err = got_error_from_errno("fflush");
3901 888b7d99 2020-12-26 stsp done:
3902 888b7d99 2020-12-26 stsp free(id_str);
3903 888b7d99 2020-12-26 stsp free(refs_str);
3904 07862c20 2018-09-15 stsp return err;
3905 f42b1b34 2018-03-12 stsp }
3906 5c860e29 2018-03-12 stsp
3907 f42b1b34 2018-03-12 stsp static const struct got_error *
3908 d1fe46f9 2020-04-18 stsp print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
3909 0208f208 2020-05-05 stsp struct got_repository *repo, const char *path, int show_changed_paths,
3910 0208f208 2020-05-05 stsp int show_patch, const char *search_pattern, int diff_context, int limit,
3911 888b7d99 2020-12-26 stsp int log_branches, int reverse_display_order,
3912 888b7d99 2020-12-26 stsp struct got_reflist_object_id_map *refs_idmap)
3913 f42b1b34 2018-03-12 stsp {
3914 f42b1b34 2018-03-12 stsp const struct got_error *err;
3915 372ccdbb 2018-06-10 stsp struct got_commit_graph *graph;
3916 6841bf13 2019-11-29 kn regex_t regex;
3917 6841bf13 2019-11-29 kn int have_match;
3918 dbec59df 2020-04-18 stsp struct got_object_id_queue reversed_commits;
3919 dbec59df 2020-04-18 stsp struct got_object_qid *qid;
3920 dbec59df 2020-04-18 stsp struct got_commit_object *commit;
3921 0208f208 2020-05-05 stsp struct got_pathlist_head changed_paths;
3922 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3923 dbec59df 2020-04-18 stsp
3924 dbdddfee 2021-06-23 naddy STAILQ_INIT(&reversed_commits);
3925 0208f208 2020-05-05 stsp TAILQ_INIT(&changed_paths);
3926 372ccdbb 2018-06-10 stsp
3927 ccecc9fd 2020-04-18 stsp if (search_pattern && regcomp(&regex, search_pattern,
3928 ccecc9fd 2020-04-18 stsp REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
3929 6841bf13 2019-11-29 kn return got_error_msg(GOT_ERR_REGEX, search_pattern);
3930 6841bf13 2019-11-29 kn
3931 48c8c60d 2020-01-27 stsp err = got_commit_graph_open(&graph, path, !log_branches);
3932 f42b1b34 2018-03-12 stsp if (err)
3933 f42b1b34 2018-03-12 stsp return err;
3934 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, root_id, repo,
3935 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
3936 372ccdbb 2018-06-10 stsp if (err)
3937 fcc85cad 2018-07-22 stsp goto done;
3938 656b1f76 2019-05-11 jcs for (;;) {
3939 372ccdbb 2018-06-10 stsp struct got_object_id *id;
3940 8bf5b3c9 2018-03-17 stsp
3941 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
3942 84453469 2018-11-11 stsp break;
3943 84453469 2018-11-11 stsp
3944 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&id, graph, repo,
3945 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
3946 372ccdbb 2018-06-10 stsp if (err) {
3947 ee780d5c 2020-01-04 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
3948 9ba79e04 2018-06-11 stsp err = NULL;
3949 ee780d5c 2020-01-04 stsp break;
3950 7e665116 2018-04-02 stsp }
3951 b43fbaa0 2018-06-11 stsp if (id == NULL)
3952 7e665116 2018-04-02 stsp break;
3953 b43fbaa0 2018-06-11 stsp
3954 f8e900f3 2018-06-11 stsp err = got_object_open_as_commit(&commit, repo, id);
3955 b43fbaa0 2018-06-11 stsp if (err)
3956 fcc85cad 2018-07-22 stsp break;
3957 6841bf13 2019-11-29 kn
3958 502b9684 2020-07-31 stsp if (show_changed_paths && !reverse_display_order) {
3959 0208f208 2020-05-05 stsp err = get_changed_paths(&changed_paths, commit, repo);
3960 0208f208 2020-05-05 stsp if (err)
3961 0208f208 2020-05-05 stsp break;
3962 0208f208 2020-05-05 stsp }
3963 0208f208 2020-05-05 stsp
3964 6841bf13 2019-11-29 kn if (search_pattern) {
3965 6841bf13 2019-11-29 kn err = match_logmsg(&have_match, id, commit, &regex);
3966 6841bf13 2019-11-29 kn if (err) {
3967 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3968 6841bf13 2019-11-29 kn break;
3969 6841bf13 2019-11-29 kn }
3970 0208f208 2020-05-05 stsp if (have_match == 0 && show_changed_paths)
3971 0208f208 2020-05-05 stsp match_changed_paths(&have_match,
3972 0208f208 2020-05-05 stsp &changed_paths, &regex);
3973 6841bf13 2019-11-29 kn if (have_match == 0) {
3974 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3975 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3976 0208f208 2020-05-05 stsp free((char *)pe->path);
3977 0208f208 2020-05-05 stsp free(pe->data);
3978 0208f208 2020-05-05 stsp }
3979 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3980 6841bf13 2019-11-29 kn continue;
3981 6841bf13 2019-11-29 kn }
3982 6841bf13 2019-11-29 kn }
3983 6841bf13 2019-11-29 kn
3984 dbec59df 2020-04-18 stsp if (reverse_display_order) {
3985 dbec59df 2020-04-18 stsp err = got_object_qid_alloc(&qid, id);
3986 dbec59df 2020-04-18 stsp if (err)
3987 dbec59df 2020-04-18 stsp break;
3988 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(&reversed_commits, qid, entry);
3989 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3990 dbec59df 2020-04-18 stsp } else {
3991 0208f208 2020-05-05 stsp err = print_commit(commit, id, repo, path,
3992 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
3993 e600f124 2021-03-21 stsp show_patch, diff_context, refs_idmap, NULL);
3994 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3995 dbec59df 2020-04-18 stsp if (err)
3996 dbec59df 2020-04-18 stsp break;
3997 dbec59df 2020-04-18 stsp }
3998 dbec59df 2020-04-18 stsp if ((limit && --limit == 0) ||
3999 dbec59df 2020-04-18 stsp (end_id && got_object_id_cmp(id, end_id) == 0))
4000 7e665116 2018-04-02 stsp break;
4001 0208f208 2020-05-05 stsp
4002 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
4003 0208f208 2020-05-05 stsp free((char *)pe->path);
4004 0208f208 2020-05-05 stsp free(pe->data);
4005 0208f208 2020-05-05 stsp }
4006 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
4007 31cedeaf 2018-09-15 stsp }
4008 dbec59df 2020-04-18 stsp if (reverse_display_order) {
4009 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, &reversed_commits, entry) {
4010 d7b5a0e8 2022-04-20 stsp err = got_object_open_as_commit(&commit, repo,
4011 d7b5a0e8 2022-04-20 stsp &qid->id);
4012 dbec59df 2020-04-18 stsp if (err)
4013 dbec59df 2020-04-18 stsp break;
4014 502b9684 2020-07-31 stsp if (show_changed_paths) {
4015 502b9684 2020-07-31 stsp err = get_changed_paths(&changed_paths,
4016 502b9684 2020-07-31 stsp commit, repo);
4017 502b9684 2020-07-31 stsp if (err)
4018 502b9684 2020-07-31 stsp break;
4019 502b9684 2020-07-31 stsp }
4020 d7b5a0e8 2022-04-20 stsp err = print_commit(commit, &qid->id, repo, path,
4021 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
4022 e600f124 2021-03-21 stsp show_patch, diff_context, refs_idmap, NULL);
4023 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
4024 dbec59df 2020-04-18 stsp if (err)
4025 dbec59df 2020-04-18 stsp break;
4026 502b9684 2020-07-31 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
4027 502b9684 2020-07-31 stsp free((char *)pe->path);
4028 502b9684 2020-07-31 stsp free(pe->data);
4029 502b9684 2020-07-31 stsp }
4030 502b9684 2020-07-31 stsp got_pathlist_free(&changed_paths);
4031 dbec59df 2020-04-18 stsp }
4032 dbec59df 2020-04-18 stsp }
4033 fcc85cad 2018-07-22 stsp done:
4034 dbdddfee 2021-06-23 naddy while (!STAILQ_EMPTY(&reversed_commits)) {
4035 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(&reversed_commits);
4036 dbdddfee 2021-06-23 naddy STAILQ_REMOVE_HEAD(&reversed_commits, entry);
4037 dbec59df 2020-04-18 stsp got_object_qid_free(qid);
4038 dbec59df 2020-04-18 stsp }
4039 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
4040 0208f208 2020-05-05 stsp free((char *)pe->path);
4041 0208f208 2020-05-05 stsp free(pe->data);
4042 0208f208 2020-05-05 stsp }
4043 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
4044 6841bf13 2019-11-29 kn if (search_pattern)
4045 6841bf13 2019-11-29 kn regfree(&regex);
4046 372ccdbb 2018-06-10 stsp got_commit_graph_close(graph);
4047 f42b1b34 2018-03-12 stsp return err;
4048 f42b1b34 2018-03-12 stsp }
4049 5c860e29 2018-03-12 stsp
4050 4ed7e80c 2018-05-20 stsp __dead static void
4051 6f3d1eb0 2018-03-12 stsp usage_log(void)
4052 6f3d1eb0 2018-03-12 stsp {
4053 d1fe46f9 2020-04-18 stsp fprintf(stderr, "usage: %s log [-b] [-c commit] [-C number] [ -l N ] "
4054 0208f208 2020-05-05 stsp "[-p] [-P] [-x commit] [-s search-pattern] [-r repository-path] "
4055 0208f208 2020-05-05 stsp "[-R] [path]\n", getprogname());
4056 6f3d1eb0 2018-03-12 stsp exit(1);
4057 b1ebc001 2019-08-13 stsp }
4058 b1ebc001 2019-08-13 stsp
4059 b1ebc001 2019-08-13 stsp static int
4060 b1ebc001 2019-08-13 stsp get_default_log_limit(void)
4061 b1ebc001 2019-08-13 stsp {
4062 b1ebc001 2019-08-13 stsp const char *got_default_log_limit;
4063 b1ebc001 2019-08-13 stsp long long n;
4064 b1ebc001 2019-08-13 stsp const char *errstr;
4065 b1ebc001 2019-08-13 stsp
4066 b1ebc001 2019-08-13 stsp got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
4067 b1ebc001 2019-08-13 stsp if (got_default_log_limit == NULL)
4068 b1ebc001 2019-08-13 stsp return 0;
4069 b1ebc001 2019-08-13 stsp n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr);
4070 b1ebc001 2019-08-13 stsp if (errstr != NULL)
4071 b1ebc001 2019-08-13 stsp return 0;
4072 b1ebc001 2019-08-13 stsp return n;
4073 6f3d1eb0 2018-03-12 stsp }
4074 6f3d1eb0 2018-03-12 stsp
4075 4ed7e80c 2018-05-20 stsp static const struct got_error *
4076 f42b1b34 2018-03-12 stsp cmd_log(int argc, char *argv[])
4077 f42b1b34 2018-03-12 stsp {
4078 f42b1b34 2018-03-12 stsp const struct got_error *error;
4079 04ca23f4 2018-07-16 stsp struct got_repository *repo = NULL;
4080 cffc0aa4 2019-02-05 stsp struct got_worktree *worktree = NULL;
4081 d1fe46f9 2020-04-18 stsp struct got_object_id *start_id = NULL, *end_id = NULL;
4082 04ca23f4 2018-07-16 stsp char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
4083 d1fe46f9 2020-04-18 stsp const char *start_commit = NULL, *end_commit = NULL;
4084 d1fe46f9 2020-04-18 stsp const char *search_pattern = NULL;
4085 dc1edbfa 2019-11-29 kn int diff_context = -1, ch;
4086 0208f208 2020-05-05 stsp int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
4087 dbec59df 2020-04-18 stsp int reverse_display_order = 0;
4088 64a96a6d 2018-04-01 stsp const char *errstr;
4089 199a4027 2019-02-02 stsp struct got_reflist_head refs;
4090 888b7d99 2020-12-26 stsp struct got_reflist_object_id_map *refs_idmap = NULL;
4091 1b3893a2 2019-03-18 stsp
4092 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
4093 5c860e29 2018-03-12 stsp
4094 6715a751 2018-03-16 stsp #ifndef PROFILE
4095 6098196c 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4096 6098196c 2019-01-04 stsp NULL)
4097 ad242220 2018-09-08 stsp == -1)
4098 f42b1b34 2018-03-12 stsp err(1, "pledge");
4099 6715a751 2018-03-16 stsp #endif
4100 79109fed 2018-03-27 stsp
4101 b1ebc001 2019-08-13 stsp limit = get_default_log_limit();
4102 b1ebc001 2019-08-13 stsp
4103 0208f208 2020-05-05 stsp while ((ch = getopt(argc, argv, "bpPc:C:l:r:Rs:x:")) != -1) {
4104 79109fed 2018-03-27 stsp switch (ch) {
4105 79109fed 2018-03-27 stsp case 'p':
4106 79109fed 2018-03-27 stsp show_patch = 1;
4107 d142fc45 2018-04-01 stsp break;
4108 0208f208 2020-05-05 stsp case 'P':
4109 0208f208 2020-05-05 stsp show_changed_paths = 1;
4110 0208f208 2020-05-05 stsp break;
4111 d142fc45 2018-04-01 stsp case 'c':
4112 d142fc45 2018-04-01 stsp start_commit = optarg;
4113 64a96a6d 2018-04-01 stsp break;
4114 c0cc5c62 2018-10-18 stsp case 'C':
4115 4a8520aa 2018-10-18 stsp diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4116 4a8520aa 2018-10-18 stsp &errstr);
4117 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
4118 5a20d08d 2022-02-09 op errx(1, "number of context lines is %s: %s",
4119 5a20d08d 2022-02-09 op errstr, optarg);
4120 c0cc5c62 2018-10-18 stsp break;
4121 64a96a6d 2018-04-01 stsp case 'l':
4122 b1ebc001 2019-08-13 stsp limit = strtonum(optarg, 0, INT_MAX, &errstr);
4123 64a96a6d 2018-04-01 stsp if (errstr != NULL)
4124 5a20d08d 2022-02-09 op errx(1, "number of commits is %s: %s",
4125 5a20d08d 2022-02-09 op errstr, optarg);
4126 cc54c501 2019-07-15 stsp break;
4127 48c8c60d 2020-01-27 stsp case 'b':
4128 48c8c60d 2020-01-27 stsp log_branches = 1;
4129 a0603db2 2018-06-10 stsp break;
4130 04ca23f4 2018-07-16 stsp case 'r':
4131 04ca23f4 2018-07-16 stsp repo_path = realpath(optarg, NULL);
4132 04ca23f4 2018-07-16 stsp if (repo_path == NULL)
4133 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4134 9ba1d308 2019-10-21 stsp optarg);
4135 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4136 04ca23f4 2018-07-16 stsp break;
4137 dbec59df 2020-04-18 stsp case 'R':
4138 dbec59df 2020-04-18 stsp reverse_display_order = 1;
4139 dbec59df 2020-04-18 stsp break;
4140 6841bf13 2019-11-29 kn case 's':
4141 6841bf13 2019-11-29 kn search_pattern = optarg;
4142 6841bf13 2019-11-29 kn break;
4143 d1fe46f9 2020-04-18 stsp case 'x':
4144 d1fe46f9 2020-04-18 stsp end_commit = optarg;
4145 d1fe46f9 2020-04-18 stsp break;
4146 79109fed 2018-03-27 stsp default:
4147 2deda0b9 2019-03-07 stsp usage_log();
4148 79109fed 2018-03-27 stsp /* NOTREACHED */
4149 79109fed 2018-03-27 stsp }
4150 79109fed 2018-03-27 stsp }
4151 79109fed 2018-03-27 stsp
4152 79109fed 2018-03-27 stsp argc -= optind;
4153 79109fed 2018-03-27 stsp argv += optind;
4154 f42b1b34 2018-03-12 stsp
4155 dc1edbfa 2019-11-29 kn if (diff_context == -1)
4156 dc1edbfa 2019-11-29 kn diff_context = 3;
4157 dc1edbfa 2019-11-29 kn else if (!show_patch)
4158 0429cd76 2020-09-15 naddy errx(1, "-C requires -p");
4159 dc1edbfa 2019-11-29 kn
4160 04ca23f4 2018-07-16 stsp cwd = getcwd(NULL, 0);
4161 04ca23f4 2018-07-16 stsp if (cwd == NULL) {
4162 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4163 04ca23f4 2018-07-16 stsp goto done;
4164 04ca23f4 2018-07-16 stsp }
4165 cffc0aa4 2019-02-05 stsp
4166 50f2fada 2020-04-24 stsp if (repo_path == NULL) {
4167 50f2fada 2020-04-24 stsp error = got_worktree_open(&worktree, cwd);
4168 50f2fada 2020-04-24 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4169 50f2fada 2020-04-24 stsp goto done;
4170 50f2fada 2020-04-24 stsp error = NULL;
4171 50f2fada 2020-04-24 stsp }
4172 cffc0aa4 2019-02-05 stsp
4173 603cdeb0 2020-10-22 stsp if (argc == 1) {
4174 e7301579 2019-03-18 stsp if (worktree) {
4175 e7301579 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
4176 e7301579 2019-03-18 stsp argv[0]);
4177 e7301579 2019-03-18 stsp if (error)
4178 e7301579 2019-03-18 stsp goto done;
4179 e7301579 2019-03-18 stsp } else {
4180 e7301579 2019-03-18 stsp path = strdup(argv[0]);
4181 e7301579 2019-03-18 stsp if (path == NULL) {
4182 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4183 e7301579 2019-03-18 stsp goto done;
4184 e7301579 2019-03-18 stsp }
4185 e7301579 2019-03-18 stsp }
4186 603cdeb0 2020-10-22 stsp } else if (argc != 0)
4187 cbd1af7a 2019-03-18 stsp usage_log();
4188 cbd1af7a 2019-03-18 stsp
4189 5486daa2 2019-05-11 stsp if (repo_path == NULL) {
4190 5486daa2 2019-05-11 stsp repo_path = worktree ?
4191 5486daa2 2019-05-11 stsp strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
4192 5486daa2 2019-05-11 stsp }
4193 04ca23f4 2018-07-16 stsp if (repo_path == NULL) {
4194 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4195 cffc0aa4 2019-02-05 stsp goto done;
4196 04ca23f4 2018-07-16 stsp }
4197 6098196c 2019-01-04 stsp
4198 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4199 d7d4f210 2018-03-12 stsp if (error != NULL)
4200 04ca23f4 2018-07-16 stsp goto done;
4201 f42b1b34 2018-03-12 stsp
4202 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
4203 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
4204 c02c541e 2019-03-29 stsp if (error)
4205 c02c541e 2019-03-29 stsp goto done;
4206 c02c541e 2019-03-29 stsp
4207 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
4208 84de9106 2020-12-26 stsp if (error)
4209 84de9106 2020-12-26 stsp goto done;
4210 84de9106 2020-12-26 stsp
4211 888b7d99 2020-12-26 stsp error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
4212 888b7d99 2020-12-26 stsp if (error)
4213 888b7d99 2020-12-26 stsp goto done;
4214 888b7d99 2020-12-26 stsp
4215 d142fc45 2018-04-01 stsp if (start_commit == NULL) {
4216 3235492e 2018-04-01 stsp struct got_reference *head_ref;
4217 d1fe46f9 2020-04-18 stsp struct got_commit_object *commit = NULL;
4218 1cc14b9f 2019-05-14 stsp error = got_ref_open(&head_ref, repo,
4219 1cc14b9f 2019-05-14 stsp worktree ? got_worktree_get_head_ref_name(worktree)
4220 1cc14b9f 2019-05-14 stsp : GOT_REF_HEAD, 0);
4221 3235492e 2018-04-01 stsp if (error != NULL)
4222 d1fe46f9 2020-04-18 stsp goto done;
4223 d1fe46f9 2020-04-18 stsp error = got_ref_resolve(&start_id, repo, head_ref);
4224 3235492e 2018-04-01 stsp got_ref_close(head_ref);
4225 3235492e 2018-04-01 stsp if (error != NULL)
4226 d1fe46f9 2020-04-18 stsp goto done;
4227 d1fe46f9 2020-04-18 stsp error = got_object_open_as_commit(&commit, repo,
4228 d1fe46f9 2020-04-18 stsp start_id);
4229 d1fe46f9 2020-04-18 stsp if (error != NULL)
4230 d1fe46f9 2020-04-18 stsp goto done;
4231 d1fe46f9 2020-04-18 stsp got_object_commit_close(commit);
4232 3235492e 2018-04-01 stsp } else {
4233 7f9bfb31 2020-11-01 stsp error = got_repo_match_object_id(&start_id, NULL,
4234 84de9106 2020-12-26 stsp start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4235 d1fe46f9 2020-04-18 stsp if (error != NULL)
4236 d1fe46f9 2020-04-18 stsp goto done;
4237 3235492e 2018-04-01 stsp }
4238 d1fe46f9 2020-04-18 stsp if (end_commit != NULL) {
4239 7f9bfb31 2020-11-01 stsp error = got_repo_match_object_id(&end_id, NULL,
4240 84de9106 2020-12-26 stsp end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4241 d1fe46f9 2020-04-18 stsp if (error != NULL)
4242 d1fe46f9 2020-04-18 stsp goto done;
4243 d1fe46f9 2020-04-18 stsp }
4244 04ca23f4 2018-07-16 stsp
4245 deeabeae 2019-08-27 stsp if (worktree) {
4246 603cdeb0 2020-10-22 stsp /*
4247 603cdeb0 2020-10-22 stsp * If a path was specified on the command line it was resolved
4248 603cdeb0 2020-10-22 stsp * to a path in the work tree above. Prepend the work tree's
4249 603cdeb0 2020-10-22 stsp * path prefix to obtain the corresponding in-repository path.
4250 603cdeb0 2020-10-22 stsp */
4251 603cdeb0 2020-10-22 stsp if (path) {
4252 603cdeb0 2020-10-22 stsp const char *prefix;
4253 603cdeb0 2020-10-22 stsp prefix = got_worktree_get_path_prefix(worktree);
4254 603cdeb0 2020-10-22 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
4255 603cdeb0 2020-10-22 stsp (path[0] != '\0') ? "/" : "", path) == -1) {
4256 603cdeb0 2020-10-22 stsp error = got_error_from_errno("asprintf");
4257 603cdeb0 2020-10-22 stsp goto done;
4258 603cdeb0 2020-10-22 stsp }
4259 603cdeb0 2020-10-22 stsp }
4260 deeabeae 2019-08-27 stsp } else
4261 603cdeb0 2020-10-22 stsp error = got_repo_map_path(&in_repo_path, repo,
4262 8fa913ec 2020-11-14 stsp path ? path : "");
4263 04ca23f4 2018-07-16 stsp if (error != NULL)
4264 04ca23f4 2018-07-16 stsp goto done;
4265 04ca23f4 2018-07-16 stsp if (in_repo_path) {
4266 04ca23f4 2018-07-16 stsp free(path);
4267 04ca23f4 2018-07-16 stsp path = in_repo_path;
4268 04ca23f4 2018-07-16 stsp }
4269 199a4027 2019-02-02 stsp
4270 f7fce2e2 2022-03-12 stsp if (worktree) {
4271 f7fce2e2 2022-03-12 stsp /* Release work tree lock. */
4272 f7fce2e2 2022-03-12 stsp got_worktree_close(worktree);
4273 f7fce2e2 2022-03-12 stsp worktree = NULL;
4274 f7fce2e2 2022-03-12 stsp }
4275 f7fce2e2 2022-03-12 stsp
4276 603cdeb0 2020-10-22 stsp error = print_commits(start_id, end_id, repo, path ? path : "",
4277 603cdeb0 2020-10-22 stsp show_changed_paths, show_patch, search_pattern, diff_context,
4278 888b7d99 2020-12-26 stsp limit, log_branches, reverse_display_order, refs_idmap);
4279 04ca23f4 2018-07-16 stsp done:
4280 04ca23f4 2018-07-16 stsp free(path);
4281 04ca23f4 2018-07-16 stsp free(repo_path);
4282 04ca23f4 2018-07-16 stsp free(cwd);
4283 cffc0aa4 2019-02-05 stsp if (worktree)
4284 cffc0aa4 2019-02-05 stsp got_worktree_close(worktree);
4285 ad242220 2018-09-08 stsp if (repo) {
4286 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
4287 ad242220 2018-09-08 stsp if (error == NULL)
4288 1d0f4054 2021-06-17 stsp error = close_err;
4289 ad242220 2018-09-08 stsp }
4290 888b7d99 2020-12-26 stsp if (refs_idmap)
4291 888b7d99 2020-12-26 stsp got_reflist_object_id_map_free(refs_idmap);
4292 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
4293 8bf5b3c9 2018-03-17 stsp return error;
4294 5c860e29 2018-03-12 stsp }
4295 5c860e29 2018-03-12 stsp
4296 4ed7e80c 2018-05-20 stsp __dead static void
4297 3f8b7d6a 2018-04-01 stsp usage_diff(void)
4298 3f8b7d6a 2018-04-01 stsp {
4299 51ed7429 2021-10-10 stsp fprintf(stderr, "usage: %s diff [-a] [-c commit] [-C number] "
4300 51ed7429 2021-10-10 stsp "[-r repository-path] [-s] [-w] [-P] "
4301 51ed7429 2021-10-10 stsp "[object1 object2 | path ...]\n", getprogname());
4302 3f8b7d6a 2018-04-01 stsp exit(1);
4303 b00d56cd 2018-04-01 stsp }
4304 b00d56cd 2018-04-01 stsp
4305 b72f483a 2019-02-05 stsp struct print_diff_arg {
4306 b72f483a 2019-02-05 stsp struct got_repository *repo;
4307 b72f483a 2019-02-05 stsp struct got_worktree *worktree;
4308 b72f483a 2019-02-05 stsp int diff_context;
4309 3fc0c068 2019-02-10 stsp const char *id_str;
4310 3fc0c068 2019-02-10 stsp int header_shown;
4311 98eaaa12 2019-08-03 stsp int diff_staged;
4312 63035f9f 2019-10-06 stsp int ignore_whitespace;
4313 64453f7e 2020-11-21 stsp int force_text_diff;
4314 b72f483a 2019-02-05 stsp };
4315 39449a05 2020-07-23 stsp
4316 39449a05 2020-07-23 stsp /*
4317 39449a05 2020-07-23 stsp * Create a file which contains the target path of a symlink so we can feed
4318 39449a05 2020-07-23 stsp * it as content to the diff engine.
4319 39449a05 2020-07-23 stsp */
4320 39449a05 2020-07-23 stsp static const struct got_error *
4321 39449a05 2020-07-23 stsp get_symlink_target_file(int *fd, int dirfd, const char *de_name,
4322 39449a05 2020-07-23 stsp const char *abspath)
4323 39449a05 2020-07-23 stsp {
4324 39449a05 2020-07-23 stsp const struct got_error *err = NULL;
4325 39449a05 2020-07-23 stsp char target_path[PATH_MAX];
4326 39449a05 2020-07-23 stsp ssize_t target_len, outlen;
4327 39449a05 2020-07-23 stsp
4328 39449a05 2020-07-23 stsp *fd = -1;
4329 39449a05 2020-07-23 stsp
4330 39449a05 2020-07-23 stsp if (dirfd != -1) {
4331 39449a05 2020-07-23 stsp target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
4332 39449a05 2020-07-23 stsp if (target_len == -1)
4333 39449a05 2020-07-23 stsp return got_error_from_errno2("readlinkat", abspath);
4334 39449a05 2020-07-23 stsp } else {
4335 39449a05 2020-07-23 stsp target_len = readlink(abspath, target_path, PATH_MAX);
4336 39449a05 2020-07-23 stsp if (target_len == -1)
4337 39449a05 2020-07-23 stsp return got_error_from_errno2("readlink", abspath);
4338 39449a05 2020-07-23 stsp }
4339 39449a05 2020-07-23 stsp
4340 39449a05 2020-07-23 stsp *fd = got_opentempfd();
4341 39449a05 2020-07-23 stsp if (*fd == -1)
4342 39449a05 2020-07-23 stsp return got_error_from_errno("got_opentempfd");
4343 39449a05 2020-07-23 stsp
4344 39449a05 2020-07-23 stsp outlen = write(*fd, target_path, target_len);
4345 39449a05 2020-07-23 stsp if (outlen == -1) {
4346 39449a05 2020-07-23 stsp err = got_error_from_errno("got_opentempfd");
4347 39449a05 2020-07-23 stsp goto done;
4348 39449a05 2020-07-23 stsp }
4349 39449a05 2020-07-23 stsp
4350 39449a05 2020-07-23 stsp if (lseek(*fd, 0, SEEK_SET) == -1) {
4351 39449a05 2020-07-23 stsp err = got_error_from_errno2("lseek", abspath);
4352 39449a05 2020-07-23 stsp goto done;
4353 39449a05 2020-07-23 stsp }
4354 39449a05 2020-07-23 stsp done:
4355 39449a05 2020-07-23 stsp if (err) {
4356 39449a05 2020-07-23 stsp close(*fd);
4357 39449a05 2020-07-23 stsp *fd = -1;
4358 39449a05 2020-07-23 stsp }
4359 39449a05 2020-07-23 stsp return err;
4360 39449a05 2020-07-23 stsp }
4361 b72f483a 2019-02-05 stsp
4362 4ed7e80c 2018-05-20 stsp static const struct got_error *
4363 88d0e355 2019-08-03 stsp print_diff(void *arg, unsigned char status, unsigned char staged_status,
4364 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
4365 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4366 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
4367 b72f483a 2019-02-05 stsp {
4368 b72f483a 2019-02-05 stsp struct print_diff_arg *a = arg;
4369 b72f483a 2019-02-05 stsp const struct got_error *err = NULL;
4370 b72f483a 2019-02-05 stsp struct got_blob_object *blob1 = NULL;
4371 12463d8b 2019-12-13 stsp int fd = -1;
4372 b72f483a 2019-02-05 stsp FILE *f2 = NULL;
4373 4ce46740 2019-08-08 stsp char *abspath = NULL, *label1 = NULL;
4374 b72f483a 2019-02-05 stsp struct stat sb;
4375 b72f483a 2019-02-05 stsp
4376 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
4377 98eaaa12 2019-08-03 stsp if (staged_status != GOT_STATUS_MODIFY &&
4378 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_ADD &&
4379 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
4380 98eaaa12 2019-08-03 stsp return NULL;
4381 98eaaa12 2019-08-03 stsp } else {
4382 98eaaa12 2019-08-03 stsp if (staged_status == GOT_STATUS_DELETE)
4383 98eaaa12 2019-08-03 stsp return NULL;
4384 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
4385 2a06fe5f 2019-08-24 stsp return got_error_set_errno(ENOENT, path);
4386 98eaaa12 2019-08-03 stsp if (status != GOT_STATUS_MODIFY &&
4387 98eaaa12 2019-08-03 stsp status != GOT_STATUS_ADD &&
4388 98eaaa12 2019-08-03 stsp status != GOT_STATUS_DELETE &&
4389 98eaaa12 2019-08-03 stsp status != GOT_STATUS_CONFLICT)
4390 98eaaa12 2019-08-03 stsp return NULL;
4391 98eaaa12 2019-08-03 stsp }
4392 3fc0c068 2019-02-10 stsp
4393 3fc0c068 2019-02-10 stsp if (!a->header_shown) {
4394 98eaaa12 2019-08-03 stsp printf("diff %s %s%s\n", a->id_str,
4395 98eaaa12 2019-08-03 stsp got_worktree_get_root_path(a->worktree),
4396 98eaaa12 2019-08-03 stsp a->diff_staged ? " (staged changes)" : "");
4397 3fc0c068 2019-02-10 stsp a->header_shown = 1;
4398 3fc0c068 2019-02-10 stsp }
4399 b72f483a 2019-02-05 stsp
4400 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
4401 98eaaa12 2019-08-03 stsp const char *label1 = NULL, *label2 = NULL;
4402 98eaaa12 2019-08-03 stsp switch (staged_status) {
4403 98eaaa12 2019-08-03 stsp case GOT_STATUS_MODIFY:
4404 98eaaa12 2019-08-03 stsp label1 = path;
4405 98eaaa12 2019-08-03 stsp label2 = path;
4406 98eaaa12 2019-08-03 stsp break;
4407 98eaaa12 2019-08-03 stsp case GOT_STATUS_ADD:
4408 98eaaa12 2019-08-03 stsp label2 = path;
4409 98eaaa12 2019-08-03 stsp break;
4410 98eaaa12 2019-08-03 stsp case GOT_STATUS_DELETE:
4411 98eaaa12 2019-08-03 stsp label1 = path;
4412 98eaaa12 2019-08-03 stsp break;
4413 98eaaa12 2019-08-03 stsp default:
4414 98eaaa12 2019-08-03 stsp return got_error(GOT_ERR_FILE_STATUS);
4415 98eaaa12 2019-08-03 stsp }
4416 fe621944 2020-11-10 stsp return got_diff_objects_as_blobs(NULL, NULL, blob_id,
4417 fe621944 2020-11-10 stsp staged_blob_id, label1, label2, a->diff_context,
4418 64453f7e 2020-11-21 stsp a->ignore_whitespace, a->force_text_diff, a->repo, stdout);
4419 98eaaa12 2019-08-03 stsp }
4420 98eaaa12 2019-08-03 stsp
4421 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
4422 4ce46740 2019-08-08 stsp staged_status == GOT_STATUS_MODIFY) {
4423 4ce46740 2019-08-08 stsp char *id_str;
4424 408b4ebc 2019-08-03 stsp err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
4425 408b4ebc 2019-08-03 stsp 8192);
4426 4ce46740 2019-08-08 stsp if (err)
4427 4ce46740 2019-08-08 stsp goto done;
4428 4ce46740 2019-08-08 stsp err = got_object_id_str(&id_str, staged_blob_id);
4429 4ce46740 2019-08-08 stsp if (err)
4430 4ce46740 2019-08-08 stsp goto done;
4431 4ce46740 2019-08-08 stsp if (asprintf(&label1, "%s (staged)", id_str) == -1) {
4432 4ce46740 2019-08-08 stsp err = got_error_from_errno("asprintf");
4433 4ce46740 2019-08-08 stsp free(id_str);
4434 4ce46740 2019-08-08 stsp goto done;
4435 4ce46740 2019-08-08 stsp }
4436 4ce46740 2019-08-08 stsp free(id_str);
4437 4ce46740 2019-08-08 stsp } else if (status != GOT_STATUS_ADD) {
4438 016a88dd 2019-05-13 stsp err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192);
4439 4ce46740 2019-08-08 stsp if (err)
4440 4ce46740 2019-08-08 stsp goto done;
4441 4ce46740 2019-08-08 stsp }
4442 d00136be 2019-03-26 stsp
4443 7154f6ce 2019-03-27 stsp if (status != GOT_STATUS_DELETE) {
4444 2ec1f75b 2019-03-26 stsp if (asprintf(&abspath, "%s/%s",
4445 2ec1f75b 2019-03-26 stsp got_worktree_get_root_path(a->worktree), path) == -1) {
4446 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
4447 2ec1f75b 2019-03-26 stsp goto done;
4448 2ec1f75b 2019-03-26 stsp }
4449 b72f483a 2019-02-05 stsp
4450 12463d8b 2019-12-13 stsp if (dirfd != -1) {
4451 e7ae0baf 2021-12-31 stsp fd = openat(dirfd, de_name,
4452 e7ae0baf 2021-12-31 stsp O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4453 12463d8b 2019-12-13 stsp if (fd == -1) {
4454 5c02d2a5 2021-09-26 stsp if (!got_err_open_nofollow_on_symlink()) {
4455 39449a05 2020-07-23 stsp err = got_error_from_errno2("openat",
4456 39449a05 2020-07-23 stsp abspath);
4457 39449a05 2020-07-23 stsp goto done;
4458 39449a05 2020-07-23 stsp }
4459 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
4460 39449a05 2020-07-23 stsp de_name, abspath);
4461 39449a05 2020-07-23 stsp if (err)
4462 39449a05 2020-07-23 stsp goto done;
4463 12463d8b 2019-12-13 stsp }
4464 12463d8b 2019-12-13 stsp } else {
4465 8bd0cdad 2021-12-31 stsp fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4466 12463d8b 2019-12-13 stsp if (fd == -1) {
4467 5c02d2a5 2021-09-26 stsp if (!got_err_open_nofollow_on_symlink()) {
4468 39449a05 2020-07-23 stsp err = got_error_from_errno2("open",
4469 39449a05 2020-07-23 stsp abspath);
4470 39449a05 2020-07-23 stsp goto done;
4471 39449a05 2020-07-23 stsp }
4472 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
4473 39449a05 2020-07-23 stsp de_name, abspath);
4474 39449a05 2020-07-23 stsp if (err)
4475 39449a05 2020-07-23 stsp goto done;
4476 12463d8b 2019-12-13 stsp }
4477 12463d8b 2019-12-13 stsp }
4478 12463d8b 2019-12-13 stsp if (fstat(fd, &sb) == -1) {
4479 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fstat", abspath);
4480 2ec1f75b 2019-03-26 stsp goto done;
4481 2ec1f75b 2019-03-26 stsp }
4482 12463d8b 2019-12-13 stsp f2 = fdopen(fd, "r");
4483 12463d8b 2019-12-13 stsp if (f2 == NULL) {
4484 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fdopen", abspath);
4485 2ec1f75b 2019-03-26 stsp goto done;
4486 2ec1f75b 2019-03-26 stsp }
4487 12463d8b 2019-12-13 stsp fd = -1;
4488 2ec1f75b 2019-03-26 stsp } else
4489 2ec1f75b 2019-03-26 stsp sb.st_size = 0;
4490 b72f483a 2019-02-05 stsp
4491 4ce46740 2019-08-08 stsp err = got_diff_blob_file(blob1, label1, f2, sb.st_size, path,
4492 64453f7e 2020-11-21 stsp a->diff_context, a->ignore_whitespace, a->force_text_diff, stdout);
4493 b72f483a 2019-02-05 stsp done:
4494 b72f483a 2019-02-05 stsp if (blob1)
4495 b72f483a 2019-02-05 stsp got_object_blob_close(blob1);
4496 12463d8b 2019-12-13 stsp if (f2 && fclose(f2) == EOF && err == NULL)
4497 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
4498 12463d8b 2019-12-13 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
4499 12463d8b 2019-12-13 stsp err = got_error_from_errno("close");
4500 b72f483a 2019-02-05 stsp free(abspath);
4501 927df6b7 2019-02-10 stsp return err;
4502 927df6b7 2019-02-10 stsp }
4503 927df6b7 2019-02-10 stsp
4504 927df6b7 2019-02-10 stsp static const struct got_error *
4505 b00d56cd 2018-04-01 stsp cmd_diff(int argc, char *argv[])
4506 b00d56cd 2018-04-01 stsp {
4507 b00d56cd 2018-04-01 stsp const struct got_error *error;
4508 b00d56cd 2018-04-01 stsp struct got_repository *repo = NULL;
4509 b72f483a 2019-02-05 stsp struct got_worktree *worktree = NULL;
4510 b72f483a 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL;
4511 67b631c9 2021-10-10 stsp const char *commit_args[2] = { NULL, NULL };
4512 67b631c9 2021-10-10 stsp int ncommit_args = 0;
4513 e7ffb0b0 2021-10-07 stsp struct got_object_id *ids[2] = { NULL, NULL };
4514 e7ffb0b0 2021-10-07 stsp char *labels[2] = { NULL, NULL };
4515 67b631c9 2021-10-10 stsp int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY;
4516 e7ffb0b0 2021-10-07 stsp int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i;
4517 e7ffb0b0 2021-10-07 stsp int force_text_diff = 0, force_path = 0, rflag = 0;
4518 c0cc5c62 2018-10-18 stsp const char *errstr;
4519 84de9106 2020-12-26 stsp struct got_reflist_head refs;
4520 e7ffb0b0 2021-10-07 stsp struct got_pathlist_head paths;
4521 e7ffb0b0 2021-10-07 stsp struct got_pathlist_entry *pe;
4522 b00d56cd 2018-04-01 stsp
4523 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
4524 e7ffb0b0 2021-10-07 stsp TAILQ_INIT(&paths);
4525 84de9106 2020-12-26 stsp
4526 b00d56cd 2018-04-01 stsp #ifndef PROFILE
4527 25eccc22 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4528 25eccc22 2019-01-04 stsp NULL) == -1)
4529 b00d56cd 2018-04-01 stsp err(1, "pledge");
4530 b00d56cd 2018-04-01 stsp #endif
4531 b00d56cd 2018-04-01 stsp
4532 67b631c9 2021-10-10 stsp while ((ch = getopt(argc, argv, "ac:C:r:swP")) != -1) {
4533 b00d56cd 2018-04-01 stsp switch (ch) {
4534 64453f7e 2020-11-21 stsp case 'a':
4535 64453f7e 2020-11-21 stsp force_text_diff = 1;
4536 64453f7e 2020-11-21 stsp break;
4537 67b631c9 2021-10-10 stsp case 'c':
4538 67b631c9 2021-10-10 stsp if (ncommit_args >= 2)
4539 67b631c9 2021-10-10 stsp errx(1, "too many -c options used");
4540 67b631c9 2021-10-10 stsp commit_args[ncommit_args++] = optarg;
4541 67b631c9 2021-10-10 stsp break;
4542 c0cc5c62 2018-10-18 stsp case 'C':
4543 dfcab68b 2019-11-29 kn diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4544 dfcab68b 2019-11-29 kn &errstr);
4545 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
4546 5a20d08d 2022-02-09 op errx(1, "number of context lines is %s: %s",
4547 5a20d08d 2022-02-09 op errstr, optarg);
4548 c0cc5c62 2018-10-18 stsp break;
4549 b72f483a 2019-02-05 stsp case 'r':
4550 b72f483a 2019-02-05 stsp repo_path = realpath(optarg, NULL);
4551 b72f483a 2019-02-05 stsp if (repo_path == NULL)
4552 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4553 9ba1d308 2019-10-21 stsp optarg);
4554 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4555 e7ffb0b0 2021-10-07 stsp rflag = 1;
4556 b72f483a 2019-02-05 stsp break;
4557 98eaaa12 2019-08-03 stsp case 's':
4558 98eaaa12 2019-08-03 stsp diff_staged = 1;
4559 63035f9f 2019-10-06 stsp break;
4560 63035f9f 2019-10-06 stsp case 'w':
4561 63035f9f 2019-10-06 stsp ignore_whitespace = 1;
4562 98eaaa12 2019-08-03 stsp break;
4563 e7ffb0b0 2021-10-07 stsp case 'P':
4564 e7ffb0b0 2021-10-07 stsp force_path = 1;
4565 e7ffb0b0 2021-10-07 stsp break;
4566 b00d56cd 2018-04-01 stsp default:
4567 2deda0b9 2019-03-07 stsp usage_diff();
4568 b00d56cd 2018-04-01 stsp /* NOTREACHED */
4569 b00d56cd 2018-04-01 stsp }
4570 b00d56cd 2018-04-01 stsp }
4571 b00d56cd 2018-04-01 stsp
4572 b00d56cd 2018-04-01 stsp argc -= optind;
4573 b00d56cd 2018-04-01 stsp argv += optind;
4574 b00d56cd 2018-04-01 stsp
4575 b72f483a 2019-02-05 stsp cwd = getcwd(NULL, 0);
4576 b72f483a 2019-02-05 stsp if (cwd == NULL) {
4577 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4578 b72f483a 2019-02-05 stsp goto done;
4579 b72f483a 2019-02-05 stsp }
4580 e7ffb0b0 2021-10-07 stsp
4581 e7ffb0b0 2021-10-07 stsp if (repo_path == NULL) {
4582 1f03b8da 2020-03-20 stsp error = got_worktree_open(&worktree, cwd);
4583 e7ffb0b0 2021-10-07 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4584 1f03b8da 2020-03-20 stsp goto done;
4585 e7ffb0b0 2021-10-07 stsp else
4586 e7ffb0b0 2021-10-07 stsp error = NULL;
4587 e7ffb0b0 2021-10-07 stsp if (worktree) {
4588 e7ffb0b0 2021-10-07 stsp repo_path =
4589 e7ffb0b0 2021-10-07 stsp strdup(got_worktree_get_repo_path(worktree));
4590 e7ffb0b0 2021-10-07 stsp if (repo_path == NULL) {
4591 e7ffb0b0 2021-10-07 stsp error = got_error_from_errno("strdup");
4592 927df6b7 2019-02-10 stsp goto done;
4593 e7ffb0b0 2021-10-07 stsp }
4594 927df6b7 2019-02-10 stsp } else {
4595 e7ffb0b0 2021-10-07 stsp repo_path = strdup(cwd);
4596 1a1242a9 2021-04-01 kn if (repo_path == NULL) {
4597 1a1242a9 2021-04-01 kn error = got_error_from_errno("strdup");
4598 1a1242a9 2021-04-01 kn goto done;
4599 30db809c 2019-06-05 stsp }
4600 30db809c 2019-06-05 stsp }
4601 e7ffb0b0 2021-10-07 stsp }
4602 b00d56cd 2018-04-01 stsp
4603 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4604 76089277 2018-04-01 stsp free(repo_path);
4605 b00d56cd 2018-04-01 stsp if (error != NULL)
4606 b00d56cd 2018-04-01 stsp goto done;
4607 67b631c9 2021-10-10 stsp
4608 67b631c9 2021-10-10 stsp if (rflag || worktree == NULL || ncommit_args > 0) {
4609 67b631c9 2021-10-10 stsp if (force_path) {
4610 67b631c9 2021-10-10 stsp error = got_error_msg(GOT_ERR_NOT_IMPL,
4611 67b631c9 2021-10-10 stsp "-P option can only be used when diffing "
4612 67b631c9 2021-10-10 stsp "a work tree");
4613 67b631c9 2021-10-10 stsp goto done;
4614 67b631c9 2021-10-10 stsp }
4615 67b631c9 2021-10-10 stsp if (diff_staged) {
4616 67b631c9 2021-10-10 stsp error = got_error_msg(GOT_ERR_NOT_IMPL,
4617 67b631c9 2021-10-10 stsp "-s option can only be used when diffing "
4618 67b631c9 2021-10-10 stsp "a work tree");
4619 67b631c9 2021-10-10 stsp goto done;
4620 67b631c9 2021-10-10 stsp }
4621 67b631c9 2021-10-10 stsp }
4622 b00d56cd 2018-04-01 stsp
4623 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
4624 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
4625 c02c541e 2019-03-29 stsp if (error)
4626 c02c541e 2019-03-29 stsp goto done;
4627 c02c541e 2019-03-29 stsp
4628 67b631c9 2021-10-10 stsp if ((!force_path && argc == 2) || ncommit_args > 0) {
4629 67b631c9 2021-10-10 stsp int obj_type = (ncommit_args > 0 ?
4630 67b631c9 2021-10-10 stsp GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY);
4631 e7ffb0b0 2021-10-07 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
4632 e7ffb0b0 2021-10-07 stsp NULL);
4633 e7ffb0b0 2021-10-07 stsp if (error)
4634 e7ffb0b0 2021-10-07 stsp goto done;
4635 67b631c9 2021-10-10 stsp for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) {
4636 67b631c9 2021-10-10 stsp const char *arg;
4637 67b631c9 2021-10-10 stsp if (ncommit_args > 0)
4638 67b631c9 2021-10-10 stsp arg = commit_args[i];
4639 67b631c9 2021-10-10 stsp else
4640 67b631c9 2021-10-10 stsp arg = argv[i];
4641 e7ffb0b0 2021-10-07 stsp error = got_repo_match_object_id(&ids[i], &labels[i],
4642 67b631c9 2021-10-10 stsp arg, obj_type, &refs, repo);
4643 e7ffb0b0 2021-10-07 stsp if (error) {
4644 e7ffb0b0 2021-10-07 stsp if (error->code != GOT_ERR_NOT_REF &&
4645 e7ffb0b0 2021-10-07 stsp error->code != GOT_ERR_NO_OBJ)
4646 e7ffb0b0 2021-10-07 stsp goto done;
4647 67b631c9 2021-10-10 stsp if (ncommit_args > 0)
4648 67b631c9 2021-10-10 stsp goto done;
4649 e7ffb0b0 2021-10-07 stsp error = NULL;
4650 e7ffb0b0 2021-10-07 stsp break;
4651 e7ffb0b0 2021-10-07 stsp }
4652 e7ffb0b0 2021-10-07 stsp }
4653 e7ffb0b0 2021-10-07 stsp }
4654 e7ffb0b0 2021-10-07 stsp
4655 67b631c9 2021-10-10 stsp if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) {
4656 b72f483a 2019-02-05 stsp struct print_diff_arg arg;
4657 b72f483a 2019-02-05 stsp char *id_str;
4658 72ea6654 2019-07-27 stsp
4659 67b631c9 2021-10-10 stsp if (worktree == NULL) {
4660 67b631c9 2021-10-10 stsp if (argc == 2 && ids[0] == NULL) {
4661 67b631c9 2021-10-10 stsp error = got_error_path(argv[0], GOT_ERR_NO_OBJ);
4662 67b631c9 2021-10-10 stsp goto done;
4663 67b631c9 2021-10-10 stsp } else if (argc == 2 && ids[1] == NULL) {
4664 67b631c9 2021-10-10 stsp error = got_error_path(argv[1], GOT_ERR_NO_OBJ);
4665 67b631c9 2021-10-10 stsp goto done;
4666 67b631c9 2021-10-10 stsp } else if (argc > 0) {
4667 67b631c9 2021-10-10 stsp error = got_error_fmt(GOT_ERR_NOT_WORKTREE,
4668 67b631c9 2021-10-10 stsp "%s", "specified paths cannot be resolved");
4669 67b631c9 2021-10-10 stsp goto done;
4670 67b631c9 2021-10-10 stsp } else {
4671 67b631c9 2021-10-10 stsp error = got_error(GOT_ERR_NOT_WORKTREE);
4672 67b631c9 2021-10-10 stsp goto done;
4673 67b631c9 2021-10-10 stsp }
4674 67b631c9 2021-10-10 stsp }
4675 67b631c9 2021-10-10 stsp
4676 67b631c9 2021-10-10 stsp error = get_worktree_paths_from_argv(&paths, argc, argv,
4677 67b631c9 2021-10-10 stsp worktree);
4678 67b631c9 2021-10-10 stsp if (error)
4679 67b631c9 2021-10-10 stsp goto done;
4680 67b631c9 2021-10-10 stsp
4681 b72f483a 2019-02-05 stsp error = got_object_id_str(&id_str,
4682 b72f483a 2019-02-05 stsp got_worktree_get_base_commit_id(worktree));
4683 b72f483a 2019-02-05 stsp if (error)
4684 b72f483a 2019-02-05 stsp goto done;
4685 b72f483a 2019-02-05 stsp arg.repo = repo;
4686 b72f483a 2019-02-05 stsp arg.worktree = worktree;
4687 b72f483a 2019-02-05 stsp arg.diff_context = diff_context;
4688 3fc0c068 2019-02-10 stsp arg.id_str = id_str;
4689 3fc0c068 2019-02-10 stsp arg.header_shown = 0;
4690 98eaaa12 2019-08-03 stsp arg.diff_staged = diff_staged;
4691 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
4692 64453f7e 2020-11-21 stsp arg.force_text_diff = force_text_diff;
4693 b72f483a 2019-02-05 stsp
4694 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, 0,
4695 f6343036 2021-06-22 stsp print_diff, &arg, check_cancelled, NULL);
4696 b72f483a 2019-02-05 stsp free(id_str);
4697 b72f483a 2019-02-05 stsp goto done;
4698 b72f483a 2019-02-05 stsp }
4699 84de9106 2020-12-26 stsp
4700 67b631c9 2021-10-10 stsp if (ncommit_args == 1) {
4701 67b631c9 2021-10-10 stsp struct got_commit_object *commit;
4702 67b631c9 2021-10-10 stsp error = got_object_open_as_commit(&commit, repo, ids[0]);
4703 67b631c9 2021-10-10 stsp if (error)
4704 e7ffb0b0 2021-10-07 stsp goto done;
4705 b00d56cd 2018-04-01 stsp
4706 67b631c9 2021-10-10 stsp labels[1] = labels[0];
4707 67b631c9 2021-10-10 stsp ids[1] = ids[0];
4708 67b631c9 2021-10-10 stsp if (got_object_commit_get_nparents(commit) > 0) {
4709 67b631c9 2021-10-10 stsp const struct got_object_id_queue *pids;
4710 67b631c9 2021-10-10 stsp struct got_object_qid *pid;
4711 67b631c9 2021-10-10 stsp pids = got_object_commit_get_parent_ids(commit);
4712 67b631c9 2021-10-10 stsp pid = STAILQ_FIRST(pids);
4713 d7b5a0e8 2022-04-20 stsp ids[0] = got_object_id_dup(&pid->id);
4714 67b631c9 2021-10-10 stsp if (ids[0] == NULL) {
4715 67b631c9 2021-10-10 stsp error = got_error_from_errno(
4716 67b631c9 2021-10-10 stsp "got_object_id_dup");
4717 67b631c9 2021-10-10 stsp got_object_commit_close(commit);
4718 67b631c9 2021-10-10 stsp goto done;
4719 67b631c9 2021-10-10 stsp }
4720 67b631c9 2021-10-10 stsp error = got_object_id_str(&labels[0], ids[0]);
4721 67b631c9 2021-10-10 stsp if (error) {
4722 67b631c9 2021-10-10 stsp got_object_commit_close(commit);
4723 67b631c9 2021-10-10 stsp goto done;
4724 67b631c9 2021-10-10 stsp }
4725 67b631c9 2021-10-10 stsp } else {
4726 67b631c9 2021-10-10 stsp ids[0] = NULL;
4727 67b631c9 2021-10-10 stsp labels[0] = strdup("/dev/null");
4728 67b631c9 2021-10-10 stsp if (labels[0] == NULL) {
4729 67b631c9 2021-10-10 stsp error = got_error_from_errno("strdup");
4730 67b631c9 2021-10-10 stsp got_object_commit_close(commit);
4731 67b631c9 2021-10-10 stsp goto done;
4732 67b631c9 2021-10-10 stsp }
4733 67b631c9 2021-10-10 stsp }
4734 67b631c9 2021-10-10 stsp
4735 67b631c9 2021-10-10 stsp got_object_commit_close(commit);
4736 67b631c9 2021-10-10 stsp }
4737 67b631c9 2021-10-10 stsp
4738 67b631c9 2021-10-10 stsp if (ncommit_args == 0 && argc > 2) {
4739 67b631c9 2021-10-10 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
4740 67b631c9 2021-10-10 stsp "path arguments cannot be used when diffing two objects");
4741 0adb7196 2019-08-11 stsp goto done;
4742 67b631c9 2021-10-10 stsp }
4743 b00d56cd 2018-04-01 stsp
4744 67b631c9 2021-10-10 stsp if (ids[0]) {
4745 67b631c9 2021-10-10 stsp error = got_object_get_type(&type1, repo, ids[0]);
4746 67b631c9 2021-10-10 stsp if (error)
4747 67b631c9 2021-10-10 stsp goto done;
4748 67b631c9 2021-10-10 stsp }
4749 67b631c9 2021-10-10 stsp
4750 e7ffb0b0 2021-10-07 stsp error = got_object_get_type(&type2, repo, ids[1]);
4751 15a94983 2018-12-23 stsp if (error)
4752 15a94983 2018-12-23 stsp goto done;
4753 67b631c9 2021-10-10 stsp if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) {
4754 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4755 b00d56cd 2018-04-01 stsp goto done;
4756 b00d56cd 2018-04-01 stsp }
4757 67b631c9 2021-10-10 stsp if (type1 == GOT_OBJ_TYPE_BLOB && argc > 0) {
4758 67b631c9 2021-10-10 stsp error = got_error_msg(GOT_ERR_OBJ_TYPE,
4759 67b631c9 2021-10-10 stsp "path arguments cannot be used when diffing blobs");
4760 67b631c9 2021-10-10 stsp goto done;
4761 67b631c9 2021-10-10 stsp }
4762 b00d56cd 2018-04-01 stsp
4763 67b631c9 2021-10-10 stsp for (i = 0; ncommit_args > 0 && i < argc; i++) {
4764 67b631c9 2021-10-10 stsp char *in_repo_path;
4765 67b631c9 2021-10-10 stsp struct got_pathlist_entry *new;
4766 67b631c9 2021-10-10 stsp if (worktree) {
4767 67b631c9 2021-10-10 stsp const char *prefix;
4768 67b631c9 2021-10-10 stsp char *p;
4769 67b631c9 2021-10-10 stsp error = got_worktree_resolve_path(&p, worktree,
4770 67b631c9 2021-10-10 stsp argv[i]);
4771 67b631c9 2021-10-10 stsp if (error)
4772 67b631c9 2021-10-10 stsp goto done;
4773 67b631c9 2021-10-10 stsp prefix = got_worktree_get_path_prefix(worktree);
4774 67b631c9 2021-10-10 stsp while (prefix[0] == '/')
4775 67b631c9 2021-10-10 stsp prefix++;
4776 67b631c9 2021-10-10 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
4777 67b631c9 2021-10-10 stsp (p[0] != '\0' && prefix[0] != '\0') ? "/" : "",
4778 67b631c9 2021-10-10 stsp p) == -1) {
4779 67b631c9 2021-10-10 stsp error = got_error_from_errno("asprintf");
4780 67b631c9 2021-10-10 stsp free(p);
4781 67b631c9 2021-10-10 stsp goto done;
4782 67b631c9 2021-10-10 stsp }
4783 67b631c9 2021-10-10 stsp free(p);
4784 67b631c9 2021-10-10 stsp } else {
4785 67b631c9 2021-10-10 stsp char *mapped_path, *s;
4786 67b631c9 2021-10-10 stsp error = got_repo_map_path(&mapped_path, repo, argv[i]);
4787 67b631c9 2021-10-10 stsp if (error)
4788 67b631c9 2021-10-10 stsp goto done;
4789 67b631c9 2021-10-10 stsp s = mapped_path;
4790 67b631c9 2021-10-10 stsp while (s[0] == '/')
4791 67b631c9 2021-10-10 stsp s++;
4792 67b631c9 2021-10-10 stsp in_repo_path = strdup(s);
4793 67b631c9 2021-10-10 stsp if (in_repo_path == NULL) {
4794 67b631c9 2021-10-10 stsp error = got_error_from_errno("asprintf");
4795 67b631c9 2021-10-10 stsp free(mapped_path);
4796 67b631c9 2021-10-10 stsp goto done;
4797 67b631c9 2021-10-10 stsp }
4798 67b631c9 2021-10-10 stsp free(mapped_path);
4799 67b631c9 2021-10-10 stsp
4800 67b631c9 2021-10-10 stsp }
4801 67b631c9 2021-10-10 stsp error = got_pathlist_insert(&new, &paths, in_repo_path, NULL);
4802 67b631c9 2021-10-10 stsp if (error || new == NULL /* duplicate */)
4803 67b631c9 2021-10-10 stsp free(in_repo_path);
4804 67b631c9 2021-10-10 stsp if (error)
4805 67b631c9 2021-10-10 stsp goto done;
4806 f7fce2e2 2022-03-12 stsp }
4807 f7fce2e2 2022-03-12 stsp
4808 f7fce2e2 2022-03-12 stsp if (worktree) {
4809 f7fce2e2 2022-03-12 stsp /* Release work tree lock. */
4810 f7fce2e2 2022-03-12 stsp got_worktree_close(worktree);
4811 f7fce2e2 2022-03-12 stsp worktree = NULL;
4812 67b631c9 2021-10-10 stsp }
4813 67b631c9 2021-10-10 stsp
4814 67b631c9 2021-10-10 stsp switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) {
4815 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_BLOB:
4816 e7ffb0b0 2021-10-07 stsp error = got_diff_objects_as_blobs(NULL, NULL, ids[0], ids[1],
4817 64453f7e 2020-11-21 stsp NULL, NULL, diff_context, ignore_whitespace,
4818 64453f7e 2020-11-21 stsp force_text_diff, repo, stdout);
4819 b00d56cd 2018-04-01 stsp break;
4820 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_TREE:
4821 e7ffb0b0 2021-10-07 stsp error = got_diff_objects_as_trees(NULL, NULL, ids[0], ids[1],
4822 67b631c9 2021-10-10 stsp &paths, "", "", diff_context, ignore_whitespace,
4823 67b631c9 2021-10-10 stsp force_text_diff, repo, stdout);
4824 b00d56cd 2018-04-01 stsp break;
4825 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_COMMIT:
4826 e7ffb0b0 2021-10-07 stsp printf("diff %s %s\n", labels[0], labels[1]);
4827 e7ffb0b0 2021-10-07 stsp error = got_diff_objects_as_commits(NULL, NULL, ids[0], ids[1],
4828 67b631c9 2021-10-10 stsp &paths, diff_context, ignore_whitespace, force_text_diff,
4829 67b631c9 2021-10-10 stsp repo, stdout);
4830 b00d56cd 2018-04-01 stsp break;
4831 b00d56cd 2018-04-01 stsp default:
4832 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4833 b00d56cd 2018-04-01 stsp }
4834 b00d56cd 2018-04-01 stsp done:
4835 e7ffb0b0 2021-10-07 stsp free(labels[0]);
4836 e7ffb0b0 2021-10-07 stsp free(labels[1]);
4837 e7ffb0b0 2021-10-07 stsp free(ids[0]);
4838 e7ffb0b0 2021-10-07 stsp free(ids[1]);
4839 b72f483a 2019-02-05 stsp if (worktree)
4840 b72f483a 2019-02-05 stsp got_worktree_close(worktree);
4841 ad242220 2018-09-08 stsp if (repo) {
4842 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
4843 ad242220 2018-09-08 stsp if (error == NULL)
4844 1d0f4054 2021-06-17 stsp error = close_err;
4845 ad242220 2018-09-08 stsp }
4846 e7ffb0b0 2021-10-07 stsp TAILQ_FOREACH(pe, &paths, entry)
4847 e7ffb0b0 2021-10-07 stsp free((char *)pe->path);
4848 e7ffb0b0 2021-10-07 stsp got_pathlist_free(&paths);
4849 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
4850 b00d56cd 2018-04-01 stsp return error;
4851 404c43c4 2018-06-21 stsp }
4852 404c43c4 2018-06-21 stsp
4853 404c43c4 2018-06-21 stsp __dead static void
4854 404c43c4 2018-06-21 stsp usage_blame(void)
4855 404c43c4 2018-06-21 stsp {
4856 9270e621 2019-02-05 stsp fprintf(stderr,
4857 9270e621 2019-02-05 stsp "usage: %s blame [-c commit] [-r repository-path] path\n",
4858 404c43c4 2018-06-21 stsp getprogname());
4859 404c43c4 2018-06-21 stsp exit(1);
4860 b00d56cd 2018-04-01 stsp }
4861 b00d56cd 2018-04-01 stsp
4862 28315671 2019-08-14 stsp struct blame_line {
4863 28315671 2019-08-14 stsp int annotated;
4864 28315671 2019-08-14 stsp char *id_str;
4865 82f6abb8 2019-08-14 stsp char *committer;
4866 11db6024 2019-10-21 stsp char datebuf[11]; /* YYYY-MM-DD + NUL */
4867 28315671 2019-08-14 stsp };
4868 28315671 2019-08-14 stsp
4869 28315671 2019-08-14 stsp struct blame_cb_args {
4870 28315671 2019-08-14 stsp struct blame_line *lines;
4871 28315671 2019-08-14 stsp int nlines;
4872 7ef28ff8 2019-08-14 stsp int nlines_prec;
4873 28315671 2019-08-14 stsp int lineno_cur;
4874 28315671 2019-08-14 stsp off_t *line_offsets;
4875 28315671 2019-08-14 stsp FILE *f;
4876 82f6abb8 2019-08-14 stsp struct got_repository *repo;
4877 28315671 2019-08-14 stsp };
4878 28315671 2019-08-14 stsp
4879 404c43c4 2018-06-21 stsp static const struct got_error *
4880 392891ce 2022-04-07 stsp blame_cb(void *arg, int nlines, int lineno,
4881 392891ce 2022-04-07 stsp struct got_commit_object *commit, struct got_object_id *id)
4882 28315671 2019-08-14 stsp {
4883 28315671 2019-08-14 stsp const struct got_error *err = NULL;
4884 28315671 2019-08-14 stsp struct blame_cb_args *a = arg;
4885 28315671 2019-08-14 stsp struct blame_line *bline;
4886 82f6abb8 2019-08-14 stsp char *line = NULL;
4887 28315671 2019-08-14 stsp size_t linesize = 0;
4888 28315671 2019-08-14 stsp off_t offset;
4889 bcb49d15 2019-08-14 stsp struct tm tm;
4890 bcb49d15 2019-08-14 stsp time_t committer_time;
4891 28315671 2019-08-14 stsp
4892 28315671 2019-08-14 stsp if (nlines != a->nlines ||
4893 28315671 2019-08-14 stsp (lineno != -1 && lineno < 1) || lineno > a->nlines)
4894 28315671 2019-08-14 stsp return got_error(GOT_ERR_RANGE);
4895 28315671 2019-08-14 stsp
4896 28315671 2019-08-14 stsp if (sigint_received)
4897 28315671 2019-08-14 stsp return got_error(GOT_ERR_ITER_COMPLETED);
4898 28315671 2019-08-14 stsp
4899 2839f8b9 2019-08-18 stsp if (lineno == -1)
4900 2839f8b9 2019-08-18 stsp return NULL; /* no change in this commit */
4901 2839f8b9 2019-08-18 stsp
4902 28315671 2019-08-14 stsp /* Annotate this line. */
4903 28315671 2019-08-14 stsp bline = &a->lines[lineno - 1];
4904 28315671 2019-08-14 stsp if (bline->annotated)
4905 28315671 2019-08-14 stsp return NULL;
4906 28315671 2019-08-14 stsp err = got_object_id_str(&bline->id_str, id);
4907 28315671 2019-08-14 stsp if (err)
4908 28315671 2019-08-14 stsp return err;
4909 82f6abb8 2019-08-14 stsp
4910 82f6abb8 2019-08-14 stsp bline->committer = strdup(got_object_commit_get_committer(commit));
4911 82f6abb8 2019-08-14 stsp if (bline->committer == NULL) {
4912 82f6abb8 2019-08-14 stsp err = got_error_from_errno("strdup");
4913 bcb49d15 2019-08-14 stsp goto done;
4914 bcb49d15 2019-08-14 stsp }
4915 bcb49d15 2019-08-14 stsp
4916 bcb49d15 2019-08-14 stsp committer_time = got_object_commit_get_committer_time(commit);
4917 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
4918 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
4919 6db9f7f6 2019-12-10 stsp if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
4920 ec6d1a36 2021-03-21 jrick &tm) == 0) {
4921 bcb49d15 2019-08-14 stsp err = got_error(GOT_ERR_NO_SPACE);
4922 82f6abb8 2019-08-14 stsp goto done;
4923 82f6abb8 2019-08-14 stsp }
4924 28315671 2019-08-14 stsp bline->annotated = 1;
4925 28315671 2019-08-14 stsp
4926 28315671 2019-08-14 stsp /* Print lines annotated so far. */
4927 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4928 28315671 2019-08-14 stsp if (!bline->annotated)
4929 82f6abb8 2019-08-14 stsp goto done;
4930 28315671 2019-08-14 stsp
4931 28315671 2019-08-14 stsp offset = a->line_offsets[a->lineno_cur - 1];
4932 82f6abb8 2019-08-14 stsp if (fseeko(a->f, offset, SEEK_SET) == -1) {
4933 82f6abb8 2019-08-14 stsp err = got_error_from_errno("fseeko");
4934 82f6abb8 2019-08-14 stsp goto done;
4935 82f6abb8 2019-08-14 stsp }
4936 28315671 2019-08-14 stsp
4937 28315671 2019-08-14 stsp while (bline->annotated) {
4938 82f6abb8 2019-08-14 stsp char *smallerthan, *at, *nl, *committer;
4939 82f6abb8 2019-08-14 stsp size_t len;
4940 82f6abb8 2019-08-14 stsp
4941 500467ff 2019-09-25 hiltjo if (getline(&line, &linesize, a->f) == -1) {
4942 28315671 2019-08-14 stsp if (ferror(a->f))
4943 28315671 2019-08-14 stsp err = got_error_from_errno("getline");
4944 28315671 2019-08-14 stsp break;
4945 28315671 2019-08-14 stsp }
4946 82f6abb8 2019-08-14 stsp
4947 82f6abb8 2019-08-14 stsp committer = bline->committer;
4948 82f6abb8 2019-08-14 stsp smallerthan = strchr(committer, '<');
4949 82f6abb8 2019-08-14 stsp if (smallerthan && smallerthan[1] != '\0')
4950 82f6abb8 2019-08-14 stsp committer = smallerthan + 1;
4951 82f6abb8 2019-08-14 stsp at = strchr(committer, '@');
4952 82f6abb8 2019-08-14 stsp if (at)
4953 82f6abb8 2019-08-14 stsp *at = '\0';
4954 82f6abb8 2019-08-14 stsp len = strlen(committer);
4955 82f6abb8 2019-08-14 stsp if (len >= 9)
4956 82f6abb8 2019-08-14 stsp committer[8] = '\0';
4957 28315671 2019-08-14 stsp
4958 28315671 2019-08-14 stsp nl = strchr(line, '\n');
4959 28315671 2019-08-14 stsp if (nl)
4960 28315671 2019-08-14 stsp *nl = '\0';
4961 bcb49d15 2019-08-14 stsp printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
4962 bcb49d15 2019-08-14 stsp bline->id_str, bline->datebuf, committer, line);
4963 28315671 2019-08-14 stsp
4964 28315671 2019-08-14 stsp a->lineno_cur++;
4965 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4966 28315671 2019-08-14 stsp }
4967 82f6abb8 2019-08-14 stsp done:
4968 28315671 2019-08-14 stsp free(line);
4969 28315671 2019-08-14 stsp return err;
4970 28315671 2019-08-14 stsp }
4971 28315671 2019-08-14 stsp
4972 28315671 2019-08-14 stsp static const struct got_error *
4973 404c43c4 2018-06-21 stsp cmd_blame(int argc, char *argv[])
4974 404c43c4 2018-06-21 stsp {
4975 404c43c4 2018-06-21 stsp const struct got_error *error;
4976 404c43c4 2018-06-21 stsp struct got_repository *repo = NULL;
4977 0c06baac 2019-02-05 stsp struct got_worktree *worktree = NULL;
4978 66bea077 2018-08-02 stsp char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
4979 0587e10c 2020-07-23 stsp char *link_target = NULL;
4980 28315671 2019-08-14 stsp struct got_object_id *obj_id = NULL;
4981 404c43c4 2018-06-21 stsp struct got_object_id *commit_id = NULL;
4982 a44927cc 2022-04-07 stsp struct got_commit_object *commit = NULL;
4983 28315671 2019-08-14 stsp struct got_blob_object *blob = NULL;
4984 404c43c4 2018-06-21 stsp char *commit_id_str = NULL;
4985 28315671 2019-08-14 stsp struct blame_cb_args bca;
4986 28315671 2019-08-14 stsp int ch, obj_type, i;
4987 be659d10 2020-11-18 stsp off_t filesize;
4988 90f3c347 2019-08-19 stsp
4989 90f3c347 2019-08-19 stsp memset(&bca, 0, sizeof(bca));
4990 404c43c4 2018-06-21 stsp
4991 404c43c4 2018-06-21 stsp #ifndef PROFILE
4992 36e2fb66 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4993 36e2fb66 2019-01-04 stsp NULL) == -1)
4994 404c43c4 2018-06-21 stsp err(1, "pledge");
4995 404c43c4 2018-06-21 stsp #endif
4996 404c43c4 2018-06-21 stsp
4997 66bea077 2018-08-02 stsp while ((ch = getopt(argc, argv, "c:r:")) != -1) {
4998 404c43c4 2018-06-21 stsp switch (ch) {
4999 404c43c4 2018-06-21 stsp case 'c':
5000 404c43c4 2018-06-21 stsp commit_id_str = optarg;
5001 404c43c4 2018-06-21 stsp break;
5002 66bea077 2018-08-02 stsp case 'r':
5003 66bea077 2018-08-02 stsp repo_path = realpath(optarg, NULL);
5004 66bea077 2018-08-02 stsp if (repo_path == NULL)
5005 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5006 9ba1d308 2019-10-21 stsp optarg);
5007 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
5008 66bea077 2018-08-02 stsp break;
5009 404c43c4 2018-06-21 stsp default:
5010 2deda0b9 2019-03-07 stsp usage_blame();
5011 404c43c4 2018-06-21 stsp /* NOTREACHED */
5012 404c43c4 2018-06-21 stsp }
5013 404c43c4 2018-06-21 stsp }
5014 404c43c4 2018-06-21 stsp
5015 404c43c4 2018-06-21 stsp argc -= optind;
5016 404c43c4 2018-06-21 stsp argv += optind;
5017 404c43c4 2018-06-21 stsp
5018 a39318fd 2018-08-02 stsp if (argc == 1)
5019 404c43c4 2018-06-21 stsp path = argv[0];
5020 a39318fd 2018-08-02 stsp else
5021 404c43c4 2018-06-21 stsp usage_blame();
5022 404c43c4 2018-06-21 stsp
5023 66bea077 2018-08-02 stsp cwd = getcwd(NULL, 0);
5024 66bea077 2018-08-02 stsp if (cwd == NULL) {
5025 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5026 66bea077 2018-08-02 stsp goto done;
5027 66bea077 2018-08-02 stsp }
5028 66bea077 2018-08-02 stsp if (repo_path == NULL) {
5029 0c06baac 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
5030 0c06baac 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5031 66bea077 2018-08-02 stsp goto done;
5032 0c06baac 2019-02-05 stsp else
5033 0c06baac 2019-02-05 stsp error = NULL;
5034 0c06baac 2019-02-05 stsp if (worktree) {
5035 0c06baac 2019-02-05 stsp repo_path =
5036 0c06baac 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
5037 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
5038 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5039 1f03b8da 2020-03-20 stsp if (error)
5040 1f03b8da 2020-03-20 stsp goto done;
5041 1f03b8da 2020-03-20 stsp }
5042 0c06baac 2019-02-05 stsp } else {
5043 0c06baac 2019-02-05 stsp repo_path = strdup(cwd);
5044 0c06baac 2019-02-05 stsp if (repo_path == NULL) {
5045 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5046 0c06baac 2019-02-05 stsp goto done;
5047 0c06baac 2019-02-05 stsp }
5048 66bea077 2018-08-02 stsp }
5049 66bea077 2018-08-02 stsp }
5050 36e2fb66 2019-01-04 stsp
5051 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5052 c02c541e 2019-03-29 stsp if (error != NULL)
5053 404c43c4 2018-06-21 stsp goto done;
5054 404c43c4 2018-06-21 stsp
5055 0c06baac 2019-02-05 stsp if (worktree) {
5056 6efaaa2d 2019-02-05 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
5057 01740607 2020-11-04 stsp char *p;
5058 01740607 2020-11-04 stsp
5059 01740607 2020-11-04 stsp error = got_worktree_resolve_path(&p, worktree, path);
5060 01740607 2020-11-04 stsp if (error)
5061 01740607 2020-11-04 stsp goto done;
5062 01740607 2020-11-04 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
5063 01740607 2020-11-04 stsp (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5064 01740607 2020-11-04 stsp p) == -1) {
5065 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
5066 01740607 2020-11-04 stsp free(p);
5067 0c06baac 2019-02-05 stsp goto done;
5068 0c06baac 2019-02-05 stsp }
5069 0c06baac 2019-02-05 stsp free(p);
5070 01740607 2020-11-04 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5071 0c06baac 2019-02-05 stsp } else {
5072 01740607 2020-11-04 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5073 01740607 2020-11-04 stsp if (error)
5074 01740607 2020-11-04 stsp goto done;
5075 8fa913ec 2020-11-14 stsp error = got_repo_map_path(&in_repo_path, repo, path);
5076 0c06baac 2019-02-05 stsp }
5077 0c06baac 2019-02-05 stsp if (error)
5078 66bea077 2018-08-02 stsp goto done;
5079 66bea077 2018-08-02 stsp
5080 404c43c4 2018-06-21 stsp if (commit_id_str == NULL) {
5081 404c43c4 2018-06-21 stsp struct got_reference *head_ref;
5082 a0975128 2020-02-07 stsp error = got_ref_open(&head_ref, repo, worktree ?
5083 a0975128 2020-02-07 stsp got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0);
5084 404c43c4 2018-06-21 stsp if (error != NULL)
5085 66bea077 2018-08-02 stsp goto done;
5086 404c43c4 2018-06-21 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
5087 404c43c4 2018-06-21 stsp got_ref_close(head_ref);
5088 404c43c4 2018-06-21 stsp if (error != NULL)
5089 66bea077 2018-08-02 stsp goto done;
5090 404c43c4 2018-06-21 stsp } else {
5091 84de9106 2020-12-26 stsp struct got_reflist_head refs;
5092 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5093 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5094 84de9106 2020-12-26 stsp NULL);
5095 84de9106 2020-12-26 stsp if (error)
5096 84de9106 2020-12-26 stsp goto done;
5097 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
5098 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5099 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
5100 30837e32 2019-07-25 stsp if (error)
5101 66bea077 2018-08-02 stsp goto done;
5102 f7fce2e2 2022-03-12 stsp }
5103 f7fce2e2 2022-03-12 stsp
5104 f7fce2e2 2022-03-12 stsp if (worktree) {
5105 f7fce2e2 2022-03-12 stsp /* Release work tree lock. */
5106 f7fce2e2 2022-03-12 stsp got_worktree_close(worktree);
5107 f7fce2e2 2022-03-12 stsp worktree = NULL;
5108 404c43c4 2018-06-21 stsp }
5109 404c43c4 2018-06-21 stsp
5110 a44927cc 2022-04-07 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
5111 a44927cc 2022-04-07 stsp if (error)
5112 a44927cc 2022-04-07 stsp goto done;
5113 a44927cc 2022-04-07 stsp
5114 0587e10c 2020-07-23 stsp error = got_object_resolve_symlinks(&link_target, in_repo_path,
5115 a44927cc 2022-04-07 stsp commit, repo);
5116 0587e10c 2020-07-23 stsp if (error)
5117 0587e10c 2020-07-23 stsp goto done;
5118 0587e10c 2020-07-23 stsp
5119 a44927cc 2022-04-07 stsp error = got_object_id_by_path(&obj_id, repo, commit,
5120 0587e10c 2020-07-23 stsp link_target ? link_target : in_repo_path);
5121 28315671 2019-08-14 stsp if (error)
5122 28315671 2019-08-14 stsp goto done;
5123 28315671 2019-08-14 stsp
5124 28315671 2019-08-14 stsp error = got_object_get_type(&obj_type, repo, obj_id);
5125 28315671 2019-08-14 stsp if (error)
5126 28315671 2019-08-14 stsp goto done;
5127 28315671 2019-08-14 stsp
5128 28315671 2019-08-14 stsp if (obj_type != GOT_OBJ_TYPE_BLOB) {
5129 eb59b6d4 2020-07-23 stsp error = got_error_path(link_target ? link_target : in_repo_path,
5130 eb59b6d4 2020-07-23 stsp GOT_ERR_OBJ_TYPE);
5131 28315671 2019-08-14 stsp goto done;
5132 28315671 2019-08-14 stsp }
5133 28315671 2019-08-14 stsp
5134 28315671 2019-08-14 stsp error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
5135 28315671 2019-08-14 stsp if (error)
5136 28315671 2019-08-14 stsp goto done;
5137 28315671 2019-08-14 stsp bca.f = got_opentemp();
5138 28315671 2019-08-14 stsp if (bca.f == NULL) {
5139 28315671 2019-08-14 stsp error = got_error_from_errno("got_opentemp");
5140 28315671 2019-08-14 stsp goto done;
5141 28315671 2019-08-14 stsp }
5142 b02560ec 2019-08-19 stsp error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
5143 28315671 2019-08-14 stsp &bca.line_offsets, bca.f, blob);
5144 7ef28ff8 2019-08-14 stsp if (error || bca.nlines == 0)
5145 28315671 2019-08-14 stsp goto done;
5146 28315671 2019-08-14 stsp
5147 b02560ec 2019-08-19 stsp /* Don't include \n at EOF in the blame line count. */
5148 b02560ec 2019-08-19 stsp if (bca.line_offsets[bca.nlines - 1] == filesize)
5149 b02560ec 2019-08-19 stsp bca.nlines--;
5150 b02560ec 2019-08-19 stsp
5151 28315671 2019-08-14 stsp bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
5152 28315671 2019-08-14 stsp if (bca.lines == NULL) {
5153 28315671 2019-08-14 stsp error = got_error_from_errno("calloc");
5154 28315671 2019-08-14 stsp goto done;
5155 28315671 2019-08-14 stsp }
5156 28315671 2019-08-14 stsp bca.lineno_cur = 1;
5157 7ef28ff8 2019-08-14 stsp bca.nlines_prec = 0;
5158 7ef28ff8 2019-08-14 stsp i = bca.nlines;
5159 7ef28ff8 2019-08-14 stsp while (i > 0) {
5160 7ef28ff8 2019-08-14 stsp i /= 10;
5161 7ef28ff8 2019-08-14 stsp bca.nlines_prec++;
5162 7ef28ff8 2019-08-14 stsp }
5163 82f6abb8 2019-08-14 stsp bca.repo = repo;
5164 7ef28ff8 2019-08-14 stsp
5165 0587e10c 2020-07-23 stsp error = got_blame(link_target ? link_target : in_repo_path, commit_id,
5166 0587e10c 2020-07-23 stsp repo, blame_cb, &bca, check_cancelled, NULL);
5167 404c43c4 2018-06-21 stsp done:
5168 66bea077 2018-08-02 stsp free(in_repo_path);
5169 0587e10c 2020-07-23 stsp free(link_target);
5170 66bea077 2018-08-02 stsp free(repo_path);
5171 66bea077 2018-08-02 stsp free(cwd);
5172 404c43c4 2018-06-21 stsp free(commit_id);
5173 28315671 2019-08-14 stsp free(obj_id);
5174 a44927cc 2022-04-07 stsp if (commit)
5175 a44927cc 2022-04-07 stsp got_object_commit_close(commit);
5176 28315671 2019-08-14 stsp if (blob)
5177 28315671 2019-08-14 stsp got_object_blob_close(blob);
5178 0c06baac 2019-02-05 stsp if (worktree)
5179 0c06baac 2019-02-05 stsp got_worktree_close(worktree);
5180 ad242220 2018-09-08 stsp if (repo) {
5181 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
5182 ad242220 2018-09-08 stsp if (error == NULL)
5183 1d0f4054 2021-06-17 stsp error = close_err;
5184 ad242220 2018-09-08 stsp }
5185 3affba96 2019-09-22 stsp if (bca.lines) {
5186 3affba96 2019-09-22 stsp for (i = 0; i < bca.nlines; i++) {
5187 3affba96 2019-09-22 stsp struct blame_line *bline = &bca.lines[i];
5188 3affba96 2019-09-22 stsp free(bline->id_str);
5189 3affba96 2019-09-22 stsp free(bline->committer);
5190 3affba96 2019-09-22 stsp }
5191 3affba96 2019-09-22 stsp free(bca.lines);
5192 28315671 2019-08-14 stsp }
5193 28315671 2019-08-14 stsp free(bca.line_offsets);
5194 28315671 2019-08-14 stsp if (bca.f && fclose(bca.f) == EOF && error == NULL)
5195 28315671 2019-08-14 stsp error = got_error_from_errno("fclose");
5196 404c43c4 2018-06-21 stsp return error;
5197 5de5890b 2018-10-18 stsp }
5198 5de5890b 2018-10-18 stsp
5199 5de5890b 2018-10-18 stsp __dead static void
5200 5de5890b 2018-10-18 stsp usage_tree(void)
5201 5de5890b 2018-10-18 stsp {
5202 c1669e2e 2019-01-09 stsp fprintf(stderr,
5203 5d58be12 2020-05-17 stsp "usage: %s tree [-c commit] [-r repository-path] [-iR] [path]\n",
5204 5de5890b 2018-10-18 stsp getprogname());
5205 5de5890b 2018-10-18 stsp exit(1);
5206 5de5890b 2018-10-18 stsp }
5207 5de5890b 2018-10-18 stsp
5208 0d6c6ee3 2020-05-20 stsp static const struct got_error *
5209 c1669e2e 2019-01-09 stsp print_entry(struct got_tree_entry *te, const char *id, const char *path,
5210 0d6c6ee3 2020-05-20 stsp const char *root_path, struct got_repository *repo)
5211 c1669e2e 2019-01-09 stsp {
5212 0d6c6ee3 2020-05-20 stsp const struct got_error *err = NULL;
5213 c1669e2e 2019-01-09 stsp int is_root_path = (strcmp(path, root_path) == 0);
5214 848d6979 2019-08-12 stsp const char *modestr = "";
5215 56e0773d 2019-11-28 stsp mode_t mode = got_tree_entry_get_mode(te);
5216 0d6c6ee3 2020-05-20 stsp char *link_target = NULL;
5217 5de5890b 2018-10-18 stsp
5218 c1669e2e 2019-01-09 stsp path += strlen(root_path);
5219 c1669e2e 2019-01-09 stsp while (path[0] == '/')
5220 c1669e2e 2019-01-09 stsp path++;
5221 c1669e2e 2019-01-09 stsp
5222 63c5ca5d 2019-08-24 stsp if (got_object_tree_entry_is_submodule(te))
5223 63c5ca5d 2019-08-24 stsp modestr = "$";
5224 0d6c6ee3 2020-05-20 stsp else if (S_ISLNK(mode)) {
5225 0d6c6ee3 2020-05-20 stsp int i;
5226 0d6c6ee3 2020-05-20 stsp
5227 0d6c6ee3 2020-05-20 stsp err = got_tree_entry_get_symlink_target(&link_target, te, repo);
5228 0d6c6ee3 2020-05-20 stsp if (err)
5229 0d6c6ee3 2020-05-20 stsp return err;
5230 0d6c6ee3 2020-05-20 stsp for (i = 0; i < strlen(link_target); i++) {
5231 0d6c6ee3 2020-05-20 stsp if (!isprint((unsigned char)link_target[i]))
5232 0d6c6ee3 2020-05-20 stsp link_target[i] = '?';
5233 0d6c6ee3 2020-05-20 stsp }
5234 0d6c6ee3 2020-05-20 stsp
5235 848d6979 2019-08-12 stsp modestr = "@";
5236 0d6c6ee3 2020-05-20 stsp }
5237 56e0773d 2019-11-28 stsp else if (S_ISDIR(mode))
5238 848d6979 2019-08-12 stsp modestr = "/";
5239 56e0773d 2019-11-28 stsp else if (mode & S_IXUSR)
5240 848d6979 2019-08-12 stsp modestr = "*";
5241 848d6979 2019-08-12 stsp
5242 0d6c6ee3 2020-05-20 stsp printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
5243 0d6c6ee3 2020-05-20 stsp is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
5244 0d6c6ee3 2020-05-20 stsp link_target ? " -> ": "", link_target ? link_target : "");
5245 0d6c6ee3 2020-05-20 stsp
5246 0d6c6ee3 2020-05-20 stsp free(link_target);
5247 0d6c6ee3 2020-05-20 stsp return NULL;
5248 c1669e2e 2019-01-09 stsp }
5249 c1669e2e 2019-01-09 stsp
5250 5de5890b 2018-10-18 stsp static const struct got_error *
5251 a44927cc 2022-04-07 stsp print_tree(const char *path, struct got_commit_object *commit,
5252 c1669e2e 2019-01-09 stsp int show_ids, int recurse, const char *root_path,
5253 c1669e2e 2019-01-09 stsp struct got_repository *repo)
5254 5de5890b 2018-10-18 stsp {
5255 5de5890b 2018-10-18 stsp const struct got_error *err = NULL;
5256 5de5890b 2018-10-18 stsp struct got_object_id *tree_id = NULL;
5257 5de5890b 2018-10-18 stsp struct got_tree_object *tree = NULL;
5258 56e0773d 2019-11-28 stsp int nentries, i;
5259 5de5890b 2018-10-18 stsp
5260 a44927cc 2022-04-07 stsp err = got_object_id_by_path(&tree_id, repo, commit, path);
5261 5de5890b 2018-10-18 stsp if (err)
5262 5de5890b 2018-10-18 stsp goto done;
5263 5de5890b 2018-10-18 stsp
5264 5de5890b 2018-10-18 stsp err = got_object_open_as_tree(&tree, repo, tree_id);
5265 5de5890b 2018-10-18 stsp if (err)
5266 5de5890b 2018-10-18 stsp goto done;
5267 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
5268 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
5269 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
5270 5de5890b 2018-10-18 stsp char *id = NULL;
5271 84453469 2018-11-11 stsp
5272 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
5273 84453469 2018-11-11 stsp break;
5274 84453469 2018-11-11 stsp
5275 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
5276 5de5890b 2018-10-18 stsp if (show_ids) {
5277 5de5890b 2018-10-18 stsp char *id_str;
5278 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str,
5279 56e0773d 2019-11-28 stsp got_tree_entry_get_id(te));
5280 5de5890b 2018-10-18 stsp if (err)
5281 5de5890b 2018-10-18 stsp goto done;
5282 5de5890b 2018-10-18 stsp if (asprintf(&id, "%s ", id_str) == -1) {
5283 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
5284 5de5890b 2018-10-18 stsp free(id_str);
5285 5de5890b 2018-10-18 stsp goto done;
5286 5de5890b 2018-10-18 stsp }
5287 5de5890b 2018-10-18 stsp free(id_str);
5288 5de5890b 2018-10-18 stsp }
5289 0d6c6ee3 2020-05-20 stsp err = print_entry(te, id, path, root_path, repo);
5290 5de5890b 2018-10-18 stsp free(id);
5291 0d6c6ee3 2020-05-20 stsp if (err)
5292 0d6c6ee3 2020-05-20 stsp goto done;
5293 c1669e2e 2019-01-09 stsp
5294 56e0773d 2019-11-28 stsp if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
5295 c1669e2e 2019-01-09 stsp char *child_path;
5296 c1669e2e 2019-01-09 stsp if (asprintf(&child_path, "%s%s%s", path,
5297 c1669e2e 2019-01-09 stsp path[0] == '/' && path[1] == '\0' ? "" : "/",
5298 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te)) == -1) {
5299 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
5300 c1669e2e 2019-01-09 stsp goto done;
5301 c1669e2e 2019-01-09 stsp }
5302 a44927cc 2022-04-07 stsp err = print_tree(child_path, commit, show_ids, 1,
5303 c1669e2e 2019-01-09 stsp root_path, repo);
5304 c1669e2e 2019-01-09 stsp free(child_path);
5305 c1669e2e 2019-01-09 stsp if (err)
5306 c1669e2e 2019-01-09 stsp goto done;
5307 c1669e2e 2019-01-09 stsp }
5308 5de5890b 2018-10-18 stsp }
5309 5de5890b 2018-10-18 stsp done:
5310 5de5890b 2018-10-18 stsp if (tree)
5311 5de5890b 2018-10-18 stsp got_object_tree_close(tree);
5312 5de5890b 2018-10-18 stsp free(tree_id);
5313 5de5890b 2018-10-18 stsp return err;
5314 404c43c4 2018-06-21 stsp }
5315 404c43c4 2018-06-21 stsp
5316 5de5890b 2018-10-18 stsp static const struct got_error *
5317 5de5890b 2018-10-18 stsp cmd_tree(int argc, char *argv[])
5318 5de5890b 2018-10-18 stsp {
5319 5de5890b 2018-10-18 stsp const struct got_error *error;
5320 5de5890b 2018-10-18 stsp struct got_repository *repo = NULL;
5321 7a2c19d6 2019-02-05 stsp struct got_worktree *worktree = NULL;
5322 4e0a20a4 2020-03-23 tracey const char *path, *refname = NULL;
5323 7a2c19d6 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5324 5de5890b 2018-10-18 stsp struct got_object_id *commit_id = NULL;
5325 a44927cc 2022-04-07 stsp struct got_commit_object *commit = NULL;
5326 5de5890b 2018-10-18 stsp char *commit_id_str = NULL;
5327 c1669e2e 2019-01-09 stsp int show_ids = 0, recurse = 0;
5328 5de5890b 2018-10-18 stsp int ch;
5329 5de5890b 2018-10-18 stsp
5330 5de5890b 2018-10-18 stsp #ifndef PROFILE
5331 0f8d269b 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5332 0f8d269b 2019-01-04 stsp NULL) == -1)
5333 5de5890b 2018-10-18 stsp err(1, "pledge");
5334 5de5890b 2018-10-18 stsp #endif
5335 5de5890b 2018-10-18 stsp
5336 c1669e2e 2019-01-09 stsp while ((ch = getopt(argc, argv, "c:r:iR")) != -1) {
5337 5de5890b 2018-10-18 stsp switch (ch) {
5338 5de5890b 2018-10-18 stsp case 'c':
5339 5de5890b 2018-10-18 stsp commit_id_str = optarg;
5340 5de5890b 2018-10-18 stsp break;
5341 5de5890b 2018-10-18 stsp case 'r':
5342 5de5890b 2018-10-18 stsp repo_path = realpath(optarg, NULL);
5343 5de5890b 2018-10-18 stsp if (repo_path == NULL)
5344 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5345 9ba1d308 2019-10-21 stsp optarg);
5346 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
5347 5de5890b 2018-10-18 stsp break;
5348 5de5890b 2018-10-18 stsp case 'i':
5349 5de5890b 2018-10-18 stsp show_ids = 1;
5350 5de5890b 2018-10-18 stsp break;
5351 c1669e2e 2019-01-09 stsp case 'R':
5352 c1669e2e 2019-01-09 stsp recurse = 1;
5353 c1669e2e 2019-01-09 stsp break;
5354 5de5890b 2018-10-18 stsp default:
5355 2deda0b9 2019-03-07 stsp usage_tree();
5356 5de5890b 2018-10-18 stsp /* NOTREACHED */
5357 5de5890b 2018-10-18 stsp }
5358 5de5890b 2018-10-18 stsp }
5359 5de5890b 2018-10-18 stsp
5360 5de5890b 2018-10-18 stsp argc -= optind;
5361 5de5890b 2018-10-18 stsp argv += optind;
5362 5de5890b 2018-10-18 stsp
5363 5de5890b 2018-10-18 stsp if (argc == 1)
5364 5de5890b 2018-10-18 stsp path = argv[0];
5365 5de5890b 2018-10-18 stsp else if (argc > 1)
5366 5de5890b 2018-10-18 stsp usage_tree();
5367 5de5890b 2018-10-18 stsp else
5368 7a2c19d6 2019-02-05 stsp path = NULL;
5369 7a2c19d6 2019-02-05 stsp
5370 9bf7a39b 2019-02-05 stsp cwd = getcwd(NULL, 0);
5371 9bf7a39b 2019-02-05 stsp if (cwd == NULL) {
5372 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5373 9bf7a39b 2019-02-05 stsp goto done;
5374 9bf7a39b 2019-02-05 stsp }
5375 5de5890b 2018-10-18 stsp if (repo_path == NULL) {
5376 7a2c19d6 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
5377 8994de28 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5378 7a2c19d6 2019-02-05 stsp goto done;
5379 7a2c19d6 2019-02-05 stsp else
5380 7a2c19d6 2019-02-05 stsp error = NULL;
5381 7a2c19d6 2019-02-05 stsp if (worktree) {
5382 7a2c19d6 2019-02-05 stsp repo_path =
5383 7a2c19d6 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
5384 7a2c19d6 2019-02-05 stsp if (repo_path == NULL)
5385 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5386 7a2c19d6 2019-02-05 stsp if (error)
5387 7a2c19d6 2019-02-05 stsp goto done;
5388 7a2c19d6 2019-02-05 stsp } else {
5389 7a2c19d6 2019-02-05 stsp repo_path = strdup(cwd);
5390 7a2c19d6 2019-02-05 stsp if (repo_path == NULL) {
5391 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5392 7a2c19d6 2019-02-05 stsp goto done;
5393 7a2c19d6 2019-02-05 stsp }
5394 5de5890b 2018-10-18 stsp }
5395 5de5890b 2018-10-18 stsp }
5396 5de5890b 2018-10-18 stsp
5397 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5398 5de5890b 2018-10-18 stsp if (error != NULL)
5399 c02c541e 2019-03-29 stsp goto done;
5400 c02c541e 2019-03-29 stsp
5401 4fedbf4c 2020-11-07 stsp if (worktree) {
5402 4fedbf4c 2020-11-07 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
5403 4fedbf4c 2020-11-07 stsp char *p;
5404 5de5890b 2018-10-18 stsp
5405 4fedbf4c 2020-11-07 stsp if (path == NULL)
5406 4fedbf4c 2020-11-07 stsp path = "";
5407 4fedbf4c 2020-11-07 stsp error = got_worktree_resolve_path(&p, worktree, path);
5408 4fedbf4c 2020-11-07 stsp if (error)
5409 4fedbf4c 2020-11-07 stsp goto done;
5410 4fedbf4c 2020-11-07 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
5411 4fedbf4c 2020-11-07 stsp (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5412 4fedbf4c 2020-11-07 stsp p) == -1) {
5413 4fedbf4c 2020-11-07 stsp error = got_error_from_errno("asprintf");
5414 9bf7a39b 2019-02-05 stsp free(p);
5415 4fedbf4c 2020-11-07 stsp goto done;
5416 4fedbf4c 2020-11-07 stsp }
5417 4fedbf4c 2020-11-07 stsp free(p);
5418 4fedbf4c 2020-11-07 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5419 4fedbf4c 2020-11-07 stsp if (error)
5420 4fedbf4c 2020-11-07 stsp goto done;
5421 4fedbf4c 2020-11-07 stsp } else {
5422 4fedbf4c 2020-11-07 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5423 4fedbf4c 2020-11-07 stsp if (error)
5424 4fedbf4c 2020-11-07 stsp goto done;
5425 4fedbf4c 2020-11-07 stsp if (path == NULL)
5426 9bf7a39b 2019-02-05 stsp path = "/";
5427 8fa913ec 2020-11-14 stsp error = got_repo_map_path(&in_repo_path, repo, path);
5428 9bf7a39b 2019-02-05 stsp if (error != NULL)
5429 9bf7a39b 2019-02-05 stsp goto done;
5430 9bf7a39b 2019-02-05 stsp }
5431 5de5890b 2018-10-18 stsp
5432 5de5890b 2018-10-18 stsp if (commit_id_str == NULL) {
5433 5de5890b 2018-10-18 stsp struct got_reference *head_ref;
5434 4e0a20a4 2020-03-23 tracey if (worktree)
5435 4e0a20a4 2020-03-23 tracey refname = got_worktree_get_head_ref_name(worktree);
5436 4e0a20a4 2020-03-23 tracey else
5437 4e0a20a4 2020-03-23 tracey refname = GOT_REF_HEAD;
5438 4e0a20a4 2020-03-23 tracey error = got_ref_open(&head_ref, repo, refname, 0);
5439 5de5890b 2018-10-18 stsp if (error != NULL)
5440 5de5890b 2018-10-18 stsp goto done;
5441 5de5890b 2018-10-18 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
5442 5de5890b 2018-10-18 stsp got_ref_close(head_ref);
5443 5de5890b 2018-10-18 stsp if (error != NULL)
5444 5de5890b 2018-10-18 stsp goto done;
5445 5de5890b 2018-10-18 stsp } else {
5446 84de9106 2020-12-26 stsp struct got_reflist_head refs;
5447 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5448 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5449 84de9106 2020-12-26 stsp NULL);
5450 84de9106 2020-12-26 stsp if (error)
5451 84de9106 2020-12-26 stsp goto done;
5452 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
5453 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5454 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
5455 30837e32 2019-07-25 stsp if (error)
5456 5de5890b 2018-10-18 stsp goto done;
5457 5de5890b 2018-10-18 stsp }
5458 5de5890b 2018-10-18 stsp
5459 f7fce2e2 2022-03-12 stsp if (worktree) {
5460 f7fce2e2 2022-03-12 stsp /* Release work tree lock. */
5461 f7fce2e2 2022-03-12 stsp got_worktree_close(worktree);
5462 f7fce2e2 2022-03-12 stsp worktree = NULL;
5463 f7fce2e2 2022-03-12 stsp }
5464 f7fce2e2 2022-03-12 stsp
5465 a44927cc 2022-04-07 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
5466 a44927cc 2022-04-07 stsp if (error)
5467 a44927cc 2022-04-07 stsp goto done;
5468 a44927cc 2022-04-07 stsp
5469 a44927cc 2022-04-07 stsp error = print_tree(in_repo_path, commit, show_ids, recurse,
5470 c1669e2e 2019-01-09 stsp in_repo_path, repo);
5471 5de5890b 2018-10-18 stsp done:
5472 5de5890b 2018-10-18 stsp free(in_repo_path);
5473 5de5890b 2018-10-18 stsp free(repo_path);
5474 5de5890b 2018-10-18 stsp free(cwd);
5475 5de5890b 2018-10-18 stsp free(commit_id);
5476 a44927cc 2022-04-07 stsp if (commit)
5477 a44927cc 2022-04-07 stsp got_object_commit_close(commit);
5478 7a2c19d6 2019-02-05 stsp if (worktree)
5479 7a2c19d6 2019-02-05 stsp got_worktree_close(worktree);
5480 5de5890b 2018-10-18 stsp if (repo) {
5481 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
5482 5de5890b 2018-10-18 stsp if (error == NULL)
5483 1d0f4054 2021-06-17 stsp error = close_err;
5484 5de5890b 2018-10-18 stsp }
5485 5de5890b 2018-10-18 stsp return error;
5486 5de5890b 2018-10-18 stsp }
5487 5de5890b 2018-10-18 stsp
5488 6bad629b 2019-02-04 stsp __dead static void
5489 6bad629b 2019-02-04 stsp usage_status(void)
5490 6bad629b 2019-02-04 stsp {
5491 00357e4d 2021-09-14 tracey fprintf(stderr, "usage: %s status [-I] [-s status-codes ] "
5492 00357e4d 2021-09-14 tracey "[-S status-codes] [path ...]\n", getprogname());
5493 6bad629b 2019-02-04 stsp exit(1);
5494 6bad629b 2019-02-04 stsp }
5495 00357e4d 2021-09-14 tracey
5496 00357e4d 2021-09-14 tracey struct got_status_arg {
5497 00357e4d 2021-09-14 tracey char *status_codes;
5498 00357e4d 2021-09-14 tracey int suppress;
5499 00357e4d 2021-09-14 tracey };
5500 5c860e29 2018-03-12 stsp
5501 b72f483a 2019-02-05 stsp static const struct got_error *
5502 88d0e355 2019-08-03 stsp print_status(void *arg, unsigned char status, unsigned char staged_status,
5503 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
5504 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5505 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
5506 6bad629b 2019-02-04 stsp {
5507 00357e4d 2021-09-14 tracey struct got_status_arg *st = arg;
5508 00357e4d 2021-09-14 tracey
5509 244725f2 2019-08-03 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
5510 c363b2c1 2019-08-03 stsp status = GOT_STATUS_NO_CHANGE;
5511 00357e4d 2021-09-14 tracey if (st != NULL && st->status_codes) {
5512 00357e4d 2021-09-14 tracey size_t ncodes = strlen(st->status_codes);
5513 00357e4d 2021-09-14 tracey int i, j = 0;
5514 00357e4d 2021-09-14 tracey
5515 081470ac 2020-08-13 stsp for (i = 0; i < ncodes ; i++) {
5516 00357e4d 2021-09-14 tracey if (st->suppress) {
5517 00357e4d 2021-09-14 tracey if (status == st->status_codes[i] ||
5518 00357e4d 2021-09-14 tracey staged_status == st->status_codes[i]) {
5519 00357e4d 2021-09-14 tracey j++;
5520 00357e4d 2021-09-14 tracey continue;
5521 00357e4d 2021-09-14 tracey }
5522 00357e4d 2021-09-14 tracey } else {
5523 00357e4d 2021-09-14 tracey if (status == st->status_codes[i] ||
5524 00357e4d 2021-09-14 tracey staged_status == st->status_codes[i])
5525 00357e4d 2021-09-14 tracey break;
5526 00357e4d 2021-09-14 tracey }
5527 081470ac 2020-08-13 stsp }
5528 00357e4d 2021-09-14 tracey
5529 00357e4d 2021-09-14 tracey if (st->suppress && j == 0)
5530 00357e4d 2021-09-14 tracey goto print;
5531 00357e4d 2021-09-14 tracey
5532 081470ac 2020-08-13 stsp if (i == ncodes)
5533 081470ac 2020-08-13 stsp return NULL;
5534 081470ac 2020-08-13 stsp }
5535 00357e4d 2021-09-14 tracey print:
5536 88d0e355 2019-08-03 stsp printf("%c%c %s\n", status, staged_status, path);
5537 b72f483a 2019-02-05 stsp return NULL;
5538 6bad629b 2019-02-04 stsp }
5539 5c860e29 2018-03-12 stsp
5540 6bad629b 2019-02-04 stsp static const struct got_error *
5541 6bad629b 2019-02-04 stsp cmd_status(int argc, char *argv[])
5542 6bad629b 2019-02-04 stsp {
5543 6bad629b 2019-02-04 stsp const struct got_error *error = NULL;
5544 6bad629b 2019-02-04 stsp struct got_repository *repo = NULL;
5545 6bad629b 2019-02-04 stsp struct got_worktree *worktree = NULL;
5546 00357e4d 2021-09-14 tracey struct got_status_arg st;
5547 00357e4d 2021-09-14 tracey char *cwd = NULL;
5548 72ea6654 2019-07-27 stsp struct got_pathlist_head paths;
5549 a5edda0a 2019-07-27 stsp struct got_pathlist_entry *pe;
5550 f6343036 2021-06-22 stsp int ch, i, no_ignores = 0;
5551 5c860e29 2018-03-12 stsp
5552 72ea6654 2019-07-27 stsp TAILQ_INIT(&paths);
5553 72ea6654 2019-07-27 stsp
5554 00357e4d 2021-09-14 tracey memset(&st, 0, sizeof(st));
5555 00357e4d 2021-09-14 tracey st.status_codes = NULL;
5556 00357e4d 2021-09-14 tracey st.suppress = 0;
5557 00357e4d 2021-09-14 tracey
5558 00357e4d 2021-09-14 tracey while ((ch = getopt(argc, argv, "Is:S:")) != -1) {
5559 6bad629b 2019-02-04 stsp switch (ch) {
5560 f6343036 2021-06-22 stsp case 'I':
5561 f6343036 2021-06-22 stsp no_ignores = 1;
5562 f6343036 2021-06-22 stsp break;
5563 788d4a19 2021-09-14 stsp case 'S':
5564 788d4a19 2021-09-14 stsp if (st.status_codes != NULL && st.suppress == 0)
5565 788d4a19 2021-09-14 stsp option_conflict('S', 's');
5566 788d4a19 2021-09-14 stsp st.suppress = 1;
5567 788d4a19 2021-09-14 stsp /* fallthrough */
5568 081470ac 2020-08-13 stsp case 's':
5569 081470ac 2020-08-13 stsp for (i = 0; i < strlen(optarg); i++) {
5570 081470ac 2020-08-13 stsp switch (optarg[i]) {
5571 081470ac 2020-08-13 stsp case GOT_STATUS_MODIFY:
5572 081470ac 2020-08-13 stsp case GOT_STATUS_ADD:
5573 081470ac 2020-08-13 stsp case GOT_STATUS_DELETE:
5574 081470ac 2020-08-13 stsp case GOT_STATUS_CONFLICT:
5575 081470ac 2020-08-13 stsp case GOT_STATUS_MISSING:
5576 081470ac 2020-08-13 stsp case GOT_STATUS_OBSTRUCTED:
5577 081470ac 2020-08-13 stsp case GOT_STATUS_UNVERSIONED:
5578 081470ac 2020-08-13 stsp case GOT_STATUS_MODE_CHANGE:
5579 081470ac 2020-08-13 stsp case GOT_STATUS_NONEXISTENT:
5580 081470ac 2020-08-13 stsp break;
5581 081470ac 2020-08-13 stsp default:
5582 081470ac 2020-08-13 stsp errx(1, "invalid status code '%c'",
5583 081470ac 2020-08-13 stsp optarg[i]);
5584 081470ac 2020-08-13 stsp }
5585 081470ac 2020-08-13 stsp }
5586 788d4a19 2021-09-14 stsp if (ch == 's' && st.suppress)
5587 b043307b 2021-09-14 stsp option_conflict('s', 'S');
5588 00357e4d 2021-09-14 tracey st.status_codes = optarg;
5589 081470ac 2020-08-13 stsp break;
5590 5c860e29 2018-03-12 stsp default:
5591 2deda0b9 2019-03-07 stsp usage_status();
5592 6bad629b 2019-02-04 stsp /* NOTREACHED */
5593 5c860e29 2018-03-12 stsp }
5594 5c860e29 2018-03-12 stsp }
5595 5c860e29 2018-03-12 stsp
5596 6bad629b 2019-02-04 stsp argc -= optind;
5597 6bad629b 2019-02-04 stsp argv += optind;
5598 5c860e29 2018-03-12 stsp
5599 6bad629b 2019-02-04 stsp #ifndef PROFILE
5600 6bad629b 2019-02-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5601 6bad629b 2019-02-04 stsp NULL) == -1)
5602 6bad629b 2019-02-04 stsp err(1, "pledge");
5603 f42b1b34 2018-03-12 stsp #endif
5604 927df6b7 2019-02-10 stsp cwd = getcwd(NULL, 0);
5605 927df6b7 2019-02-10 stsp if (cwd == NULL) {
5606 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5607 927df6b7 2019-02-10 stsp goto done;
5608 927df6b7 2019-02-10 stsp }
5609 927df6b7 2019-02-10 stsp
5610 927df6b7 2019-02-10 stsp error = got_worktree_open(&worktree, cwd);
5611 fa51e947 2020-03-27 stsp if (error) {
5612 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
5613 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "status", cwd);
5614 a5edda0a 2019-07-27 stsp goto done;
5615 fa51e947 2020-03-27 stsp }
5616 6bad629b 2019-02-04 stsp
5617 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
5618 c9956ddf 2019-09-08 stsp NULL);
5619 6bad629b 2019-02-04 stsp if (error != NULL)
5620 6bad629b 2019-02-04 stsp goto done;
5621 6bad629b 2019-02-04 stsp
5622 d0eebce4 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 1,
5623 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
5624 087fb88c 2019-08-04 stsp if (error)
5625 087fb88c 2019-08-04 stsp goto done;
5626 087fb88c 2019-08-04 stsp
5627 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
5628 6bad629b 2019-02-04 stsp if (error)
5629 6bad629b 2019-02-04 stsp goto done;
5630 6bad629b 2019-02-04 stsp
5631 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, no_ignores,
5632 00357e4d 2021-09-14 tracey print_status, &st, check_cancelled, NULL);
5633 6bad629b 2019-02-04 stsp done:
5634 a5edda0a 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
5635 a5edda0a 2019-07-27 stsp free((char *)pe->path);
5636 72ea6654 2019-07-27 stsp got_pathlist_free(&paths);
5637 927df6b7 2019-02-10 stsp free(cwd);
5638 d0eebce4 2019-03-11 stsp return error;
5639 d0eebce4 2019-03-11 stsp }
5640 d0eebce4 2019-03-11 stsp
5641 d0eebce4 2019-03-11 stsp __dead static void
5642 d0eebce4 2019-03-11 stsp usage_ref(void)
5643 d0eebce4 2019-03-11 stsp {
5644 d0eebce4 2019-03-11 stsp fprintf(stderr,
5645 0f104432 2021-11-20 stsp "usage: %s ref [-r repository] [-l] [-t] [-c object] "
5646 0f104432 2021-11-20 stsp "[-s reference] [-d] [name]\n",
5647 d0eebce4 2019-03-11 stsp getprogname());
5648 d0eebce4 2019-03-11 stsp exit(1);
5649 d0eebce4 2019-03-11 stsp }
5650 d0eebce4 2019-03-11 stsp
5651 d0eebce4 2019-03-11 stsp static const struct got_error *
5652 0f104432 2021-11-20 stsp list_refs(struct got_repository *repo, const char *refname, int sort_by_time)
5653 d0eebce4 2019-03-11 stsp {
5654 d0eebce4 2019-03-11 stsp static const struct got_error *err = NULL;
5655 d0eebce4 2019-03-11 stsp struct got_reflist_head refs;
5656 d0eebce4 2019-03-11 stsp struct got_reflist_entry *re;
5657 d0eebce4 2019-03-11 stsp
5658 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5659 0f104432 2021-11-20 stsp err = got_ref_list(&refs, repo, refname, sort_by_time ?
5660 0f104432 2021-11-20 stsp got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
5661 0f104432 2021-11-20 stsp repo);
5662 d0eebce4 2019-03-11 stsp if (err)
5663 d0eebce4 2019-03-11 stsp return err;
5664 d0eebce4 2019-03-11 stsp
5665 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry) {
5666 d0eebce4 2019-03-11 stsp char *refstr;
5667 d0eebce4 2019-03-11 stsp refstr = got_ref_to_str(re->ref);
5668 3e99fbc5 2022-03-23 op if (refstr == NULL) {
5669 3e99fbc5 2022-03-23 op err = got_error_from_errno("got_ref_to_str");
5670 3e99fbc5 2022-03-23 op break;
5671 3e99fbc5 2022-03-23 op }
5672 d0eebce4 2019-03-11 stsp printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
5673 d0eebce4 2019-03-11 stsp free(refstr);
5674 d0eebce4 2019-03-11 stsp }
5675 d0eebce4 2019-03-11 stsp
5676 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
5677 3e99fbc5 2022-03-23 op return err;
5678 d0eebce4 2019-03-11 stsp }
5679 d0eebce4 2019-03-11 stsp
5680 d0eebce4 2019-03-11 stsp static const struct got_error *
5681 161728eb 2021-07-24 stsp delete_ref_by_name(struct got_repository *repo, const char *refname)
5682 d0eebce4 2019-03-11 stsp {
5683 161728eb 2021-07-24 stsp const struct got_error *err;
5684 d0eebce4 2019-03-11 stsp struct got_reference *ref;
5685 d0eebce4 2019-03-11 stsp
5686 2f17228e 2019-05-12 stsp err = got_ref_open(&ref, repo, refname, 0);
5687 d0eebce4 2019-03-11 stsp if (err)
5688 d0eebce4 2019-03-11 stsp return err;
5689 993f033b 2021-07-16 stsp
5690 161728eb 2021-07-24 stsp err = delete_ref(repo, ref);
5691 d0eebce4 2019-03-11 stsp got_ref_close(ref);
5692 d0eebce4 2019-03-11 stsp return err;
5693 d0eebce4 2019-03-11 stsp }
5694 d0eebce4 2019-03-11 stsp
5695 d0eebce4 2019-03-11 stsp static const struct got_error *
5696 d83d9d5c 2019-05-13 stsp add_ref(struct got_repository *repo, const char *refname, const char *target)
5697 d0eebce4 2019-03-11 stsp {
5698 d0eebce4 2019-03-11 stsp const struct got_error *err = NULL;
5699 d8247bfd 2022-03-10 naddy struct got_object_id *id = NULL;
5700 d0eebce4 2019-03-11 stsp struct got_reference *ref = NULL;
5701 d8247bfd 2022-03-10 naddy struct got_reflist_head refs;
5702 d1644381 2019-07-14 stsp
5703 d1644381 2019-07-14 stsp /*
5704 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
5705 d1644381 2019-07-14 stsp * While technically a valid reference name, this case is usually
5706 d1644381 2019-07-14 stsp * an unintended typo.
5707 d1644381 2019-07-14 stsp */
5708 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
5709 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
5710 d0eebce4 2019-03-11 stsp
5711 d8247bfd 2022-03-10 naddy TAILQ_INIT(&refs);
5712 d8247bfd 2022-03-10 naddy err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
5713 d8247bfd 2022-03-10 naddy if (err)
5714 d8247bfd 2022-03-10 naddy goto done;
5715 d8247bfd 2022-03-10 naddy err = got_repo_match_object_id(&id, NULL, target, GOT_OBJ_TYPE_ANY,
5716 d8247bfd 2022-03-10 naddy &refs, repo);
5717 d8247bfd 2022-03-10 naddy got_ref_list_free(&refs);
5718 d8247bfd 2022-03-10 naddy if (err)
5719 d8247bfd 2022-03-10 naddy goto done;
5720 d83d9d5c 2019-05-13 stsp
5721 d0eebce4 2019-03-11 stsp err = got_ref_alloc(&ref, refname, id);
5722 d0eebce4 2019-03-11 stsp if (err)
5723 d0eebce4 2019-03-11 stsp goto done;
5724 d0eebce4 2019-03-11 stsp
5725 d0eebce4 2019-03-11 stsp err = got_ref_write(ref, repo);
5726 d0eebce4 2019-03-11 stsp done:
5727 d0eebce4 2019-03-11 stsp if (ref)
5728 d0eebce4 2019-03-11 stsp got_ref_close(ref);
5729 d0eebce4 2019-03-11 stsp free(id);
5730 d1c1ae5f 2019-08-12 stsp return err;
5731 d1c1ae5f 2019-08-12 stsp }
5732 d1c1ae5f 2019-08-12 stsp
5733 d1c1ae5f 2019-08-12 stsp static const struct got_error *
5734 d1c1ae5f 2019-08-12 stsp add_symref(struct got_repository *repo, const char *refname, const char *target)
5735 d1c1ae5f 2019-08-12 stsp {
5736 d1c1ae5f 2019-08-12 stsp const struct got_error *err = NULL;
5737 d1c1ae5f 2019-08-12 stsp struct got_reference *ref = NULL;
5738 d1c1ae5f 2019-08-12 stsp struct got_reference *target_ref = NULL;
5739 d1c1ae5f 2019-08-12 stsp
5740 d1c1ae5f 2019-08-12 stsp /*
5741 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
5742 d1c1ae5f 2019-08-12 stsp * While technically a valid reference name, this case is usually
5743 d1c1ae5f 2019-08-12 stsp * an unintended typo.
5744 d1c1ae5f 2019-08-12 stsp */
5745 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
5746 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
5747 d1c1ae5f 2019-08-12 stsp
5748 d1c1ae5f 2019-08-12 stsp err = got_ref_open(&target_ref, repo, target, 0);
5749 d1c1ae5f 2019-08-12 stsp if (err)
5750 d1c1ae5f 2019-08-12 stsp return err;
5751 d1c1ae5f 2019-08-12 stsp
5752 d1c1ae5f 2019-08-12 stsp err = got_ref_alloc_symref(&ref, refname, target_ref);
5753 d1c1ae5f 2019-08-12 stsp if (err)
5754 d1c1ae5f 2019-08-12 stsp goto done;
5755 d1c1ae5f 2019-08-12 stsp
5756 d1c1ae5f 2019-08-12 stsp err = got_ref_write(ref, repo);
5757 d1c1ae5f 2019-08-12 stsp done:
5758 d1c1ae5f 2019-08-12 stsp if (target_ref)
5759 d1c1ae5f 2019-08-12 stsp got_ref_close(target_ref);
5760 d1c1ae5f 2019-08-12 stsp if (ref)
5761 d1c1ae5f 2019-08-12 stsp got_ref_close(ref);
5762 d0eebce4 2019-03-11 stsp return err;
5763 d0eebce4 2019-03-11 stsp }
5764 d0eebce4 2019-03-11 stsp
5765 d0eebce4 2019-03-11 stsp static const struct got_error *
5766 d0eebce4 2019-03-11 stsp cmd_ref(int argc, char *argv[])
5767 d0eebce4 2019-03-11 stsp {
5768 d0eebce4 2019-03-11 stsp const struct got_error *error = NULL;
5769 d0eebce4 2019-03-11 stsp struct got_repository *repo = NULL;
5770 d0eebce4 2019-03-11 stsp struct got_worktree *worktree = NULL;
5771 d0eebce4 2019-03-11 stsp char *cwd = NULL, *repo_path = NULL;
5772 0f104432 2021-11-20 stsp int ch, do_list = 0, do_delete = 0, sort_by_time = 0;
5773 b2070a3f 2020-03-22 stsp const char *obj_arg = NULL, *symref_target= NULL;
5774 b2070a3f 2020-03-22 stsp char *refname = NULL;
5775 d0eebce4 2019-03-11 stsp
5776 0f104432 2021-11-20 stsp while ((ch = getopt(argc, argv, "c:dr:ls:t")) != -1) {
5777 d0eebce4 2019-03-11 stsp switch (ch) {
5778 e31abbf2 2020-03-22 stsp case 'c':
5779 e31abbf2 2020-03-22 stsp obj_arg = optarg;
5780 e31abbf2 2020-03-22 stsp break;
5781 d0eebce4 2019-03-11 stsp case 'd':
5782 e31abbf2 2020-03-22 stsp do_delete = 1;
5783 d0eebce4 2019-03-11 stsp break;
5784 d0eebce4 2019-03-11 stsp case 'r':
5785 d0eebce4 2019-03-11 stsp repo_path = realpath(optarg, NULL);
5786 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
5787 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5788 9ba1d308 2019-10-21 stsp optarg);
5789 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
5790 d0eebce4 2019-03-11 stsp break;
5791 d0eebce4 2019-03-11 stsp case 'l':
5792 d0eebce4 2019-03-11 stsp do_list = 1;
5793 d1c1ae5f 2019-08-12 stsp break;
5794 d1c1ae5f 2019-08-12 stsp case 's':
5795 e31abbf2 2020-03-22 stsp symref_target = optarg;
5796 0f104432 2021-11-20 stsp break;
5797 0f104432 2021-11-20 stsp case 't':
5798 0f104432 2021-11-20 stsp sort_by_time = 1;
5799 d0eebce4 2019-03-11 stsp break;
5800 d0eebce4 2019-03-11 stsp default:
5801 d0eebce4 2019-03-11 stsp usage_ref();
5802 d0eebce4 2019-03-11 stsp /* NOTREACHED */
5803 d0eebce4 2019-03-11 stsp }
5804 d0eebce4 2019-03-11 stsp }
5805 d0eebce4 2019-03-11 stsp
5806 e31abbf2 2020-03-22 stsp if (obj_arg && do_list)
5807 ff69268e 2020-12-13 stsp option_conflict('c', 'l');
5808 ff69268e 2020-12-13 stsp if (obj_arg && do_delete)
5809 ff69268e 2020-12-13 stsp option_conflict('c', 'd');
5810 907f15e2 2020-03-22 stsp if (obj_arg && symref_target)
5811 ff69268e 2020-12-13 stsp option_conflict('c', 's');
5812 e31abbf2 2020-03-22 stsp if (symref_target && do_delete)
5813 ff69268e 2020-12-13 stsp option_conflict('s', 'd');
5814 e31abbf2 2020-03-22 stsp if (symref_target && do_list)
5815 ff69268e 2020-12-13 stsp option_conflict('s', 'l');
5816 e31abbf2 2020-03-22 stsp if (do_delete && do_list)
5817 ff69268e 2020-12-13 stsp option_conflict('d', 'l');
5818 0f104432 2021-11-20 stsp if (sort_by_time && !do_list)
5819 0f104432 2021-11-20 stsp errx(1, "-t option requires -l option");
5820 d0eebce4 2019-03-11 stsp
5821 d0eebce4 2019-03-11 stsp argc -= optind;
5822 d0eebce4 2019-03-11 stsp argv += optind;
5823 d0eebce4 2019-03-11 stsp
5824 e31abbf2 2020-03-22 stsp if (do_list) {
5825 b2070a3f 2020-03-22 stsp if (argc != 0 && argc != 1)
5826 d0eebce4 2019-03-11 stsp usage_ref();
5827 b2070a3f 2020-03-22 stsp if (argc == 1) {
5828 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
5829 b2070a3f 2020-03-22 stsp if (refname == NULL) {
5830 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
5831 b2070a3f 2020-03-22 stsp goto done;
5832 b2070a3f 2020-03-22 stsp }
5833 b2070a3f 2020-03-22 stsp }
5834 e31abbf2 2020-03-22 stsp } else {
5835 e31abbf2 2020-03-22 stsp if (argc != 1)
5836 e31abbf2 2020-03-22 stsp usage_ref();
5837 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
5838 b2070a3f 2020-03-22 stsp if (refname == NULL) {
5839 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
5840 b2070a3f 2020-03-22 stsp goto done;
5841 b2070a3f 2020-03-22 stsp }
5842 e31abbf2 2020-03-22 stsp }
5843 b2070a3f 2020-03-22 stsp
5844 b2070a3f 2020-03-22 stsp if (refname)
5845 b2070a3f 2020-03-22 stsp got_path_strip_trailing_slashes(refname);
5846 d0eebce4 2019-03-11 stsp
5847 d0eebce4 2019-03-11 stsp #ifndef PROFILE
5848 e0b57350 2019-03-12 stsp if (do_list) {
5849 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5850 e0b57350 2019-03-12 stsp NULL) == -1)
5851 e0b57350 2019-03-12 stsp err(1, "pledge");
5852 e0b57350 2019-03-12 stsp } else {
5853 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5854 e0b57350 2019-03-12 stsp "sendfd unveil", NULL) == -1)
5855 e0b57350 2019-03-12 stsp err(1, "pledge");
5856 e0b57350 2019-03-12 stsp }
5857 d0eebce4 2019-03-11 stsp #endif
5858 d0eebce4 2019-03-11 stsp cwd = getcwd(NULL, 0);
5859 d0eebce4 2019-03-11 stsp if (cwd == NULL) {
5860 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5861 d0eebce4 2019-03-11 stsp goto done;
5862 d0eebce4 2019-03-11 stsp }
5863 d0eebce4 2019-03-11 stsp
5864 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
5865 d0eebce4 2019-03-11 stsp error = got_worktree_open(&worktree, cwd);
5866 d0eebce4 2019-03-11 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5867 d0eebce4 2019-03-11 stsp goto done;
5868 d0eebce4 2019-03-11 stsp else
5869 d0eebce4 2019-03-11 stsp error = NULL;
5870 d0eebce4 2019-03-11 stsp if (worktree) {
5871 d0eebce4 2019-03-11 stsp repo_path =
5872 d0eebce4 2019-03-11 stsp strdup(got_worktree_get_repo_path(worktree));
5873 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
5874 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5875 d0eebce4 2019-03-11 stsp if (error)
5876 d0eebce4 2019-03-11 stsp goto done;
5877 d0eebce4 2019-03-11 stsp } else {
5878 d0eebce4 2019-03-11 stsp repo_path = strdup(cwd);
5879 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
5880 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5881 d0eebce4 2019-03-11 stsp goto done;
5882 d0eebce4 2019-03-11 stsp }
5883 d0eebce4 2019-03-11 stsp }
5884 d0eebce4 2019-03-11 stsp }
5885 d0eebce4 2019-03-11 stsp
5886 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5887 d0eebce4 2019-03-11 stsp if (error != NULL)
5888 d0eebce4 2019-03-11 stsp goto done;
5889 d0eebce4 2019-03-11 stsp
5890 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
5891 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
5892 c02c541e 2019-03-29 stsp if (error)
5893 c02c541e 2019-03-29 stsp goto done;
5894 c02c541e 2019-03-29 stsp
5895 d0eebce4 2019-03-11 stsp if (do_list)
5896 0f104432 2021-11-20 stsp error = list_refs(repo, refname, sort_by_time);
5897 e31abbf2 2020-03-22 stsp else if (do_delete)
5898 161728eb 2021-07-24 stsp error = delete_ref_by_name(repo, refname);
5899 e31abbf2 2020-03-22 stsp else if (symref_target)
5900 e31abbf2 2020-03-22 stsp error = add_symref(repo, refname, symref_target);
5901 e31abbf2 2020-03-22 stsp else {
5902 e31abbf2 2020-03-22 stsp if (obj_arg == NULL)
5903 e31abbf2 2020-03-22 stsp usage_ref();
5904 e31abbf2 2020-03-22 stsp error = add_ref(repo, refname, obj_arg);
5905 e31abbf2 2020-03-22 stsp }
5906 4e759de4 2019-06-26 stsp done:
5907 b2070a3f 2020-03-22 stsp free(refname);
5908 1d0f4054 2021-06-17 stsp if (repo) {
5909 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
5910 1d0f4054 2021-06-17 stsp if (error == NULL)
5911 1d0f4054 2021-06-17 stsp error = close_err;
5912 1d0f4054 2021-06-17 stsp }
5913 4e759de4 2019-06-26 stsp if (worktree)
5914 4e759de4 2019-06-26 stsp got_worktree_close(worktree);
5915 4e759de4 2019-06-26 stsp free(cwd);
5916 4e759de4 2019-06-26 stsp free(repo_path);
5917 4e759de4 2019-06-26 stsp return error;
5918 4e759de4 2019-06-26 stsp }
5919 4e759de4 2019-06-26 stsp
5920 4e759de4 2019-06-26 stsp __dead static void
5921 4e759de4 2019-06-26 stsp usage_branch(void)
5922 4e759de4 2019-06-26 stsp {
5923 4e759de4 2019-06-26 stsp fprintf(stderr,
5924 f76670f0 2021-11-20 stsp "usage: %s branch [-c commit] [-d] [-r repository] [-l] [-t] "
5925 f76670f0 2021-11-20 stsp "[-n] [name]\n", getprogname());
5926 4e759de4 2019-06-26 stsp exit(1);
5927 4e759de4 2019-06-26 stsp }
5928 4e759de4 2019-06-26 stsp
5929 4e759de4 2019-06-26 stsp static const struct got_error *
5930 4e99b47e 2019-10-04 stsp list_branch(struct got_repository *repo, struct got_worktree *worktree,
5931 4e99b47e 2019-10-04 stsp struct got_reference *ref)
5932 4e99b47e 2019-10-04 stsp {
5933 4e99b47e 2019-10-04 stsp const struct got_error *err = NULL;
5934 4e99b47e 2019-10-04 stsp const char *refname, *marker = " ";
5935 4e99b47e 2019-10-04 stsp char *refstr;
5936 4e99b47e 2019-10-04 stsp
5937 4e99b47e 2019-10-04 stsp refname = got_ref_get_name(ref);
5938 4e99b47e 2019-10-04 stsp if (worktree && strcmp(refname,
5939 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree)) == 0) {
5940 4e99b47e 2019-10-04 stsp struct got_object_id *id = NULL;
5941 4e99b47e 2019-10-04 stsp
5942 4e99b47e 2019-10-04 stsp err = got_ref_resolve(&id, repo, ref);
5943 4e99b47e 2019-10-04 stsp if (err)
5944 4e99b47e 2019-10-04 stsp return err;
5945 4e99b47e 2019-10-04 stsp if (got_object_id_cmp(id,
5946 4e99b47e 2019-10-04 stsp got_worktree_get_base_commit_id(worktree)) == 0)
5947 4e99b47e 2019-10-04 stsp marker = "* ";
5948 4e99b47e 2019-10-04 stsp else
5949 4e99b47e 2019-10-04 stsp marker = "~ ";
5950 4e99b47e 2019-10-04 stsp free(id);
5951 4e99b47e 2019-10-04 stsp }
5952 4e99b47e 2019-10-04 stsp
5953 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5954 4e99b47e 2019-10-04 stsp refname += 11;
5955 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5956 4e99b47e 2019-10-04 stsp refname += 18;
5957 34d4e04c 2021-02-08 stsp if (strncmp(refname, "refs/remotes/", 13) == 0)
5958 34d4e04c 2021-02-08 stsp refname += 13;
5959 4e99b47e 2019-10-04 stsp
5960 4e99b47e 2019-10-04 stsp refstr = got_ref_to_str(ref);
5961 4e99b47e 2019-10-04 stsp if (refstr == NULL)
5962 4e99b47e 2019-10-04 stsp return got_error_from_errno("got_ref_to_str");
5963 4e99b47e 2019-10-04 stsp
5964 4e99b47e 2019-10-04 stsp printf("%s%s: %s\n", marker, refname, refstr);
5965 4e99b47e 2019-10-04 stsp free(refstr);
5966 4e99b47e 2019-10-04 stsp return NULL;
5967 4e99b47e 2019-10-04 stsp }
5968 4e99b47e 2019-10-04 stsp
5969 4e99b47e 2019-10-04 stsp static const struct got_error *
5970 ad89fa31 2019-10-04 stsp show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
5971 ad89fa31 2019-10-04 stsp {
5972 ad89fa31 2019-10-04 stsp const char *refname;
5973 ad89fa31 2019-10-04 stsp
5974 ad89fa31 2019-10-04 stsp if (worktree == NULL)
5975 ad89fa31 2019-10-04 stsp return got_error(GOT_ERR_NOT_WORKTREE);
5976 ad89fa31 2019-10-04 stsp
5977 ad89fa31 2019-10-04 stsp refname = got_worktree_get_head_ref_name(worktree);
5978 ad89fa31 2019-10-04 stsp
5979 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5980 ad89fa31 2019-10-04 stsp refname += 11;
5981 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5982 ad89fa31 2019-10-04 stsp refname += 18;
5983 ad89fa31 2019-10-04 stsp
5984 ad89fa31 2019-10-04 stsp printf("%s\n", refname);
5985 ad89fa31 2019-10-04 stsp
5986 ad89fa31 2019-10-04 stsp return NULL;
5987 ad89fa31 2019-10-04 stsp }
5988 ad89fa31 2019-10-04 stsp
5989 ad89fa31 2019-10-04 stsp static const struct got_error *
5990 f76670f0 2021-11-20 stsp list_branches(struct got_repository *repo, struct got_worktree *worktree,
5991 f76670f0 2021-11-20 stsp int sort_by_time)
5992 4e759de4 2019-06-26 stsp {
5993 4e759de4 2019-06-26 stsp static const struct got_error *err = NULL;
5994 4e759de4 2019-06-26 stsp struct got_reflist_head refs;
5995 4e759de4 2019-06-26 stsp struct got_reflist_entry *re;
5996 4e99b47e 2019-10-04 stsp struct got_reference *temp_ref = NULL;
5997 4e99b47e 2019-10-04 stsp int rebase_in_progress, histedit_in_progress;
5998 4e759de4 2019-06-26 stsp
5999 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6000 ba882ee3 2019-07-11 stsp
6001 4e99b47e 2019-10-04 stsp if (worktree) {
6002 4e99b47e 2019-10-04 stsp err = got_worktree_rebase_in_progress(&rebase_in_progress,
6003 4e99b47e 2019-10-04 stsp worktree);
6004 4e99b47e 2019-10-04 stsp if (err)
6005 4e99b47e 2019-10-04 stsp return err;
6006 4e99b47e 2019-10-04 stsp
6007 4e99b47e 2019-10-04 stsp err = got_worktree_histedit_in_progress(&histedit_in_progress,
6008 4e99b47e 2019-10-04 stsp worktree);
6009 4e99b47e 2019-10-04 stsp if (err)
6010 4e99b47e 2019-10-04 stsp return err;
6011 4e99b47e 2019-10-04 stsp
6012 4e99b47e 2019-10-04 stsp if (rebase_in_progress || histedit_in_progress) {
6013 4e99b47e 2019-10-04 stsp err = got_ref_open(&temp_ref, repo,
6014 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree), 0);
6015 4e99b47e 2019-10-04 stsp if (err)
6016 4e99b47e 2019-10-04 stsp return err;
6017 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, temp_ref);
6018 4e99b47e 2019-10-04 stsp got_ref_close(temp_ref);
6019 4e99b47e 2019-10-04 stsp }
6020 4e99b47e 2019-10-04 stsp }
6021 4e99b47e 2019-10-04 stsp
6022 f76670f0 2021-11-20 stsp err = got_ref_list(&refs, repo, "refs/heads", sort_by_time ?
6023 f76670f0 2021-11-20 stsp got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6024 f76670f0 2021-11-20 stsp repo);
6025 4e759de4 2019-06-26 stsp if (err)
6026 4e759de4 2019-06-26 stsp return err;
6027 4e759de4 2019-06-26 stsp
6028 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry)
6029 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, re->ref);
6030 4e759de4 2019-06-26 stsp
6031 4e759de4 2019-06-26 stsp got_ref_list_free(&refs);
6032 34d4e04c 2021-02-08 stsp
6033 f76670f0 2021-11-20 stsp err = got_ref_list(&refs, repo, "refs/remotes", sort_by_time ?
6034 f76670f0 2021-11-20 stsp got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6035 f76670f0 2021-11-20 stsp repo);
6036 34d4e04c 2021-02-08 stsp if (err)
6037 34d4e04c 2021-02-08 stsp return err;
6038 34d4e04c 2021-02-08 stsp
6039 34d4e04c 2021-02-08 stsp TAILQ_FOREACH(re, &refs, entry)
6040 34d4e04c 2021-02-08 stsp list_branch(repo, worktree, re->ref);
6041 34d4e04c 2021-02-08 stsp
6042 34d4e04c 2021-02-08 stsp got_ref_list_free(&refs);
6043 34d4e04c 2021-02-08 stsp
6044 4e759de4 2019-06-26 stsp return NULL;
6045 4e759de4 2019-06-26 stsp }
6046 4e759de4 2019-06-26 stsp
6047 4e759de4 2019-06-26 stsp static const struct got_error *
6048 45cd4e47 2019-08-25 stsp delete_branch(struct got_repository *repo, struct got_worktree *worktree,
6049 45cd4e47 2019-08-25 stsp const char *branch_name)
6050 4e759de4 2019-06-26 stsp {
6051 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
6052 45cd4e47 2019-08-25 stsp struct got_reference *ref = NULL;
6053 2f1457c6 2021-08-27 stsp char *refname, *remote_refname = NULL;
6054 4e759de4 2019-06-26 stsp
6055 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "refs/", 5) == 0)
6056 2f1457c6 2021-08-27 stsp branch_name += 5;
6057 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "heads/", 6) == 0)
6058 2f1457c6 2021-08-27 stsp branch_name += 6;
6059 2f1457c6 2021-08-27 stsp else if (strncmp(branch_name, "remotes/", 8) == 0)
6060 2f1457c6 2021-08-27 stsp branch_name += 8;
6061 2f1457c6 2021-08-27 stsp
6062 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
6063 4e759de4 2019-06-26 stsp return got_error_from_errno("asprintf");
6064 4e759de4 2019-06-26 stsp
6065 2f1457c6 2021-08-27 stsp if (asprintf(&remote_refname, "refs/remotes/%s",
6066 2f1457c6 2021-08-27 stsp branch_name) == -1) {
6067 2f1457c6 2021-08-27 stsp err = got_error_from_errno("asprintf");
6068 4e759de4 2019-06-26 stsp goto done;
6069 2f1457c6 2021-08-27 stsp }
6070 4e759de4 2019-06-26 stsp
6071 2f1457c6 2021-08-27 stsp err = got_ref_open(&ref, repo, refname, 0);
6072 2f1457c6 2021-08-27 stsp if (err) {
6073 2f1457c6 2021-08-27 stsp const struct got_error *err2;
6074 2f1457c6 2021-08-27 stsp if (err->code != GOT_ERR_NOT_REF)
6075 2f1457c6 2021-08-27 stsp goto done;
6076 2f1457c6 2021-08-27 stsp /*
6077 2f1457c6 2021-08-27 stsp * Keep 'err' intact such that if neither branch exists
6078 2f1457c6 2021-08-27 stsp * we report "refs/heads" rather than "refs/remotes" in
6079 2f1457c6 2021-08-27 stsp * our error message.
6080 2f1457c6 2021-08-27 stsp */
6081 2f1457c6 2021-08-27 stsp err2 = got_ref_open(&ref, repo, remote_refname, 0);
6082 2f1457c6 2021-08-27 stsp if (err2)
6083 2f1457c6 2021-08-27 stsp goto done;
6084 2f1457c6 2021-08-27 stsp err = NULL;
6085 2f1457c6 2021-08-27 stsp }
6086 2f1457c6 2021-08-27 stsp
6087 45cd4e47 2019-08-25 stsp if (worktree &&
6088 45cd4e47 2019-08-25 stsp strcmp(got_worktree_get_head_ref_name(worktree),
6089 45cd4e47 2019-08-25 stsp got_ref_get_name(ref)) == 0) {
6090 45cd4e47 2019-08-25 stsp err = got_error_msg(GOT_ERR_SAME_BRANCH,
6091 45cd4e47 2019-08-25 stsp "will not delete this work tree's current branch");
6092 45cd4e47 2019-08-25 stsp goto done;
6093 45cd4e47 2019-08-25 stsp }
6094 45cd4e47 2019-08-25 stsp
6095 978a28a1 2021-09-04 naddy err = delete_ref(repo, ref);
6096 4e759de4 2019-06-26 stsp done:
6097 45cd4e47 2019-08-25 stsp if (ref)
6098 45cd4e47 2019-08-25 stsp got_ref_close(ref);
6099 4e759de4 2019-06-26 stsp free(refname);
6100 2f1457c6 2021-08-27 stsp free(remote_refname);
6101 4e759de4 2019-06-26 stsp return err;
6102 4e759de4 2019-06-26 stsp }
6103 4e759de4 2019-06-26 stsp
6104 4e759de4 2019-06-26 stsp static const struct got_error *
6105 4e759de4 2019-06-26 stsp add_branch(struct got_repository *repo, const char *branch_name,
6106 a74f7e83 2019-11-10 stsp struct got_object_id *base_commit_id)
6107 4e759de4 2019-06-26 stsp {
6108 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
6109 4e759de4 2019-06-26 stsp struct got_reference *ref = NULL;
6110 4e759de4 2019-06-26 stsp char *base_refname = NULL, *refname = NULL;
6111 d3f84d51 2019-07-11 stsp
6112 d3f84d51 2019-07-11 stsp /*
6113 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
6114 d3f84d51 2019-07-11 stsp * While technically a valid reference name, this case is usually
6115 d3f84d51 2019-07-11 stsp * an unintended typo.
6116 d3f84d51 2019-07-11 stsp */
6117 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
6118 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
6119 2f1457c6 2021-08-27 stsp
6120 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "refs/heads/", 11) == 0)
6121 2f1457c6 2021-08-27 stsp branch_name += 11;
6122 4e759de4 2019-06-26 stsp
6123 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
6124 62d463ca 2020-10-20 naddy err = got_error_from_errno("asprintf");
6125 62d463ca 2020-10-20 naddy goto done;
6126 4e759de4 2019-06-26 stsp }
6127 4e759de4 2019-06-26 stsp
6128 4e759de4 2019-06-26 stsp err = got_ref_open(&ref, repo, refname, 0);
6129 4e759de4 2019-06-26 stsp if (err == NULL) {
6130 4e759de4 2019-06-26 stsp err = got_error(GOT_ERR_BRANCH_EXISTS);
6131 4e759de4 2019-06-26 stsp goto done;
6132 4e759de4 2019-06-26 stsp } else if (err->code != GOT_ERR_NOT_REF)
6133 4e759de4 2019-06-26 stsp goto done;
6134 4e759de4 2019-06-26 stsp
6135 a74f7e83 2019-11-10 stsp err = got_ref_alloc(&ref, refname, base_commit_id);
6136 4e759de4 2019-06-26 stsp if (err)
6137 4e759de4 2019-06-26 stsp goto done;
6138 4e759de4 2019-06-26 stsp
6139 4e759de4 2019-06-26 stsp err = got_ref_write(ref, repo);
6140 d0eebce4 2019-03-11 stsp done:
6141 4e759de4 2019-06-26 stsp if (ref)
6142 4e759de4 2019-06-26 stsp got_ref_close(ref);
6143 4e759de4 2019-06-26 stsp free(base_refname);
6144 4e759de4 2019-06-26 stsp free(refname);
6145 4e759de4 2019-06-26 stsp return err;
6146 4e759de4 2019-06-26 stsp }
6147 4e759de4 2019-06-26 stsp
6148 4e759de4 2019-06-26 stsp static const struct got_error *
6149 4e759de4 2019-06-26 stsp cmd_branch(int argc, char *argv[])
6150 4e759de4 2019-06-26 stsp {
6151 4e759de4 2019-06-26 stsp const struct got_error *error = NULL;
6152 4e759de4 2019-06-26 stsp struct got_repository *repo = NULL;
6153 4e759de4 2019-06-26 stsp struct got_worktree *worktree = NULL;
6154 4e759de4 2019-06-26 stsp char *cwd = NULL, *repo_path = NULL;
6155 f76670f0 2021-11-20 stsp int ch, do_list = 0, do_show = 0, do_update = 1, sort_by_time = 0;
6156 a74f7e83 2019-11-10 stsp const char *delref = NULL, *commit_id_arg = NULL;
6157 da76fce2 2020-02-24 stsp struct got_reference *ref = NULL;
6158 da76fce2 2020-02-24 stsp struct got_pathlist_head paths;
6159 da76fce2 2020-02-24 stsp struct got_pathlist_entry *pe;
6160 da76fce2 2020-02-24 stsp struct got_object_id *commit_id = NULL;
6161 da76fce2 2020-02-24 stsp char *commit_id_str = NULL;
6162 4e759de4 2019-06-26 stsp
6163 da76fce2 2020-02-24 stsp TAILQ_INIT(&paths);
6164 da76fce2 2020-02-24 stsp
6165 f76670f0 2021-11-20 stsp while ((ch = getopt(argc, argv, "c:d:r:lnt")) != -1) {
6166 4e759de4 2019-06-26 stsp switch (ch) {
6167 a74f7e83 2019-11-10 stsp case 'c':
6168 a74f7e83 2019-11-10 stsp commit_id_arg = optarg;
6169 a74f7e83 2019-11-10 stsp break;
6170 4e759de4 2019-06-26 stsp case 'd':
6171 4e759de4 2019-06-26 stsp delref = optarg;
6172 4e759de4 2019-06-26 stsp break;
6173 4e759de4 2019-06-26 stsp case 'r':
6174 4e759de4 2019-06-26 stsp repo_path = realpath(optarg, NULL);
6175 4e759de4 2019-06-26 stsp if (repo_path == NULL)
6176 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
6177 9ba1d308 2019-10-21 stsp optarg);
6178 4e759de4 2019-06-26 stsp got_path_strip_trailing_slashes(repo_path);
6179 4e759de4 2019-06-26 stsp break;
6180 4e759de4 2019-06-26 stsp case 'l':
6181 4e759de4 2019-06-26 stsp do_list = 1;
6182 da76fce2 2020-02-24 stsp break;
6183 da76fce2 2020-02-24 stsp case 'n':
6184 da76fce2 2020-02-24 stsp do_update = 0;
6185 4e759de4 2019-06-26 stsp break;
6186 f76670f0 2021-11-20 stsp case 't':
6187 f76670f0 2021-11-20 stsp sort_by_time = 1;
6188 f76670f0 2021-11-20 stsp break;
6189 4e759de4 2019-06-26 stsp default:
6190 4e759de4 2019-06-26 stsp usage_branch();
6191 4e759de4 2019-06-26 stsp /* NOTREACHED */
6192 4e759de4 2019-06-26 stsp }
6193 4e759de4 2019-06-26 stsp }
6194 4e759de4 2019-06-26 stsp
6195 4e759de4 2019-06-26 stsp if (do_list && delref)
6196 ff69268e 2020-12-13 stsp option_conflict('l', 'd');
6197 f76670f0 2021-11-20 stsp if (sort_by_time && !do_list)
6198 f76670f0 2021-11-20 stsp errx(1, "-t option requires -l option");
6199 4e759de4 2019-06-26 stsp
6200 4e759de4 2019-06-26 stsp argc -= optind;
6201 4e759de4 2019-06-26 stsp argv += optind;
6202 ad89fa31 2019-10-04 stsp
6203 ad89fa31 2019-10-04 stsp if (!do_list && !delref && argc == 0)
6204 ad89fa31 2019-10-04 stsp do_show = 1;
6205 4e759de4 2019-06-26 stsp
6206 a74f7e83 2019-11-10 stsp if ((do_list || delref || do_show) && commit_id_arg != NULL)
6207 a74f7e83 2019-11-10 stsp errx(1, "-c option can only be used when creating a branch");
6208 a74f7e83 2019-11-10 stsp
6209 4e759de4 2019-06-26 stsp if (do_list || delref) {
6210 4e759de4 2019-06-26 stsp if (argc > 0)
6211 4e759de4 2019-06-26 stsp usage_branch();
6212 a74f7e83 2019-11-10 stsp } else if (!do_show && argc != 1)
6213 4e759de4 2019-06-26 stsp usage_branch();
6214 4e759de4 2019-06-26 stsp
6215 4e759de4 2019-06-26 stsp #ifndef PROFILE
6216 ad89fa31 2019-10-04 stsp if (do_list || do_show) {
6217 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6218 4e759de4 2019-06-26 stsp NULL) == -1)
6219 4e759de4 2019-06-26 stsp err(1, "pledge");
6220 4e759de4 2019-06-26 stsp } else {
6221 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6222 4e759de4 2019-06-26 stsp "sendfd unveil", NULL) == -1)
6223 4e759de4 2019-06-26 stsp err(1, "pledge");
6224 4e759de4 2019-06-26 stsp }
6225 4e759de4 2019-06-26 stsp #endif
6226 4e759de4 2019-06-26 stsp cwd = getcwd(NULL, 0);
6227 4e759de4 2019-06-26 stsp if (cwd == NULL) {
6228 4e759de4 2019-06-26 stsp error = got_error_from_errno("getcwd");
6229 4e759de4 2019-06-26 stsp goto done;
6230 4e759de4 2019-06-26 stsp }
6231 4e759de4 2019-06-26 stsp
6232 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
6233 4e759de4 2019-06-26 stsp error = got_worktree_open(&worktree, cwd);
6234 4e759de4 2019-06-26 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
6235 4e759de4 2019-06-26 stsp goto done;
6236 4e759de4 2019-06-26 stsp else
6237 4e759de4 2019-06-26 stsp error = NULL;
6238 4e759de4 2019-06-26 stsp if (worktree) {
6239 4e759de4 2019-06-26 stsp repo_path =
6240 4e759de4 2019-06-26 stsp strdup(got_worktree_get_repo_path(worktree));
6241 4e759de4 2019-06-26 stsp if (repo_path == NULL)
6242 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
6243 4e759de4 2019-06-26 stsp if (error)
6244 4e759de4 2019-06-26 stsp goto done;
6245 4e759de4 2019-06-26 stsp } else {
6246 4e759de4 2019-06-26 stsp repo_path = strdup(cwd);
6247 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
6248 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
6249 4e759de4 2019-06-26 stsp goto done;
6250 4e759de4 2019-06-26 stsp }
6251 4e759de4 2019-06-26 stsp }
6252 4e759de4 2019-06-26 stsp }
6253 4e759de4 2019-06-26 stsp
6254 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
6255 4e759de4 2019-06-26 stsp if (error != NULL)
6256 4e759de4 2019-06-26 stsp goto done;
6257 4e759de4 2019-06-26 stsp
6258 4e759de4 2019-06-26 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
6259 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
6260 4e759de4 2019-06-26 stsp if (error)
6261 4e759de4 2019-06-26 stsp goto done;
6262 4e759de4 2019-06-26 stsp
6263 ad89fa31 2019-10-04 stsp if (do_show)
6264 ad89fa31 2019-10-04 stsp error = show_current_branch(repo, worktree);
6265 ad89fa31 2019-10-04 stsp else if (do_list)
6266 f76670f0 2021-11-20 stsp error = list_branches(repo, worktree, sort_by_time);
6267 4e759de4 2019-06-26 stsp else if (delref)
6268 45cd4e47 2019-08-25 stsp error = delete_branch(repo, worktree, delref);
6269 4e759de4 2019-06-26 stsp else {
6270 84de9106 2020-12-26 stsp struct got_reflist_head refs;
6271 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6272 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
6273 84de9106 2020-12-26 stsp NULL);
6274 84de9106 2020-12-26 stsp if (error)
6275 84de9106 2020-12-26 stsp goto done;
6276 a74f7e83 2019-11-10 stsp if (commit_id_arg == NULL)
6277 a74f7e83 2019-11-10 stsp commit_id_arg = worktree ?
6278 4e759de4 2019-06-26 stsp got_worktree_get_head_ref_name(worktree) :
6279 4e759de4 2019-06-26 stsp GOT_REF_HEAD;
6280 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
6281 84de9106 2020-12-26 stsp commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo);
6282 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
6283 a74f7e83 2019-11-10 stsp if (error)
6284 a74f7e83 2019-11-10 stsp goto done;
6285 a74f7e83 2019-11-10 stsp error = add_branch(repo, argv[0], commit_id);
6286 da76fce2 2020-02-24 stsp if (error)
6287 da76fce2 2020-02-24 stsp goto done;
6288 da76fce2 2020-02-24 stsp if (worktree && do_update) {
6289 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
6290 da76fce2 2020-02-24 stsp char *branch_refname = NULL;
6291 da76fce2 2020-02-24 stsp
6292 da76fce2 2020-02-24 stsp error = got_object_id_str(&commit_id_str, commit_id);
6293 da76fce2 2020-02-24 stsp if (error)
6294 da76fce2 2020-02-24 stsp goto done;
6295 da76fce2 2020-02-24 stsp error = get_worktree_paths_from_argv(&paths, 0, NULL,
6296 da76fce2 2020-02-24 stsp worktree);
6297 da76fce2 2020-02-24 stsp if (error)
6298 da76fce2 2020-02-24 stsp goto done;
6299 da76fce2 2020-02-24 stsp if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
6300 da76fce2 2020-02-24 stsp == -1) {
6301 da76fce2 2020-02-24 stsp error = got_error_from_errno("asprintf");
6302 da76fce2 2020-02-24 stsp goto done;
6303 da76fce2 2020-02-24 stsp }
6304 da76fce2 2020-02-24 stsp error = got_ref_open(&ref, repo, branch_refname, 0);
6305 da76fce2 2020-02-24 stsp free(branch_refname);
6306 da76fce2 2020-02-24 stsp if (error)
6307 da76fce2 2020-02-24 stsp goto done;
6308 da76fce2 2020-02-24 stsp error = switch_head_ref(ref, commit_id, worktree,
6309 da76fce2 2020-02-24 stsp repo);
6310 da76fce2 2020-02-24 stsp if (error)
6311 da76fce2 2020-02-24 stsp goto done;
6312 da76fce2 2020-02-24 stsp error = got_worktree_set_base_commit_id(worktree, repo,
6313 da76fce2 2020-02-24 stsp commit_id);
6314 da76fce2 2020-02-24 stsp if (error)
6315 da76fce2 2020-02-24 stsp goto done;
6316 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
6317 da76fce2 2020-02-24 stsp error = got_worktree_checkout_files(worktree, &paths,
6318 9627c110 2020-04-18 stsp repo, update_progress, &upa, check_cancelled,
6319 9627c110 2020-04-18 stsp NULL);
6320 da76fce2 2020-02-24 stsp if (error)
6321 da76fce2 2020-02-24 stsp goto done;
6322 4f3c844b 2021-09-14 stsp if (upa.did_something) {
6323 4f3c844b 2021-09-14 stsp printf("Updated to %s: %s\n",
6324 4f3c844b 2021-09-14 stsp got_worktree_get_head_ref_name(worktree),
6325 4f3c844b 2021-09-14 stsp commit_id_str);
6326 4f3c844b 2021-09-14 stsp }
6327 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
6328 da76fce2 2020-02-24 stsp }
6329 4e759de4 2019-06-26 stsp }
6330 4e759de4 2019-06-26 stsp done:
6331 da76fce2 2020-02-24 stsp if (ref)
6332 da76fce2 2020-02-24 stsp got_ref_close(ref);
6333 1d0f4054 2021-06-17 stsp if (repo) {
6334 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6335 1d0f4054 2021-06-17 stsp if (error == NULL)
6336 1d0f4054 2021-06-17 stsp error = close_err;
6337 1d0f4054 2021-06-17 stsp }
6338 d0eebce4 2019-03-11 stsp if (worktree)
6339 d0eebce4 2019-03-11 stsp got_worktree_close(worktree);
6340 d0eebce4 2019-03-11 stsp free(cwd);
6341 d0eebce4 2019-03-11 stsp free(repo_path);
6342 da76fce2 2020-02-24 stsp free(commit_id);
6343 da76fce2 2020-02-24 stsp free(commit_id_str);
6344 da76fce2 2020-02-24 stsp TAILQ_FOREACH(pe, &paths, entry)
6345 da76fce2 2020-02-24 stsp free((char *)pe->path);
6346 da76fce2 2020-02-24 stsp got_pathlist_free(&paths);
6347 d00136be 2019-03-26 stsp return error;
6348 d00136be 2019-03-26 stsp }
6349 d00136be 2019-03-26 stsp
6350 8e7bd50a 2019-08-22 stsp
6351 d00136be 2019-03-26 stsp __dead static void
6352 8e7bd50a 2019-08-22 stsp usage_tag(void)
6353 8e7bd50a 2019-08-22 stsp {
6354 8e7bd50a 2019-08-22 stsp fprintf(stderr,
6355 80106605 2020-02-24 stsp "usage: %s tag [-c commit] [-r repository] [-l] "
6356 80106605 2020-02-24 stsp "[-m message] name\n", getprogname());
6357 8e7bd50a 2019-08-22 stsp exit(1);
6358 b8bad2ba 2019-08-23 stsp }
6359 b8bad2ba 2019-08-23 stsp
6360 b8bad2ba 2019-08-23 stsp #if 0
6361 b8bad2ba 2019-08-23 stsp static const struct got_error *
6362 b8bad2ba 2019-08-23 stsp sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
6363 b8bad2ba 2019-08-23 stsp {
6364 b8bad2ba 2019-08-23 stsp const struct got_error *err = NULL;
6365 b8bad2ba 2019-08-23 stsp struct got_reflist_entry *re, *se, *new;
6366 b8bad2ba 2019-08-23 stsp struct got_object_id *re_id, *se_id;
6367 b8bad2ba 2019-08-23 stsp struct got_tag_object *re_tag, *se_tag;
6368 b8bad2ba 2019-08-23 stsp time_t re_time, se_time;
6369 b8bad2ba 2019-08-23 stsp
6370 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(re, tags, entry) {
6371 dbdddfee 2021-06-23 naddy se = STAILQ_FIRST(sorted);
6372 b8bad2ba 2019-08-23 stsp if (se == NULL) {
6373 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
6374 b8bad2ba 2019-08-23 stsp if (err)
6375 b8bad2ba 2019-08-23 stsp return err;
6376 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(sorted, new, entry);
6377 b8bad2ba 2019-08-23 stsp continue;
6378 b8bad2ba 2019-08-23 stsp } else {
6379 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&re_id, repo, re->ref);
6380 b8bad2ba 2019-08-23 stsp if (err)
6381 b8bad2ba 2019-08-23 stsp break;
6382 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&re_tag, repo, re_id);
6383 b8bad2ba 2019-08-23 stsp free(re_id);
6384 b8bad2ba 2019-08-23 stsp if (err)
6385 b8bad2ba 2019-08-23 stsp break;
6386 b8bad2ba 2019-08-23 stsp re_time = got_object_tag_get_tagger_time(re_tag);
6387 b8bad2ba 2019-08-23 stsp got_object_tag_close(re_tag);
6388 b8bad2ba 2019-08-23 stsp }
6389 b8bad2ba 2019-08-23 stsp
6390 b8bad2ba 2019-08-23 stsp while (se) {
6391 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&se_id, repo, re->ref);
6392 b8bad2ba 2019-08-23 stsp if (err)
6393 b8bad2ba 2019-08-23 stsp break;
6394 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&se_tag, repo, se_id);
6395 b8bad2ba 2019-08-23 stsp free(se_id);
6396 b8bad2ba 2019-08-23 stsp if (err)
6397 b8bad2ba 2019-08-23 stsp break;
6398 b8bad2ba 2019-08-23 stsp se_time = got_object_tag_get_tagger_time(se_tag);
6399 b8bad2ba 2019-08-23 stsp got_object_tag_close(se_tag);
6400 b8bad2ba 2019-08-23 stsp
6401 b8bad2ba 2019-08-23 stsp if (se_time > re_time) {
6402 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
6403 b8bad2ba 2019-08-23 stsp if (err)
6404 b8bad2ba 2019-08-23 stsp return err;
6405 dbdddfee 2021-06-23 naddy STAILQ_INSERT_AFTER(sorted, se, new, entry);
6406 b8bad2ba 2019-08-23 stsp break;
6407 b8bad2ba 2019-08-23 stsp }
6408 dbdddfee 2021-06-23 naddy se = STAILQ_NEXT(se, entry);
6409 b8bad2ba 2019-08-23 stsp continue;
6410 b8bad2ba 2019-08-23 stsp }
6411 b8bad2ba 2019-08-23 stsp }
6412 b8bad2ba 2019-08-23 stsp done:
6413 b8bad2ba 2019-08-23 stsp return err;
6414 8e7bd50a 2019-08-22 stsp }
6415 b8bad2ba 2019-08-23 stsp #endif
6416 b8bad2ba 2019-08-23 stsp
6417 b8bad2ba 2019-08-23 stsp static const struct got_error *
6418 2a261ce7 2022-04-09 stsp list_tags(struct got_repository *repo)
6419 8e7bd50a 2019-08-22 stsp {
6420 8e7bd50a 2019-08-22 stsp static const struct got_error *err = NULL;
6421 8e7bd50a 2019-08-22 stsp struct got_reflist_head refs;
6422 8e7bd50a 2019-08-22 stsp struct got_reflist_entry *re;
6423 8e7bd50a 2019-08-22 stsp
6424 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6425 8e7bd50a 2019-08-22 stsp
6426 d1f16636 2020-01-15 stsp err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
6427 8e7bd50a 2019-08-22 stsp if (err)
6428 8e7bd50a 2019-08-22 stsp return err;
6429 8e7bd50a 2019-08-22 stsp
6430 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry) {
6431 8e7bd50a 2019-08-22 stsp const char *refname;
6432 8e7bd50a 2019-08-22 stsp char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
6433 8e7bd50a 2019-08-22 stsp char datebuf[26];
6434 d4efa91b 2020-01-14 stsp const char *tagger;
6435 8e7bd50a 2019-08-22 stsp time_t tagger_time;
6436 8e7bd50a 2019-08-22 stsp struct got_object_id *id;
6437 8e7bd50a 2019-08-22 stsp struct got_tag_object *tag;
6438 d4efa91b 2020-01-14 stsp struct got_commit_object *commit = NULL;
6439 8e7bd50a 2019-08-22 stsp
6440 8e7bd50a 2019-08-22 stsp refname = got_ref_get_name(re->ref);
6441 8e7bd50a 2019-08-22 stsp if (strncmp(refname, "refs/tags/", 10) != 0)
6442 8e7bd50a 2019-08-22 stsp continue;
6443 8e7bd50a 2019-08-22 stsp refname += 10;
6444 8e7bd50a 2019-08-22 stsp refstr = got_ref_to_str(re->ref);
6445 8e7bd50a 2019-08-22 stsp if (refstr == NULL) {
6446 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("got_ref_to_str");
6447 8e7bd50a 2019-08-22 stsp break;
6448 8e7bd50a 2019-08-22 stsp }
6449 8e7bd50a 2019-08-22 stsp printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr);
6450 8e7bd50a 2019-08-22 stsp free(refstr);
6451 8e7bd50a 2019-08-22 stsp
6452 8e7bd50a 2019-08-22 stsp err = got_ref_resolve(&id, repo, re->ref);
6453 8e7bd50a 2019-08-22 stsp if (err)
6454 8e7bd50a 2019-08-22 stsp break;
6455 8e7bd50a 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
6456 d4efa91b 2020-01-14 stsp if (err) {
6457 d4efa91b 2020-01-14 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
6458 d4efa91b 2020-01-14 stsp free(id);
6459 d4efa91b 2020-01-14 stsp break;
6460 d4efa91b 2020-01-14 stsp }
6461 d4efa91b 2020-01-14 stsp /* "lightweight" tag */
6462 d4efa91b 2020-01-14 stsp err = got_object_open_as_commit(&commit, repo, id);
6463 d4efa91b 2020-01-14 stsp if (err) {
6464 d4efa91b 2020-01-14 stsp free(id);
6465 d4efa91b 2020-01-14 stsp break;
6466 d4efa91b 2020-01-14 stsp }
6467 d4efa91b 2020-01-14 stsp tagger = got_object_commit_get_committer(commit);
6468 d4efa91b 2020-01-14 stsp tagger_time =
6469 d4efa91b 2020-01-14 stsp got_object_commit_get_committer_time(commit);
6470 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str, id);
6471 d4efa91b 2020-01-14 stsp free(id);
6472 d4efa91b 2020-01-14 stsp if (err)
6473 d4efa91b 2020-01-14 stsp break;
6474 d4efa91b 2020-01-14 stsp } else {
6475 d4efa91b 2020-01-14 stsp free(id);
6476 d4efa91b 2020-01-14 stsp tagger = got_object_tag_get_tagger(tag);
6477 d4efa91b 2020-01-14 stsp tagger_time = got_object_tag_get_tagger_time(tag);
6478 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str,
6479 d4efa91b 2020-01-14 stsp got_object_tag_get_object_id(tag));
6480 d4efa91b 2020-01-14 stsp if (err)
6481 d4efa91b 2020-01-14 stsp break;
6482 d4efa91b 2020-01-14 stsp }
6483 d4efa91b 2020-01-14 stsp printf("from: %s\n", tagger);
6484 2417344c 2019-08-23 stsp datestr = get_datestr(&tagger_time, datebuf);
6485 2417344c 2019-08-23 stsp if (datestr)
6486 2417344c 2019-08-23 stsp printf("date: %s UTC\n", datestr);
6487 d4efa91b 2020-01-14 stsp if (commit)
6488 2417344c 2019-08-23 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str);
6489 d4efa91b 2020-01-14 stsp else {
6490 d4efa91b 2020-01-14 stsp switch (got_object_tag_get_object_type(tag)) {
6491 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_BLOB:
6492 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB,
6493 d4efa91b 2020-01-14 stsp id_str);
6494 d4efa91b 2020-01-14 stsp break;
6495 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TREE:
6496 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TREE,
6497 d4efa91b 2020-01-14 stsp id_str);
6498 d4efa91b 2020-01-14 stsp break;
6499 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_COMMIT:
6500 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT,
6501 d4efa91b 2020-01-14 stsp id_str);
6502 d4efa91b 2020-01-14 stsp break;
6503 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TAG:
6504 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TAG,
6505 d4efa91b 2020-01-14 stsp id_str);
6506 d4efa91b 2020-01-14 stsp break;
6507 d4efa91b 2020-01-14 stsp default:
6508 d4efa91b 2020-01-14 stsp break;
6509 d4efa91b 2020-01-14 stsp }
6510 8e7bd50a 2019-08-22 stsp }
6511 8e7bd50a 2019-08-22 stsp free(id_str);
6512 d4efa91b 2020-01-14 stsp if (commit) {
6513 d4efa91b 2020-01-14 stsp err = got_object_commit_get_logmsg(&tagmsg0, commit);
6514 d4efa91b 2020-01-14 stsp if (err)
6515 d4efa91b 2020-01-14 stsp break;
6516 d4efa91b 2020-01-14 stsp got_object_commit_close(commit);
6517 d4efa91b 2020-01-14 stsp } else {
6518 d4efa91b 2020-01-14 stsp tagmsg0 = strdup(got_object_tag_get_message(tag));
6519 d4efa91b 2020-01-14 stsp got_object_tag_close(tag);
6520 d4efa91b 2020-01-14 stsp if (tagmsg0 == NULL) {
6521 d4efa91b 2020-01-14 stsp err = got_error_from_errno("strdup");
6522 d4efa91b 2020-01-14 stsp break;
6523 d4efa91b 2020-01-14 stsp }
6524 8e7bd50a 2019-08-22 stsp }
6525 8e7bd50a 2019-08-22 stsp
6526 8e7bd50a 2019-08-22 stsp tagmsg = tagmsg0;
6527 8e7bd50a 2019-08-22 stsp do {
6528 8e7bd50a 2019-08-22 stsp line = strsep(&tagmsg, "\n");
6529 8e7bd50a 2019-08-22 stsp if (line)
6530 8e7bd50a 2019-08-22 stsp printf(" %s\n", line);
6531 8e7bd50a 2019-08-22 stsp } while (line);
6532 8e7bd50a 2019-08-22 stsp free(tagmsg0);
6533 8e7bd50a 2019-08-22 stsp }
6534 8e7bd50a 2019-08-22 stsp
6535 8e7bd50a 2019-08-22 stsp got_ref_list_free(&refs);
6536 8e7bd50a 2019-08-22 stsp return NULL;
6537 8e7bd50a 2019-08-22 stsp }
6538 8e7bd50a 2019-08-22 stsp
6539 8e7bd50a 2019-08-22 stsp static const struct got_error *
6540 f372d5cd 2019-10-21 stsp get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
6541 62870f63 2019-08-22 stsp const char *tag_name, const char *repo_path)
6542 8e7bd50a 2019-08-22 stsp {
6543 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
6544 8e7bd50a 2019-08-22 stsp char *template = NULL, *initial_content = NULL;
6545 f372d5cd 2019-10-21 stsp char *editor = NULL;
6546 1601cb9f 2020-09-11 naddy int initial_content_len;
6547 8e7bd50a 2019-08-22 stsp int fd = -1;
6548 8e7bd50a 2019-08-22 stsp
6549 bb63914a 2020-02-17 stsp if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) {
6550 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
6551 8e7bd50a 2019-08-22 stsp goto done;
6552 8e7bd50a 2019-08-22 stsp }
6553 8e7bd50a 2019-08-22 stsp
6554 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
6555 1601cb9f 2020-09-11 naddy "\n# tagging commit %s as %s\n",
6556 1601cb9f 2020-09-11 naddy commit_id_str, tag_name);
6557 1601cb9f 2020-09-11 naddy if (initial_content_len == -1) {
6558 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
6559 8e7bd50a 2019-08-22 stsp goto done;
6560 8e7bd50a 2019-08-22 stsp }
6561 8e7bd50a 2019-08-22 stsp
6562 f372d5cd 2019-10-21 stsp err = got_opentemp_named_fd(tagmsg_path, &fd, template);
6563 8e7bd50a 2019-08-22 stsp if (err)
6564 8e7bd50a 2019-08-22 stsp goto done;
6565 8e7bd50a 2019-08-22 stsp
6566 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
6567 97972933 2020-09-11 stsp err = got_error_from_errno2("write", *tagmsg_path);
6568 97972933 2020-09-11 stsp goto done;
6569 97972933 2020-09-11 stsp }
6570 8e7bd50a 2019-08-22 stsp
6571 8e7bd50a 2019-08-22 stsp err = get_editor(&editor);
6572 8e7bd50a 2019-08-22 stsp if (err)
6573 8e7bd50a 2019-08-22 stsp goto done;
6574 bfa12d5e 2020-09-26 stsp err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content,
6575 0d5bb276 2020-12-15 stsp initial_content_len, 1);
6576 8e7bd50a 2019-08-22 stsp done:
6577 8e7bd50a 2019-08-22 stsp free(initial_content);
6578 8e7bd50a 2019-08-22 stsp free(template);
6579 8e7bd50a 2019-08-22 stsp free(editor);
6580 8e7bd50a 2019-08-22 stsp
6581 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
6582 97972933 2020-09-11 stsp err = got_error_from_errno2("close", *tagmsg_path);
6583 97972933 2020-09-11 stsp
6584 8e7bd50a 2019-08-22 stsp /* Editor is done; we can now apply unveil(2) */
6585 59f86c76 2020-09-11 stsp if (err == NULL)
6586 8e7bd50a 2019-08-22 stsp err = apply_unveil(repo_path, 0, NULL);
6587 59f86c76 2020-09-11 stsp if (err) {
6588 59f86c76 2020-09-11 stsp free(*tagmsg);
6589 59f86c76 2020-09-11 stsp *tagmsg = NULL;
6590 8e7bd50a 2019-08-22 stsp }
6591 8e7bd50a 2019-08-22 stsp return err;
6592 8e7bd50a 2019-08-22 stsp }
6593 8e7bd50a 2019-08-22 stsp
6594 8e7bd50a 2019-08-22 stsp static const struct got_error *
6595 ffd9dda7 2022-04-10 stsp add_tag(struct got_repository *repo, const char *tagger,
6596 50b0790e 2020-09-11 stsp const char *tag_name, const char *commit_arg, const char *tagmsg_arg)
6597 8e7bd50a 2019-08-22 stsp {
6598 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
6599 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id = NULL, *tag_id = NULL;
6600 8e7bd50a 2019-08-22 stsp char *label = NULL, *commit_id_str = NULL;
6601 8e7bd50a 2019-08-22 stsp struct got_reference *ref = NULL;
6602 ffd9dda7 2022-04-10 stsp char *refname = NULL, *tagmsg = NULL;
6603 f372d5cd 2019-10-21 stsp char *tagmsg_path = NULL, *tag_id_str = NULL;
6604 f372d5cd 2019-10-21 stsp int preserve_tagmsg = 0;
6605 84de9106 2020-12-26 stsp struct got_reflist_head refs;
6606 8e7bd50a 2019-08-22 stsp
6607 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6608 84de9106 2020-12-26 stsp
6609 8e7bd50a 2019-08-22 stsp /*
6610 bd5895f3 2019-11-28 stsp * Don't let the user create a tag name with a leading '-'.
6611 8e7bd50a 2019-08-22 stsp * While technically a valid reference name, this case is usually
6612 8e7bd50a 2019-08-22 stsp * an unintended typo.
6613 8e7bd50a 2019-08-22 stsp */
6614 bd5895f3 2019-11-28 stsp if (tag_name[0] == '-')
6615 bd5895f3 2019-11-28 stsp return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS);
6616 8e7bd50a 2019-08-22 stsp
6617 84de9106 2020-12-26 stsp err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
6618 84de9106 2020-12-26 stsp if (err)
6619 84de9106 2020-12-26 stsp goto done;
6620 84de9106 2020-12-26 stsp
6621 71a27632 2020-01-15 stsp err = got_repo_match_object_id(&commit_id, &label, commit_arg,
6622 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_COMMIT, &refs, repo);
6623 8e7bd50a 2019-08-22 stsp if (err)
6624 8e7bd50a 2019-08-22 stsp goto done;
6625 8e7bd50a 2019-08-22 stsp
6626 8e7bd50a 2019-08-22 stsp err = got_object_id_str(&commit_id_str, commit_id);
6627 8e7bd50a 2019-08-22 stsp if (err)
6628 8e7bd50a 2019-08-22 stsp goto done;
6629 8e7bd50a 2019-08-22 stsp
6630 8e7bd50a 2019-08-22 stsp if (strncmp("refs/tags/", tag_name, 10) == 0) {
6631 8e7bd50a 2019-08-22 stsp refname = strdup(tag_name);
6632 8e7bd50a 2019-08-22 stsp if (refname == NULL) {
6633 62d463ca 2020-10-20 naddy err = got_error_from_errno("strdup");
6634 62d463ca 2020-10-20 naddy goto done;
6635 8e7bd50a 2019-08-22 stsp }
6636 8e7bd50a 2019-08-22 stsp tag_name += 10;
6637 8e7bd50a 2019-08-22 stsp } else if (asprintf(&refname, "refs/tags/%s", tag_name) == -1) {
6638 62d463ca 2020-10-20 naddy err = got_error_from_errno("asprintf");
6639 62d463ca 2020-10-20 naddy goto done;
6640 8e7bd50a 2019-08-22 stsp }
6641 8e7bd50a 2019-08-22 stsp
6642 8e7bd50a 2019-08-22 stsp err = got_ref_open(&ref, repo, refname, 0);
6643 8e7bd50a 2019-08-22 stsp if (err == NULL) {
6644 8e7bd50a 2019-08-22 stsp err = got_error(GOT_ERR_TAG_EXISTS);
6645 8e7bd50a 2019-08-22 stsp goto done;
6646 8e7bd50a 2019-08-22 stsp } else if (err->code != GOT_ERR_NOT_REF)
6647 8e7bd50a 2019-08-22 stsp goto done;
6648 8e7bd50a 2019-08-22 stsp
6649 8e7bd50a 2019-08-22 stsp if (tagmsg_arg == NULL) {
6650 f372d5cd 2019-10-21 stsp err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
6651 62870f63 2019-08-22 stsp tag_name, got_repo_get_path(repo));
6652 f372d5cd 2019-10-21 stsp if (err) {
6653 f372d5cd 2019-10-21 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY &&
6654 f372d5cd 2019-10-21 stsp tagmsg_path != NULL)
6655 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6656 8e7bd50a 2019-08-22 stsp goto done;
6657 f372d5cd 2019-10-21 stsp }
6658 8e7bd50a 2019-08-22 stsp }
6659 8e7bd50a 2019-08-22 stsp
6660 8e7bd50a 2019-08-22 stsp err = got_object_tag_create(&tag_id, tag_name, commit_id,
6661 8e7bd50a 2019-08-22 stsp tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, repo);
6662 f372d5cd 2019-10-21 stsp if (err) {
6663 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6664 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6665 8e7bd50a 2019-08-22 stsp goto done;
6666 f372d5cd 2019-10-21 stsp }
6667 8e7bd50a 2019-08-22 stsp
6668 8e7bd50a 2019-08-22 stsp err = got_ref_alloc(&ref, refname, tag_id);
6669 f372d5cd 2019-10-21 stsp if (err) {
6670 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6671 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6672 8e7bd50a 2019-08-22 stsp goto done;
6673 f372d5cd 2019-10-21 stsp }
6674 8e7bd50a 2019-08-22 stsp
6675 8e7bd50a 2019-08-22 stsp err = got_ref_write(ref, repo);
6676 f372d5cd 2019-10-21 stsp if (err) {
6677 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6678 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6679 f372d5cd 2019-10-21 stsp goto done;
6680 f372d5cd 2019-10-21 stsp }
6681 8e7bd50a 2019-08-22 stsp
6682 f372d5cd 2019-10-21 stsp err = got_object_id_str(&tag_id_str, tag_id);
6683 f372d5cd 2019-10-21 stsp if (err) {
6684 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6685 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6686 f372d5cd 2019-10-21 stsp goto done;
6687 8e7bd50a 2019-08-22 stsp }
6688 f372d5cd 2019-10-21 stsp printf("Created tag %s\n", tag_id_str);
6689 8e7bd50a 2019-08-22 stsp done:
6690 f372d5cd 2019-10-21 stsp if (preserve_tagmsg) {
6691 f372d5cd 2019-10-21 stsp fprintf(stderr, "%s: tag message preserved in %s\n",
6692 f372d5cd 2019-10-21 stsp getprogname(), tagmsg_path);
6693 f372d5cd 2019-10-21 stsp } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL)
6694 f372d5cd 2019-10-21 stsp err = got_error_from_errno2("unlink", tagmsg_path);
6695 f372d5cd 2019-10-21 stsp free(tag_id_str);
6696 8e7bd50a 2019-08-22 stsp if (ref)
6697 8e7bd50a 2019-08-22 stsp got_ref_close(ref);
6698 8e7bd50a 2019-08-22 stsp free(commit_id);
6699 8e7bd50a 2019-08-22 stsp free(commit_id_str);
6700 8e7bd50a 2019-08-22 stsp free(refname);
6701 8e7bd50a 2019-08-22 stsp free(tagmsg);
6702 f372d5cd 2019-10-21 stsp free(tagmsg_path);
6703 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
6704 8e7bd50a 2019-08-22 stsp return err;
6705 8e7bd50a 2019-08-22 stsp }
6706 8e7bd50a 2019-08-22 stsp
6707 8e7bd50a 2019-08-22 stsp static const struct got_error *
6708 8e7bd50a 2019-08-22 stsp cmd_tag(int argc, char *argv[])
6709 8e7bd50a 2019-08-22 stsp {
6710 8e7bd50a 2019-08-22 stsp const struct got_error *error = NULL;
6711 8e7bd50a 2019-08-22 stsp struct got_repository *repo = NULL;
6712 8e7bd50a 2019-08-22 stsp struct got_worktree *worktree = NULL;
6713 8e7bd50a 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
6714 ffd9dda7 2022-04-10 stsp char *gitconfig_path = NULL, *tagger = NULL;
6715 8e7bd50a 2019-08-22 stsp const char *tag_name, *commit_id_arg = NULL, *tagmsg = NULL;
6716 8e7bd50a 2019-08-22 stsp int ch, do_list = 0;
6717 8e7bd50a 2019-08-22 stsp
6718 80106605 2020-02-24 stsp while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) {
6719 8e7bd50a 2019-08-22 stsp switch (ch) {
6720 80106605 2020-02-24 stsp case 'c':
6721 80106605 2020-02-24 stsp commit_id_arg = optarg;
6722 80106605 2020-02-24 stsp break;
6723 8e7bd50a 2019-08-22 stsp case 'm':
6724 8e7bd50a 2019-08-22 stsp tagmsg = optarg;
6725 8e7bd50a 2019-08-22 stsp break;
6726 8e7bd50a 2019-08-22 stsp case 'r':
6727 8e7bd50a 2019-08-22 stsp repo_path = realpath(optarg, NULL);
6728 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
6729 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
6730 9ba1d308 2019-10-21 stsp optarg);
6731 8e7bd50a 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
6732 8e7bd50a 2019-08-22 stsp break;
6733 8e7bd50a 2019-08-22 stsp case 'l':
6734 8e7bd50a 2019-08-22 stsp do_list = 1;
6735 8e7bd50a 2019-08-22 stsp break;
6736 8e7bd50a 2019-08-22 stsp default:
6737 8e7bd50a 2019-08-22 stsp usage_tag();
6738 8e7bd50a 2019-08-22 stsp /* NOTREACHED */
6739 8e7bd50a 2019-08-22 stsp }
6740 8e7bd50a 2019-08-22 stsp }
6741 8e7bd50a 2019-08-22 stsp
6742 8e7bd50a 2019-08-22 stsp argc -= optind;
6743 8e7bd50a 2019-08-22 stsp argv += optind;
6744 8e7bd50a 2019-08-22 stsp
6745 8e7bd50a 2019-08-22 stsp if (do_list) {
6746 80106605 2020-02-24 stsp if (commit_id_arg != NULL)
6747 775ce909 2020-03-22 stsp errx(1,
6748 775ce909 2020-03-22 stsp "-c option can only be used when creating a tag");
6749 8e7bd50a 2019-08-22 stsp if (tagmsg)
6750 ff69268e 2020-12-13 stsp option_conflict('l', 'm');
6751 8e7bd50a 2019-08-22 stsp if (argc > 0)
6752 8e7bd50a 2019-08-22 stsp usage_tag();
6753 80106605 2020-02-24 stsp } else if (argc != 1)
6754 8e7bd50a 2019-08-22 stsp usage_tag();
6755 80106605 2020-02-24 stsp
6756 a2887370 2019-08-23 stsp tag_name = argv[0];
6757 8e7bd50a 2019-08-22 stsp
6758 8e7bd50a 2019-08-22 stsp #ifndef PROFILE
6759 8e7bd50a 2019-08-22 stsp if (do_list) {
6760 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6761 8e7bd50a 2019-08-22 stsp NULL) == -1)
6762 8e7bd50a 2019-08-22 stsp err(1, "pledge");
6763 8e7bd50a 2019-08-22 stsp } else {
6764 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6765 8e7bd50a 2019-08-22 stsp "sendfd unveil", NULL) == -1)
6766 8e7bd50a 2019-08-22 stsp err(1, "pledge");
6767 8e7bd50a 2019-08-22 stsp }
6768 8e7bd50a 2019-08-22 stsp #endif
6769 8e7bd50a 2019-08-22 stsp cwd = getcwd(NULL, 0);
6770 8e7bd50a 2019-08-22 stsp if (cwd == NULL) {
6771 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("getcwd");
6772 8e7bd50a 2019-08-22 stsp goto done;
6773 8e7bd50a 2019-08-22 stsp }
6774 8e7bd50a 2019-08-22 stsp
6775 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
6776 8e7bd50a 2019-08-22 stsp error = got_worktree_open(&worktree, cwd);
6777 8e7bd50a 2019-08-22 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
6778 8e7bd50a 2019-08-22 stsp goto done;
6779 8e7bd50a 2019-08-22 stsp else
6780 8e7bd50a 2019-08-22 stsp error = NULL;
6781 8e7bd50a 2019-08-22 stsp if (worktree) {
6782 8e7bd50a 2019-08-22 stsp repo_path =
6783 8e7bd50a 2019-08-22 stsp strdup(got_worktree_get_repo_path(worktree));
6784 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
6785 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
6786 8e7bd50a 2019-08-22 stsp if (error)
6787 8e7bd50a 2019-08-22 stsp goto done;
6788 8e7bd50a 2019-08-22 stsp } else {
6789 8e7bd50a 2019-08-22 stsp repo_path = strdup(cwd);
6790 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
6791 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
6792 8e7bd50a 2019-08-22 stsp goto done;
6793 8e7bd50a 2019-08-22 stsp }
6794 8e7bd50a 2019-08-22 stsp }
6795 8e7bd50a 2019-08-22 stsp }
6796 8e7bd50a 2019-08-22 stsp
6797 8e7bd50a 2019-08-22 stsp if (do_list) {
6798 2a261ce7 2022-04-09 stsp if (worktree) {
6799 2a261ce7 2022-04-09 stsp /* Release work tree lock. */
6800 2a261ce7 2022-04-09 stsp got_worktree_close(worktree);
6801 2a261ce7 2022-04-09 stsp worktree = NULL;
6802 2a261ce7 2022-04-09 stsp }
6803 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
6804 c9956ddf 2019-09-08 stsp if (error != NULL)
6805 c9956ddf 2019-09-08 stsp goto done;
6806 8e7bd50a 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
6807 8e7bd50a 2019-08-22 stsp if (error)
6808 8e7bd50a 2019-08-22 stsp goto done;
6809 2a261ce7 2022-04-09 stsp error = list_tags(repo);
6810 8e7bd50a 2019-08-22 stsp } else {
6811 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
6812 c9956ddf 2019-09-08 stsp if (error)
6813 c9956ddf 2019-09-08 stsp goto done;
6814 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
6815 c9956ddf 2019-09-08 stsp if (error != NULL)
6816 c9956ddf 2019-09-08 stsp goto done;
6817 c9956ddf 2019-09-08 stsp
6818 ffd9dda7 2022-04-10 stsp error = get_author(&tagger, repo, worktree);
6819 ffd9dda7 2022-04-10 stsp if (error)
6820 ffd9dda7 2022-04-10 stsp goto done;
6821 ffd9dda7 2022-04-10 stsp if (worktree) {
6822 ffd9dda7 2022-04-10 stsp /* Release work tree lock. */
6823 ffd9dda7 2022-04-10 stsp got_worktree_close(worktree);
6824 ffd9dda7 2022-04-10 stsp worktree = NULL;
6825 ffd9dda7 2022-04-10 stsp }
6826 ffd9dda7 2022-04-10 stsp
6827 8e7bd50a 2019-08-22 stsp if (tagmsg) {
6828 42a285e2 2020-10-01 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
6829 8e7bd50a 2019-08-22 stsp if (error)
6830 8e7bd50a 2019-08-22 stsp goto done;
6831 8e7bd50a 2019-08-22 stsp }
6832 8e7bd50a 2019-08-22 stsp
6833 8e7bd50a 2019-08-22 stsp if (commit_id_arg == NULL) {
6834 8e7bd50a 2019-08-22 stsp struct got_reference *head_ref;
6835 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id;
6836 8e7bd50a 2019-08-22 stsp error = got_ref_open(&head_ref, repo,
6837 8e7bd50a 2019-08-22 stsp worktree ? got_worktree_get_head_ref_name(worktree)
6838 8e7bd50a 2019-08-22 stsp : GOT_REF_HEAD, 0);
6839 8e7bd50a 2019-08-22 stsp if (error)
6840 8e7bd50a 2019-08-22 stsp goto done;
6841 8e7bd50a 2019-08-22 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
6842 8e7bd50a 2019-08-22 stsp got_ref_close(head_ref);
6843 8e7bd50a 2019-08-22 stsp if (error)
6844 8e7bd50a 2019-08-22 stsp goto done;
6845 8e7bd50a 2019-08-22 stsp error = got_object_id_str(&commit_id_str, commit_id);
6846 8e7bd50a 2019-08-22 stsp free(commit_id);
6847 8e7bd50a 2019-08-22 stsp if (error)
6848 8e7bd50a 2019-08-22 stsp goto done;
6849 8e7bd50a 2019-08-22 stsp }
6850 8e7bd50a 2019-08-22 stsp
6851 ffd9dda7 2022-04-10 stsp error = add_tag(repo, tagger, tag_name,
6852 8e7bd50a 2019-08-22 stsp commit_id_str ? commit_id_str : commit_id_arg, tagmsg);
6853 8e7bd50a 2019-08-22 stsp }
6854 8e7bd50a 2019-08-22 stsp done:
6855 1d0f4054 2021-06-17 stsp if (repo) {
6856 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6857 1d0f4054 2021-06-17 stsp if (error == NULL)
6858 1d0f4054 2021-06-17 stsp error = close_err;
6859 1d0f4054 2021-06-17 stsp }
6860 8e7bd50a 2019-08-22 stsp if (worktree)
6861 8e7bd50a 2019-08-22 stsp got_worktree_close(worktree);
6862 8e7bd50a 2019-08-22 stsp free(cwd);
6863 8e7bd50a 2019-08-22 stsp free(repo_path);
6864 c9956ddf 2019-09-08 stsp free(gitconfig_path);
6865 8e7bd50a 2019-08-22 stsp free(commit_id_str);
6866 ffd9dda7 2022-04-10 stsp free(tagger);
6867 8e7bd50a 2019-08-22 stsp return error;
6868 8e7bd50a 2019-08-22 stsp }
6869 8e7bd50a 2019-08-22 stsp
6870 8e7bd50a 2019-08-22 stsp __dead static void
6871 d00136be 2019-03-26 stsp usage_add(void)
6872 d00136be 2019-03-26 stsp {
6873 c29c428a 2019-12-16 stsp fprintf(stderr, "usage: %s add [-R] [-I] path ...\n",
6874 022fae89 2019-12-06 tracey getprogname());
6875 d00136be 2019-03-26 stsp exit(1);
6876 d00136be 2019-03-26 stsp }
6877 d00136be 2019-03-26 stsp
6878 d00136be 2019-03-26 stsp static const struct got_error *
6879 4e68cba3 2019-11-23 stsp add_progress(void *arg, unsigned char status, const char *path)
6880 4e68cba3 2019-11-23 stsp {
6881 4e68cba3 2019-11-23 stsp while (path[0] == '/')
6882 4e68cba3 2019-11-23 stsp path++;
6883 4e68cba3 2019-11-23 stsp printf("%c %s\n", status, path);
6884 4e68cba3 2019-11-23 stsp return NULL;
6885 4e68cba3 2019-11-23 stsp }
6886 4e68cba3 2019-11-23 stsp
6887 4e68cba3 2019-11-23 stsp static const struct got_error *
6888 d00136be 2019-03-26 stsp cmd_add(int argc, char *argv[])
6889 d00136be 2019-03-26 stsp {
6890 d00136be 2019-03-26 stsp const struct got_error *error = NULL;
6891 031a5338 2019-03-26 stsp struct got_repository *repo = NULL;
6892 d00136be 2019-03-26 stsp struct got_worktree *worktree = NULL;
6893 1dd54920 2019-05-11 stsp char *cwd = NULL;
6894 1dd54920 2019-05-11 stsp struct got_pathlist_head paths;
6895 1dd54920 2019-05-11 stsp struct got_pathlist_entry *pe;
6896 022fae89 2019-12-06 tracey int ch, can_recurse = 0, no_ignores = 0;
6897 1dd54920 2019-05-11 stsp
6898 1dd54920 2019-05-11 stsp TAILQ_INIT(&paths);
6899 d00136be 2019-03-26 stsp
6900 022fae89 2019-12-06 tracey while ((ch = getopt(argc, argv, "IR")) != -1) {
6901 d00136be 2019-03-26 stsp switch (ch) {
6902 022fae89 2019-12-06 tracey case 'I':
6903 022fae89 2019-12-06 tracey no_ignores = 1;
6904 022fae89 2019-12-06 tracey break;
6905 4e68cba3 2019-11-23 stsp case 'R':
6906 4e68cba3 2019-11-23 stsp can_recurse = 1;
6907 4e68cba3 2019-11-23 stsp break;
6908 d00136be 2019-03-26 stsp default:
6909 d00136be 2019-03-26 stsp usage_add();
6910 d00136be 2019-03-26 stsp /* NOTREACHED */
6911 d00136be 2019-03-26 stsp }
6912 d00136be 2019-03-26 stsp }
6913 d00136be 2019-03-26 stsp
6914 d00136be 2019-03-26 stsp argc -= optind;
6915 d00136be 2019-03-26 stsp argv += optind;
6916 d00136be 2019-03-26 stsp
6917 43012d58 2019-07-14 stsp #ifndef PROFILE
6918 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6919 43012d58 2019-07-14 stsp NULL) == -1)
6920 43012d58 2019-07-14 stsp err(1, "pledge");
6921 43012d58 2019-07-14 stsp #endif
6922 723c305c 2019-05-11 jcs if (argc < 1)
6923 d00136be 2019-03-26 stsp usage_add();
6924 d00136be 2019-03-26 stsp
6925 d00136be 2019-03-26 stsp cwd = getcwd(NULL, 0);
6926 d00136be 2019-03-26 stsp if (cwd == NULL) {
6927 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6928 d00136be 2019-03-26 stsp goto done;
6929 d00136be 2019-03-26 stsp }
6930 723c305c 2019-05-11 jcs
6931 d00136be 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
6932 fa51e947 2020-03-27 stsp if (error) {
6933 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6934 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "add", cwd);
6935 d00136be 2019-03-26 stsp goto done;
6936 fa51e947 2020-03-27 stsp }
6937 d00136be 2019-03-26 stsp
6938 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6939 c9956ddf 2019-09-08 stsp NULL);
6940 031a5338 2019-03-26 stsp if (error != NULL)
6941 031a5338 2019-03-26 stsp goto done;
6942 031a5338 2019-03-26 stsp
6943 031a5338 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
6944 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6945 d00136be 2019-03-26 stsp if (error)
6946 d00136be 2019-03-26 stsp goto done;
6947 d00136be 2019-03-26 stsp
6948 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6949 6d022e97 2019-08-04 stsp if (error)
6950 022fae89 2019-12-06 tracey goto done;
6951 022fae89 2019-12-06 tracey
6952 4e68cba3 2019-11-23 stsp if (!can_recurse) {
6953 4e68cba3 2019-11-23 stsp char *ondisk_path;
6954 4e68cba3 2019-11-23 stsp struct stat sb;
6955 4e68cba3 2019-11-23 stsp TAILQ_FOREACH(pe, &paths, entry) {
6956 4e68cba3 2019-11-23 stsp if (asprintf(&ondisk_path, "%s/%s",
6957 4e68cba3 2019-11-23 stsp got_worktree_get_root_path(worktree),
6958 62d463ca 2020-10-20 naddy pe->path) == -1) {
6959 4e68cba3 2019-11-23 stsp error = got_error_from_errno("asprintf");
6960 4e68cba3 2019-11-23 stsp goto done;
6961 4e68cba3 2019-11-23 stsp }
6962 4e68cba3 2019-11-23 stsp if (lstat(ondisk_path, &sb) == -1) {
6963 4e68cba3 2019-11-23 stsp if (errno == ENOENT) {
6964 4e68cba3 2019-11-23 stsp free(ondisk_path);
6965 4e68cba3 2019-11-23 stsp continue;
6966 4e68cba3 2019-11-23 stsp }
6967 4e68cba3 2019-11-23 stsp error = got_error_from_errno2("lstat",
6968 4e68cba3 2019-11-23 stsp ondisk_path);
6969 4e68cba3 2019-11-23 stsp free(ondisk_path);
6970 4e68cba3 2019-11-23 stsp goto done;
6971 4e68cba3 2019-11-23 stsp }
6972 4e68cba3 2019-11-23 stsp free(ondisk_path);
6973 4e68cba3 2019-11-23 stsp if (S_ISDIR(sb.st_mode)) {
6974 4e68cba3 2019-11-23 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
6975 4e68cba3 2019-11-23 stsp "adding directories requires -R option");
6976 4e68cba3 2019-11-23 stsp goto done;
6977 4e68cba3 2019-11-23 stsp }
6978 4e68cba3 2019-11-23 stsp }
6979 4e68cba3 2019-11-23 stsp }
6980 022fae89 2019-12-06 tracey
6981 4e68cba3 2019-11-23 stsp error = got_worktree_schedule_add(worktree, &paths, add_progress,
6982 022fae89 2019-12-06 tracey NULL, repo, no_ignores);
6983 d00136be 2019-03-26 stsp done:
6984 1d0f4054 2021-06-17 stsp if (repo) {
6985 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6986 1d0f4054 2021-06-17 stsp if (error == NULL)
6987 1d0f4054 2021-06-17 stsp error = close_err;
6988 1d0f4054 2021-06-17 stsp }
6989 d00136be 2019-03-26 stsp if (worktree)
6990 d00136be 2019-03-26 stsp got_worktree_close(worktree);
6991 1dd54920 2019-05-11 stsp TAILQ_FOREACH(pe, &paths, entry)
6992 1dd54920 2019-05-11 stsp free((char *)pe->path);
6993 1dd54920 2019-05-11 stsp got_pathlist_free(&paths);
6994 2ec1f75b 2019-03-26 stsp free(cwd);
6995 2ec1f75b 2019-03-26 stsp return error;
6996 2ec1f75b 2019-03-26 stsp }
6997 2ec1f75b 2019-03-26 stsp
6998 2ec1f75b 2019-03-26 stsp __dead static void
6999 648e4ef7 2019-07-09 stsp usage_remove(void)
7000 2ec1f75b 2019-03-26 stsp {
7001 766841c2 2020-08-13 stsp fprintf(stderr, "usage: %s remove [-f] [-k] [-R] [-s status-codes] "
7002 766841c2 2020-08-13 stsp "path ...\n", getprogname());
7003 2ec1f75b 2019-03-26 stsp exit(1);
7004 2a06fe5f 2019-08-24 stsp }
7005 2a06fe5f 2019-08-24 stsp
7006 2a06fe5f 2019-08-24 stsp static const struct got_error *
7007 2a06fe5f 2019-08-24 stsp print_remove_status(void *arg, unsigned char status,
7008 f2a9dc41 2019-12-13 tracey unsigned char staged_status, const char *path)
7009 2a06fe5f 2019-08-24 stsp {
7010 f2a9dc41 2019-12-13 tracey while (path[0] == '/')
7011 f2a9dc41 2019-12-13 tracey path++;
7012 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
7013 2a06fe5f 2019-08-24 stsp return NULL;
7014 2a06fe5f 2019-08-24 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
7015 2a06fe5f 2019-08-24 stsp status = GOT_STATUS_NO_CHANGE;
7016 2a06fe5f 2019-08-24 stsp printf("%c%c %s\n", status, staged_status, path);
7017 2a06fe5f 2019-08-24 stsp return NULL;
7018 2ec1f75b 2019-03-26 stsp }
7019 2ec1f75b 2019-03-26 stsp
7020 2ec1f75b 2019-03-26 stsp static const struct got_error *
7021 648e4ef7 2019-07-09 stsp cmd_remove(int argc, char *argv[])
7022 2ec1f75b 2019-03-26 stsp {
7023 2ec1f75b 2019-03-26 stsp const struct got_error *error = NULL;
7024 2ec1f75b 2019-03-26 stsp struct got_worktree *worktree = NULL;
7025 2ec1f75b 2019-03-26 stsp struct got_repository *repo = NULL;
7026 766841c2 2020-08-13 stsp const char *status_codes = NULL;
7027 17ed4618 2019-06-02 stsp char *cwd = NULL;
7028 17ed4618 2019-06-02 stsp struct got_pathlist_head paths;
7029 17ed4618 2019-06-02 stsp struct got_pathlist_entry *pe;
7030 766841c2 2020-08-13 stsp int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i;
7031 4e12cd97 2022-01-25 stsp int ignore_missing_paths = 0;
7032 2ec1f75b 2019-03-26 stsp
7033 17ed4618 2019-06-02 stsp TAILQ_INIT(&paths);
7034 17ed4618 2019-06-02 stsp
7035 766841c2 2020-08-13 stsp while ((ch = getopt(argc, argv, "fkRs:")) != -1) {
7036 2ec1f75b 2019-03-26 stsp switch (ch) {
7037 2ec1f75b 2019-03-26 stsp case 'f':
7038 2ec1f75b 2019-03-26 stsp delete_local_mods = 1;
7039 4e12cd97 2022-01-25 stsp ignore_missing_paths = 1;
7040 2ec1f75b 2019-03-26 stsp break;
7041 70e3e7f5 2019-12-13 tracey case 'k':
7042 70e3e7f5 2019-12-13 tracey keep_on_disk = 1;
7043 70e3e7f5 2019-12-13 tracey break;
7044 f2a9dc41 2019-12-13 tracey case 'R':
7045 f2a9dc41 2019-12-13 tracey can_recurse = 1;
7046 f2a9dc41 2019-12-13 tracey break;
7047 766841c2 2020-08-13 stsp case 's':
7048 766841c2 2020-08-13 stsp for (i = 0; i < strlen(optarg); i++) {
7049 766841c2 2020-08-13 stsp switch (optarg[i]) {
7050 766841c2 2020-08-13 stsp case GOT_STATUS_MODIFY:
7051 766841c2 2020-08-13 stsp delete_local_mods = 1;
7052 766841c2 2020-08-13 stsp break;
7053 766841c2 2020-08-13 stsp case GOT_STATUS_MISSING:
7054 4e12cd97 2022-01-25 stsp ignore_missing_paths = 1;
7055 766841c2 2020-08-13 stsp break;
7056 766841c2 2020-08-13 stsp default:
7057 766841c2 2020-08-13 stsp errx(1, "invalid status code '%c'",
7058 766841c2 2020-08-13 stsp optarg[i]);
7059 766841c2 2020-08-13 stsp }
7060 766841c2 2020-08-13 stsp }
7061 766841c2 2020-08-13 stsp status_codes = optarg;
7062 766841c2 2020-08-13 stsp break;
7063 2ec1f75b 2019-03-26 stsp default:
7064 f2a9dc41 2019-12-13 tracey usage_remove();
7065 2ec1f75b 2019-03-26 stsp /* NOTREACHED */
7066 2ec1f75b 2019-03-26 stsp }
7067 2ec1f75b 2019-03-26 stsp }
7068 2ec1f75b 2019-03-26 stsp
7069 2ec1f75b 2019-03-26 stsp argc -= optind;
7070 2ec1f75b 2019-03-26 stsp argv += optind;
7071 2ec1f75b 2019-03-26 stsp
7072 43012d58 2019-07-14 stsp #ifndef PROFILE
7073 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7074 43012d58 2019-07-14 stsp NULL) == -1)
7075 43012d58 2019-07-14 stsp err(1, "pledge");
7076 43012d58 2019-07-14 stsp #endif
7077 17ed4618 2019-06-02 stsp if (argc < 1)
7078 648e4ef7 2019-07-09 stsp usage_remove();
7079 2ec1f75b 2019-03-26 stsp
7080 2ec1f75b 2019-03-26 stsp cwd = getcwd(NULL, 0);
7081 2ec1f75b 2019-03-26 stsp if (cwd == NULL) {
7082 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
7083 2ec1f75b 2019-03-26 stsp goto done;
7084 2ec1f75b 2019-03-26 stsp }
7085 2ec1f75b 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
7086 fa51e947 2020-03-27 stsp if (error) {
7087 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7088 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "remove", cwd);
7089 2ec1f75b 2019-03-26 stsp goto done;
7090 fa51e947 2020-03-27 stsp }
7091 2ec1f75b 2019-03-26 stsp
7092 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7093 c9956ddf 2019-09-08 stsp NULL);
7094 2af4a041 2019-05-11 jcs if (error)
7095 2ec1f75b 2019-03-26 stsp goto done;
7096 2ec1f75b 2019-03-26 stsp
7097 c2253644 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
7098 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7099 2ec1f75b 2019-03-26 stsp if (error)
7100 2ec1f75b 2019-03-26 stsp goto done;
7101 2ec1f75b 2019-03-26 stsp
7102 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7103 6d022e97 2019-08-04 stsp if (error)
7104 6d022e97 2019-08-04 stsp goto done;
7105 17ed4618 2019-06-02 stsp
7106 f2a9dc41 2019-12-13 tracey if (!can_recurse) {
7107 f2a9dc41 2019-12-13 tracey char *ondisk_path;
7108 f2a9dc41 2019-12-13 tracey struct stat sb;
7109 f2a9dc41 2019-12-13 tracey TAILQ_FOREACH(pe, &paths, entry) {
7110 f2a9dc41 2019-12-13 tracey if (asprintf(&ondisk_path, "%s/%s",
7111 f2a9dc41 2019-12-13 tracey got_worktree_get_root_path(worktree),
7112 62d463ca 2020-10-20 naddy pe->path) == -1) {
7113 f2a9dc41 2019-12-13 tracey error = got_error_from_errno("asprintf");
7114 f2a9dc41 2019-12-13 tracey goto done;
7115 f2a9dc41 2019-12-13 tracey }
7116 f2a9dc41 2019-12-13 tracey if (lstat(ondisk_path, &sb) == -1) {
7117 f2a9dc41 2019-12-13 tracey if (errno == ENOENT) {
7118 f2a9dc41 2019-12-13 tracey free(ondisk_path);
7119 f2a9dc41 2019-12-13 tracey continue;
7120 f2a9dc41 2019-12-13 tracey }
7121 f2a9dc41 2019-12-13 tracey error = got_error_from_errno2("lstat",
7122 f2a9dc41 2019-12-13 tracey ondisk_path);
7123 f2a9dc41 2019-12-13 tracey free(ondisk_path);
7124 f2a9dc41 2019-12-13 tracey goto done;
7125 f2a9dc41 2019-12-13 tracey }
7126 f2a9dc41 2019-12-13 tracey free(ondisk_path);
7127 f2a9dc41 2019-12-13 tracey if (S_ISDIR(sb.st_mode)) {
7128 f2a9dc41 2019-12-13 tracey error = got_error_msg(GOT_ERR_BAD_PATH,
7129 f2a9dc41 2019-12-13 tracey "removing directories requires -R option");
7130 f2a9dc41 2019-12-13 tracey goto done;
7131 f2a9dc41 2019-12-13 tracey }
7132 f2a9dc41 2019-12-13 tracey }
7133 f2a9dc41 2019-12-13 tracey }
7134 f2a9dc41 2019-12-13 tracey
7135 17ed4618 2019-06-02 stsp error = got_worktree_schedule_delete(worktree, &paths,
7136 766841c2 2020-08-13 stsp delete_local_mods, status_codes, print_remove_status, NULL,
7137 4e12cd97 2022-01-25 stsp repo, keep_on_disk, ignore_missing_paths);
7138 a129376b 2019-03-28 stsp done:
7139 1d0f4054 2021-06-17 stsp if (repo) {
7140 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
7141 1d0f4054 2021-06-17 stsp if (error == NULL)
7142 1d0f4054 2021-06-17 stsp error = close_err;
7143 1d0f4054 2021-06-17 stsp }
7144 a129376b 2019-03-28 stsp if (worktree)
7145 a129376b 2019-03-28 stsp got_worktree_close(worktree);
7146 17ed4618 2019-06-02 stsp TAILQ_FOREACH(pe, &paths, entry)
7147 17ed4618 2019-06-02 stsp free((char *)pe->path);
7148 17ed4618 2019-06-02 stsp got_pathlist_free(&paths);
7149 e9ce266e 2022-03-07 op free(cwd);
7150 e9ce266e 2022-03-07 op return error;
7151 e9ce266e 2022-03-07 op }
7152 e9ce266e 2022-03-07 op
7153 e9ce266e 2022-03-07 op __dead static void
7154 e9ce266e 2022-03-07 op usage_patch(void)
7155 e9ce266e 2022-03-07 op {
7156 899fcfdf 2022-03-13 op fprintf(stderr, "usage: %s patch [-n] [patchfile]\n",
7157 e9ce266e 2022-03-07 op getprogname());
7158 e9ce266e 2022-03-07 op exit(1);
7159 e9ce266e 2022-03-07 op }
7160 e9ce266e 2022-03-07 op
7161 e9ce266e 2022-03-07 op static const struct got_error *
7162 e9ce266e 2022-03-07 op patch_from_stdin(int *patchfd)
7163 e9ce266e 2022-03-07 op {
7164 e9ce266e 2022-03-07 op const struct got_error *err = NULL;
7165 e9ce266e 2022-03-07 op ssize_t r;
7166 e9ce266e 2022-03-07 op char *path, buf[BUFSIZ];
7167 e9ce266e 2022-03-07 op sig_t sighup, sigint, sigquit;
7168 e9ce266e 2022-03-07 op
7169 e9ce266e 2022-03-07 op err = got_opentemp_named_fd(&path, patchfd,
7170 e9ce266e 2022-03-07 op GOT_TMPDIR_STR "/got-patch");
7171 e9ce266e 2022-03-07 op if (err)
7172 e9ce266e 2022-03-07 op return err;
7173 e9ce266e 2022-03-07 op unlink(path);
7174 e9ce266e 2022-03-07 op free(path);
7175 e9ce266e 2022-03-07 op
7176 e9ce266e 2022-03-07 op sighup = signal(SIGHUP, SIG_DFL);
7177 e9ce266e 2022-03-07 op sigint = signal(SIGINT, SIG_DFL);
7178 e9ce266e 2022-03-07 op sigquit = signal(SIGQUIT, SIG_DFL);
7179 e9ce266e 2022-03-07 op
7180 e9ce266e 2022-03-07 op for (;;) {
7181 e9ce266e 2022-03-07 op r = read(0, buf, sizeof(buf));
7182 e9ce266e 2022-03-07 op if (r == -1) {
7183 e9ce266e 2022-03-07 op err = got_error_from_errno("read");
7184 e9ce266e 2022-03-07 op break;
7185 e9ce266e 2022-03-07 op }
7186 e9ce266e 2022-03-07 op if (r == 0)
7187 e9ce266e 2022-03-07 op break;
7188 e9ce266e 2022-03-07 op if (write(*patchfd, buf, r) == -1) {
7189 e9ce266e 2022-03-07 op err = got_error_from_errno("write");
7190 e9ce266e 2022-03-07 op break;
7191 e9ce266e 2022-03-07 op }
7192 e9ce266e 2022-03-07 op }
7193 e9ce266e 2022-03-07 op
7194 e9ce266e 2022-03-07 op signal(SIGHUP, sighup);
7195 e9ce266e 2022-03-07 op signal(SIGINT, sigint);
7196 e9ce266e 2022-03-07 op signal(SIGQUIT, sigquit);
7197 e9ce266e 2022-03-07 op
7198 ca6444c5 2022-03-11 op if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1)
7199 ca6444c5 2022-03-11 op err = got_error_from_errno("lseek");
7200 ca6444c5 2022-03-11 op
7201 ca6444c5 2022-03-11 op if (err != NULL) {
7202 e9ce266e 2022-03-07 op close(*patchfd);
7203 ca6444c5 2022-03-11 op *patchfd = -1;
7204 ca6444c5 2022-03-11 op }
7205 ca6444c5 2022-03-11 op
7206 ca6444c5 2022-03-11 op return err;
7207 e9ce266e 2022-03-07 op }
7208 e9ce266e 2022-03-07 op
7209 e9ce266e 2022-03-07 op static const struct got_error *
7210 60aa1fa0 2022-03-17 op patch_progress(void *arg, const char *old, const char *new,
7211 60aa1fa0 2022-03-17 op unsigned char status, const struct got_error *error, long old_from,
7212 60aa1fa0 2022-03-17 op long old_lines, long new_from, long new_lines, long offset,
7213 60aa1fa0 2022-03-17 op const struct got_error *hunk_err)
7214 b22138f5 2022-03-16 op {
7215 b22138f5 2022-03-16 op const char *path = new == NULL ? old : new;
7216 b22138f5 2022-03-16 op
7217 b22138f5 2022-03-16 op while (*path == '/')
7218 b22138f5 2022-03-16 op path++;
7219 60aa1fa0 2022-03-17 op
7220 60aa1fa0 2022-03-17 op if (status != 0)
7221 60aa1fa0 2022-03-17 op printf("%c %s\n", status, path);
7222 60aa1fa0 2022-03-17 op
7223 60aa1fa0 2022-03-17 op if (error != NULL)
7224 60aa1fa0 2022-03-17 op fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
7225 60aa1fa0 2022-03-17 op
7226 60aa1fa0 2022-03-17 op if (offset != 0 || hunk_err != NULL) {
7227 60aa1fa0 2022-03-17 op printf("@@ -%ld,%ld +%ld,%ld @@ ", old_from,
7228 60aa1fa0 2022-03-17 op old_lines, new_from, new_lines);
7229 60aa1fa0 2022-03-17 op if (hunk_err != NULL)
7230 60aa1fa0 2022-03-17 op printf("%s\n", hunk_err->msg);
7231 60aa1fa0 2022-03-17 op else
7232 60aa1fa0 2022-03-17 op printf("applied with offset %ld\n", offset);
7233 60aa1fa0 2022-03-17 op }
7234 60aa1fa0 2022-03-17 op
7235 b22138f5 2022-03-16 op return NULL;
7236 b22138f5 2022-03-16 op }
7237 b22138f5 2022-03-16 op
7238 b22138f5 2022-03-16 op static const struct got_error *
7239 e9ce266e 2022-03-07 op cmd_patch(int argc, char *argv[])
7240 e9ce266e 2022-03-07 op {
7241 e9ce266e 2022-03-07 op const struct got_error *error = NULL, *close_error = NULL;
7242 e9ce266e 2022-03-07 op struct got_worktree *worktree = NULL;
7243 e9ce266e 2022-03-07 op struct got_repository *repo = NULL;
7244 9d6cabd5 2022-04-07 op const char *errstr;
7245 e9ce266e 2022-03-07 op char *cwd = NULL;
7246 9d6cabd5 2022-04-07 op int ch, nop = 0, strip = -1;
7247 e9ce266e 2022-03-07 op int patchfd;
7248 e9ce266e 2022-03-07 op
7249 9d6cabd5 2022-04-07 op while ((ch = getopt(argc, argv, "np:")) != -1) {
7250 e9ce266e 2022-03-07 op switch (ch) {
7251 899fcfdf 2022-03-13 op case 'n':
7252 899fcfdf 2022-03-13 op nop = 1;
7253 899fcfdf 2022-03-13 op break;
7254 9d6cabd5 2022-04-07 op case 'p':
7255 9d6cabd5 2022-04-07 op strip = strtonum(optarg, 0, INT_MAX, &errstr);
7256 9d6cabd5 2022-04-07 op if (errstr != NULL)
7257 9d6cabd5 2022-04-07 op errx(1, "pathname strip count is %s: %s",
7258 9d6cabd5 2022-04-07 op errstr, optarg);
7259 9d6cabd5 2022-04-07 op break;
7260 e9ce266e 2022-03-07 op default:
7261 e9ce266e 2022-03-07 op usage_patch();
7262 e9ce266e 2022-03-07 op /* NOTREACHED */
7263 e9ce266e 2022-03-07 op }
7264 e9ce266e 2022-03-07 op }
7265 e9ce266e 2022-03-07 op
7266 e9ce266e 2022-03-07 op argc -= optind;
7267 e9ce266e 2022-03-07 op argv += optind;
7268 e9ce266e 2022-03-07 op
7269 e9ce266e 2022-03-07 op if (argc == 0) {
7270 e9ce266e 2022-03-07 op error = patch_from_stdin(&patchfd);
7271 e9ce266e 2022-03-07 op if (error)
7272 e9ce266e 2022-03-07 op return error;
7273 e9ce266e 2022-03-07 op } else if (argc == 1) {
7274 e9ce266e 2022-03-07 op patchfd = open(argv[0], O_RDONLY);
7275 e9ce266e 2022-03-07 op if (patchfd == -1) {
7276 e9ce266e 2022-03-07 op error = got_error_from_errno2("open", argv[0]);
7277 e9ce266e 2022-03-07 op return error;
7278 e9ce266e 2022-03-07 op }
7279 e9ce266e 2022-03-07 op } else
7280 e9ce266e 2022-03-07 op usage_patch();
7281 e9ce266e 2022-03-07 op
7282 e9ce266e 2022-03-07 op if ((cwd = getcwd(NULL, 0)) == NULL) {
7283 e9ce266e 2022-03-07 op error = got_error_from_errno("getcwd");
7284 e9ce266e 2022-03-07 op goto done;
7285 e9ce266e 2022-03-07 op }
7286 e9ce266e 2022-03-07 op
7287 e9ce266e 2022-03-07 op error = got_worktree_open(&worktree, cwd);
7288 e9ce266e 2022-03-07 op if (error != NULL)
7289 e9ce266e 2022-03-07 op goto done;
7290 e9ce266e 2022-03-07 op
7291 e9ce266e 2022-03-07 op const char *repo_path = got_worktree_get_repo_path(worktree);
7292 e9ce266e 2022-03-07 op error = got_repo_open(&repo, repo_path, NULL);
7293 e9ce266e 2022-03-07 op if (error != NULL)
7294 e9ce266e 2022-03-07 op goto done;
7295 e9ce266e 2022-03-07 op
7296 e9ce266e 2022-03-07 op error = apply_unveil(got_repo_get_path(repo), 0,
7297 728ed142 2022-04-19 op got_worktree_get_root_path(worktree));
7298 e9ce266e 2022-03-07 op if (error != NULL)
7299 e9ce266e 2022-03-07 op goto done;
7300 e9ce266e 2022-03-07 op
7301 e9ce266e 2022-03-07 op #ifndef PROFILE
7302 2be5e1a2 2022-03-16 op if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock",
7303 e9ce266e 2022-03-07 op NULL) == -1)
7304 e9ce266e 2022-03-07 op err(1, "pledge");
7305 e9ce266e 2022-03-07 op #endif
7306 e9ce266e 2022-03-07 op
7307 9d6cabd5 2022-04-07 op error = got_patch(patchfd, worktree, repo, nop, strip,
7308 9d6cabd5 2022-04-07 op &patch_progress, NULL, check_cancelled, NULL);
7309 e9ce266e 2022-03-07 op
7310 e9ce266e 2022-03-07 op done:
7311 e9ce266e 2022-03-07 op if (repo) {
7312 e9ce266e 2022-03-07 op close_error = got_repo_close(repo);
7313 e9ce266e 2022-03-07 op if (error == NULL)
7314 e9ce266e 2022-03-07 op error = close_error;
7315 e9ce266e 2022-03-07 op }
7316 e9ce266e 2022-03-07 op if (worktree != NULL) {
7317 e9ce266e 2022-03-07 op close_error = got_worktree_close(worktree);
7318 e9ce266e 2022-03-07 op if (error == NULL)
7319 e9ce266e 2022-03-07 op error = close_error;
7320 e9ce266e 2022-03-07 op }
7321 a129376b 2019-03-28 stsp free(cwd);
7322 a129376b 2019-03-28 stsp return error;
7323 a129376b 2019-03-28 stsp }
7324 a129376b 2019-03-28 stsp
7325 a129376b 2019-03-28 stsp __dead static void
7326 a129376b 2019-03-28 stsp usage_revert(void)
7327 a129376b 2019-03-28 stsp {
7328 33aa809d 2019-08-08 stsp fprintf(stderr, "usage: %s revert [-p] [-F response-script] [-R] "
7329 33aa809d 2019-08-08 stsp "path ...\n", getprogname());
7330 a129376b 2019-03-28 stsp exit(1);
7331 a129376b 2019-03-28 stsp }
7332 a129376b 2019-03-28 stsp
7333 1ee397ad 2019-07-12 stsp static const struct got_error *
7334 a129376b 2019-03-28 stsp revert_progress(void *arg, unsigned char status, const char *path)
7335 a129376b 2019-03-28 stsp {
7336 fb9704af 2020-01-27 stsp if (status == GOT_STATUS_UNVERSIONED)
7337 fb9704af 2020-01-27 stsp return NULL;
7338 fb9704af 2020-01-27 stsp
7339 a129376b 2019-03-28 stsp while (path[0] == '/')
7340 a129376b 2019-03-28 stsp path++;
7341 a129376b 2019-03-28 stsp printf("%c %s\n", status, path);
7342 33aa809d 2019-08-08 stsp return NULL;
7343 33aa809d 2019-08-08 stsp }
7344 33aa809d 2019-08-08 stsp
7345 33aa809d 2019-08-08 stsp struct choose_patch_arg {
7346 33aa809d 2019-08-08 stsp FILE *patch_script_file;
7347 33aa809d 2019-08-08 stsp const char *action;
7348 33aa809d 2019-08-08 stsp };
7349 33aa809d 2019-08-08 stsp
7350 33aa809d 2019-08-08 stsp static const struct got_error *
7351 33aa809d 2019-08-08 stsp show_change(unsigned char status, const char *path, FILE *patch_file, int n,
7352 33aa809d 2019-08-08 stsp int nchanges, const char *action)
7353 33aa809d 2019-08-08 stsp {
7354 33aa809d 2019-08-08 stsp char *line = NULL;
7355 33aa809d 2019-08-08 stsp size_t linesize = 0;
7356 33aa809d 2019-08-08 stsp ssize_t linelen;
7357 33aa809d 2019-08-08 stsp
7358 33aa809d 2019-08-08 stsp switch (status) {
7359 33aa809d 2019-08-08 stsp case GOT_STATUS_ADD:
7360 33aa809d 2019-08-08 stsp printf("A %s\n%s this addition? [y/n] ", path, action);
7361 33aa809d 2019-08-08 stsp break;
7362 33aa809d 2019-08-08 stsp case GOT_STATUS_DELETE:
7363 33aa809d 2019-08-08 stsp printf("D %s\n%s this deletion? [y/n] ", path, action);
7364 33aa809d 2019-08-08 stsp break;
7365 33aa809d 2019-08-08 stsp case GOT_STATUS_MODIFY:
7366 33aa809d 2019-08-08 stsp if (fseek(patch_file, 0L, SEEK_SET) == -1)
7367 33aa809d 2019-08-08 stsp return got_error_from_errno("fseek");
7368 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
7369 9516e7cb 2019-08-11 stsp while ((linelen = getline(&line, &linesize, patch_file)) != -1)
7370 33aa809d 2019-08-08 stsp printf("%s", line);
7371 33aa809d 2019-08-08 stsp if (ferror(patch_file))
7372 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
7373 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
7374 33aa809d 2019-08-08 stsp printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
7375 33aa809d 2019-08-08 stsp path, n, nchanges, action);
7376 33aa809d 2019-08-08 stsp break;
7377 33aa809d 2019-08-08 stsp default:
7378 33aa809d 2019-08-08 stsp return got_error_path(path, GOT_ERR_FILE_STATUS);
7379 33aa809d 2019-08-08 stsp }
7380 33aa809d 2019-08-08 stsp
7381 33aa809d 2019-08-08 stsp return NULL;
7382 33aa809d 2019-08-08 stsp }
7383 33aa809d 2019-08-08 stsp
7384 33aa809d 2019-08-08 stsp static const struct got_error *
7385 33aa809d 2019-08-08 stsp choose_patch(int *choice, void *arg, unsigned char status, const char *path,
7386 33aa809d 2019-08-08 stsp FILE *patch_file, int n, int nchanges)
7387 33aa809d 2019-08-08 stsp {
7388 33aa809d 2019-08-08 stsp const struct got_error *err = NULL;
7389 33aa809d 2019-08-08 stsp char *line = NULL;
7390 33aa809d 2019-08-08 stsp size_t linesize = 0;
7391 33aa809d 2019-08-08 stsp ssize_t linelen;
7392 33aa809d 2019-08-08 stsp int resp = ' ';
7393 33aa809d 2019-08-08 stsp struct choose_patch_arg *a = arg;
7394 33aa809d 2019-08-08 stsp
7395 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NONE;
7396 33aa809d 2019-08-08 stsp
7397 33aa809d 2019-08-08 stsp if (a->patch_script_file) {
7398 33aa809d 2019-08-08 stsp char *nl;
7399 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
7400 33aa809d 2019-08-08 stsp a->action);
7401 33aa809d 2019-08-08 stsp if (err)
7402 33aa809d 2019-08-08 stsp return err;
7403 33aa809d 2019-08-08 stsp linelen = getline(&line, &linesize, a->patch_script_file);
7404 33aa809d 2019-08-08 stsp if (linelen == -1) {
7405 33aa809d 2019-08-08 stsp if (ferror(a->patch_script_file))
7406 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
7407 33aa809d 2019-08-08 stsp return NULL;
7408 33aa809d 2019-08-08 stsp }
7409 33aa809d 2019-08-08 stsp nl = strchr(line, '\n');
7410 33aa809d 2019-08-08 stsp if (nl)
7411 33aa809d 2019-08-08 stsp *nl = '\0';
7412 33aa809d 2019-08-08 stsp if (strcmp(line, "y") == 0) {
7413 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
7414 33aa809d 2019-08-08 stsp printf("y\n");
7415 33aa809d 2019-08-08 stsp } else if (strcmp(line, "n") == 0) {
7416 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
7417 33aa809d 2019-08-08 stsp printf("n\n");
7418 33aa809d 2019-08-08 stsp } else if (strcmp(line, "q") == 0 &&
7419 33aa809d 2019-08-08 stsp status == GOT_STATUS_MODIFY) {
7420 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
7421 33aa809d 2019-08-08 stsp printf("q\n");
7422 33aa809d 2019-08-08 stsp } else
7423 33aa809d 2019-08-08 stsp printf("invalid response '%s'\n", line);
7424 33aa809d 2019-08-08 stsp free(line);
7425 33aa809d 2019-08-08 stsp return NULL;
7426 33aa809d 2019-08-08 stsp }
7427 33aa809d 2019-08-08 stsp
7428 33aa809d 2019-08-08 stsp while (resp != 'y' && resp != 'n' && resp != 'q') {
7429 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
7430 33aa809d 2019-08-08 stsp a->action);
7431 33aa809d 2019-08-08 stsp if (err)
7432 33aa809d 2019-08-08 stsp return err;
7433 33aa809d 2019-08-08 stsp resp = getchar();
7434 33aa809d 2019-08-08 stsp if (resp == '\n')
7435 33aa809d 2019-08-08 stsp resp = getchar();
7436 33aa809d 2019-08-08 stsp if (status == GOT_STATUS_MODIFY) {
7437 33aa809d 2019-08-08 stsp if (resp != 'y' && resp != 'n' && resp != 'q') {
7438 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
7439 33aa809d 2019-08-08 stsp resp = ' ';
7440 33aa809d 2019-08-08 stsp }
7441 33aa809d 2019-08-08 stsp } else if (resp != 'y' && resp != 'n') {
7442 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
7443 33aa809d 2019-08-08 stsp resp = ' ';
7444 33aa809d 2019-08-08 stsp }
7445 33aa809d 2019-08-08 stsp }
7446 33aa809d 2019-08-08 stsp
7447 33aa809d 2019-08-08 stsp if (resp == 'y')
7448 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
7449 33aa809d 2019-08-08 stsp else if (resp == 'n')
7450 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
7451 33aa809d 2019-08-08 stsp else if (resp == 'q' && status == GOT_STATUS_MODIFY)
7452 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
7453 33aa809d 2019-08-08 stsp
7454 1ee397ad 2019-07-12 stsp return NULL;
7455 a129376b 2019-03-28 stsp }
7456 a129376b 2019-03-28 stsp
7457 a129376b 2019-03-28 stsp static const struct got_error *
7458 a129376b 2019-03-28 stsp cmd_revert(int argc, char *argv[])
7459 a129376b 2019-03-28 stsp {
7460 a129376b 2019-03-28 stsp const struct got_error *error = NULL;
7461 a129376b 2019-03-28 stsp struct got_worktree *worktree = NULL;
7462 a129376b 2019-03-28 stsp struct got_repository *repo = NULL;
7463 a129376b 2019-03-28 stsp char *cwd = NULL, *path = NULL;
7464 e20a8b6f 2019-06-04 stsp struct got_pathlist_head paths;
7465 0f6d7415 2019-08-08 stsp struct got_pathlist_entry *pe;
7466 33aa809d 2019-08-08 stsp int ch, can_recurse = 0, pflag = 0;
7467 33aa809d 2019-08-08 stsp FILE *patch_script_file = NULL;
7468 33aa809d 2019-08-08 stsp const char *patch_script_path = NULL;
7469 33aa809d 2019-08-08 stsp struct choose_patch_arg cpa;
7470 a129376b 2019-03-28 stsp
7471 e20a8b6f 2019-06-04 stsp TAILQ_INIT(&paths);
7472 e20a8b6f 2019-06-04 stsp
7473 33aa809d 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:R")) != -1) {
7474 a129376b 2019-03-28 stsp switch (ch) {
7475 33aa809d 2019-08-08 stsp case 'p':
7476 33aa809d 2019-08-08 stsp pflag = 1;
7477 33aa809d 2019-08-08 stsp break;
7478 33aa809d 2019-08-08 stsp case 'F':
7479 33aa809d 2019-08-08 stsp patch_script_path = optarg;
7480 33aa809d 2019-08-08 stsp break;
7481 0f6d7415 2019-08-08 stsp case 'R':
7482 0f6d7415 2019-08-08 stsp can_recurse = 1;
7483 0f6d7415 2019-08-08 stsp break;
7484 a129376b 2019-03-28 stsp default:
7485 a129376b 2019-03-28 stsp usage_revert();
7486 a129376b 2019-03-28 stsp /* NOTREACHED */
7487 a129376b 2019-03-28 stsp }
7488 a129376b 2019-03-28 stsp }
7489 a129376b 2019-03-28 stsp
7490 a129376b 2019-03-28 stsp argc -= optind;
7491 a129376b 2019-03-28 stsp argv += optind;
7492 a129376b 2019-03-28 stsp
7493 43012d58 2019-07-14 stsp #ifndef PROFILE
7494 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7495 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
7496 43012d58 2019-07-14 stsp err(1, "pledge");
7497 43012d58 2019-07-14 stsp #endif
7498 e20a8b6f 2019-06-04 stsp if (argc < 1)
7499 a129376b 2019-03-28 stsp usage_revert();
7500 33aa809d 2019-08-08 stsp if (patch_script_path && !pflag)
7501 33aa809d 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
7502 a129376b 2019-03-28 stsp
7503 a129376b 2019-03-28 stsp cwd = getcwd(NULL, 0);
7504 a129376b 2019-03-28 stsp if (cwd == NULL) {
7505 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
7506 a129376b 2019-03-28 stsp goto done;
7507 a129376b 2019-03-28 stsp }
7508 a129376b 2019-03-28 stsp error = got_worktree_open(&worktree, cwd);
7509 fa51e947 2020-03-27 stsp if (error) {
7510 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7511 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "revert", cwd);
7512 2ec1f75b 2019-03-26 stsp goto done;
7513 fa51e947 2020-03-27 stsp }
7514 a129376b 2019-03-28 stsp
7515 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7516 c9956ddf 2019-09-08 stsp NULL);
7517 a129376b 2019-03-28 stsp if (error != NULL)
7518 a129376b 2019-03-28 stsp goto done;
7519 a129376b 2019-03-28 stsp
7520 33aa809d 2019-08-08 stsp if (patch_script_path) {
7521 00fe21f2 2021-12-31 stsp patch_script_file = fopen(patch_script_path, "re");
7522 33aa809d 2019-08-08 stsp if (patch_script_file == NULL) {
7523 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fopen",
7524 33aa809d 2019-08-08 stsp patch_script_path);
7525 33aa809d 2019-08-08 stsp goto done;
7526 33aa809d 2019-08-08 stsp }
7527 33aa809d 2019-08-08 stsp }
7528 a129376b 2019-03-28 stsp error = apply_unveil(got_repo_get_path(repo), 1,
7529 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7530 a129376b 2019-03-28 stsp if (error)
7531 a129376b 2019-03-28 stsp goto done;
7532 a129376b 2019-03-28 stsp
7533 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7534 6d022e97 2019-08-04 stsp if (error)
7535 6d022e97 2019-08-04 stsp goto done;
7536 00db391e 2019-08-03 stsp
7537 0f6d7415 2019-08-08 stsp if (!can_recurse) {
7538 0f6d7415 2019-08-08 stsp char *ondisk_path;
7539 0f6d7415 2019-08-08 stsp struct stat sb;
7540 0f6d7415 2019-08-08 stsp TAILQ_FOREACH(pe, &paths, entry) {
7541 0f6d7415 2019-08-08 stsp if (asprintf(&ondisk_path, "%s/%s",
7542 0f6d7415 2019-08-08 stsp got_worktree_get_root_path(worktree),
7543 62d463ca 2020-10-20 naddy pe->path) == -1) {
7544 0f6d7415 2019-08-08 stsp error = got_error_from_errno("asprintf");
7545 0f6d7415 2019-08-08 stsp goto done;
7546 0f6d7415 2019-08-08 stsp }
7547 0f6d7415 2019-08-08 stsp if (lstat(ondisk_path, &sb) == -1) {
7548 0f6d7415 2019-08-08 stsp if (errno == ENOENT) {
7549 0f6d7415 2019-08-08 stsp free(ondisk_path);
7550 0f6d7415 2019-08-08 stsp continue;
7551 0f6d7415 2019-08-08 stsp }
7552 0f6d7415 2019-08-08 stsp error = got_error_from_errno2("lstat",
7553 0f6d7415 2019-08-08 stsp ondisk_path);
7554 0f6d7415 2019-08-08 stsp free(ondisk_path);
7555 0f6d7415 2019-08-08 stsp goto done;
7556 0f6d7415 2019-08-08 stsp }
7557 0f6d7415 2019-08-08 stsp free(ondisk_path);
7558 0f6d7415 2019-08-08 stsp if (S_ISDIR(sb.st_mode)) {
7559 0f6d7415 2019-08-08 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
7560 0f6d7415 2019-08-08 stsp "reverting directories requires -R option");
7561 0f6d7415 2019-08-08 stsp goto done;
7562 0f6d7415 2019-08-08 stsp }
7563 0f6d7415 2019-08-08 stsp }
7564 0f6d7415 2019-08-08 stsp }
7565 0f6d7415 2019-08-08 stsp
7566 33aa809d 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
7567 33aa809d 2019-08-08 stsp cpa.action = "revert";
7568 33aa809d 2019-08-08 stsp error = got_worktree_revert(worktree, &paths, revert_progress, NULL,
7569 33aa809d 2019-08-08 stsp pflag ? choose_patch : NULL, &cpa, repo);
7570 2ec1f75b 2019-03-26 stsp done:
7571 33aa809d 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
7572 33aa809d 2019-08-08 stsp error == NULL)
7573 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
7574 1d0f4054 2021-06-17 stsp if (repo) {
7575 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
7576 1d0f4054 2021-06-17 stsp if (error == NULL)
7577 1d0f4054 2021-06-17 stsp error = close_err;
7578 1d0f4054 2021-06-17 stsp }
7579 2ec1f75b 2019-03-26 stsp if (worktree)
7580 2ec1f75b 2019-03-26 stsp got_worktree_close(worktree);
7581 2ec1f75b 2019-03-26 stsp free(path);
7582 d00136be 2019-03-26 stsp free(cwd);
7583 6bad629b 2019-02-04 stsp return error;
7584 c4296144 2019-05-09 stsp }
7585 c4296144 2019-05-09 stsp
7586 c4296144 2019-05-09 stsp __dead static void
7587 c4296144 2019-05-09 stsp usage_commit(void)
7588 c4296144 2019-05-09 stsp {
7589 28cf319f 2021-01-28 stsp fprintf(stderr, "usage: %s commit [-F path] [-m msg] [-N] [-S] "
7590 28cf319f 2021-01-28 stsp "[path ...]\n", getprogname());
7591 c4296144 2019-05-09 stsp exit(1);
7592 33ad4cbe 2019-05-12 jcs }
7593 33ad4cbe 2019-05-12 jcs
7594 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg {
7595 e2ba3d07 2019-05-13 stsp const char *cmdline_log;
7596 28cf319f 2021-01-28 stsp const char *prepared_log;
7597 28cf319f 2021-01-28 stsp int non_interactive;
7598 e2ba3d07 2019-05-13 stsp const char *editor;
7599 e0870e44 2019-05-13 stsp const char *worktree_path;
7600 76d98825 2019-06-03 stsp const char *branch_name;
7601 314a6357 2019-05-13 stsp const char *repo_path;
7602 e0870e44 2019-05-13 stsp char *logmsg_path;
7603 e2ba3d07 2019-05-13 stsp
7604 e2ba3d07 2019-05-13 stsp };
7605 28cf319f 2021-01-28 stsp
7606 28cf319f 2021-01-28 stsp static const struct got_error *
7607 28cf319f 2021-01-28 stsp read_prepared_logmsg(char **logmsg, const char *path)
7608 28cf319f 2021-01-28 stsp {
7609 28cf319f 2021-01-28 stsp const struct got_error *err = NULL;
7610 28cf319f 2021-01-28 stsp FILE *f = NULL;
7611 28cf319f 2021-01-28 stsp struct stat sb;
7612 28cf319f 2021-01-28 stsp size_t r;
7613 28cf319f 2021-01-28 stsp
7614 28cf319f 2021-01-28 stsp *logmsg = NULL;
7615 28cf319f 2021-01-28 stsp memset(&sb, 0, sizeof(sb));
7616 28cf319f 2021-01-28 stsp
7617 00fe21f2 2021-12-31 stsp f = fopen(path, "re");
7618 28cf319f 2021-01-28 stsp if (f == NULL)
7619 28cf319f 2021-01-28 stsp return got_error_from_errno2("fopen", path);
7620 28cf319f 2021-01-28 stsp
7621 28cf319f 2021-01-28 stsp if (fstat(fileno(f), &sb) == -1) {
7622 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fstat", path);
7623 28cf319f 2021-01-28 stsp goto done;
7624 28cf319f 2021-01-28 stsp }
7625 28cf319f 2021-01-28 stsp if (sb.st_size == 0) {
7626 28cf319f 2021-01-28 stsp err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
7627 28cf319f 2021-01-28 stsp goto done;
7628 28cf319f 2021-01-28 stsp }
7629 28cf319f 2021-01-28 stsp
7630 28cf319f 2021-01-28 stsp *logmsg = malloc(sb.st_size + 1);
7631 28cf319f 2021-01-28 stsp if (*logmsg == NULL) {
7632 28cf319f 2021-01-28 stsp err = got_error_from_errno("malloc");
7633 28cf319f 2021-01-28 stsp goto done;
7634 28cf319f 2021-01-28 stsp }
7635 28cf319f 2021-01-28 stsp
7636 28cf319f 2021-01-28 stsp r = fread(*logmsg, 1, sb.st_size, f);
7637 28cf319f 2021-01-28 stsp if (r != sb.st_size) {
7638 28cf319f 2021-01-28 stsp if (ferror(f))
7639 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fread", path);
7640 28cf319f 2021-01-28 stsp else
7641 28cf319f 2021-01-28 stsp err = got_error(GOT_ERR_IO);
7642 28cf319f 2021-01-28 stsp goto done;
7643 28cf319f 2021-01-28 stsp }
7644 28cf319f 2021-01-28 stsp (*logmsg)[sb.st_size] = '\0';
7645 28cf319f 2021-01-28 stsp done:
7646 28cf319f 2021-01-28 stsp if (fclose(f) == EOF && err == NULL)
7647 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fclose", path);
7648 28cf319f 2021-01-28 stsp if (err) {
7649 28cf319f 2021-01-28 stsp free(*logmsg);
7650 28cf319f 2021-01-28 stsp *logmsg = NULL;
7651 28cf319f 2021-01-28 stsp }
7652 28cf319f 2021-01-28 stsp return err;
7653 28cf319f 2021-01-28 stsp
7654 28cf319f 2021-01-28 stsp }
7655 e0870e44 2019-05-13 stsp
7656 33ad4cbe 2019-05-12 jcs static const struct got_error *
7657 33ad4cbe 2019-05-12 jcs collect_commit_logmsg(struct got_pathlist_head *commitable_paths, char **logmsg,
7658 33ad4cbe 2019-05-12 jcs void *arg)
7659 33ad4cbe 2019-05-12 jcs {
7660 76d98825 2019-06-03 stsp char *initial_content = NULL;
7661 33ad4cbe 2019-05-12 jcs struct got_pathlist_entry *pe;
7662 33ad4cbe 2019-05-12 jcs const struct got_error *err = NULL;
7663 e0870e44 2019-05-13 stsp char *template = NULL;
7664 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg *a = arg;
7665 1601cb9f 2020-09-11 naddy int initial_content_len;
7666 97972933 2020-09-11 stsp int fd = -1;
7667 33ad4cbe 2019-05-12 jcs size_t len;
7668 33ad4cbe 2019-05-12 jcs
7669 33ad4cbe 2019-05-12 jcs /* if a message was specified on the command line, just use it */
7670 e2ba3d07 2019-05-13 stsp if (a->cmdline_log != NULL && strlen(a->cmdline_log) != 0) {
7671 e2ba3d07 2019-05-13 stsp len = strlen(a->cmdline_log) + 1;
7672 33ad4cbe 2019-05-12 jcs *logmsg = malloc(len + 1);
7673 9f42ff69 2019-05-13 stsp if (*logmsg == NULL)
7674 638f9024 2019-05-13 stsp return got_error_from_errno("malloc");
7675 e2ba3d07 2019-05-13 stsp strlcpy(*logmsg, a->cmdline_log, len);
7676 33ad4cbe 2019-05-12 jcs return NULL;
7677 28cf319f 2021-01-28 stsp } else if (a->prepared_log != NULL && a->non_interactive)
7678 28cf319f 2021-01-28 stsp return read_prepared_logmsg(logmsg, a->prepared_log);
7679 33ad4cbe 2019-05-12 jcs
7680 e0870e44 2019-05-13 stsp if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
7681 76d98825 2019-06-03 stsp return got_error_from_errno("asprintf");
7682 76d98825 2019-06-03 stsp
7683 28cf319f 2021-01-28 stsp err = got_opentemp_named_fd(&a->logmsg_path, &fd, template);
7684 28cf319f 2021-01-28 stsp if (err)
7685 28cf319f 2021-01-28 stsp goto done;
7686 28cf319f 2021-01-28 stsp
7687 28cf319f 2021-01-28 stsp if (a->prepared_log) {
7688 28cf319f 2021-01-28 stsp char *msg;
7689 28cf319f 2021-01-28 stsp err = read_prepared_logmsg(&msg, a->prepared_log);
7690 28cf319f 2021-01-28 stsp if (err)
7691 28cf319f 2021-01-28 stsp goto done;
7692 28cf319f 2021-01-28 stsp if (write(fd, msg, strlen(msg)) == -1) {
7693 28cf319f 2021-01-28 stsp err = got_error_from_errno2("write", a->logmsg_path);
7694 28cf319f 2021-01-28 stsp free(msg);
7695 28cf319f 2021-01-28 stsp goto done;
7696 28cf319f 2021-01-28 stsp }
7697 28cf319f 2021-01-28 stsp free(msg);
7698 28cf319f 2021-01-28 stsp }
7699 28cf319f 2021-01-28 stsp
7700 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
7701 76d98825 2019-06-03 stsp "\n# changes to be committed on branch %s:\n",
7702 1601cb9f 2020-09-11 naddy a->branch_name);
7703 28cf319f 2021-01-28 stsp if (initial_content_len == -1) {
7704 28cf319f 2021-01-28 stsp err = got_error_from_errno("asprintf");
7705 e0870e44 2019-05-13 stsp goto done;
7706 28cf319f 2021-01-28 stsp }
7707 33ad4cbe 2019-05-12 jcs
7708 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
7709 97972933 2020-09-11 stsp err = got_error_from_errno2("write", a->logmsg_path);
7710 97972933 2020-09-11 stsp goto done;
7711 97972933 2020-09-11 stsp }
7712 33ad4cbe 2019-05-12 jcs
7713 33ad4cbe 2019-05-12 jcs TAILQ_FOREACH(pe, commitable_paths, entry) {
7714 33ad4cbe 2019-05-12 jcs struct got_commitable *ct = pe->data;
7715 8656d6c4 2019-05-20 stsp dprintf(fd, "# %c %s\n",
7716 8656d6c4 2019-05-20 stsp got_commitable_get_status(ct),
7717 8656d6c4 2019-05-20 stsp got_commitable_get_path(ct));
7718 33ad4cbe 2019-05-12 jcs }
7719 33ad4cbe 2019-05-12 jcs
7720 bfa12d5e 2020-09-26 stsp err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content,
7721 28cf319f 2021-01-28 stsp initial_content_len, a->prepared_log ? 0 : 1);
7722 33ad4cbe 2019-05-12 jcs done:
7723 76d98825 2019-06-03 stsp free(initial_content);
7724 e0870e44 2019-05-13 stsp free(template);
7725 314a6357 2019-05-13 stsp
7726 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
7727 97972933 2020-09-11 stsp err = got_error_from_errno2("close", a->logmsg_path);
7728 97972933 2020-09-11 stsp
7729 314a6357 2019-05-13 stsp /* Editor is done; we can now apply unveil(2) */
7730 59f86c76 2020-09-11 stsp if (err == NULL)
7731 c530dc23 2019-07-23 stsp err = apply_unveil(a->repo_path, 0, a->worktree_path);
7732 59f86c76 2020-09-11 stsp if (err) {
7733 59f86c76 2020-09-11 stsp free(*logmsg);
7734 59f86c76 2020-09-11 stsp *logmsg = NULL;
7735 3ce1b845 2019-07-15 stsp }
7736 33ad4cbe 2019-05-12 jcs return err;
7737 6bad629b 2019-02-04 stsp }
7738 c4296144 2019-05-09 stsp
7739 c4296144 2019-05-09 stsp static const struct got_error *
7740 c4296144 2019-05-09 stsp cmd_commit(int argc, char *argv[])
7741 c4296144 2019-05-09 stsp {
7742 c4296144 2019-05-09 stsp const struct got_error *error = NULL;
7743 c4296144 2019-05-09 stsp struct got_worktree *worktree = NULL;
7744 c4296144 2019-05-09 stsp struct got_repository *repo = NULL;
7745 5c1e53bc 2019-07-28 stsp char *cwd = NULL, *id_str = NULL;
7746 c4296144 2019-05-09 stsp struct got_object_id *id = NULL;
7747 33ad4cbe 2019-05-12 jcs const char *logmsg = NULL;
7748 28cf319f 2021-01-28 stsp char *prepared_logmsg = NULL;
7749 aba9c984 2019-09-08 stsp struct collect_commit_logmsg_arg cl_arg;
7750 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
7751 7266f21f 2019-10-21 stsp int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
7752 f259c4c1 2021-09-24 stsp int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0;
7753 5c1e53bc 2019-07-28 stsp struct got_pathlist_head paths;
7754 5c1e53bc 2019-07-28 stsp
7755 5c1e53bc 2019-07-28 stsp TAILQ_INIT(&paths);
7756 6ac5a73c 2019-08-08 stsp cl_arg.logmsg_path = NULL;
7757 c4296144 2019-05-09 stsp
7758 28cf319f 2021-01-28 stsp while ((ch = getopt(argc, argv, "F:m:NS")) != -1) {
7759 c4296144 2019-05-09 stsp switch (ch) {
7760 28cf319f 2021-01-28 stsp case 'F':
7761 28cf319f 2021-01-28 stsp if (logmsg != NULL)
7762 28cf319f 2021-01-28 stsp option_conflict('F', 'm');
7763 28cf319f 2021-01-28 stsp prepared_logmsg = realpath(optarg, NULL);
7764 28cf319f 2021-01-28 stsp if (prepared_logmsg == NULL)
7765 28cf319f 2021-01-28 stsp return got_error_from_errno2("realpath",
7766 28cf319f 2021-01-28 stsp optarg);
7767 28cf319f 2021-01-28 stsp break;
7768 c4296144 2019-05-09 stsp case 'm':
7769 28cf319f 2021-01-28 stsp if (prepared_logmsg)
7770 28cf319f 2021-01-28 stsp option_conflict('m', 'F');
7771 c4296144 2019-05-09 stsp logmsg = optarg;
7772 28cf319f 2021-01-28 stsp break;
7773 28cf319f 2021-01-28 stsp case 'N':
7774 28cf319f 2021-01-28 stsp non_interactive = 1;
7775 c4296144 2019-05-09 stsp break;
7776 35213c7c 2020-07-23 stsp case 'S':
7777 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
7778 35213c7c 2020-07-23 stsp break;
7779 c4296144 2019-05-09 stsp default:
7780 c4296144 2019-05-09 stsp usage_commit();
7781 c4296144 2019-05-09 stsp /* NOTREACHED */
7782 c4296144 2019-05-09 stsp }
7783 c4296144 2019-05-09 stsp }
7784 c4296144 2019-05-09 stsp
7785 c4296144 2019-05-09 stsp argc -= optind;
7786 c4296144 2019-05-09 stsp argv += optind;
7787 c4296144 2019-05-09 stsp
7788 43012d58 2019-07-14 stsp #ifndef PROFILE
7789 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7790 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
7791 43012d58 2019-07-14 stsp err(1, "pledge");
7792 43012d58 2019-07-14 stsp #endif
7793 c4296144 2019-05-09 stsp cwd = getcwd(NULL, 0);
7794 c4296144 2019-05-09 stsp if (cwd == NULL) {
7795 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
7796 c4296144 2019-05-09 stsp goto done;
7797 c4296144 2019-05-09 stsp }
7798 c4296144 2019-05-09 stsp error = got_worktree_open(&worktree, cwd);
7799 fa51e947 2020-03-27 stsp if (error) {
7800 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7801 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "commit", cwd);
7802 7d5807f4 2019-07-11 stsp goto done;
7803 fa51e947 2020-03-27 stsp }
7804 7d5807f4 2019-07-11 stsp
7805 a698f62e 2019-07-25 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
7806 c4296144 2019-05-09 stsp if (error)
7807 a698f62e 2019-07-25 stsp goto done;
7808 a698f62e 2019-07-25 stsp if (rebase_in_progress) {
7809 a698f62e 2019-07-25 stsp error = got_error(GOT_ERR_REBASING);
7810 c4296144 2019-05-09 stsp goto done;
7811 a698f62e 2019-07-25 stsp }
7812 5c1e53bc 2019-07-28 stsp
7813 916f288c 2019-07-30 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
7814 916f288c 2019-07-30 stsp worktree);
7815 5c1e53bc 2019-07-28 stsp if (error)
7816 5c1e53bc 2019-07-28 stsp goto done;
7817 c4296144 2019-05-09 stsp
7818 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
7819 c9956ddf 2019-09-08 stsp if (error)
7820 c9956ddf 2019-09-08 stsp goto done;
7821 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7822 c9956ddf 2019-09-08 stsp gitconfig_path);
7823 c4296144 2019-05-09 stsp if (error != NULL)
7824 c4296144 2019-05-09 stsp goto done;
7825 c4296144 2019-05-09 stsp
7826 f259c4c1 2021-09-24 stsp error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo);
7827 f259c4c1 2021-09-24 stsp if (error)
7828 f259c4c1 2021-09-24 stsp goto done;
7829 f259c4c1 2021-09-24 stsp if (merge_in_progress) {
7830 f259c4c1 2021-09-24 stsp error = got_error(GOT_ERR_MERGE_BUSY);
7831 f259c4c1 2021-09-24 stsp goto done;
7832 f259c4c1 2021-09-24 stsp }
7833 f259c4c1 2021-09-24 stsp
7834 50b0790e 2020-09-11 stsp error = get_author(&author, repo, worktree);
7835 aba9c984 2019-09-08 stsp if (error)
7836 aba9c984 2019-09-08 stsp return error;
7837 aba9c984 2019-09-08 stsp
7838 314a6357 2019-05-13 stsp /*
7839 314a6357 2019-05-13 stsp * unveil(2) traverses exec(2); if an editor is used we have
7840 314a6357 2019-05-13 stsp * to apply unveil after the log message has been written.
7841 314a6357 2019-05-13 stsp */
7842 314a6357 2019-05-13 stsp if (logmsg == NULL || strlen(logmsg) == 0)
7843 314a6357 2019-05-13 stsp error = get_editor(&editor);
7844 314a6357 2019-05-13 stsp else
7845 314a6357 2019-05-13 stsp error = apply_unveil(got_repo_get_path(repo), 0,
7846 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7847 c4296144 2019-05-09 stsp if (error)
7848 c4296144 2019-05-09 stsp goto done;
7849 c4296144 2019-05-09 stsp
7850 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7851 087fb88c 2019-08-04 stsp if (error)
7852 087fb88c 2019-08-04 stsp goto done;
7853 087fb88c 2019-08-04 stsp
7854 e2ba3d07 2019-05-13 stsp cl_arg.editor = editor;
7855 e2ba3d07 2019-05-13 stsp cl_arg.cmdline_log = logmsg;
7856 28cf319f 2021-01-28 stsp cl_arg.prepared_log = prepared_logmsg;
7857 28cf319f 2021-01-28 stsp cl_arg.non_interactive = non_interactive;
7858 e0870e44 2019-05-13 stsp cl_arg.worktree_path = got_worktree_get_root_path(worktree);
7859 76d98825 2019-06-03 stsp cl_arg.branch_name = got_worktree_get_head_ref_name(worktree);
7860 916f288c 2019-07-30 stsp if (!histedit_in_progress) {
7861 916f288c 2019-07-30 stsp if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) {
7862 916f288c 2019-07-30 stsp error = got_error(GOT_ERR_COMMIT_BRANCH);
7863 916f288c 2019-07-30 stsp goto done;
7864 916f288c 2019-07-30 stsp }
7865 916f288c 2019-07-30 stsp cl_arg.branch_name += 11;
7866 916f288c 2019-07-30 stsp }
7867 314a6357 2019-05-13 stsp cl_arg.repo_path = got_repo_get_path(repo);
7868 84792843 2019-08-09 stsp error = got_worktree_commit(&id, worktree, &paths, author, NULL,
7869 35213c7c 2020-07-23 stsp allow_bad_symlinks, collect_commit_logmsg, &cl_arg,
7870 35213c7c 2020-07-23 stsp print_status, NULL, repo);
7871 e0870e44 2019-05-13 stsp if (error) {
7872 7266f21f 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
7873 7266f21f 2019-10-21 stsp cl_arg.logmsg_path != NULL)
7874 7266f21f 2019-10-21 stsp preserve_logmsg = 1;
7875 c4296144 2019-05-09 stsp goto done;
7876 e0870e44 2019-05-13 stsp }
7877 c4296144 2019-05-09 stsp
7878 c4296144 2019-05-09 stsp error = got_object_id_str(&id_str, id);
7879 c4296144 2019-05-09 stsp if (error)
7880 c4296144 2019-05-09 stsp goto done;
7881 a7648d7a 2019-06-02 stsp printf("Created commit %s\n", id_str);
7882 c4296144 2019-05-09 stsp done:
7883 7266f21f 2019-10-21 stsp if (preserve_logmsg) {
7884 7266f21f 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
7885 7266f21f 2019-10-21 stsp getprogname(), cl_arg.logmsg_path);
7886 7266f21f 2019-10-21 stsp } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
7887 7266f21f 2019-10-21 stsp error == NULL)
7888 7266f21f 2019-10-21 stsp error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
7889 6ac5a73c 2019-08-08 stsp free(cl_arg.logmsg_path);
7890 1d0f4054 2021-06-17 stsp if (repo) {
7891 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
7892 1d0f4054 2021-06-17 stsp if (error == NULL)
7893 1d0f4054 2021-06-17 stsp error = close_err;
7894 1d0f4054 2021-06-17 stsp }
7895 c4296144 2019-05-09 stsp if (worktree)
7896 c4296144 2019-05-09 stsp got_worktree_close(worktree);
7897 c4296144 2019-05-09 stsp free(cwd);
7898 c4296144 2019-05-09 stsp free(id_str);
7899 c9956ddf 2019-09-08 stsp free(gitconfig_path);
7900 e2ba3d07 2019-05-13 stsp free(editor);
7901 aba9c984 2019-09-08 stsp free(author);
7902 28cf319f 2021-01-28 stsp free(prepared_logmsg);
7903 f8a36e22 2021-08-26 stsp return error;
7904 f8a36e22 2021-08-26 stsp }
7905 f8a36e22 2021-08-26 stsp
7906 f8a36e22 2021-08-26 stsp __dead static void
7907 f8a36e22 2021-08-26 stsp usage_send(void)
7908 f8a36e22 2021-08-26 stsp {
7909 f8a36e22 2021-08-26 stsp fprintf(stderr, "usage: %s send [-a] [-b branch] [-d branch] [-f] "
7910 f8a36e22 2021-08-26 stsp "[-r repository-path] [-t tag] [-T] [-q] [-v] "
7911 f8a36e22 2021-08-26 stsp "[remote-repository]\n", getprogname());
7912 f8a36e22 2021-08-26 stsp exit(1);
7913 f8a36e22 2021-08-26 stsp }
7914 f8a36e22 2021-08-26 stsp
7915 b8af7c06 2022-03-15 stsp static void
7916 b8af7c06 2022-03-15 stsp print_load_info(int print_colored, int print_found, int print_trees,
7917 b8af7c06 2022-03-15 stsp int ncolored, int nfound, int ntrees)
7918 b8af7c06 2022-03-15 stsp {
7919 b8af7c06 2022-03-15 stsp if (print_colored) {
7920 b8af7c06 2022-03-15 stsp printf("%d commit%s colored", ncolored,
7921 b8af7c06 2022-03-15 stsp ncolored == 1 ? "" : "s");
7922 b8af7c06 2022-03-15 stsp }
7923 b8af7c06 2022-03-15 stsp if (print_found) {
7924 b8af7c06 2022-03-15 stsp printf("%s%d object%s found",
7925 b8af7c06 2022-03-15 stsp ncolored > 0 ? "; " : "",
7926 b8af7c06 2022-03-15 stsp nfound, nfound == 1 ? "" : "s");
7927 b8af7c06 2022-03-15 stsp }
7928 b8af7c06 2022-03-15 stsp if (print_trees) {
7929 b8af7c06 2022-03-15 stsp printf("; %d tree%s scanned", ntrees,
7930 b8af7c06 2022-03-15 stsp ntrees == 1 ? "" : "s");
7931 b8af7c06 2022-03-15 stsp }
7932 b8af7c06 2022-03-15 stsp }
7933 b8af7c06 2022-03-15 stsp
7934 f8a36e22 2021-08-26 stsp struct got_send_progress_arg {
7935 f8a36e22 2021-08-26 stsp char last_scaled_packsize[FMT_SCALED_STRSIZE];
7936 f8a36e22 2021-08-26 stsp int verbosity;
7937 b8af7c06 2022-03-15 stsp int last_ncolored;
7938 b8af7c06 2022-03-15 stsp int last_nfound;
7939 b8af7c06 2022-03-15 stsp int last_ntrees;
7940 b8af7c06 2022-03-15 stsp int loading_done;
7941 f8a36e22 2021-08-26 stsp int last_ncommits;
7942 f8a36e22 2021-08-26 stsp int last_nobj_total;
7943 f8a36e22 2021-08-26 stsp int last_p_deltify;
7944 f8a36e22 2021-08-26 stsp int last_p_written;
7945 f8a36e22 2021-08-26 stsp int last_p_sent;
7946 f8a36e22 2021-08-26 stsp int printed_something;
7947 f8a36e22 2021-08-26 stsp int sent_something;
7948 f8a36e22 2021-08-26 stsp struct got_pathlist_head *delete_branches;
7949 f8a36e22 2021-08-26 stsp };
7950 f8a36e22 2021-08-26 stsp
7951 f8a36e22 2021-08-26 stsp static const struct got_error *
7952 b8af7c06 2022-03-15 stsp send_progress(void *arg, int ncolored, int nfound, int ntrees,
7953 b8af7c06 2022-03-15 stsp off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify,
7954 b8af7c06 2022-03-15 stsp int nobj_written, off_t bytes_sent, const char *refname, int success)
7955 f8a36e22 2021-08-26 stsp {
7956 f8a36e22 2021-08-26 stsp struct got_send_progress_arg *a = arg;
7957 f8a36e22 2021-08-26 stsp char scaled_packsize[FMT_SCALED_STRSIZE];
7958 f8a36e22 2021-08-26 stsp char scaled_sent[FMT_SCALED_STRSIZE];
7959 f8a36e22 2021-08-26 stsp int p_deltify = 0, p_written = 0, p_sent = 0;
7960 b8af7c06 2022-03-15 stsp int print_colored = 0, print_found = 0, print_trees = 0;
7961 f8a36e22 2021-08-26 stsp int print_searching = 0, print_total = 0;
7962 f8a36e22 2021-08-26 stsp int print_deltify = 0, print_written = 0, print_sent = 0;
7963 f8a36e22 2021-08-26 stsp
7964 f8a36e22 2021-08-26 stsp if (a->verbosity < 0)
7965 f8a36e22 2021-08-26 stsp return NULL;
7966 f8a36e22 2021-08-26 stsp
7967 f8a36e22 2021-08-26 stsp if (refname) {
7968 f8a36e22 2021-08-26 stsp const char *status = success ? "accepted" : "rejected";
7969 f8a36e22 2021-08-26 stsp
7970 f8a36e22 2021-08-26 stsp if (success) {
7971 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *pe;
7972 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, a->delete_branches, entry) {
7973 f8a36e22 2021-08-26 stsp const char *branchname = pe->path;
7974 f8a36e22 2021-08-26 stsp if (got_path_cmp(branchname, refname,
7975 f8a36e22 2021-08-26 stsp strlen(branchname), strlen(refname)) == 0) {
7976 f8a36e22 2021-08-26 stsp status = "deleted";
7977 27b75514 2021-08-28 stsp a->sent_something = 1;
7978 f8a36e22 2021-08-26 stsp break;
7979 f8a36e22 2021-08-26 stsp }
7980 f8a36e22 2021-08-26 stsp }
7981 f8a36e22 2021-08-26 stsp }
7982 f8a36e22 2021-08-26 stsp
7983 27b75514 2021-08-28 stsp if (a->printed_something)
7984 27b75514 2021-08-28 stsp putchar('\n');
7985 27b75514 2021-08-28 stsp printf("Server has %s %s", status, refname);
7986 f8a36e22 2021-08-26 stsp a->printed_something = 1;
7987 f8a36e22 2021-08-26 stsp return NULL;
7988 f8a36e22 2021-08-26 stsp }
7989 f8a36e22 2021-08-26 stsp
7990 b8af7c06 2022-03-15 stsp if (a->last_ncolored != ncolored) {
7991 b8af7c06 2022-03-15 stsp print_colored = 1;
7992 b8af7c06 2022-03-15 stsp a->last_ncolored = ncolored;
7993 b8af7c06 2022-03-15 stsp }
7994 b8af7c06 2022-03-15 stsp
7995 b8af7c06 2022-03-15 stsp if (a->last_nfound != nfound) {
7996 b8af7c06 2022-03-15 stsp print_colored = 1;
7997 b8af7c06 2022-03-15 stsp print_found = 1;
7998 b8af7c06 2022-03-15 stsp a->last_nfound = nfound;
7999 b8af7c06 2022-03-15 stsp }
8000 b8af7c06 2022-03-15 stsp
8001 b8af7c06 2022-03-15 stsp if (a->last_ntrees != ntrees) {
8002 b8af7c06 2022-03-15 stsp print_colored = 1;
8003 b8af7c06 2022-03-15 stsp print_found = 1;
8004 b8af7c06 2022-03-15 stsp print_trees = 1;
8005 b8af7c06 2022-03-15 stsp a->last_ntrees = ntrees;
8006 b8af7c06 2022-03-15 stsp }
8007 b8af7c06 2022-03-15 stsp
8008 b8af7c06 2022-03-15 stsp if ((print_colored || print_found || print_trees) &&
8009 b8af7c06 2022-03-15 stsp !a->loading_done) {
8010 b8af7c06 2022-03-15 stsp printf("\r");
8011 b8af7c06 2022-03-15 stsp print_load_info(print_colored, print_found, print_trees,
8012 b8af7c06 2022-03-15 stsp ncolored, nfound, ntrees);
8013 b8af7c06 2022-03-15 stsp a->printed_something = 1;
8014 b8af7c06 2022-03-15 stsp fflush(stdout);
8015 b8af7c06 2022-03-15 stsp return NULL;
8016 b8af7c06 2022-03-15 stsp } else if (!a->loading_done) {
8017 b8af7c06 2022-03-15 stsp printf("\r");
8018 b8af7c06 2022-03-15 stsp print_load_info(1, 1, 1, ncolored, nfound, ntrees);
8019 b8af7c06 2022-03-15 stsp printf("\n");
8020 b8af7c06 2022-03-15 stsp a->loading_done = 1;
8021 b8af7c06 2022-03-15 stsp }
8022 b8af7c06 2022-03-15 stsp
8023 f8a36e22 2021-08-26 stsp if (fmt_scaled(packfile_size, scaled_packsize) == -1)
8024 f8a36e22 2021-08-26 stsp return got_error_from_errno("fmt_scaled");
8025 f8a36e22 2021-08-26 stsp if (fmt_scaled(bytes_sent, scaled_sent) == -1)
8026 f8a36e22 2021-08-26 stsp return got_error_from_errno("fmt_scaled");
8027 f8a36e22 2021-08-26 stsp
8028 f8a36e22 2021-08-26 stsp if (a->last_ncommits != ncommits) {
8029 f8a36e22 2021-08-26 stsp print_searching = 1;
8030 f8a36e22 2021-08-26 stsp a->last_ncommits = ncommits;
8031 f8a36e22 2021-08-26 stsp }
8032 f8a36e22 2021-08-26 stsp
8033 f8a36e22 2021-08-26 stsp if (a->last_nobj_total != nobj_total) {
8034 f8a36e22 2021-08-26 stsp print_searching = 1;
8035 f8a36e22 2021-08-26 stsp print_total = 1;
8036 f8a36e22 2021-08-26 stsp a->last_nobj_total = nobj_total;
8037 f8a36e22 2021-08-26 stsp }
8038 f8a36e22 2021-08-26 stsp
8039 f8a36e22 2021-08-26 stsp if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' ||
8040 f8a36e22 2021-08-26 stsp strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) {
8041 f8a36e22 2021-08-26 stsp if (strlcpy(a->last_scaled_packsize, scaled_packsize,
8042 f8a36e22 2021-08-26 stsp FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
8043 f8a36e22 2021-08-26 stsp return got_error(GOT_ERR_NO_SPACE);
8044 f8a36e22 2021-08-26 stsp }
8045 f8a36e22 2021-08-26 stsp
8046 f8a36e22 2021-08-26 stsp if (nobj_deltify > 0 || nobj_written > 0) {
8047 f8a36e22 2021-08-26 stsp if (nobj_deltify > 0) {
8048 f8a36e22 2021-08-26 stsp p_deltify = (nobj_deltify * 100) / nobj_total;
8049 f8a36e22 2021-08-26 stsp if (p_deltify != a->last_p_deltify) {
8050 f8a36e22 2021-08-26 stsp a->last_p_deltify = p_deltify;
8051 f8a36e22 2021-08-26 stsp print_searching = 1;
8052 f8a36e22 2021-08-26 stsp print_total = 1;
8053 f8a36e22 2021-08-26 stsp print_deltify = 1;
8054 f8a36e22 2021-08-26 stsp }
8055 f8a36e22 2021-08-26 stsp }
8056 f8a36e22 2021-08-26 stsp if (nobj_written > 0) {
8057 f8a36e22 2021-08-26 stsp p_written = (nobj_written * 100) / nobj_total;
8058 f8a36e22 2021-08-26 stsp if (p_written != a->last_p_written) {
8059 f8a36e22 2021-08-26 stsp a->last_p_written = p_written;
8060 f8a36e22 2021-08-26 stsp print_searching = 1;
8061 f8a36e22 2021-08-26 stsp print_total = 1;
8062 f8a36e22 2021-08-26 stsp print_deltify = 1;
8063 f8a36e22 2021-08-26 stsp print_written = 1;
8064 f8a36e22 2021-08-26 stsp }
8065 f8a36e22 2021-08-26 stsp }
8066 f8a36e22 2021-08-26 stsp }
8067 f8a36e22 2021-08-26 stsp
8068 f8a36e22 2021-08-26 stsp if (bytes_sent > 0) {
8069 f8a36e22 2021-08-26 stsp p_sent = (bytes_sent * 100) / packfile_size;
8070 f8a36e22 2021-08-26 stsp if (p_sent != a->last_p_sent) {
8071 f8a36e22 2021-08-26 stsp a->last_p_sent = p_sent;
8072 f8a36e22 2021-08-26 stsp print_searching = 1;
8073 f8a36e22 2021-08-26 stsp print_total = 1;
8074 f8a36e22 2021-08-26 stsp print_deltify = 1;
8075 f8a36e22 2021-08-26 stsp print_written = 1;
8076 f8a36e22 2021-08-26 stsp print_sent = 1;
8077 f8a36e22 2021-08-26 stsp }
8078 f8a36e22 2021-08-26 stsp a->sent_something = 1;
8079 f8a36e22 2021-08-26 stsp }
8080 f8a36e22 2021-08-26 stsp
8081 f8a36e22 2021-08-26 stsp if (print_searching || print_total || print_deltify || print_written ||
8082 f8a36e22 2021-08-26 stsp print_sent)
8083 f8a36e22 2021-08-26 stsp printf("\r");
8084 f8a36e22 2021-08-26 stsp if (print_searching)
8085 f8a36e22 2021-08-26 stsp printf("packing %d reference%s", ncommits,
8086 f8a36e22 2021-08-26 stsp ncommits == 1 ? "" : "s");
8087 f8a36e22 2021-08-26 stsp if (print_total)
8088 f8a36e22 2021-08-26 stsp printf("; %d object%s", nobj_total,
8089 f8a36e22 2021-08-26 stsp nobj_total == 1 ? "" : "s");
8090 f8a36e22 2021-08-26 stsp if (print_deltify)
8091 f8a36e22 2021-08-26 stsp printf("; deltify: %d%%", p_deltify);
8092 f8a36e22 2021-08-26 stsp if (print_sent)
8093 b5934965 2022-02-12 naddy printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
8094 f8a36e22 2021-08-26 stsp scaled_packsize, p_sent);
8095 f8a36e22 2021-08-26 stsp else if (print_written)
8096 b5934965 2022-02-12 naddy printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
8097 f8a36e22 2021-08-26 stsp scaled_packsize, p_written);
8098 f8a36e22 2021-08-26 stsp if (print_searching || print_total || print_deltify ||
8099 f8a36e22 2021-08-26 stsp print_written || print_sent) {
8100 f8a36e22 2021-08-26 stsp a->printed_something = 1;
8101 f8a36e22 2021-08-26 stsp fflush(stdout);
8102 f8a36e22 2021-08-26 stsp }
8103 f8a36e22 2021-08-26 stsp return NULL;
8104 f8a36e22 2021-08-26 stsp }
8105 f8a36e22 2021-08-26 stsp
8106 f8a36e22 2021-08-26 stsp static const struct got_error *
8107 f8a36e22 2021-08-26 stsp cmd_send(int argc, char *argv[])
8108 f8a36e22 2021-08-26 stsp {
8109 f8a36e22 2021-08-26 stsp const struct got_error *error = NULL;
8110 f8a36e22 2021-08-26 stsp char *cwd = NULL, *repo_path = NULL;
8111 f8a36e22 2021-08-26 stsp const char *remote_name;
8112 f8a36e22 2021-08-26 stsp char *proto = NULL, *host = NULL, *port = NULL;
8113 f8a36e22 2021-08-26 stsp char *repo_name = NULL, *server_path = NULL;
8114 f8a36e22 2021-08-26 stsp const struct got_remote_repo *remotes, *remote = NULL;
8115 f8a36e22 2021-08-26 stsp int nremotes, nbranches = 0, ntags = 0, ndelete_branches = 0;
8116 f8a36e22 2021-08-26 stsp struct got_repository *repo = NULL;
8117 f8a36e22 2021-08-26 stsp struct got_worktree *worktree = NULL;
8118 f8a36e22 2021-08-26 stsp const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
8119 f8a36e22 2021-08-26 stsp struct got_pathlist_head branches;
8120 f8a36e22 2021-08-26 stsp struct got_pathlist_head tags;
8121 f8a36e22 2021-08-26 stsp struct got_reflist_head all_branches;
8122 f8a36e22 2021-08-26 stsp struct got_reflist_head all_tags;
8123 f8a36e22 2021-08-26 stsp struct got_pathlist_head delete_args;
8124 f8a36e22 2021-08-26 stsp struct got_pathlist_head delete_branches;
8125 f8a36e22 2021-08-26 stsp struct got_reflist_entry *re;
8126 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *pe;
8127 f8a36e22 2021-08-26 stsp int i, ch, sendfd = -1, sendstatus;
8128 f8a36e22 2021-08-26 stsp pid_t sendpid = -1;
8129 f8a36e22 2021-08-26 stsp struct got_send_progress_arg spa;
8130 f8a36e22 2021-08-26 stsp int verbosity = 0, overwrite_refs = 0;
8131 f8a36e22 2021-08-26 stsp int send_all_branches = 0, send_all_tags = 0;
8132 f8a36e22 2021-08-26 stsp struct got_reference *ref = NULL;
8133 f8a36e22 2021-08-26 stsp
8134 f8a36e22 2021-08-26 stsp TAILQ_INIT(&branches);
8135 f8a36e22 2021-08-26 stsp TAILQ_INIT(&tags);
8136 f8a36e22 2021-08-26 stsp TAILQ_INIT(&all_branches);
8137 f8a36e22 2021-08-26 stsp TAILQ_INIT(&all_tags);
8138 f8a36e22 2021-08-26 stsp TAILQ_INIT(&delete_args);
8139 f8a36e22 2021-08-26 stsp TAILQ_INIT(&delete_branches);
8140 f8a36e22 2021-08-26 stsp
8141 f8a36e22 2021-08-26 stsp while ((ch = getopt(argc, argv, "ab:d:fr:t:Tvq")) != -1) {
8142 f8a36e22 2021-08-26 stsp switch (ch) {
8143 f8a36e22 2021-08-26 stsp case 'a':
8144 f8a36e22 2021-08-26 stsp send_all_branches = 1;
8145 f8a36e22 2021-08-26 stsp break;
8146 f8a36e22 2021-08-26 stsp case 'b':
8147 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches, optarg, NULL);
8148 f8a36e22 2021-08-26 stsp if (error)
8149 f8a36e22 2021-08-26 stsp return error;
8150 f8a36e22 2021-08-26 stsp nbranches++;
8151 f8a36e22 2021-08-26 stsp break;
8152 f8a36e22 2021-08-26 stsp case 'd':
8153 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&delete_args, optarg, NULL);
8154 f8a36e22 2021-08-26 stsp if (error)
8155 f8a36e22 2021-08-26 stsp return error;
8156 f8a36e22 2021-08-26 stsp break;
8157 f8a36e22 2021-08-26 stsp case 'f':
8158 f8a36e22 2021-08-26 stsp overwrite_refs = 1;
8159 f8a36e22 2021-08-26 stsp break;
8160 f8a36e22 2021-08-26 stsp case 'r':
8161 f8a36e22 2021-08-26 stsp repo_path = realpath(optarg, NULL);
8162 f8a36e22 2021-08-26 stsp if (repo_path == NULL)
8163 f8a36e22 2021-08-26 stsp return got_error_from_errno2("realpath",
8164 f8a36e22 2021-08-26 stsp optarg);
8165 f8a36e22 2021-08-26 stsp got_path_strip_trailing_slashes(repo_path);
8166 f8a36e22 2021-08-26 stsp break;
8167 f8a36e22 2021-08-26 stsp case 't':
8168 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&tags, optarg, NULL);
8169 f8a36e22 2021-08-26 stsp if (error)
8170 f8a36e22 2021-08-26 stsp return error;
8171 f8a36e22 2021-08-26 stsp ntags++;
8172 f8a36e22 2021-08-26 stsp break;
8173 f8a36e22 2021-08-26 stsp case 'T':
8174 f8a36e22 2021-08-26 stsp send_all_tags = 1;
8175 f8a36e22 2021-08-26 stsp break;
8176 f8a36e22 2021-08-26 stsp case 'v':
8177 f8a36e22 2021-08-26 stsp if (verbosity < 0)
8178 f8a36e22 2021-08-26 stsp verbosity = 0;
8179 f8a36e22 2021-08-26 stsp else if (verbosity < 3)
8180 f8a36e22 2021-08-26 stsp verbosity++;
8181 f8a36e22 2021-08-26 stsp break;
8182 f8a36e22 2021-08-26 stsp case 'q':
8183 f8a36e22 2021-08-26 stsp verbosity = -1;
8184 f8a36e22 2021-08-26 stsp break;
8185 f8a36e22 2021-08-26 stsp default:
8186 f8a36e22 2021-08-26 stsp usage_send();
8187 f8a36e22 2021-08-26 stsp /* NOTREACHED */
8188 f8a36e22 2021-08-26 stsp }
8189 f8a36e22 2021-08-26 stsp }
8190 f8a36e22 2021-08-26 stsp argc -= optind;
8191 f8a36e22 2021-08-26 stsp argv += optind;
8192 f8a36e22 2021-08-26 stsp
8193 f8a36e22 2021-08-26 stsp if (send_all_branches && !TAILQ_EMPTY(&branches))
8194 f8a36e22 2021-08-26 stsp option_conflict('a', 'b');
8195 f8a36e22 2021-08-26 stsp if (send_all_tags && !TAILQ_EMPTY(&tags))
8196 f8a36e22 2021-08-26 stsp option_conflict('T', 't');
8197 f8a36e22 2021-08-26 stsp
8198 f8a36e22 2021-08-26 stsp
8199 f8a36e22 2021-08-26 stsp if (argc == 0)
8200 f8a36e22 2021-08-26 stsp remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
8201 f8a36e22 2021-08-26 stsp else if (argc == 1)
8202 f8a36e22 2021-08-26 stsp remote_name = argv[0];
8203 f8a36e22 2021-08-26 stsp else
8204 f8a36e22 2021-08-26 stsp usage_send();
8205 f8a36e22 2021-08-26 stsp
8206 f8a36e22 2021-08-26 stsp cwd = getcwd(NULL, 0);
8207 f8a36e22 2021-08-26 stsp if (cwd == NULL) {
8208 f8a36e22 2021-08-26 stsp error = got_error_from_errno("getcwd");
8209 f8a36e22 2021-08-26 stsp goto done;
8210 f8a36e22 2021-08-26 stsp }
8211 f8a36e22 2021-08-26 stsp
8212 f8a36e22 2021-08-26 stsp if (repo_path == NULL) {
8213 f8a36e22 2021-08-26 stsp error = got_worktree_open(&worktree, cwd);
8214 f8a36e22 2021-08-26 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
8215 f8a36e22 2021-08-26 stsp goto done;
8216 f8a36e22 2021-08-26 stsp else
8217 f8a36e22 2021-08-26 stsp error = NULL;
8218 f8a36e22 2021-08-26 stsp if (worktree) {
8219 f8a36e22 2021-08-26 stsp repo_path =
8220 f8a36e22 2021-08-26 stsp strdup(got_worktree_get_repo_path(worktree));
8221 f8a36e22 2021-08-26 stsp if (repo_path == NULL)
8222 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
8223 f8a36e22 2021-08-26 stsp if (error)
8224 f8a36e22 2021-08-26 stsp goto done;
8225 f8a36e22 2021-08-26 stsp } else {
8226 f8a36e22 2021-08-26 stsp repo_path = strdup(cwd);
8227 f8a36e22 2021-08-26 stsp if (repo_path == NULL) {
8228 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
8229 f8a36e22 2021-08-26 stsp goto done;
8230 f8a36e22 2021-08-26 stsp }
8231 f8a36e22 2021-08-26 stsp }
8232 f8a36e22 2021-08-26 stsp }
8233 f8a36e22 2021-08-26 stsp
8234 f8a36e22 2021-08-26 stsp error = got_repo_open(&repo, repo_path, NULL);
8235 f8a36e22 2021-08-26 stsp if (error)
8236 f8a36e22 2021-08-26 stsp goto done;
8237 f8a36e22 2021-08-26 stsp
8238 f8a36e22 2021-08-26 stsp if (worktree) {
8239 f8a36e22 2021-08-26 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
8240 f8a36e22 2021-08-26 stsp if (worktree_conf) {
8241 f8a36e22 2021-08-26 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
8242 f8a36e22 2021-08-26 stsp worktree_conf);
8243 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
8244 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
8245 f8a36e22 2021-08-26 stsp remote = &remotes[i];
8246 f8a36e22 2021-08-26 stsp break;
8247 f8a36e22 2021-08-26 stsp }
8248 f8a36e22 2021-08-26 stsp }
8249 f8a36e22 2021-08-26 stsp }
8250 f8a36e22 2021-08-26 stsp }
8251 f8a36e22 2021-08-26 stsp if (remote == NULL) {
8252 f8a36e22 2021-08-26 stsp repo_conf = got_repo_get_gotconfig(repo);
8253 f8a36e22 2021-08-26 stsp if (repo_conf) {
8254 f8a36e22 2021-08-26 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
8255 f8a36e22 2021-08-26 stsp repo_conf);
8256 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
8257 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
8258 f8a36e22 2021-08-26 stsp remote = &remotes[i];
8259 f8a36e22 2021-08-26 stsp break;
8260 f8a36e22 2021-08-26 stsp }
8261 f8a36e22 2021-08-26 stsp }
8262 f8a36e22 2021-08-26 stsp }
8263 f8a36e22 2021-08-26 stsp }
8264 f8a36e22 2021-08-26 stsp if (remote == NULL) {
8265 f8a36e22 2021-08-26 stsp got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
8266 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
8267 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
8268 f8a36e22 2021-08-26 stsp remote = &remotes[i];
8269 f8a36e22 2021-08-26 stsp break;
8270 f8a36e22 2021-08-26 stsp }
8271 f8a36e22 2021-08-26 stsp }
8272 f8a36e22 2021-08-26 stsp }
8273 f8a36e22 2021-08-26 stsp if (remote == NULL) {
8274 f8a36e22 2021-08-26 stsp error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
8275 f8a36e22 2021-08-26 stsp goto done;
8276 f8a36e22 2021-08-26 stsp }
8277 f8a36e22 2021-08-26 stsp
8278 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
8279 6480c871 2021-08-30 stsp &repo_name, remote->send_url);
8280 f8a36e22 2021-08-26 stsp if (error)
8281 f8a36e22 2021-08-26 stsp goto done;
8282 f8a36e22 2021-08-26 stsp
8283 f8a36e22 2021-08-26 stsp if (strcmp(proto, "git") == 0) {
8284 f8a36e22 2021-08-26 stsp #ifndef PROFILE
8285 f8a36e22 2021-08-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
8286 f8a36e22 2021-08-26 stsp "sendfd dns inet unveil", NULL) == -1)
8287 f8a36e22 2021-08-26 stsp err(1, "pledge");
8288 f8a36e22 2021-08-26 stsp #endif
8289 f8a36e22 2021-08-26 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
8290 f8a36e22 2021-08-26 stsp strcmp(proto, "ssh") == 0) {
8291 f8a36e22 2021-08-26 stsp #ifndef PROFILE
8292 f8a36e22 2021-08-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
8293 f8a36e22 2021-08-26 stsp "sendfd unveil", NULL) == -1)
8294 f8a36e22 2021-08-26 stsp err(1, "pledge");
8295 f8a36e22 2021-08-26 stsp #endif
8296 f8a36e22 2021-08-26 stsp } else if (strcmp(proto, "http") == 0 ||
8297 f8a36e22 2021-08-26 stsp strcmp(proto, "git+http") == 0) {
8298 f8a36e22 2021-08-26 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
8299 f8a36e22 2021-08-26 stsp goto done;
8300 f8a36e22 2021-08-26 stsp } else {
8301 f8a36e22 2021-08-26 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
8302 f8a36e22 2021-08-26 stsp goto done;
8303 f8a36e22 2021-08-26 stsp }
8304 f8a36e22 2021-08-26 stsp
8305 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
8306 d65a88a2 2021-09-05 stsp if (error)
8307 d65a88a2 2021-09-05 stsp goto done;
8308 d65a88a2 2021-09-05 stsp
8309 f8a36e22 2021-08-26 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
8310 f8a36e22 2021-08-26 stsp if (error)
8311 f8a36e22 2021-08-26 stsp goto done;
8312 f8a36e22 2021-08-26 stsp
8313 f8a36e22 2021-08-26 stsp if (send_all_branches) {
8314 f8a36e22 2021-08-26 stsp error = got_ref_list(&all_branches, repo, "refs/heads",
8315 f8a36e22 2021-08-26 stsp got_ref_cmp_by_name, NULL);
8316 f8a36e22 2021-08-26 stsp if (error)
8317 f8a36e22 2021-08-26 stsp goto done;
8318 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(re, &all_branches, entry) {
8319 f8a36e22 2021-08-26 stsp const char *branchname = got_ref_get_name(re->ref);
8320 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches,
8321 f8a36e22 2021-08-26 stsp branchname, NULL);
8322 f8a36e22 2021-08-26 stsp if (error)
8323 f8a36e22 2021-08-26 stsp goto done;
8324 f8a36e22 2021-08-26 stsp nbranches++;
8325 f8a36e22 2021-08-26 stsp }
8326 eac1df47 2021-09-01 stsp } else if (nbranches == 0) {
8327 eac1df47 2021-09-01 stsp for (i = 0; i < remote->nsend_branches; i++) {
8328 eac1df47 2021-09-01 stsp got_pathlist_append(&branches,
8329 eac1df47 2021-09-01 stsp remote->send_branches[i], NULL);
8330 eac1df47 2021-09-01 stsp }
8331 f8a36e22 2021-08-26 stsp }
8332 f8a36e22 2021-08-26 stsp
8333 f8a36e22 2021-08-26 stsp if (send_all_tags) {
8334 f8a36e22 2021-08-26 stsp error = got_ref_list(&all_tags, repo, "refs/tags",
8335 f8a36e22 2021-08-26 stsp got_ref_cmp_by_name, NULL);
8336 f8a36e22 2021-08-26 stsp if (error)
8337 f8a36e22 2021-08-26 stsp goto done;
8338 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(re, &all_tags, entry) {
8339 f8a36e22 2021-08-26 stsp const char *tagname = got_ref_get_name(re->ref);
8340 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&tags,
8341 f8a36e22 2021-08-26 stsp tagname, NULL);
8342 f8a36e22 2021-08-26 stsp if (error)
8343 f8a36e22 2021-08-26 stsp goto done;
8344 f8a36e22 2021-08-26 stsp ntags++;
8345 f8a36e22 2021-08-26 stsp }
8346 f8a36e22 2021-08-26 stsp }
8347 f8a36e22 2021-08-26 stsp
8348 f8a36e22 2021-08-26 stsp /*
8349 f8a36e22 2021-08-26 stsp * To prevent accidents only branches in refs/heads/ can be deleted
8350 f8a36e22 2021-08-26 stsp * with 'got send -d'.
8351 f8a36e22 2021-08-26 stsp * Deleting anything else requires local repository access or Git.
8352 f8a36e22 2021-08-26 stsp */
8353 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, &delete_args, entry) {
8354 f8a36e22 2021-08-26 stsp const char *branchname = pe->path;
8355 f8a36e22 2021-08-26 stsp char *s;
8356 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *new;
8357 f8a36e22 2021-08-26 stsp if (strncmp(branchname, "refs/heads/", 11) == 0) {
8358 f8a36e22 2021-08-26 stsp s = strdup(branchname);
8359 f8a36e22 2021-08-26 stsp if (s == NULL) {
8360 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
8361 f8a36e22 2021-08-26 stsp goto done;
8362 f8a36e22 2021-08-26 stsp }
8363 f8a36e22 2021-08-26 stsp } else {
8364 f8a36e22 2021-08-26 stsp if (asprintf(&s, "refs/heads/%s", branchname) == -1) {
8365 f8a36e22 2021-08-26 stsp error = got_error_from_errno("asprintf");
8366 f8a36e22 2021-08-26 stsp goto done;
8367 f8a36e22 2021-08-26 stsp }
8368 f8a36e22 2021-08-26 stsp }
8369 f8a36e22 2021-08-26 stsp error = got_pathlist_insert(&new, &delete_branches, s, NULL);
8370 f8a36e22 2021-08-26 stsp if (error || new == NULL /* duplicate */)
8371 f8a36e22 2021-08-26 stsp free(s);
8372 f8a36e22 2021-08-26 stsp if (error)
8373 f8a36e22 2021-08-26 stsp goto done;
8374 f8a36e22 2021-08-26 stsp ndelete_branches++;
8375 f8a36e22 2021-08-26 stsp }
8376 f8a36e22 2021-08-26 stsp
8377 f8a36e22 2021-08-26 stsp if (nbranches == 0 && ndelete_branches == 0) {
8378 f8a36e22 2021-08-26 stsp struct got_reference *head_ref;
8379 f8a36e22 2021-08-26 stsp if (worktree)
8380 f8a36e22 2021-08-26 stsp error = got_ref_open(&head_ref, repo,
8381 f8a36e22 2021-08-26 stsp got_worktree_get_head_ref_name(worktree), 0);
8382 f8a36e22 2021-08-26 stsp else
8383 f8a36e22 2021-08-26 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
8384 f8a36e22 2021-08-26 stsp if (error)
8385 f8a36e22 2021-08-26 stsp goto done;
8386 f8a36e22 2021-08-26 stsp if (got_ref_is_symbolic(head_ref)) {
8387 f8a36e22 2021-08-26 stsp error = got_ref_resolve_symbolic(&ref, repo, head_ref);
8388 f8a36e22 2021-08-26 stsp got_ref_close(head_ref);
8389 f8a36e22 2021-08-26 stsp if (error)
8390 f8a36e22 2021-08-26 stsp goto done;
8391 f8a36e22 2021-08-26 stsp } else
8392 f8a36e22 2021-08-26 stsp ref = head_ref;
8393 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches, got_ref_get_name(ref),
8394 abc59930 2021-09-05 naddy NULL);
8395 f8a36e22 2021-08-26 stsp if (error)
8396 f8a36e22 2021-08-26 stsp goto done;
8397 f8a36e22 2021-08-26 stsp nbranches++;
8398 f8a36e22 2021-08-26 stsp }
8399 f8a36e22 2021-08-26 stsp
8400 f8a36e22 2021-08-26 stsp if (verbosity >= 0)
8401 f8a36e22 2021-08-26 stsp printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
8402 f8a36e22 2021-08-26 stsp port ? ":" : "", port ? port : "");
8403 f8a36e22 2021-08-26 stsp
8404 f8a36e22 2021-08-26 stsp error = got_send_connect(&sendpid, &sendfd, proto, host, port,
8405 f8a36e22 2021-08-26 stsp server_path, verbosity);
8406 f8a36e22 2021-08-26 stsp if (error)
8407 f8a36e22 2021-08-26 stsp goto done;
8408 f8a36e22 2021-08-26 stsp
8409 f8a36e22 2021-08-26 stsp memset(&spa, 0, sizeof(spa));
8410 f8a36e22 2021-08-26 stsp spa.last_scaled_packsize[0] = '\0';
8411 f8a36e22 2021-08-26 stsp spa.last_p_deltify = -1;
8412 f8a36e22 2021-08-26 stsp spa.last_p_written = -1;
8413 f8a36e22 2021-08-26 stsp spa.verbosity = verbosity;
8414 f8a36e22 2021-08-26 stsp spa.delete_branches = &delete_branches;
8415 f8a36e22 2021-08-26 stsp error = got_send_pack(remote_name, &branches, &tags, &delete_branches,
8416 f8a36e22 2021-08-26 stsp verbosity, overwrite_refs, sendfd, repo, send_progress, &spa,
8417 f8a36e22 2021-08-26 stsp check_cancelled, NULL);
8418 f8a36e22 2021-08-26 stsp if (spa.printed_something)
8419 f8a36e22 2021-08-26 stsp putchar('\n');
8420 f8a36e22 2021-08-26 stsp if (error)
8421 f8a36e22 2021-08-26 stsp goto done;
8422 f8a36e22 2021-08-26 stsp if (!spa.sent_something && verbosity >= 0)
8423 f8a36e22 2021-08-26 stsp printf("Already up-to-date\n");
8424 f8a36e22 2021-08-26 stsp done:
8425 f8a36e22 2021-08-26 stsp if (sendpid > 0) {
8426 f8a36e22 2021-08-26 stsp if (kill(sendpid, SIGTERM) == -1)
8427 f8a36e22 2021-08-26 stsp error = got_error_from_errno("kill");
8428 f8a36e22 2021-08-26 stsp if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL)
8429 f8a36e22 2021-08-26 stsp error = got_error_from_errno("waitpid");
8430 f8a36e22 2021-08-26 stsp }
8431 f8a36e22 2021-08-26 stsp if (sendfd != -1 && close(sendfd) == -1 && error == NULL)
8432 f8a36e22 2021-08-26 stsp error = got_error_from_errno("close");
8433 f8a36e22 2021-08-26 stsp if (repo) {
8434 f8a36e22 2021-08-26 stsp const struct got_error *close_err = got_repo_close(repo);
8435 f8a36e22 2021-08-26 stsp if (error == NULL)
8436 f8a36e22 2021-08-26 stsp error = close_err;
8437 f8a36e22 2021-08-26 stsp }
8438 f8a36e22 2021-08-26 stsp if (worktree)
8439 f8a36e22 2021-08-26 stsp got_worktree_close(worktree);
8440 f8a36e22 2021-08-26 stsp if (ref)
8441 f8a36e22 2021-08-26 stsp got_ref_close(ref);
8442 f8a36e22 2021-08-26 stsp got_pathlist_free(&branches);
8443 f8a36e22 2021-08-26 stsp got_pathlist_free(&tags);
8444 f8a36e22 2021-08-26 stsp got_ref_list_free(&all_branches);
8445 f8a36e22 2021-08-26 stsp got_ref_list_free(&all_tags);
8446 f8a36e22 2021-08-26 stsp got_pathlist_free(&delete_args);
8447 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, &delete_branches, entry)
8448 f8a36e22 2021-08-26 stsp free((char *)pe->path);
8449 f8a36e22 2021-08-26 stsp got_pathlist_free(&delete_branches);
8450 f8a36e22 2021-08-26 stsp free(cwd);
8451 f8a36e22 2021-08-26 stsp free(repo_path);
8452 f8a36e22 2021-08-26 stsp free(proto);
8453 f8a36e22 2021-08-26 stsp free(host);
8454 f8a36e22 2021-08-26 stsp free(port);
8455 f8a36e22 2021-08-26 stsp free(server_path);
8456 f8a36e22 2021-08-26 stsp free(repo_name);
8457 234035bc 2019-06-01 stsp return error;
8458 234035bc 2019-06-01 stsp }
8459 234035bc 2019-06-01 stsp
8460 234035bc 2019-06-01 stsp __dead static void
8461 234035bc 2019-06-01 stsp usage_cherrypick(void)
8462 234035bc 2019-06-01 stsp {
8463 234035bc 2019-06-01 stsp fprintf(stderr, "usage: %s cherrypick commit-id\n", getprogname());
8464 234035bc 2019-06-01 stsp exit(1);
8465 234035bc 2019-06-01 stsp }
8466 234035bc 2019-06-01 stsp
8467 234035bc 2019-06-01 stsp static const struct got_error *
8468 234035bc 2019-06-01 stsp cmd_cherrypick(int argc, char *argv[])
8469 234035bc 2019-06-01 stsp {
8470 234035bc 2019-06-01 stsp const struct got_error *error = NULL;
8471 234035bc 2019-06-01 stsp struct got_worktree *worktree = NULL;
8472 234035bc 2019-06-01 stsp struct got_repository *repo = NULL;
8473 234035bc 2019-06-01 stsp char *cwd = NULL, *commit_id_str = NULL;
8474 234035bc 2019-06-01 stsp struct got_object_id *commit_id = NULL;
8475 234035bc 2019-06-01 stsp struct got_commit_object *commit = NULL;
8476 234035bc 2019-06-01 stsp struct got_object_qid *pid;
8477 9627c110 2020-04-18 stsp int ch;
8478 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8479 234035bc 2019-06-01 stsp
8480 234035bc 2019-06-01 stsp while ((ch = getopt(argc, argv, "")) != -1) {
8481 234035bc 2019-06-01 stsp switch (ch) {
8482 234035bc 2019-06-01 stsp default:
8483 234035bc 2019-06-01 stsp usage_cherrypick();
8484 234035bc 2019-06-01 stsp /* NOTREACHED */
8485 234035bc 2019-06-01 stsp }
8486 234035bc 2019-06-01 stsp }
8487 234035bc 2019-06-01 stsp
8488 234035bc 2019-06-01 stsp argc -= optind;
8489 234035bc 2019-06-01 stsp argv += optind;
8490 234035bc 2019-06-01 stsp
8491 43012d58 2019-07-14 stsp #ifndef PROFILE
8492 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8493 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
8494 43012d58 2019-07-14 stsp err(1, "pledge");
8495 43012d58 2019-07-14 stsp #endif
8496 234035bc 2019-06-01 stsp if (argc != 1)
8497 234035bc 2019-06-01 stsp usage_cherrypick();
8498 234035bc 2019-06-01 stsp
8499 234035bc 2019-06-01 stsp cwd = getcwd(NULL, 0);
8500 234035bc 2019-06-01 stsp if (cwd == NULL) {
8501 234035bc 2019-06-01 stsp error = got_error_from_errno("getcwd");
8502 234035bc 2019-06-01 stsp goto done;
8503 234035bc 2019-06-01 stsp }
8504 234035bc 2019-06-01 stsp error = got_worktree_open(&worktree, cwd);
8505 fa51e947 2020-03-27 stsp if (error) {
8506 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8507 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "cherrypick",
8508 fa51e947 2020-03-27 stsp cwd);
8509 234035bc 2019-06-01 stsp goto done;
8510 fa51e947 2020-03-27 stsp }
8511 234035bc 2019-06-01 stsp
8512 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8513 c9956ddf 2019-09-08 stsp NULL);
8514 234035bc 2019-06-01 stsp if (error != NULL)
8515 234035bc 2019-06-01 stsp goto done;
8516 234035bc 2019-06-01 stsp
8517 234035bc 2019-06-01 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8518 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
8519 234035bc 2019-06-01 stsp if (error)
8520 234035bc 2019-06-01 stsp goto done;
8521 234035bc 2019-06-01 stsp
8522 39479dae 2022-03-10 naddy error = got_repo_match_object_id(&commit_id, NULL, argv[0],
8523 39479dae 2022-03-10 naddy GOT_OBJ_TYPE_COMMIT, NULL, repo);
8524 39479dae 2022-03-10 naddy if (error)
8525 39479dae 2022-03-10 naddy goto done;
8526 234035bc 2019-06-01 stsp error = got_object_id_str(&commit_id_str, commit_id);
8527 234035bc 2019-06-01 stsp if (error)
8528 234035bc 2019-06-01 stsp goto done;
8529 234035bc 2019-06-01 stsp
8530 234035bc 2019-06-01 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8531 234035bc 2019-06-01 stsp if (error)
8532 234035bc 2019-06-01 stsp goto done;
8533 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8534 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8535 d7b5a0e8 2022-04-20 stsp error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL,
8536 9627c110 2020-04-18 stsp commit_id, repo, update_progress, &upa, check_cancelled,
8537 03415a1a 2019-06-02 stsp NULL);
8538 234035bc 2019-06-01 stsp if (error != NULL)
8539 234035bc 2019-06-01 stsp goto done;
8540 234035bc 2019-06-01 stsp
8541 9627c110 2020-04-18 stsp if (upa.did_something)
8542 a7648d7a 2019-06-02 stsp printf("Merged commit %s\n", commit_id_str);
8543 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
8544 234035bc 2019-06-01 stsp done:
8545 234035bc 2019-06-01 stsp if (commit)
8546 234035bc 2019-06-01 stsp got_object_commit_close(commit);
8547 234035bc 2019-06-01 stsp free(commit_id_str);
8548 234035bc 2019-06-01 stsp if (worktree)
8549 234035bc 2019-06-01 stsp got_worktree_close(worktree);
8550 1d0f4054 2021-06-17 stsp if (repo) {
8551 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
8552 1d0f4054 2021-06-17 stsp if (error == NULL)
8553 1d0f4054 2021-06-17 stsp error = close_err;
8554 1d0f4054 2021-06-17 stsp }
8555 c4296144 2019-05-09 stsp return error;
8556 c4296144 2019-05-09 stsp }
8557 5ef14e63 2019-06-02 stsp
8558 5ef14e63 2019-06-02 stsp __dead static void
8559 5ef14e63 2019-06-02 stsp usage_backout(void)
8560 5ef14e63 2019-06-02 stsp {
8561 5ef14e63 2019-06-02 stsp fprintf(stderr, "usage: %s backout commit-id\n", getprogname());
8562 5ef14e63 2019-06-02 stsp exit(1);
8563 5ef14e63 2019-06-02 stsp }
8564 5ef14e63 2019-06-02 stsp
8565 5ef14e63 2019-06-02 stsp static const struct got_error *
8566 5ef14e63 2019-06-02 stsp cmd_backout(int argc, char *argv[])
8567 5ef14e63 2019-06-02 stsp {
8568 5ef14e63 2019-06-02 stsp const struct got_error *error = NULL;
8569 5ef14e63 2019-06-02 stsp struct got_worktree *worktree = NULL;
8570 5ef14e63 2019-06-02 stsp struct got_repository *repo = NULL;
8571 5ef14e63 2019-06-02 stsp char *cwd = NULL, *commit_id_str = NULL;
8572 5ef14e63 2019-06-02 stsp struct got_object_id *commit_id = NULL;
8573 5ef14e63 2019-06-02 stsp struct got_commit_object *commit = NULL;
8574 5ef14e63 2019-06-02 stsp struct got_object_qid *pid;
8575 9627c110 2020-04-18 stsp int ch;
8576 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8577 5ef14e63 2019-06-02 stsp
8578 5ef14e63 2019-06-02 stsp while ((ch = getopt(argc, argv, "")) != -1) {
8579 5ef14e63 2019-06-02 stsp switch (ch) {
8580 5ef14e63 2019-06-02 stsp default:
8581 5ef14e63 2019-06-02 stsp usage_backout();
8582 5ef14e63 2019-06-02 stsp /* NOTREACHED */
8583 5ef14e63 2019-06-02 stsp }
8584 5ef14e63 2019-06-02 stsp }
8585 5ef14e63 2019-06-02 stsp
8586 5ef14e63 2019-06-02 stsp argc -= optind;
8587 5ef14e63 2019-06-02 stsp argv += optind;
8588 5ef14e63 2019-06-02 stsp
8589 43012d58 2019-07-14 stsp #ifndef PROFILE
8590 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8591 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
8592 43012d58 2019-07-14 stsp err(1, "pledge");
8593 43012d58 2019-07-14 stsp #endif
8594 5ef14e63 2019-06-02 stsp if (argc != 1)
8595 5ef14e63 2019-06-02 stsp usage_backout();
8596 5ef14e63 2019-06-02 stsp
8597 5ef14e63 2019-06-02 stsp cwd = getcwd(NULL, 0);
8598 5ef14e63 2019-06-02 stsp if (cwd == NULL) {
8599 5ef14e63 2019-06-02 stsp error = got_error_from_errno("getcwd");
8600 5ef14e63 2019-06-02 stsp goto done;
8601 5ef14e63 2019-06-02 stsp }
8602 5ef14e63 2019-06-02 stsp error = got_worktree_open(&worktree, cwd);
8603 fa51e947 2020-03-27 stsp if (error) {
8604 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8605 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "backout", cwd);
8606 5ef14e63 2019-06-02 stsp goto done;
8607 fa51e947 2020-03-27 stsp }
8608 5ef14e63 2019-06-02 stsp
8609 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8610 c9956ddf 2019-09-08 stsp NULL);
8611 5ef14e63 2019-06-02 stsp if (error != NULL)
8612 5ef14e63 2019-06-02 stsp goto done;
8613 5ef14e63 2019-06-02 stsp
8614 5ef14e63 2019-06-02 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8615 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
8616 5ef14e63 2019-06-02 stsp if (error)
8617 5ef14e63 2019-06-02 stsp goto done;
8618 5ef14e63 2019-06-02 stsp
8619 39479dae 2022-03-10 naddy error = got_repo_match_object_id(&commit_id, NULL, argv[0],
8620 39479dae 2022-03-10 naddy GOT_OBJ_TYPE_COMMIT, NULL, repo);
8621 39479dae 2022-03-10 naddy if (error)
8622 39479dae 2022-03-10 naddy goto done;
8623 5ef14e63 2019-06-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
8624 5ef14e63 2019-06-02 stsp if (error)
8625 5ef14e63 2019-06-02 stsp goto done;
8626 5ef14e63 2019-06-02 stsp
8627 5ef14e63 2019-06-02 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8628 5ef14e63 2019-06-02 stsp if (error)
8629 5ef14e63 2019-06-02 stsp goto done;
8630 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8631 5ef14e63 2019-06-02 stsp if (pid == NULL) {
8632 5ef14e63 2019-06-02 stsp error = got_error(GOT_ERR_ROOT_COMMIT);
8633 5ef14e63 2019-06-02 stsp goto done;
8634 5ef14e63 2019-06-02 stsp }
8635 5ef14e63 2019-06-02 stsp
8636 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8637 d7b5a0e8 2022-04-20 stsp error = got_worktree_merge_files(worktree, commit_id, &pid->id,
8638 f259c4c1 2021-09-24 stsp repo, update_progress, &upa, check_cancelled, NULL);
8639 5ef14e63 2019-06-02 stsp if (error != NULL)
8640 5ef14e63 2019-06-02 stsp goto done;
8641 5ef14e63 2019-06-02 stsp
8642 9627c110 2020-04-18 stsp if (upa.did_something)
8643 a7648d7a 2019-06-02 stsp printf("Backed out commit %s\n", commit_id_str);
8644 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
8645 5ef14e63 2019-06-02 stsp done:
8646 5ef14e63 2019-06-02 stsp if (commit)
8647 5ef14e63 2019-06-02 stsp got_object_commit_close(commit);
8648 5ef14e63 2019-06-02 stsp free(commit_id_str);
8649 818c7501 2019-07-11 stsp if (worktree)
8650 818c7501 2019-07-11 stsp got_worktree_close(worktree);
8651 1d0f4054 2021-06-17 stsp if (repo) {
8652 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
8653 1d0f4054 2021-06-17 stsp if (error == NULL)
8654 1d0f4054 2021-06-17 stsp error = close_err;
8655 1d0f4054 2021-06-17 stsp }
8656 818c7501 2019-07-11 stsp return error;
8657 818c7501 2019-07-11 stsp }
8658 818c7501 2019-07-11 stsp
8659 818c7501 2019-07-11 stsp __dead static void
8660 818c7501 2019-07-11 stsp usage_rebase(void)
8661 818c7501 2019-07-11 stsp {
8662 643b85bc 2021-07-16 stsp fprintf(stderr, "usage: %s rebase [-a] [-c] [-l] [-X] [branch]\n",
8663 af54c8f8 2019-07-11 stsp getprogname());
8664 818c7501 2019-07-11 stsp exit(1);
8665 0ebf8283 2019-07-24 stsp }
8666 0ebf8283 2019-07-24 stsp
8667 0ebf8283 2019-07-24 stsp void
8668 0ebf8283 2019-07-24 stsp trim_logmsg(char *logmsg, int limit)
8669 0ebf8283 2019-07-24 stsp {
8670 0ebf8283 2019-07-24 stsp char *nl;
8671 0ebf8283 2019-07-24 stsp size_t len;
8672 0ebf8283 2019-07-24 stsp
8673 0ebf8283 2019-07-24 stsp len = strlen(logmsg);
8674 0ebf8283 2019-07-24 stsp if (len > limit)
8675 0ebf8283 2019-07-24 stsp len = limit;
8676 0ebf8283 2019-07-24 stsp logmsg[len] = '\0';
8677 0ebf8283 2019-07-24 stsp nl = strchr(logmsg, '\n');
8678 0ebf8283 2019-07-24 stsp if (nl)
8679 0ebf8283 2019-07-24 stsp *nl = '\0';
8680 0ebf8283 2019-07-24 stsp }
8681 0ebf8283 2019-07-24 stsp
8682 0ebf8283 2019-07-24 stsp static const struct got_error *
8683 0ebf8283 2019-07-24 stsp get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
8684 0ebf8283 2019-07-24 stsp {
8685 5943eee2 2019-08-13 stsp const struct got_error *err;
8686 5943eee2 2019-08-13 stsp char *logmsg0 = NULL;
8687 5943eee2 2019-08-13 stsp const char *s;
8688 0ebf8283 2019-07-24 stsp
8689 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
8690 5943eee2 2019-08-13 stsp if (err)
8691 5943eee2 2019-08-13 stsp return err;
8692 0ebf8283 2019-07-24 stsp
8693 5943eee2 2019-08-13 stsp s = logmsg0;
8694 5943eee2 2019-08-13 stsp while (isspace((unsigned char)s[0]))
8695 5943eee2 2019-08-13 stsp s++;
8696 5943eee2 2019-08-13 stsp
8697 5943eee2 2019-08-13 stsp *logmsg = strdup(s);
8698 5943eee2 2019-08-13 stsp if (*logmsg == NULL) {
8699 5943eee2 2019-08-13 stsp err = got_error_from_errno("strdup");
8700 5943eee2 2019-08-13 stsp goto done;
8701 5943eee2 2019-08-13 stsp }
8702 0ebf8283 2019-07-24 stsp
8703 0ebf8283 2019-07-24 stsp trim_logmsg(*logmsg, limit);
8704 5943eee2 2019-08-13 stsp done:
8705 5943eee2 2019-08-13 stsp free(logmsg0);
8706 a0ea4fc0 2020-02-28 stsp return err;
8707 a0ea4fc0 2020-02-28 stsp }
8708 a0ea4fc0 2020-02-28 stsp
8709 a0ea4fc0 2020-02-28 stsp static const struct got_error *
8710 c0df5966 2021-12-31 stsp show_rebase_merge_conflict(struct got_object_id *id,
8711 c0df5966 2021-12-31 stsp struct got_repository *repo)
8712 a0ea4fc0 2020-02-28 stsp {
8713 a0ea4fc0 2020-02-28 stsp const struct got_error *err;
8714 a0ea4fc0 2020-02-28 stsp struct got_commit_object *commit = NULL;
8715 a0ea4fc0 2020-02-28 stsp char *id_str = NULL, *logmsg = NULL;
8716 a0ea4fc0 2020-02-28 stsp
8717 a0ea4fc0 2020-02-28 stsp err = got_object_open_as_commit(&commit, repo, id);
8718 a0ea4fc0 2020-02-28 stsp if (err)
8719 a0ea4fc0 2020-02-28 stsp return err;
8720 a0ea4fc0 2020-02-28 stsp
8721 a0ea4fc0 2020-02-28 stsp err = got_object_id_str(&id_str, id);
8722 a0ea4fc0 2020-02-28 stsp if (err)
8723 a0ea4fc0 2020-02-28 stsp goto done;
8724 a0ea4fc0 2020-02-28 stsp
8725 a0ea4fc0 2020-02-28 stsp id_str[12] = '\0';
8726 a0ea4fc0 2020-02-28 stsp
8727 a0ea4fc0 2020-02-28 stsp err = get_short_logmsg(&logmsg, 42, commit);
8728 a0ea4fc0 2020-02-28 stsp if (err)
8729 a0ea4fc0 2020-02-28 stsp goto done;
8730 a0ea4fc0 2020-02-28 stsp
8731 a0ea4fc0 2020-02-28 stsp printf("%s -> merge conflict: %s\n", id_str, logmsg);
8732 a0ea4fc0 2020-02-28 stsp done:
8733 a0ea4fc0 2020-02-28 stsp free(id_str);
8734 a0ea4fc0 2020-02-28 stsp got_object_commit_close(commit);
8735 a0ea4fc0 2020-02-28 stsp free(logmsg);
8736 5943eee2 2019-08-13 stsp return err;
8737 818c7501 2019-07-11 stsp }
8738 818c7501 2019-07-11 stsp
8739 818c7501 2019-07-11 stsp static const struct got_error *
8740 818c7501 2019-07-11 stsp show_rebase_progress(struct got_commit_object *commit,
8741 818c7501 2019-07-11 stsp struct got_object_id *old_id, struct got_object_id *new_id)
8742 818c7501 2019-07-11 stsp {
8743 818c7501 2019-07-11 stsp const struct got_error *err;
8744 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
8745 818c7501 2019-07-11 stsp
8746 818c7501 2019-07-11 stsp err = got_object_id_str(&old_id_str, old_id);
8747 818c7501 2019-07-11 stsp if (err)
8748 818c7501 2019-07-11 stsp goto done;
8749 818c7501 2019-07-11 stsp
8750 ff0d2220 2019-07-11 stsp if (new_id) {
8751 ff0d2220 2019-07-11 stsp err = got_object_id_str(&new_id_str, new_id);
8752 ff0d2220 2019-07-11 stsp if (err)
8753 ff0d2220 2019-07-11 stsp goto done;
8754 ff0d2220 2019-07-11 stsp }
8755 818c7501 2019-07-11 stsp
8756 818c7501 2019-07-11 stsp old_id_str[12] = '\0';
8757 ff0d2220 2019-07-11 stsp if (new_id_str)
8758 ff0d2220 2019-07-11 stsp new_id_str[12] = '\0';
8759 0ebf8283 2019-07-24 stsp
8760 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
8761 0ebf8283 2019-07-24 stsp if (err)
8762 0ebf8283 2019-07-24 stsp goto done;
8763 0ebf8283 2019-07-24 stsp
8764 ff0d2220 2019-07-11 stsp printf("%s -> %s: %s\n", old_id_str,
8765 ff0d2220 2019-07-11 stsp new_id_str ? new_id_str : "no-op change", logmsg);
8766 818c7501 2019-07-11 stsp done:
8767 818c7501 2019-07-11 stsp free(old_id_str);
8768 818c7501 2019-07-11 stsp free(new_id_str);
8769 272a1371 2020-02-28 stsp free(logmsg);
8770 818c7501 2019-07-11 stsp return err;
8771 818c7501 2019-07-11 stsp }
8772 818c7501 2019-07-11 stsp
8773 1ee397ad 2019-07-12 stsp static const struct got_error *
8774 3e3a69f1 2019-07-25 stsp rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
8775 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_reference *new_base_branch,
8776 e600f124 2021-03-21 stsp struct got_reference *tmp_branch, struct got_repository *repo,
8777 e600f124 2021-03-21 stsp int create_backup)
8778 818c7501 2019-07-11 stsp {
8779 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n", got_ref_get_name(branch));
8780 3e3a69f1 2019-07-25 stsp return got_worktree_rebase_complete(worktree, fileindex,
8781 e600f124 2021-03-21 stsp new_base_branch, tmp_branch, branch, repo, create_backup);
8782 818c7501 2019-07-11 stsp }
8783 818c7501 2019-07-11 stsp
8784 818c7501 2019-07-11 stsp static const struct got_error *
8785 01757395 2019-07-12 stsp rebase_commit(struct got_pathlist_head *merged_paths,
8786 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
8787 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch,
8788 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id, struct got_repository *repo)
8789 ff0d2220 2019-07-11 stsp {
8790 ff0d2220 2019-07-11 stsp const struct got_error *error;
8791 ff0d2220 2019-07-11 stsp struct got_commit_object *commit;
8792 ff0d2220 2019-07-11 stsp struct got_object_id *new_commit_id;
8793 ff0d2220 2019-07-11 stsp
8794 ff0d2220 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8795 ff0d2220 2019-07-11 stsp if (error)
8796 ff0d2220 2019-07-11 stsp return error;
8797 ff0d2220 2019-07-11 stsp
8798 01757395 2019-07-12 stsp error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
8799 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, commit_id, repo);
8800 ff0d2220 2019-07-11 stsp if (error) {
8801 ff0d2220 2019-07-11 stsp if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
8802 ff0d2220 2019-07-11 stsp goto done;
8803 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, NULL);
8804 ff0d2220 2019-07-11 stsp } else {
8805 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, new_commit_id);
8806 ff0d2220 2019-07-11 stsp free(new_commit_id);
8807 ff0d2220 2019-07-11 stsp }
8808 ff0d2220 2019-07-11 stsp done:
8809 ff0d2220 2019-07-11 stsp got_object_commit_close(commit);
8810 ff0d2220 2019-07-11 stsp return error;
8811 64c6d990 2019-07-11 stsp }
8812 64c6d990 2019-07-11 stsp
8813 64c6d990 2019-07-11 stsp struct check_path_prefix_arg {
8814 64c6d990 2019-07-11 stsp const char *path_prefix;
8815 64c6d990 2019-07-11 stsp size_t len;
8816 8ca9bd68 2019-07-25 stsp int errcode;
8817 64c6d990 2019-07-11 stsp };
8818 64c6d990 2019-07-11 stsp
8819 64c6d990 2019-07-11 stsp static const struct got_error *
8820 8ca9bd68 2019-07-25 stsp check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
8821 64c6d990 2019-07-11 stsp struct got_blob_object *blob2, struct got_object_id *id1,
8822 64c6d990 2019-07-11 stsp struct got_object_id *id2, const char *path1, const char *path2,
8823 46f68b20 2019-10-19 stsp mode_t mode1, mode_t mode2, struct got_repository *repo)
8824 64c6d990 2019-07-11 stsp {
8825 64c6d990 2019-07-11 stsp struct check_path_prefix_arg *a = arg;
8826 64c6d990 2019-07-11 stsp
8827 64c6d990 2019-07-11 stsp if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
8828 64c6d990 2019-07-11 stsp (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
8829 8ca9bd68 2019-07-25 stsp return got_error(a->errcode);
8830 64c6d990 2019-07-11 stsp
8831 64c6d990 2019-07-11 stsp return NULL;
8832 64c6d990 2019-07-11 stsp }
8833 64c6d990 2019-07-11 stsp
8834 64c6d990 2019-07-11 stsp static const struct got_error *
8835 8ca9bd68 2019-07-25 stsp check_path_prefix(struct got_object_id *parent_id,
8836 64c6d990 2019-07-11 stsp struct got_object_id *commit_id, const char *path_prefix,
8837 8ca9bd68 2019-07-25 stsp int errcode, struct got_repository *repo)
8838 64c6d990 2019-07-11 stsp {
8839 64c6d990 2019-07-11 stsp const struct got_error *err;
8840 64c6d990 2019-07-11 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
8841 64c6d990 2019-07-11 stsp struct got_commit_object *commit = NULL, *parent_commit = NULL;
8842 64c6d990 2019-07-11 stsp struct check_path_prefix_arg cpp_arg;
8843 64c6d990 2019-07-11 stsp
8844 64c6d990 2019-07-11 stsp if (got_path_is_root_dir(path_prefix))
8845 64c6d990 2019-07-11 stsp return NULL;
8846 64c6d990 2019-07-11 stsp
8847 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
8848 64c6d990 2019-07-11 stsp if (err)
8849 64c6d990 2019-07-11 stsp goto done;
8850 64c6d990 2019-07-11 stsp
8851 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&parent_commit, repo, parent_id);
8852 64c6d990 2019-07-11 stsp if (err)
8853 64c6d990 2019-07-11 stsp goto done;
8854 64c6d990 2019-07-11 stsp
8855 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree1, repo,
8856 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(parent_commit));
8857 64c6d990 2019-07-11 stsp if (err)
8858 64c6d990 2019-07-11 stsp goto done;
8859 64c6d990 2019-07-11 stsp
8860 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree2, repo,
8861 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(commit));
8862 64c6d990 2019-07-11 stsp if (err)
8863 64c6d990 2019-07-11 stsp goto done;
8864 64c6d990 2019-07-11 stsp
8865 64c6d990 2019-07-11 stsp cpp_arg.path_prefix = path_prefix;
8866 d23ace97 2019-07-25 stsp while (cpp_arg.path_prefix[0] == '/')
8867 d23ace97 2019-07-25 stsp cpp_arg.path_prefix++;
8868 d23ace97 2019-07-25 stsp cpp_arg.len = strlen(cpp_arg.path_prefix);
8869 8ca9bd68 2019-07-25 stsp cpp_arg.errcode = errcode;
8870 8ca9bd68 2019-07-25 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
8871 31b4484f 2019-07-27 stsp check_path_prefix_in_diff, &cpp_arg, 0);
8872 64c6d990 2019-07-11 stsp done:
8873 64c6d990 2019-07-11 stsp if (tree1)
8874 64c6d990 2019-07-11 stsp got_object_tree_close(tree1);
8875 64c6d990 2019-07-11 stsp if (tree2)
8876 64c6d990 2019-07-11 stsp got_object_tree_close(tree2);
8877 64c6d990 2019-07-11 stsp if (commit)
8878 64c6d990 2019-07-11 stsp got_object_commit_close(commit);
8879 64c6d990 2019-07-11 stsp if (parent_commit)
8880 64c6d990 2019-07-11 stsp got_object_commit_close(parent_commit);
8881 64c6d990 2019-07-11 stsp return err;
8882 ff0d2220 2019-07-11 stsp }
8883 ff0d2220 2019-07-11 stsp
8884 ff0d2220 2019-07-11 stsp static const struct got_error *
8885 8ca9bd68 2019-07-25 stsp collect_commits(struct got_object_id_queue *commits,
8886 af61c510 2019-07-19 stsp struct got_object_id *initial_commit_id,
8887 af61c510 2019-07-19 stsp struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
8888 8ca9bd68 2019-07-25 stsp const char *path_prefix, int path_prefix_errcode,
8889 8ca9bd68 2019-07-25 stsp struct got_repository *repo)
8890 af61c510 2019-07-19 stsp {
8891 af61c510 2019-07-19 stsp const struct got_error *err = NULL;
8892 af61c510 2019-07-19 stsp struct got_commit_graph *graph = NULL;
8893 af61c510 2019-07-19 stsp struct got_object_id *parent_id = NULL;
8894 af61c510 2019-07-19 stsp struct got_object_qid *qid;
8895 af61c510 2019-07-19 stsp struct got_object_id *commit_id = initial_commit_id;
8896 af61c510 2019-07-19 stsp
8897 3d509237 2020-01-04 stsp err = got_commit_graph_open(&graph, "/", 1);
8898 af61c510 2019-07-19 stsp if (err)
8899 af61c510 2019-07-19 stsp return err;
8900 af61c510 2019-07-19 stsp
8901 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, iter_start_id, repo,
8902 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
8903 af61c510 2019-07-19 stsp if (err)
8904 af61c510 2019-07-19 stsp goto done;
8905 af61c510 2019-07-19 stsp while (got_object_id_cmp(commit_id, iter_stop_id) != 0) {
8906 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&parent_id, graph, repo,
8907 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
8908 af61c510 2019-07-19 stsp if (err) {
8909 af61c510 2019-07-19 stsp if (err->code == GOT_ERR_ITER_COMPLETED) {
8910 af61c510 2019-07-19 stsp err = got_error_msg(GOT_ERR_ANCESTRY,
8911 af61c510 2019-07-19 stsp "ran out of commits to rebase before "
8912 af61c510 2019-07-19 stsp "youngest common ancestor commit has "
8913 af61c510 2019-07-19 stsp "been reached?!?");
8914 ee780d5c 2020-01-04 stsp }
8915 ee780d5c 2020-01-04 stsp goto done;
8916 af61c510 2019-07-19 stsp } else {
8917 8ca9bd68 2019-07-25 stsp err = check_path_prefix(parent_id, commit_id,
8918 8ca9bd68 2019-07-25 stsp path_prefix, path_prefix_errcode, repo);
8919 af61c510 2019-07-19 stsp if (err)
8920 af61c510 2019-07-19 stsp goto done;
8921 af61c510 2019-07-19 stsp
8922 af61c510 2019-07-19 stsp err = got_object_qid_alloc(&qid, commit_id);
8923 af61c510 2019-07-19 stsp if (err)
8924 af61c510 2019-07-19 stsp goto done;
8925 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(commits, qid, entry);
8926 af61c510 2019-07-19 stsp commit_id = parent_id;
8927 af61c510 2019-07-19 stsp }
8928 af61c510 2019-07-19 stsp }
8929 af61c510 2019-07-19 stsp done:
8930 af61c510 2019-07-19 stsp got_commit_graph_close(graph);
8931 af61c510 2019-07-19 stsp return err;
8932 e600f124 2021-03-21 stsp }
8933 e600f124 2021-03-21 stsp
8934 e600f124 2021-03-21 stsp static const struct got_error *
8935 e600f124 2021-03-21 stsp get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
8936 e600f124 2021-03-21 stsp {
8937 e600f124 2021-03-21 stsp const struct got_error *err = NULL;
8938 e600f124 2021-03-21 stsp time_t committer_time;
8939 e600f124 2021-03-21 stsp struct tm tm;
8940 e600f124 2021-03-21 stsp char datebuf[11]; /* YYYY-MM-DD + NUL */
8941 e600f124 2021-03-21 stsp char *author0 = NULL, *author, *smallerthan;
8942 e600f124 2021-03-21 stsp char *logmsg0 = NULL, *logmsg, *newline;
8943 e600f124 2021-03-21 stsp
8944 e600f124 2021-03-21 stsp committer_time = got_object_commit_get_committer_time(commit);
8945 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
8946 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
8947 e3199de8 2021-03-21 stsp if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
8948 e600f124 2021-03-21 stsp return got_error(GOT_ERR_NO_SPACE);
8949 e600f124 2021-03-21 stsp
8950 e600f124 2021-03-21 stsp author0 = strdup(got_object_commit_get_author(commit));
8951 e600f124 2021-03-21 stsp if (author0 == NULL)
8952 e600f124 2021-03-21 stsp return got_error_from_errno("strdup");
8953 e600f124 2021-03-21 stsp author = author0;
8954 e600f124 2021-03-21 stsp smallerthan = strchr(author, '<');
8955 e600f124 2021-03-21 stsp if (smallerthan && smallerthan[1] != '\0')
8956 e600f124 2021-03-21 stsp author = smallerthan + 1;
8957 e600f124 2021-03-21 stsp author[strcspn(author, "@>")] = '\0';
8958 e600f124 2021-03-21 stsp
8959 e600f124 2021-03-21 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
8960 e600f124 2021-03-21 stsp if (err)
8961 e600f124 2021-03-21 stsp goto done;
8962 e600f124 2021-03-21 stsp logmsg = logmsg0;
8963 e600f124 2021-03-21 stsp while (*logmsg == '\n')
8964 e600f124 2021-03-21 stsp logmsg++;
8965 e600f124 2021-03-21 stsp newline = strchr(logmsg, '\n');
8966 e600f124 2021-03-21 stsp if (newline)
8967 e600f124 2021-03-21 stsp *newline = '\0';
8968 e600f124 2021-03-21 stsp
8969 e600f124 2021-03-21 stsp if (asprintf(brief_str, "%s %s %s",
8970 e600f124 2021-03-21 stsp datebuf, author, logmsg) == -1)
8971 e600f124 2021-03-21 stsp err = got_error_from_errno("asprintf");
8972 e600f124 2021-03-21 stsp done:
8973 e600f124 2021-03-21 stsp free(author0);
8974 e600f124 2021-03-21 stsp free(logmsg0);
8975 643b85bc 2021-07-16 stsp return err;
8976 643b85bc 2021-07-16 stsp }
8977 643b85bc 2021-07-16 stsp
8978 643b85bc 2021-07-16 stsp static const struct got_error *
8979 643b85bc 2021-07-16 stsp delete_backup_ref(struct got_reference *ref, struct got_object_id *id,
8980 643b85bc 2021-07-16 stsp struct got_repository *repo)
8981 643b85bc 2021-07-16 stsp {
8982 643b85bc 2021-07-16 stsp const struct got_error *err;
8983 643b85bc 2021-07-16 stsp char *id_str;
8984 643b85bc 2021-07-16 stsp
8985 643b85bc 2021-07-16 stsp err = got_object_id_str(&id_str, id);
8986 643b85bc 2021-07-16 stsp if (err)
8987 643b85bc 2021-07-16 stsp return err;
8988 643b85bc 2021-07-16 stsp
8989 643b85bc 2021-07-16 stsp err = got_ref_delete(ref, repo);
8990 643b85bc 2021-07-16 stsp if (err)
8991 643b85bc 2021-07-16 stsp goto done;
8992 643b85bc 2021-07-16 stsp
8993 643b85bc 2021-07-16 stsp printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str);
8994 643b85bc 2021-07-16 stsp done:
8995 643b85bc 2021-07-16 stsp free(id_str);
8996 e600f124 2021-03-21 stsp return err;
8997 e600f124 2021-03-21 stsp }
8998 e600f124 2021-03-21 stsp
8999 e600f124 2021-03-21 stsp static const struct got_error *
9000 e600f124 2021-03-21 stsp print_backup_ref(const char *branch_name, const char *new_id_str,
9001 e600f124 2021-03-21 stsp struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
9002 e600f124 2021-03-21 stsp struct got_reflist_object_id_map *refs_idmap,
9003 e600f124 2021-03-21 stsp struct got_repository *repo)
9004 e600f124 2021-03-21 stsp {
9005 e600f124 2021-03-21 stsp const struct got_error *err = NULL;
9006 e600f124 2021-03-21 stsp struct got_reflist_head *refs;
9007 e600f124 2021-03-21 stsp char *refs_str = NULL;
9008 e600f124 2021-03-21 stsp struct got_object_id *new_commit_id = NULL;
9009 e600f124 2021-03-21 stsp struct got_commit_object *new_commit = NULL;
9010 e600f124 2021-03-21 stsp char *new_commit_brief_str = NULL;
9011 e600f124 2021-03-21 stsp struct got_object_id *yca_id = NULL;
9012 e600f124 2021-03-21 stsp struct got_commit_object *yca_commit = NULL;
9013 e600f124 2021-03-21 stsp char *yca_id_str = NULL, *yca_brief_str = NULL;
9014 e600f124 2021-03-21 stsp char *custom_refs_str;
9015 e600f124 2021-03-21 stsp
9016 e600f124 2021-03-21 stsp if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
9017 e600f124 2021-03-21 stsp return got_error_from_errno("asprintf");
9018 e600f124 2021-03-21 stsp
9019 e600f124 2021-03-21 stsp err = print_commit(old_commit, old_commit_id, repo, NULL, NULL,
9020 e600f124 2021-03-21 stsp 0, 0, refs_idmap, custom_refs_str);
9021 e600f124 2021-03-21 stsp if (err)
9022 e600f124 2021-03-21 stsp goto done;
9023 e600f124 2021-03-21 stsp
9024 e600f124 2021-03-21 stsp err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
9025 e600f124 2021-03-21 stsp if (err)
9026 e600f124 2021-03-21 stsp goto done;
9027 e600f124 2021-03-21 stsp
9028 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
9029 e600f124 2021-03-21 stsp if (refs) {
9030 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, new_commit_id, repo);
9031 e600f124 2021-03-21 stsp if (err)
9032 e600f124 2021-03-21 stsp goto done;
9033 e600f124 2021-03-21 stsp }
9034 e600f124 2021-03-21 stsp
9035 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
9036 e600f124 2021-03-21 stsp if (err)
9037 e600f124 2021-03-21 stsp goto done;
9038 e600f124 2021-03-21 stsp
9039 e600f124 2021-03-21 stsp err = get_commit_brief_str(&new_commit_brief_str, new_commit);
9040 e600f124 2021-03-21 stsp if (err)
9041 e600f124 2021-03-21 stsp goto done;
9042 e600f124 2021-03-21 stsp
9043 e600f124 2021-03-21 stsp err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
9044 4e91ef15 2021-09-26 stsp old_commit_id, new_commit_id, 1, repo, check_cancelled, NULL);
9045 e600f124 2021-03-21 stsp if (err)
9046 e600f124 2021-03-21 stsp goto done;
9047 e600f124 2021-03-21 stsp
9048 e600f124 2021-03-21 stsp printf("has become commit %s%s%s%s\n %s\n", new_id_str,
9049 e600f124 2021-03-21 stsp refs_str ? " (" : "", refs_str ? refs_str : "",
9050 e600f124 2021-03-21 stsp refs_str ? ")" : "", new_commit_brief_str);
9051 e600f124 2021-03-21 stsp if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
9052 e600f124 2021-03-21 stsp got_object_id_cmp(yca_id, old_commit_id) != 0) {
9053 e600f124 2021-03-21 stsp free(refs_str);
9054 e600f124 2021-03-21 stsp refs_str = NULL;
9055 e600f124 2021-03-21 stsp
9056 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&yca_commit, repo, yca_id);
9057 e600f124 2021-03-21 stsp if (err)
9058 e600f124 2021-03-21 stsp goto done;
9059 e600f124 2021-03-21 stsp
9060 e600f124 2021-03-21 stsp err = get_commit_brief_str(&yca_brief_str, yca_commit);
9061 e600f124 2021-03-21 stsp if (err)
9062 e600f124 2021-03-21 stsp goto done;
9063 e600f124 2021-03-21 stsp
9064 e600f124 2021-03-21 stsp err = got_object_id_str(&yca_id_str, yca_id);
9065 e600f124 2021-03-21 stsp if (err)
9066 e600f124 2021-03-21 stsp goto done;
9067 e600f124 2021-03-21 stsp
9068 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
9069 e600f124 2021-03-21 stsp if (refs) {
9070 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, yca_id, repo);
9071 e600f124 2021-03-21 stsp if (err)
9072 e600f124 2021-03-21 stsp goto done;
9073 e600f124 2021-03-21 stsp }
9074 e600f124 2021-03-21 stsp printf("history forked at %s%s%s%s\n %s\n",
9075 e600f124 2021-03-21 stsp yca_id_str,
9076 e600f124 2021-03-21 stsp refs_str ? " (" : "", refs_str ? refs_str : "",
9077 e600f124 2021-03-21 stsp refs_str ? ")" : "", yca_brief_str);
9078 e600f124 2021-03-21 stsp }
9079 e600f124 2021-03-21 stsp done:
9080 e600f124 2021-03-21 stsp free(custom_refs_str);
9081 e600f124 2021-03-21 stsp free(new_commit_id);
9082 e600f124 2021-03-21 stsp free(refs_str);
9083 e600f124 2021-03-21 stsp free(yca_id);
9084 e600f124 2021-03-21 stsp free(yca_id_str);
9085 e600f124 2021-03-21 stsp free(yca_brief_str);
9086 e600f124 2021-03-21 stsp if (new_commit)
9087 e600f124 2021-03-21 stsp got_object_commit_close(new_commit);
9088 e600f124 2021-03-21 stsp if (yca_commit)
9089 e600f124 2021-03-21 stsp got_object_commit_close(yca_commit);
9090 e600f124 2021-03-21 stsp
9091 e600f124 2021-03-21 stsp return NULL;
9092 af61c510 2019-07-19 stsp }
9093 af61c510 2019-07-19 stsp
9094 af61c510 2019-07-19 stsp static const struct got_error *
9095 c0df5966 2021-12-31 stsp process_backup_refs(const char *backup_ref_prefix,
9096 c0df5966 2021-12-31 stsp const char *wanted_branch_name,
9097 643b85bc 2021-07-16 stsp int delete, struct got_repository *repo)
9098 e600f124 2021-03-21 stsp {
9099 e600f124 2021-03-21 stsp const struct got_error *err;
9100 e600f124 2021-03-21 stsp struct got_reflist_head refs, backup_refs;
9101 e600f124 2021-03-21 stsp struct got_reflist_entry *re;
9102 e600f124 2021-03-21 stsp const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
9103 e600f124 2021-03-21 stsp struct got_object_id *old_commit_id = NULL;
9104 e600f124 2021-03-21 stsp char *branch_name = NULL;
9105 e600f124 2021-03-21 stsp struct got_commit_object *old_commit = NULL;
9106 e600f124 2021-03-21 stsp struct got_reflist_object_id_map *refs_idmap = NULL;
9107 9e822917 2021-03-23 stsp int wanted_branch_found = 0;
9108 e600f124 2021-03-21 stsp
9109 e600f124 2021-03-21 stsp TAILQ_INIT(&refs);
9110 e600f124 2021-03-21 stsp TAILQ_INIT(&backup_refs);
9111 e600f124 2021-03-21 stsp
9112 e600f124 2021-03-21 stsp err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
9113 e600f124 2021-03-21 stsp if (err)
9114 e600f124 2021-03-21 stsp return err;
9115 e600f124 2021-03-21 stsp
9116 e600f124 2021-03-21 stsp err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
9117 e600f124 2021-03-21 stsp if (err)
9118 e600f124 2021-03-21 stsp goto done;
9119 e600f124 2021-03-21 stsp
9120 e600f124 2021-03-21 stsp if (wanted_branch_name) {
9121 e600f124 2021-03-21 stsp if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
9122 e600f124 2021-03-21 stsp wanted_branch_name += 11;
9123 e600f124 2021-03-21 stsp }
9124 e600f124 2021-03-21 stsp
9125 e600f124 2021-03-21 stsp err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
9126 e600f124 2021-03-21 stsp got_ref_cmp_by_commit_timestamp_descending, repo);
9127 e600f124 2021-03-21 stsp if (err)
9128 e600f124 2021-03-21 stsp goto done;
9129 e600f124 2021-03-21 stsp
9130 e600f124 2021-03-21 stsp TAILQ_FOREACH(re, &backup_refs, entry) {
9131 e600f124 2021-03-21 stsp const char *refname = got_ref_get_name(re->ref);
9132 e600f124 2021-03-21 stsp char *slash;
9133 e600f124 2021-03-21 stsp
9134 643b85bc 2021-07-16 stsp err = check_cancelled(NULL);
9135 643b85bc 2021-07-16 stsp if (err)
9136 643b85bc 2021-07-16 stsp break;
9137 643b85bc 2021-07-16 stsp
9138 e600f124 2021-03-21 stsp err = got_ref_resolve(&old_commit_id, repo, re->ref);
9139 e600f124 2021-03-21 stsp if (err)
9140 e600f124 2021-03-21 stsp break;
9141 e600f124 2021-03-21 stsp
9142 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&old_commit, repo,
9143 e600f124 2021-03-21 stsp old_commit_id);
9144 e600f124 2021-03-21 stsp if (err)
9145 e600f124 2021-03-21 stsp break;
9146 e600f124 2021-03-21 stsp
9147 e600f124 2021-03-21 stsp if (strncmp(backup_ref_prefix, refname,
9148 e600f124 2021-03-21 stsp backup_ref_prefix_len) == 0)
9149 e600f124 2021-03-21 stsp refname += backup_ref_prefix_len;
9150 e600f124 2021-03-21 stsp
9151 e600f124 2021-03-21 stsp while (refname[0] == '/')
9152 e600f124 2021-03-21 stsp refname++;
9153 e600f124 2021-03-21 stsp
9154 e600f124 2021-03-21 stsp branch_name = strdup(refname);
9155 e600f124 2021-03-21 stsp if (branch_name == NULL) {
9156 e600f124 2021-03-21 stsp err = got_error_from_errno("strdup");
9157 e600f124 2021-03-21 stsp break;
9158 e600f124 2021-03-21 stsp }
9159 e600f124 2021-03-21 stsp slash = strrchr(branch_name, '/');
9160 e600f124 2021-03-21 stsp if (slash) {
9161 e600f124 2021-03-21 stsp *slash = '\0';
9162 e600f124 2021-03-21 stsp refname += strlen(branch_name) + 1;
9163 e600f124 2021-03-21 stsp }
9164 e600f124 2021-03-21 stsp
9165 e600f124 2021-03-21 stsp if (wanted_branch_name == NULL ||
9166 e600f124 2021-03-21 stsp strcmp(wanted_branch_name, branch_name) == 0) {
9167 9e822917 2021-03-23 stsp wanted_branch_found = 1;
9168 643b85bc 2021-07-16 stsp if (delete) {
9169 643b85bc 2021-07-16 stsp err = delete_backup_ref(re->ref,
9170 643b85bc 2021-07-16 stsp old_commit_id, repo);
9171 643b85bc 2021-07-16 stsp } else {
9172 643b85bc 2021-07-16 stsp err = print_backup_ref(branch_name, refname,
9173 abc59930 2021-09-05 naddy old_commit_id, old_commit, refs_idmap,
9174 abc59930 2021-09-05 naddy repo);
9175 643b85bc 2021-07-16 stsp }
9176 e600f124 2021-03-21 stsp if (err)
9177 e600f124 2021-03-21 stsp break;
9178 e600f124 2021-03-21 stsp }
9179 e600f124 2021-03-21 stsp
9180 e600f124 2021-03-21 stsp free(old_commit_id);
9181 e600f124 2021-03-21 stsp old_commit_id = NULL;
9182 e600f124 2021-03-21 stsp free(branch_name);
9183 e600f124 2021-03-21 stsp branch_name = NULL;
9184 e600f124 2021-03-21 stsp got_object_commit_close(old_commit);
9185 e600f124 2021-03-21 stsp old_commit = NULL;
9186 e600f124 2021-03-21 stsp }
9187 9e822917 2021-03-23 stsp
9188 9e822917 2021-03-23 stsp if (wanted_branch_name && !wanted_branch_found) {
9189 9e822917 2021-03-23 stsp err = got_error_fmt(GOT_ERR_NOT_REF,
9190 9e822917 2021-03-23 stsp "%s/%s/", backup_ref_prefix, wanted_branch_name);
9191 9e822917 2021-03-23 stsp }
9192 e600f124 2021-03-21 stsp done:
9193 e600f124 2021-03-21 stsp if (refs_idmap)
9194 e600f124 2021-03-21 stsp got_reflist_object_id_map_free(refs_idmap);
9195 e600f124 2021-03-21 stsp got_ref_list_free(&refs);
9196 e600f124 2021-03-21 stsp got_ref_list_free(&backup_refs);
9197 e600f124 2021-03-21 stsp free(old_commit_id);
9198 e600f124 2021-03-21 stsp free(branch_name);
9199 e600f124 2021-03-21 stsp if (old_commit)
9200 e600f124 2021-03-21 stsp got_object_commit_close(old_commit);
9201 e600f124 2021-03-21 stsp return err;
9202 e600f124 2021-03-21 stsp }
9203 e600f124 2021-03-21 stsp
9204 e600f124 2021-03-21 stsp static const struct got_error *
9205 41f061b2 2021-10-05 stsp abort_progress(void *arg, unsigned char status, const char *path)
9206 41f061b2 2021-10-05 stsp {
9207 41f061b2 2021-10-05 stsp /*
9208 41f061b2 2021-10-05 stsp * Unversioned files should not clutter progress output when
9209 41f061b2 2021-10-05 stsp * an operation is aborted.
9210 41f061b2 2021-10-05 stsp */
9211 41f061b2 2021-10-05 stsp if (status == GOT_STATUS_UNVERSIONED)
9212 41f061b2 2021-10-05 stsp return NULL;
9213 41f061b2 2021-10-05 stsp
9214 41f061b2 2021-10-05 stsp return update_progress(arg, status, path);
9215 41f061b2 2021-10-05 stsp }
9216 41f061b2 2021-10-05 stsp
9217 41f061b2 2021-10-05 stsp static const struct got_error *
9218 818c7501 2019-07-11 stsp cmd_rebase(int argc, char *argv[])
9219 818c7501 2019-07-11 stsp {
9220 818c7501 2019-07-11 stsp const struct got_error *error = NULL;
9221 818c7501 2019-07-11 stsp struct got_worktree *worktree = NULL;
9222 818c7501 2019-07-11 stsp struct got_repository *repo = NULL;
9223 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
9224 818c7501 2019-07-11 stsp char *cwd = NULL;
9225 818c7501 2019-07-11 stsp struct got_reference *branch = NULL;
9226 818c7501 2019-07-11 stsp struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
9227 818c7501 2019-07-11 stsp struct got_object_id *commit_id = NULL, *parent_id = NULL;
9228 818c7501 2019-07-11 stsp struct got_object_id *resume_commit_id = NULL;
9229 818c7501 2019-07-11 stsp struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
9230 818c7501 2019-07-11 stsp struct got_commit_object *commit = NULL;
9231 818c7501 2019-07-11 stsp int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
9232 f259c4c1 2021-09-24 stsp int histedit_in_progress = 0, merge_in_progress = 0;
9233 f259c4c1 2021-09-24 stsp int create_backup = 1, list_backups = 0, delete_backups = 0;
9234 818c7501 2019-07-11 stsp struct got_object_id_queue commits;
9235 01757395 2019-07-12 stsp struct got_pathlist_head merged_paths;
9236 818c7501 2019-07-11 stsp const struct got_object_id_queue *parent_ids;
9237 818c7501 2019-07-11 stsp struct got_object_qid *qid, *pid;
9238 1fa49072 2021-09-28 stsp struct got_update_progress_arg upa;
9239 818c7501 2019-07-11 stsp
9240 dbdddfee 2021-06-23 naddy STAILQ_INIT(&commits);
9241 01757395 2019-07-12 stsp TAILQ_INIT(&merged_paths);
9242 1fa49072 2021-09-28 stsp memset(&upa, 0, sizeof(upa));
9243 818c7501 2019-07-11 stsp
9244 643b85bc 2021-07-16 stsp while ((ch = getopt(argc, argv, "aclX")) != -1) {
9245 818c7501 2019-07-11 stsp switch (ch) {
9246 818c7501 2019-07-11 stsp case 'a':
9247 818c7501 2019-07-11 stsp abort_rebase = 1;
9248 818c7501 2019-07-11 stsp break;
9249 818c7501 2019-07-11 stsp case 'c':
9250 818c7501 2019-07-11 stsp continue_rebase = 1;
9251 818c7501 2019-07-11 stsp break;
9252 e600f124 2021-03-21 stsp case 'l':
9253 e600f124 2021-03-21 stsp list_backups = 1;
9254 e600f124 2021-03-21 stsp break;
9255 643b85bc 2021-07-16 stsp case 'X':
9256 643b85bc 2021-07-16 stsp delete_backups = 1;
9257 643b85bc 2021-07-16 stsp break;
9258 818c7501 2019-07-11 stsp default:
9259 818c7501 2019-07-11 stsp usage_rebase();
9260 818c7501 2019-07-11 stsp /* NOTREACHED */
9261 818c7501 2019-07-11 stsp }
9262 818c7501 2019-07-11 stsp }
9263 818c7501 2019-07-11 stsp
9264 818c7501 2019-07-11 stsp argc -= optind;
9265 818c7501 2019-07-11 stsp argv += optind;
9266 818c7501 2019-07-11 stsp
9267 43012d58 2019-07-14 stsp #ifndef PROFILE
9268 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9269 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
9270 43012d58 2019-07-14 stsp err(1, "pledge");
9271 43012d58 2019-07-14 stsp #endif
9272 e600f124 2021-03-21 stsp if (list_backups) {
9273 e600f124 2021-03-21 stsp if (abort_rebase)
9274 e600f124 2021-03-21 stsp option_conflict('l', 'a');
9275 e600f124 2021-03-21 stsp if (continue_rebase)
9276 e600f124 2021-03-21 stsp option_conflict('l', 'c');
9277 643b85bc 2021-07-16 stsp if (delete_backups)
9278 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
9279 643b85bc 2021-07-16 stsp if (argc != 0 && argc != 1)
9280 643b85bc 2021-07-16 stsp usage_rebase();
9281 643b85bc 2021-07-16 stsp } else if (delete_backups) {
9282 643b85bc 2021-07-16 stsp if (abort_rebase)
9283 643b85bc 2021-07-16 stsp option_conflict('X', 'a');
9284 643b85bc 2021-07-16 stsp if (continue_rebase)
9285 643b85bc 2021-07-16 stsp option_conflict('X', 'c');
9286 643b85bc 2021-07-16 stsp if (list_backups)
9287 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
9288 e600f124 2021-03-21 stsp if (argc != 0 && argc != 1)
9289 818c7501 2019-07-11 stsp usage_rebase();
9290 e600f124 2021-03-21 stsp } else {
9291 e600f124 2021-03-21 stsp if (abort_rebase && continue_rebase)
9292 e600f124 2021-03-21 stsp usage_rebase();
9293 e600f124 2021-03-21 stsp else if (abort_rebase || continue_rebase) {
9294 e600f124 2021-03-21 stsp if (argc != 0)
9295 e600f124 2021-03-21 stsp usage_rebase();
9296 e600f124 2021-03-21 stsp } else if (argc != 1)
9297 e600f124 2021-03-21 stsp usage_rebase();
9298 e600f124 2021-03-21 stsp }
9299 818c7501 2019-07-11 stsp
9300 818c7501 2019-07-11 stsp cwd = getcwd(NULL, 0);
9301 818c7501 2019-07-11 stsp if (cwd == NULL) {
9302 818c7501 2019-07-11 stsp error = got_error_from_errno("getcwd");
9303 818c7501 2019-07-11 stsp goto done;
9304 818c7501 2019-07-11 stsp }
9305 818c7501 2019-07-11 stsp error = got_worktree_open(&worktree, cwd);
9306 fa51e947 2020-03-27 stsp if (error) {
9307 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
9308 e600f124 2021-03-21 stsp if (error->code != GOT_ERR_NOT_WORKTREE)
9309 e600f124 2021-03-21 stsp goto done;
9310 e600f124 2021-03-21 stsp } else {
9311 e600f124 2021-03-21 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
9312 e600f124 2021-03-21 stsp error = wrap_not_worktree_error(error,
9313 e600f124 2021-03-21 stsp "rebase", cwd);
9314 e600f124 2021-03-21 stsp goto done;
9315 e600f124 2021-03-21 stsp }
9316 fa51e947 2020-03-27 stsp }
9317 818c7501 2019-07-11 stsp
9318 e600f124 2021-03-21 stsp error = got_repo_open(&repo,
9319 e600f124 2021-03-21 stsp worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL);
9320 818c7501 2019-07-11 stsp if (error != NULL)
9321 818c7501 2019-07-11 stsp goto done;
9322 818c7501 2019-07-11 stsp
9323 818c7501 2019-07-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
9324 e600f124 2021-03-21 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
9325 7ef62c4e 2020-02-24 stsp if (error)
9326 7ef62c4e 2020-02-24 stsp goto done;
9327 7ef62c4e 2020-02-24 stsp
9328 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
9329 643b85bc 2021-07-16 stsp error = process_backup_refs(
9330 643b85bc 2021-07-16 stsp GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
9331 643b85bc 2021-07-16 stsp argc == 1 ? argv[0] : NULL, delete_backups, repo);
9332 e600f124 2021-03-21 stsp goto done; /* nothing else to do */
9333 e600f124 2021-03-21 stsp }
9334 e600f124 2021-03-21 stsp
9335 7ef62c4e 2020-02-24 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
9336 7ef62c4e 2020-02-24 stsp worktree);
9337 818c7501 2019-07-11 stsp if (error)
9338 7ef62c4e 2020-02-24 stsp goto done;
9339 7ef62c4e 2020-02-24 stsp if (histedit_in_progress) {
9340 7ef62c4e 2020-02-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
9341 f259c4c1 2021-09-24 stsp goto done;
9342 f259c4c1 2021-09-24 stsp }
9343 f259c4c1 2021-09-24 stsp
9344 f259c4c1 2021-09-24 stsp error = got_worktree_merge_in_progress(&merge_in_progress,
9345 f259c4c1 2021-09-24 stsp worktree, repo);
9346 f259c4c1 2021-09-24 stsp if (error)
9347 f259c4c1 2021-09-24 stsp goto done;
9348 f259c4c1 2021-09-24 stsp if (merge_in_progress) {
9349 f259c4c1 2021-09-24 stsp error = got_error(GOT_ERR_MERGE_BUSY);
9350 818c7501 2019-07-11 stsp goto done;
9351 7ef62c4e 2020-02-24 stsp }
9352 818c7501 2019-07-11 stsp
9353 818c7501 2019-07-11 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
9354 818c7501 2019-07-11 stsp if (error)
9355 818c7501 2019-07-11 stsp goto done;
9356 818c7501 2019-07-11 stsp
9357 f6794adc 2019-07-23 stsp if (abort_rebase) {
9358 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
9359 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
9360 f6794adc 2019-07-23 stsp goto done;
9361 f6794adc 2019-07-23 stsp }
9362 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
9363 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
9364 3e3a69f1 2019-07-25 stsp worktree, repo);
9365 818c7501 2019-07-11 stsp if (error)
9366 818c7501 2019-07-11 stsp goto done;
9367 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n",
9368 818c7501 2019-07-11 stsp got_ref_get_symref_target(new_base_branch));
9369 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_abort(worktree, fileindex, repo,
9370 41f061b2 2021-10-05 stsp new_base_branch, abort_progress, &upa);
9371 818c7501 2019-07-11 stsp if (error)
9372 818c7501 2019-07-11 stsp goto done;
9373 818c7501 2019-07-11 stsp printf("Rebase of %s aborted\n", got_ref_get_name(branch));
9374 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
9375 818c7501 2019-07-11 stsp goto done; /* nothing else to do */
9376 818c7501 2019-07-11 stsp }
9377 818c7501 2019-07-11 stsp
9378 818c7501 2019-07-11 stsp if (continue_rebase) {
9379 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
9380 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
9381 f6794adc 2019-07-23 stsp goto done;
9382 f6794adc 2019-07-23 stsp }
9383 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
9384 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
9385 3e3a69f1 2019-07-25 stsp worktree, repo);
9386 818c7501 2019-07-11 stsp if (error)
9387 818c7501 2019-07-11 stsp goto done;
9388 818c7501 2019-07-11 stsp
9389 3e3a69f1 2019-07-25 stsp error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
9390 01757395 2019-07-12 stsp resume_commit_id, repo);
9391 818c7501 2019-07-11 stsp if (error)
9392 818c7501 2019-07-11 stsp goto done;
9393 818c7501 2019-07-11 stsp
9394 ff0d2220 2019-07-11 stsp yca_id = got_object_id_dup(resume_commit_id);
9395 ff0d2220 2019-07-11 stsp if (yca_id == NULL) {
9396 818c7501 2019-07-11 stsp error = got_error_from_errno("got_object_id_dup");
9397 818c7501 2019-07-11 stsp goto done;
9398 818c7501 2019-07-11 stsp }
9399 818c7501 2019-07-11 stsp } else {
9400 818c7501 2019-07-11 stsp error = got_ref_open(&branch, repo, argv[0], 0);
9401 818c7501 2019-07-11 stsp if (error != NULL)
9402 818c7501 2019-07-11 stsp goto done;
9403 ff0d2220 2019-07-11 stsp }
9404 818c7501 2019-07-11 stsp
9405 ff0d2220 2019-07-11 stsp error = got_ref_resolve(&branch_head_commit_id, repo, branch);
9406 ff0d2220 2019-07-11 stsp if (error)
9407 ff0d2220 2019-07-11 stsp goto done;
9408 ff0d2220 2019-07-11 stsp
9409 ff0d2220 2019-07-11 stsp if (!continue_rebase) {
9410 a51a74b3 2019-07-27 stsp struct got_object_id *base_commit_id;
9411 a51a74b3 2019-07-27 stsp
9412 a51a74b3 2019-07-27 stsp base_commit_id = got_worktree_get_base_commit_id(worktree);
9413 818c7501 2019-07-11 stsp error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
9414 4e91ef15 2021-09-26 stsp base_commit_id, branch_head_commit_id, 1, repo,
9415 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
9416 818c7501 2019-07-11 stsp if (error)
9417 818c7501 2019-07-11 stsp goto done;
9418 818c7501 2019-07-11 stsp if (yca_id == NULL) {
9419 818c7501 2019-07-11 stsp error = got_error_msg(GOT_ERR_ANCESTRY,
9420 818c7501 2019-07-11 stsp "specified branch shares no common ancestry "
9421 818c7501 2019-07-11 stsp "with work tree's branch");
9422 818c7501 2019-07-11 stsp goto done;
9423 818c7501 2019-07-11 stsp }
9424 818c7501 2019-07-11 stsp
9425 a51a74b3 2019-07-27 stsp error = check_same_branch(base_commit_id, branch, yca_id, repo);
9426 a51a74b3 2019-07-27 stsp if (error) {
9427 a51a74b3 2019-07-27 stsp if (error->code != GOT_ERR_ANCESTRY)
9428 a51a74b3 2019-07-27 stsp goto done;
9429 a51a74b3 2019-07-27 stsp error = NULL;
9430 a51a74b3 2019-07-27 stsp } else {
9431 3d42b266 2021-11-03 jrick struct got_pathlist_head paths;
9432 3d42b266 2021-11-03 jrick printf("%s is already based on %s\n",
9433 df3ed485 2021-01-31 stsp got_ref_get_name(branch),
9434 df3ed485 2021-01-31 stsp got_worktree_get_head_ref_name(worktree));
9435 3d42b266 2021-11-03 jrick error = switch_head_ref(branch, branch_head_commit_id,
9436 3d42b266 2021-11-03 jrick worktree, repo);
9437 3d42b266 2021-11-03 jrick if (error)
9438 3d42b266 2021-11-03 jrick goto done;
9439 3d42b266 2021-11-03 jrick error = got_worktree_set_base_commit_id(worktree, repo,
9440 3d42b266 2021-11-03 jrick branch_head_commit_id);
9441 3d42b266 2021-11-03 jrick if (error)
9442 3d42b266 2021-11-03 jrick goto done;
9443 3d42b266 2021-11-03 jrick TAILQ_INIT(&paths);
9444 3d42b266 2021-11-03 jrick error = got_pathlist_append(&paths, "", NULL);
9445 3d42b266 2021-11-03 jrick if (error)
9446 3d42b266 2021-11-03 jrick goto done;
9447 3d42b266 2021-11-03 jrick error = got_worktree_checkout_files(worktree,
9448 3d42b266 2021-11-03 jrick &paths, repo, update_progress, &upa,
9449 3d42b266 2021-11-03 jrick check_cancelled, NULL);
9450 3d42b266 2021-11-03 jrick got_pathlist_free(&paths);
9451 3d42b266 2021-11-03 jrick if (error)
9452 3d42b266 2021-11-03 jrick goto done;
9453 3d42b266 2021-11-03 jrick if (upa.did_something) {
9454 3d42b266 2021-11-03 jrick char *id_str;
9455 3d42b266 2021-11-03 jrick error = got_object_id_str(&id_str,
9456 3d42b266 2021-11-03 jrick branch_head_commit_id);
9457 3d42b266 2021-11-03 jrick if (error)
9458 3d42b266 2021-11-03 jrick goto done;
9459 3d42b266 2021-11-03 jrick printf("Updated to %s: %s\n",
9460 3d42b266 2021-11-03 jrick got_worktree_get_head_ref_name(worktree),
9461 3d42b266 2021-11-03 jrick id_str);
9462 3d42b266 2021-11-03 jrick free(id_str);
9463 3d42b266 2021-11-03 jrick } else
9464 3d42b266 2021-11-03 jrick printf("Already up-to-date\n");
9465 3d42b266 2021-11-03 jrick print_update_progress_stats(&upa);
9466 a51a74b3 2019-07-27 stsp goto done;
9467 a51a74b3 2019-07-27 stsp }
9468 818c7501 2019-07-11 stsp }
9469 818c7501 2019-07-11 stsp
9470 ff0d2220 2019-07-11 stsp commit_id = branch_head_commit_id;
9471 818c7501 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
9472 818c7501 2019-07-11 stsp if (error)
9473 818c7501 2019-07-11 stsp goto done;
9474 818c7501 2019-07-11 stsp
9475 818c7501 2019-07-11 stsp parent_ids = got_object_commit_get_parent_ids(commit);
9476 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
9477 fc66b545 2019-08-12 stsp if (pid == NULL) {
9478 fc66b545 2019-08-12 stsp error = got_error(GOT_ERR_EMPTY_REBASE);
9479 fc66b545 2019-08-12 stsp goto done;
9480 fc66b545 2019-08-12 stsp }
9481 d7b5a0e8 2022-04-20 stsp error = collect_commits(&commits, commit_id, &pid->id,
9482 8ca9bd68 2019-07-25 stsp yca_id, got_worktree_get_path_prefix(worktree),
9483 8ca9bd68 2019-07-25 stsp GOT_ERR_REBASE_PATH, repo);
9484 818c7501 2019-07-11 stsp got_object_commit_close(commit);
9485 818c7501 2019-07-11 stsp commit = NULL;
9486 818c7501 2019-07-11 stsp if (error)
9487 818c7501 2019-07-11 stsp goto done;
9488 67ba6161 2022-04-08 stsp
9489 67ba6161 2022-04-08 stsp if (!continue_rebase) {
9490 67ba6161 2022-04-08 stsp error = got_worktree_rebase_prepare(&new_base_branch,
9491 67ba6161 2022-04-08 stsp &tmp_branch, &fileindex, worktree, branch, repo);
9492 67ba6161 2022-04-08 stsp if (error)
9493 67ba6161 2022-04-08 stsp goto done;
9494 67ba6161 2022-04-08 stsp }
9495 64c6d990 2019-07-11 stsp
9496 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(&commits)) {
9497 38b0338b 2019-11-29 stsp if (continue_rebase) {
9498 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex,
9499 e600f124 2021-03-21 stsp branch, new_base_branch, tmp_branch, repo,
9500 e600f124 2021-03-21 stsp create_backup);
9501 38b0338b 2019-11-29 stsp goto done;
9502 38b0338b 2019-11-29 stsp } else {
9503 38b0338b 2019-11-29 stsp /* Fast-forward the reference of the branch. */
9504 38b0338b 2019-11-29 stsp struct got_object_id *new_head_commit_id;
9505 38b0338b 2019-11-29 stsp char *id_str;
9506 38b0338b 2019-11-29 stsp error = got_ref_resolve(&new_head_commit_id, repo,
9507 38b0338b 2019-11-29 stsp new_base_branch);
9508 38b0338b 2019-11-29 stsp if (error)
9509 38b0338b 2019-11-29 stsp goto done;
9510 38b0338b 2019-11-29 stsp error = got_object_id_str(&id_str, new_head_commit_id);
9511 38b0338b 2019-11-29 stsp printf("Forwarding %s to commit %s\n",
9512 38b0338b 2019-11-29 stsp got_ref_get_name(branch), id_str);
9513 38b0338b 2019-11-29 stsp free(id_str);
9514 38b0338b 2019-11-29 stsp error = got_ref_change_ref(branch,
9515 38b0338b 2019-11-29 stsp new_head_commit_id);
9516 38b0338b 2019-11-29 stsp if (error)
9517 38b0338b 2019-11-29 stsp goto done;
9518 e600f124 2021-03-21 stsp /* No backup needed since objects did not change. */
9519 e600f124 2021-03-21 stsp create_backup = 0;
9520 38b0338b 2019-11-29 stsp }
9521 818c7501 2019-07-11 stsp }
9522 818c7501 2019-07-11 stsp
9523 818c7501 2019-07-11 stsp pid = NULL;
9524 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, &commits, entry) {
9525 9627c110 2020-04-18 stsp
9526 d7b5a0e8 2022-04-20 stsp commit_id = &qid->id;
9527 d7b5a0e8 2022-04-20 stsp parent_id = pid ? &pid->id : yca_id;
9528 818c7501 2019-07-11 stsp pid = qid;
9529 818c7501 2019-07-11 stsp
9530 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
9531 01757395 2019-07-12 stsp error = got_worktree_rebase_merge_files(&merged_paths,
9532 3e3a69f1 2019-07-25 stsp worktree, fileindex, parent_id, commit_id, repo,
9533 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
9534 818c7501 2019-07-11 stsp if (error)
9535 818c7501 2019-07-11 stsp goto done;
9536 9627c110 2020-04-18 stsp
9537 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
9538 1fa49072 2021-09-28 stsp if (upa.conflicts > 0 || upa.missing > 0 ||
9539 1fa49072 2021-09-28 stsp upa.not_deleted > 0 || upa.unversioned > 0) {
9540 1fa49072 2021-09-28 stsp if (upa.conflicts > 0) {
9541 d7b5a0e8 2022-04-20 stsp error = show_rebase_merge_conflict(&qid->id,
9542 1fa49072 2021-09-28 stsp repo);
9543 1fa49072 2021-09-28 stsp if (error)
9544 1fa49072 2021-09-28 stsp goto done;
9545 1fa49072 2021-09-28 stsp }
9546 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
9547 818c7501 2019-07-11 stsp break;
9548 01757395 2019-07-12 stsp }
9549 818c7501 2019-07-11 stsp
9550 3e3a69f1 2019-07-25 stsp error = rebase_commit(&merged_paths, worktree, fileindex,
9551 3e3a69f1 2019-07-25 stsp tmp_branch, commit_id, repo);
9552 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
9553 818c7501 2019-07-11 stsp if (error)
9554 818c7501 2019-07-11 stsp goto done;
9555 818c7501 2019-07-11 stsp }
9556 818c7501 2019-07-11 stsp
9557 1fa49072 2021-09-28 stsp if (upa.conflicts > 0 || upa.missing > 0 ||
9558 1fa49072 2021-09-28 stsp upa.not_deleted > 0 || upa.unversioned > 0) {
9559 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_postpone(worktree, fileindex);
9560 818c7501 2019-07-11 stsp if (error)
9561 818c7501 2019-07-11 stsp goto done;
9562 1fa49072 2021-09-28 stsp if (upa.conflicts > 0 && upa.missing == 0 &&
9563 1fa49072 2021-09-28 stsp upa.not_deleted == 0 && upa.unversioned == 0) {
9564 1fa49072 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
9565 1fa49072 2021-09-28 stsp "conflicts must be resolved before rebasing "
9566 1fa49072 2021-09-28 stsp "can continue");
9567 1fa49072 2021-09-28 stsp } else if (upa.conflicts > 0) {
9568 1fa49072 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
9569 1fa49072 2021-09-28 stsp "conflicts must be resolved before rebasing "
9570 1fa49072 2021-09-28 stsp "can continue; changes destined for some "
9571 1fa49072 2021-09-28 stsp "files were not yet merged and should be "
9572 1fa49072 2021-09-28 stsp "merged manually if required before the "
9573 1fa49072 2021-09-28 stsp "rebase operation is continued");
9574 1fa49072 2021-09-28 stsp } else {
9575 1fa49072 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
9576 1fa49072 2021-09-28 stsp "changes destined for some files were not "
9577 1fa49072 2021-09-28 stsp "yet merged and should be merged manually "
9578 1fa49072 2021-09-28 stsp "if required before the rebase operation "
9579 1fa49072 2021-09-28 stsp "is continued");
9580 1fa49072 2021-09-28 stsp }
9581 818c7501 2019-07-11 stsp } else
9582 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex, branch,
9583 e600f124 2021-03-21 stsp new_base_branch, tmp_branch, repo, create_backup);
9584 818c7501 2019-07-11 stsp done:
9585 818c7501 2019-07-11 stsp got_object_id_queue_free(&commits);
9586 818c7501 2019-07-11 stsp free(branch_head_commit_id);
9587 818c7501 2019-07-11 stsp free(resume_commit_id);
9588 818c7501 2019-07-11 stsp free(yca_id);
9589 818c7501 2019-07-11 stsp if (commit)
9590 818c7501 2019-07-11 stsp got_object_commit_close(commit);
9591 818c7501 2019-07-11 stsp if (branch)
9592 818c7501 2019-07-11 stsp got_ref_close(branch);
9593 818c7501 2019-07-11 stsp if (new_base_branch)
9594 818c7501 2019-07-11 stsp got_ref_close(new_base_branch);
9595 818c7501 2019-07-11 stsp if (tmp_branch)
9596 818c7501 2019-07-11 stsp got_ref_close(tmp_branch);
9597 5ef14e63 2019-06-02 stsp if (worktree)
9598 5ef14e63 2019-06-02 stsp got_worktree_close(worktree);
9599 1d0f4054 2021-06-17 stsp if (repo) {
9600 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
9601 1d0f4054 2021-06-17 stsp if (error == NULL)
9602 1d0f4054 2021-06-17 stsp error = close_err;
9603 1d0f4054 2021-06-17 stsp }
9604 5ef14e63 2019-06-02 stsp return error;
9605 0ebf8283 2019-07-24 stsp }
9606 0ebf8283 2019-07-24 stsp
9607 0ebf8283 2019-07-24 stsp __dead static void
9608 0ebf8283 2019-07-24 stsp usage_histedit(void)
9609 0ebf8283 2019-07-24 stsp {
9610 b93c7142 2021-10-01 stsp fprintf(stderr, "usage: %s histedit [-a] [-c] [-e] [-f] "
9611 643b85bc 2021-07-16 stsp "[-F histedit-script] [-m] [-l] [-X] [branch]\n",
9612 643b85bc 2021-07-16 stsp getprogname());
9613 0ebf8283 2019-07-24 stsp exit(1);
9614 0ebf8283 2019-07-24 stsp }
9615 0ebf8283 2019-07-24 stsp
9616 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_PICK 'p'
9617 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_EDIT 'e'
9618 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_FOLD 'f'
9619 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_DROP 'd'
9620 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_MESG 'm'
9621 0ebf8283 2019-07-24 stsp
9622 3e166534 2022-02-16 naddy static const struct got_histedit_cmd {
9623 0ebf8283 2019-07-24 stsp unsigned char code;
9624 0ebf8283 2019-07-24 stsp const char *name;
9625 0ebf8283 2019-07-24 stsp const char *desc;
9626 0ebf8283 2019-07-24 stsp } got_histedit_cmds[] = {
9627 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_PICK, "pick", "use commit" },
9628 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
9629 82997472 2020-01-29 stsp { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
9630 82997472 2020-01-29 stsp "be used" },
9631 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
9632 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_MESG, "mesg",
9633 0ebf8283 2019-07-24 stsp "single-line log message for commit above (open editor if empty)" },
9634 0ebf8283 2019-07-24 stsp };
9635 0ebf8283 2019-07-24 stsp
9636 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry {
9637 0ebf8283 2019-07-24 stsp TAILQ_ENTRY(got_histedit_list_entry) entry;
9638 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id;
9639 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
9640 0ebf8283 2019-07-24 stsp char *logmsg;
9641 0ebf8283 2019-07-24 stsp };
9642 0ebf8283 2019-07-24 stsp TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
9643 0ebf8283 2019-07-24 stsp
9644 0ebf8283 2019-07-24 stsp static const struct got_error *
9645 0ebf8283 2019-07-24 stsp histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
9646 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
9647 0ebf8283 2019-07-24 stsp {
9648 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9649 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *id_str = NULL;
9650 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9651 8138f3e1 2019-08-11 stsp int n;
9652 0ebf8283 2019-07-24 stsp
9653 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
9654 0ebf8283 2019-07-24 stsp if (err)
9655 0ebf8283 2019-07-24 stsp goto done;
9656 0ebf8283 2019-07-24 stsp
9657 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 34, commit);
9658 0ebf8283 2019-07-24 stsp if (err)
9659 0ebf8283 2019-07-24 stsp goto done;
9660 0ebf8283 2019-07-24 stsp
9661 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, commit_id);
9662 0ebf8283 2019-07-24 stsp if (err)
9663 0ebf8283 2019-07-24 stsp goto done;
9664 0ebf8283 2019-07-24 stsp
9665 0ebf8283 2019-07-24 stsp n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
9666 0ebf8283 2019-07-24 stsp if (n < 0)
9667 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
9668 0ebf8283 2019-07-24 stsp done:
9669 0ebf8283 2019-07-24 stsp if (commit)
9670 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9671 0ebf8283 2019-07-24 stsp free(id_str);
9672 0ebf8283 2019-07-24 stsp free(logmsg);
9673 0ebf8283 2019-07-24 stsp return err;
9674 0ebf8283 2019-07-24 stsp }
9675 0ebf8283 2019-07-24 stsp
9676 0ebf8283 2019-07-24 stsp static const struct got_error *
9677 083957f4 2020-02-24 stsp histedit_write_commit_list(struct got_object_id_queue *commits,
9678 b93c7142 2021-10-01 stsp FILE *f, int edit_logmsg_only, int fold_only, int edit_only,
9679 b93c7142 2021-10-01 stsp struct got_repository *repo)
9680 0ebf8283 2019-07-24 stsp {
9681 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9682 0ebf8283 2019-07-24 stsp struct got_object_qid *qid;
9683 466785b9 2020-12-10 jrick const char *histedit_cmd = NULL;
9684 0ebf8283 2019-07-24 stsp
9685 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(commits))
9686 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
9687 0ebf8283 2019-07-24 stsp
9688 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, commits, entry) {
9689 466785b9 2020-12-10 jrick histedit_cmd = got_histedit_cmds[0].name;
9690 b93c7142 2021-10-01 stsp if (edit_only)
9691 b93c7142 2021-10-01 stsp histedit_cmd = "edit";
9692 b93c7142 2021-10-01 stsp else if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
9693 466785b9 2020-12-10 jrick histedit_cmd = "fold";
9694 d7b5a0e8 2022-04-20 stsp err = histedit_write_commit(&qid->id, histedit_cmd, f, repo);
9695 0ebf8283 2019-07-24 stsp if (err)
9696 0ebf8283 2019-07-24 stsp break;
9697 083957f4 2020-02-24 stsp if (edit_logmsg_only) {
9698 083957f4 2020-02-24 stsp int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
9699 083957f4 2020-02-24 stsp if (n < 0) {
9700 083957f4 2020-02-24 stsp err = got_ferror(f, GOT_ERR_IO);
9701 083957f4 2020-02-24 stsp break;
9702 083957f4 2020-02-24 stsp }
9703 083957f4 2020-02-24 stsp }
9704 0ebf8283 2019-07-24 stsp }
9705 0ebf8283 2019-07-24 stsp
9706 0ebf8283 2019-07-24 stsp return err;
9707 0ebf8283 2019-07-24 stsp }
9708 0ebf8283 2019-07-24 stsp
9709 0ebf8283 2019-07-24 stsp static const struct got_error *
9710 514f2ffe 2020-01-29 stsp write_cmd_list(FILE *f, const char *branch_name,
9711 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits)
9712 0ebf8283 2019-07-24 stsp {
9713 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9714 6059809a 2020-12-17 stsp size_t i;
9715 6059809a 2020-12-17 stsp int n;
9716 514f2ffe 2020-01-29 stsp char *id_str;
9717 514f2ffe 2020-01-29 stsp struct got_object_qid *qid;
9718 514f2ffe 2020-01-29 stsp
9719 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(commits);
9720 d7b5a0e8 2022-04-20 stsp err = got_object_id_str(&id_str, &qid->id);
9721 514f2ffe 2020-01-29 stsp if (err)
9722 514f2ffe 2020-01-29 stsp return err;
9723 514f2ffe 2020-01-29 stsp
9724 514f2ffe 2020-01-29 stsp n = fprintf(f,
9725 514f2ffe 2020-01-29 stsp "# Editing the history of branch '%s' starting at\n"
9726 514f2ffe 2020-01-29 stsp "# commit %s\n"
9727 514f2ffe 2020-01-29 stsp "# Commits will be processed in order from top to "
9728 514f2ffe 2020-01-29 stsp "bottom of this file.\n", branch_name, id_str);
9729 514f2ffe 2020-01-29 stsp if (n < 0) {
9730 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
9731 514f2ffe 2020-01-29 stsp goto done;
9732 514f2ffe 2020-01-29 stsp }
9733 0ebf8283 2019-07-24 stsp
9734 0ebf8283 2019-07-24 stsp n = fprintf(f, "# Available histedit commands:\n");
9735 514f2ffe 2020-01-29 stsp if (n < 0) {
9736 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
9737 514f2ffe 2020-01-29 stsp goto done;
9738 514f2ffe 2020-01-29 stsp }
9739 0ebf8283 2019-07-24 stsp
9740 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
9741 3e166534 2022-02-16 naddy const struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
9742 0ebf8283 2019-07-24 stsp n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
9743 0ebf8283 2019-07-24 stsp cmd->desc);
9744 0ebf8283 2019-07-24 stsp if (n < 0) {
9745 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
9746 0ebf8283 2019-07-24 stsp break;
9747 0ebf8283 2019-07-24 stsp }
9748 0ebf8283 2019-07-24 stsp }
9749 514f2ffe 2020-01-29 stsp done:
9750 514f2ffe 2020-01-29 stsp free(id_str);
9751 0ebf8283 2019-07-24 stsp return err;
9752 0ebf8283 2019-07-24 stsp }
9753 0ebf8283 2019-07-24 stsp
9754 0ebf8283 2019-07-24 stsp static const struct got_error *
9755 0ebf8283 2019-07-24 stsp histedit_syntax_error(int lineno)
9756 0ebf8283 2019-07-24 stsp {
9757 0ebf8283 2019-07-24 stsp static char msg[42];
9758 0ebf8283 2019-07-24 stsp int ret;
9759 0ebf8283 2019-07-24 stsp
9760 0ebf8283 2019-07-24 stsp ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
9761 0ebf8283 2019-07-24 stsp lineno);
9762 0ebf8283 2019-07-24 stsp if (ret == -1 || ret >= sizeof(msg))
9763 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_SYNTAX);
9764 0ebf8283 2019-07-24 stsp
9765 0ebf8283 2019-07-24 stsp return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
9766 0ebf8283 2019-07-24 stsp }
9767 0ebf8283 2019-07-24 stsp
9768 0ebf8283 2019-07-24 stsp static const struct got_error *
9769 0ebf8283 2019-07-24 stsp append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
9770 0ebf8283 2019-07-24 stsp char *logmsg, struct got_repository *repo)
9771 0ebf8283 2019-07-24 stsp {
9772 0ebf8283 2019-07-24 stsp const struct got_error *err;
9773 0ebf8283 2019-07-24 stsp struct got_commit_object *folded_commit = NULL;
9774 5943eee2 2019-08-13 stsp char *id_str, *folded_logmsg = NULL;
9775 0ebf8283 2019-07-24 stsp
9776 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9777 0ebf8283 2019-07-24 stsp if (err)
9778 0ebf8283 2019-07-24 stsp return err;
9779 0ebf8283 2019-07-24 stsp
9780 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
9781 0ebf8283 2019-07-24 stsp if (err)
9782 0ebf8283 2019-07-24 stsp goto done;
9783 0ebf8283 2019-07-24 stsp
9784 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
9785 5943eee2 2019-08-13 stsp if (err)
9786 5943eee2 2019-08-13 stsp goto done;
9787 0ebf8283 2019-07-24 stsp if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
9788 0ebf8283 2019-07-24 stsp logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
9789 5943eee2 2019-08-13 stsp folded_logmsg) == -1) {
9790 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
9791 0ebf8283 2019-07-24 stsp }
9792 0ebf8283 2019-07-24 stsp done:
9793 0ebf8283 2019-07-24 stsp if (folded_commit)
9794 0ebf8283 2019-07-24 stsp got_object_commit_close(folded_commit);
9795 0ebf8283 2019-07-24 stsp free(id_str);
9796 5943eee2 2019-08-13 stsp free(folded_logmsg);
9797 0ebf8283 2019-07-24 stsp return err;
9798 0ebf8283 2019-07-24 stsp }
9799 0ebf8283 2019-07-24 stsp
9800 0ebf8283 2019-07-24 stsp static struct got_histedit_list_entry *
9801 0ebf8283 2019-07-24 stsp get_folded_commits(struct got_histedit_list_entry *hle)
9802 0ebf8283 2019-07-24 stsp {
9803 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *prev, *folded = NULL;
9804 0ebf8283 2019-07-24 stsp
9805 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(hle, got_histedit_list, entry);
9806 3f9de99f 2019-07-24 stsp while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
9807 3f9de99f 2019-07-24 stsp prev->cmd->code == GOT_HISTEDIT_DROP)) {
9808 3f9de99f 2019-07-24 stsp if (prev->cmd->code == GOT_HISTEDIT_FOLD)
9809 3f9de99f 2019-07-24 stsp folded = prev;
9810 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(prev, got_histedit_list, entry);
9811 0ebf8283 2019-07-24 stsp }
9812 0ebf8283 2019-07-24 stsp
9813 0ebf8283 2019-07-24 stsp return folded;
9814 0ebf8283 2019-07-24 stsp }
9815 0ebf8283 2019-07-24 stsp
9816 0ebf8283 2019-07-24 stsp static const struct got_error *
9817 0ebf8283 2019-07-24 stsp histedit_edit_logmsg(struct got_histedit_list_entry *hle,
9818 0ebf8283 2019-07-24 stsp struct got_repository *repo)
9819 0ebf8283 2019-07-24 stsp {
9820 5943eee2 2019-08-13 stsp char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
9821 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
9822 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9823 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9824 1601cb9f 2020-09-11 naddy int logmsg_len;
9825 0ebf8283 2019-07-24 stsp int fd;
9826 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *folded = NULL;
9827 0ebf8283 2019-07-24 stsp
9828 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
9829 0ebf8283 2019-07-24 stsp if (err)
9830 0ebf8283 2019-07-24 stsp return err;
9831 0ebf8283 2019-07-24 stsp
9832 0ebf8283 2019-07-24 stsp folded = get_folded_commits(hle);
9833 0ebf8283 2019-07-24 stsp if (folded) {
9834 0ebf8283 2019-07-24 stsp while (folded != hle) {
9835 3f9de99f 2019-07-24 stsp if (folded->cmd->code == GOT_HISTEDIT_DROP) {
9836 3f9de99f 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
9837 3f9de99f 2019-07-24 stsp continue;
9838 3f9de99f 2019-07-24 stsp }
9839 0ebf8283 2019-07-24 stsp err = append_folded_commit_msg(&new_msg, folded,
9840 0ebf8283 2019-07-24 stsp logmsg, repo);
9841 0ebf8283 2019-07-24 stsp if (err)
9842 0ebf8283 2019-07-24 stsp goto done;
9843 0ebf8283 2019-07-24 stsp free(logmsg);
9844 0ebf8283 2019-07-24 stsp logmsg = new_msg;
9845 0ebf8283 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
9846 0ebf8283 2019-07-24 stsp }
9847 0ebf8283 2019-07-24 stsp }
9848 0ebf8283 2019-07-24 stsp
9849 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9850 0ebf8283 2019-07-24 stsp if (err)
9851 0ebf8283 2019-07-24 stsp goto done;
9852 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&orig_logmsg, commit);
9853 5943eee2 2019-08-13 stsp if (err)
9854 5943eee2 2019-08-13 stsp goto done;
9855 1601cb9f 2020-09-11 naddy logmsg_len = asprintf(&new_msg,
9856 0ebf8283 2019-07-24 stsp "%s\n# original log message of commit %s: %s",
9857 1601cb9f 2020-09-11 naddy logmsg ? logmsg : "", id_str, orig_logmsg);
9858 1601cb9f 2020-09-11 naddy if (logmsg_len == -1) {
9859 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
9860 0ebf8283 2019-07-24 stsp goto done;
9861 0ebf8283 2019-07-24 stsp }
9862 0ebf8283 2019-07-24 stsp free(logmsg);
9863 0ebf8283 2019-07-24 stsp logmsg = new_msg;
9864 0ebf8283 2019-07-24 stsp
9865 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9866 0ebf8283 2019-07-24 stsp if (err)
9867 0ebf8283 2019-07-24 stsp goto done;
9868 0ebf8283 2019-07-24 stsp
9869 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(&logmsg_path, &fd,
9870 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-logmsg");
9871 0ebf8283 2019-07-24 stsp if (err)
9872 0ebf8283 2019-07-24 stsp goto done;
9873 0ebf8283 2019-07-24 stsp
9874 1601cb9f 2020-09-11 naddy write(fd, logmsg, logmsg_len);
9875 0ebf8283 2019-07-24 stsp close(fd);
9876 0ebf8283 2019-07-24 stsp
9877 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
9878 0ebf8283 2019-07-24 stsp if (err)
9879 0ebf8283 2019-07-24 stsp goto done;
9880 0ebf8283 2019-07-24 stsp
9881 bfa12d5e 2020-09-26 stsp err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
9882 0d5bb276 2020-12-15 stsp logmsg_len, 0);
9883 0ebf8283 2019-07-24 stsp if (err) {
9884 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
9885 0ebf8283 2019-07-24 stsp goto done;
9886 71392a05 2020-12-13 stsp err = NULL;
9887 71392a05 2020-12-13 stsp hle->logmsg = strdup(new_msg);
9888 71392a05 2020-12-13 stsp if (hle->logmsg == NULL)
9889 71392a05 2020-12-13 stsp err = got_error_from_errno("strdup");
9890 0ebf8283 2019-07-24 stsp }
9891 0ebf8283 2019-07-24 stsp done:
9892 0ebf8283 2019-07-24 stsp if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
9893 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", logmsg_path);
9894 0ebf8283 2019-07-24 stsp free(logmsg_path);
9895 0ebf8283 2019-07-24 stsp free(logmsg);
9896 5943eee2 2019-08-13 stsp free(orig_logmsg);
9897 0ebf8283 2019-07-24 stsp free(editor);
9898 0ebf8283 2019-07-24 stsp if (commit)
9899 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9900 0ebf8283 2019-07-24 stsp return err;
9901 5ef14e63 2019-06-02 stsp }
9902 0ebf8283 2019-07-24 stsp
9903 0ebf8283 2019-07-24 stsp static const struct got_error *
9904 0ebf8283 2019-07-24 stsp histedit_parse_list(struct got_histedit_list *histedit_cmds,
9905 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
9906 0ebf8283 2019-07-24 stsp {
9907 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9908 0ebf8283 2019-07-24 stsp char *line = NULL, *p, *end;
9909 6059809a 2020-12-17 stsp size_t i, size;
9910 0ebf8283 2019-07-24 stsp ssize_t len;
9911 6059809a 2020-12-17 stsp int lineno = 0;
9912 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
9913 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id = NULL;
9914 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle = NULL;
9915 0ebf8283 2019-07-24 stsp
9916 0ebf8283 2019-07-24 stsp for (;;) {
9917 0ebf8283 2019-07-24 stsp len = getline(&line, &size, f);
9918 0ebf8283 2019-07-24 stsp if (len == -1) {
9919 0ebf8283 2019-07-24 stsp const struct got_error *getline_err;
9920 0ebf8283 2019-07-24 stsp if (feof(f))
9921 0ebf8283 2019-07-24 stsp break;
9922 0ebf8283 2019-07-24 stsp getline_err = got_error_from_errno("getline");
9923 0ebf8283 2019-07-24 stsp err = got_ferror(f, getline_err->code);
9924 0ebf8283 2019-07-24 stsp break;
9925 0ebf8283 2019-07-24 stsp }
9926 0ebf8283 2019-07-24 stsp lineno++;
9927 0ebf8283 2019-07-24 stsp p = line;
9928 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
9929 0ebf8283 2019-07-24 stsp p++;
9930 0ebf8283 2019-07-24 stsp if (p[0] == '#' || p[0] == '\0') {
9931 0ebf8283 2019-07-24 stsp free(line);
9932 0ebf8283 2019-07-24 stsp line = NULL;
9933 0ebf8283 2019-07-24 stsp continue;
9934 0ebf8283 2019-07-24 stsp }
9935 0ebf8283 2019-07-24 stsp cmd = NULL;
9936 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
9937 0ebf8283 2019-07-24 stsp cmd = &got_histedit_cmds[i];
9938 0ebf8283 2019-07-24 stsp if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
9939 0ebf8283 2019-07-24 stsp isspace((unsigned char)p[strlen(cmd->name)])) {
9940 0ebf8283 2019-07-24 stsp p += strlen(cmd->name);
9941 0ebf8283 2019-07-24 stsp break;
9942 0ebf8283 2019-07-24 stsp }
9943 0ebf8283 2019-07-24 stsp if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
9944 0ebf8283 2019-07-24 stsp p++;
9945 0ebf8283 2019-07-24 stsp break;
9946 0ebf8283 2019-07-24 stsp }
9947 0ebf8283 2019-07-24 stsp }
9948 6c1844f6 2019-07-25 stsp if (i == nitems(got_histedit_cmds)) {
9949 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
9950 0ebf8283 2019-07-24 stsp break;
9951 0ebf8283 2019-07-24 stsp }
9952 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
9953 0ebf8283 2019-07-24 stsp p++;
9954 0ebf8283 2019-07-24 stsp if (cmd->code == GOT_HISTEDIT_MESG) {
9955 0ebf8283 2019-07-24 stsp if (hle == NULL || hle->logmsg != NULL) {
9956 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CMD);
9957 0ebf8283 2019-07-24 stsp break;
9958 0ebf8283 2019-07-24 stsp }
9959 0ebf8283 2019-07-24 stsp if (p[0] == '\0') {
9960 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
9961 0ebf8283 2019-07-24 stsp if (err)
9962 0ebf8283 2019-07-24 stsp break;
9963 0ebf8283 2019-07-24 stsp } else {
9964 0ebf8283 2019-07-24 stsp hle->logmsg = strdup(p);
9965 0ebf8283 2019-07-24 stsp if (hle->logmsg == NULL) {
9966 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
9967 0ebf8283 2019-07-24 stsp break;
9968 0ebf8283 2019-07-24 stsp }
9969 0ebf8283 2019-07-24 stsp }
9970 0ebf8283 2019-07-24 stsp free(line);
9971 0ebf8283 2019-07-24 stsp line = NULL;
9972 0ebf8283 2019-07-24 stsp continue;
9973 0ebf8283 2019-07-24 stsp } else {
9974 0ebf8283 2019-07-24 stsp end = p;
9975 0ebf8283 2019-07-24 stsp while (end[0] && !isspace((unsigned char)end[0]))
9976 0ebf8283 2019-07-24 stsp end++;
9977 0ebf8283 2019-07-24 stsp *end = '\0';
9978 0ebf8283 2019-07-24 stsp
9979 0ebf8283 2019-07-24 stsp err = got_object_resolve_id_str(&commit_id, repo, p);
9980 0ebf8283 2019-07-24 stsp if (err) {
9981 0ebf8283 2019-07-24 stsp /* override error code */
9982 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
9983 0ebf8283 2019-07-24 stsp break;
9984 0ebf8283 2019-07-24 stsp }
9985 0ebf8283 2019-07-24 stsp }
9986 0ebf8283 2019-07-24 stsp hle = malloc(sizeof(*hle));
9987 0ebf8283 2019-07-24 stsp if (hle == NULL) {
9988 0ebf8283 2019-07-24 stsp err = got_error_from_errno("malloc");
9989 0ebf8283 2019-07-24 stsp break;
9990 0ebf8283 2019-07-24 stsp }
9991 0ebf8283 2019-07-24 stsp hle->cmd = cmd;
9992 0ebf8283 2019-07-24 stsp hle->commit_id = commit_id;
9993 0ebf8283 2019-07-24 stsp hle->logmsg = NULL;
9994 0ebf8283 2019-07-24 stsp commit_id = NULL;
9995 0ebf8283 2019-07-24 stsp free(line);
9996 0ebf8283 2019-07-24 stsp line = NULL;
9997 0ebf8283 2019-07-24 stsp TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
9998 0ebf8283 2019-07-24 stsp }
9999 0ebf8283 2019-07-24 stsp
10000 0ebf8283 2019-07-24 stsp free(line);
10001 0ebf8283 2019-07-24 stsp free(commit_id);
10002 0ebf8283 2019-07-24 stsp return err;
10003 0ebf8283 2019-07-24 stsp }
10004 0ebf8283 2019-07-24 stsp
10005 0ebf8283 2019-07-24 stsp static const struct got_error *
10006 bfce7f83 2019-07-27 stsp histedit_check_script(struct got_histedit_list *histedit_cmds,
10007 bfce7f83 2019-07-27 stsp struct got_object_id_queue *commits, struct got_repository *repo)
10008 bfce7f83 2019-07-27 stsp {
10009 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL;
10010 bfce7f83 2019-07-27 stsp struct got_object_qid *qid;
10011 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
10012 5b87815e 2020-03-05 stsp static char msg[92];
10013 bfce7f83 2019-07-27 stsp char *id_str;
10014 bfce7f83 2019-07-27 stsp
10015 bfce7f83 2019-07-27 stsp if (TAILQ_EMPTY(histedit_cmds))
10016 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
10017 bfce7f83 2019-07-27 stsp "histedit script contains no commands");
10018 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(commits))
10019 a0de39f3 2019-08-09 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
10020 5b87815e 2020-03-05 stsp
10021 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
10022 5b87815e 2020-03-05 stsp struct got_histedit_list_entry *hle2;
10023 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle2, histedit_cmds, entry) {
10024 5b87815e 2020-03-05 stsp if (hle == hle2)
10025 5b87815e 2020-03-05 stsp continue;
10026 5b87815e 2020-03-05 stsp if (got_object_id_cmp(hle->commit_id,
10027 5b87815e 2020-03-05 stsp hle2->commit_id) != 0)
10028 5b87815e 2020-03-05 stsp continue;
10029 5b87815e 2020-03-05 stsp err = got_object_id_str(&id_str, hle->commit_id);
10030 5b87815e 2020-03-05 stsp if (err)
10031 5b87815e 2020-03-05 stsp return err;
10032 5b87815e 2020-03-05 stsp snprintf(msg, sizeof(msg), "commit %s is listed "
10033 5b87815e 2020-03-05 stsp "more than once in histedit script", id_str);
10034 5b87815e 2020-03-05 stsp free(id_str);
10035 5b87815e 2020-03-05 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
10036 5b87815e 2020-03-05 stsp }
10037 5b87815e 2020-03-05 stsp }
10038 bfce7f83 2019-07-27 stsp
10039 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, commits, entry) {
10040 bfce7f83 2019-07-27 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
10041 d7b5a0e8 2022-04-20 stsp if (got_object_id_cmp(&qid->id, hle->commit_id) == 0)
10042 bfce7f83 2019-07-27 stsp break;
10043 bfce7f83 2019-07-27 stsp }
10044 bfce7f83 2019-07-27 stsp if (hle == NULL) {
10045 d7b5a0e8 2022-04-20 stsp err = got_object_id_str(&id_str, &qid->id);
10046 bfce7f83 2019-07-27 stsp if (err)
10047 bfce7f83 2019-07-27 stsp return err;
10048 bfce7f83 2019-07-27 stsp snprintf(msg, sizeof(msg),
10049 bfce7f83 2019-07-27 stsp "commit %s missing from histedit script", id_str);
10050 bfce7f83 2019-07-27 stsp free(id_str);
10051 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
10052 bfce7f83 2019-07-27 stsp }
10053 bfce7f83 2019-07-27 stsp }
10054 bfce7f83 2019-07-27 stsp
10055 0def28b1 2019-08-17 stsp hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
10056 0def28b1 2019-08-17 stsp if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
10057 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD,
10058 bfce7f83 2019-07-27 stsp "last commit in histedit script cannot be folded");
10059 bfce7f83 2019-07-27 stsp
10060 bfce7f83 2019-07-27 stsp return NULL;
10061 bfce7f83 2019-07-27 stsp }
10062 bfce7f83 2019-07-27 stsp
10063 bfce7f83 2019-07-27 stsp static const struct got_error *
10064 0ebf8283 2019-07-24 stsp histedit_run_editor(struct got_histedit_list *histedit_cmds,
10065 bfce7f83 2019-07-27 stsp const char *path, struct got_object_id_queue *commits,
10066 bfce7f83 2019-07-27 stsp struct got_repository *repo)
10067 0ebf8283 2019-07-24 stsp {
10068 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
10069 0ebf8283 2019-07-24 stsp char *editor;
10070 0ebf8283 2019-07-24 stsp FILE *f = NULL;
10071 0ebf8283 2019-07-24 stsp
10072 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
10073 0ebf8283 2019-07-24 stsp if (err)
10074 0ebf8283 2019-07-24 stsp return err;
10075 0ebf8283 2019-07-24 stsp
10076 0ebf8283 2019-07-24 stsp if (spawn_editor(editor, path) == -1) {
10077 0ebf8283 2019-07-24 stsp err = got_error_from_errno("failed spawning editor");
10078 0ebf8283 2019-07-24 stsp goto done;
10079 0ebf8283 2019-07-24 stsp }
10080 0ebf8283 2019-07-24 stsp
10081 00fe21f2 2021-12-31 stsp f = fopen(path, "re");
10082 0ebf8283 2019-07-24 stsp if (f == NULL) {
10083 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fopen");
10084 0ebf8283 2019-07-24 stsp goto done;
10085 0ebf8283 2019-07-24 stsp }
10086 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
10087 bfce7f83 2019-07-27 stsp if (err)
10088 bfce7f83 2019-07-27 stsp goto done;
10089 bfce7f83 2019-07-27 stsp
10090 bfce7f83 2019-07-27 stsp err = histedit_check_script(histedit_cmds, commits, repo);
10091 0ebf8283 2019-07-24 stsp done:
10092 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
10093 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
10094 0ebf8283 2019-07-24 stsp free(editor);
10095 0ebf8283 2019-07-24 stsp return err;
10096 0ebf8283 2019-07-24 stsp }
10097 0ebf8283 2019-07-24 stsp
10098 0ebf8283 2019-07-24 stsp static const struct got_error *
10099 bfce7f83 2019-07-27 stsp histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
10100 514f2ffe 2020-01-29 stsp struct got_object_id_queue *, const char *, const char *,
10101 514f2ffe 2020-01-29 stsp struct got_repository *);
10102 0ebf8283 2019-07-24 stsp
10103 0ebf8283 2019-07-24 stsp static const struct got_error *
10104 0ebf8283 2019-07-24 stsp histedit_edit_script(struct got_histedit_list *histedit_cmds,
10105 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits, const char *branch_name,
10106 b93c7142 2021-10-01 stsp int edit_logmsg_only, int fold_only, int edit_only,
10107 b93c7142 2021-10-01 stsp struct got_repository *repo)
10108 0ebf8283 2019-07-24 stsp {
10109 0ebf8283 2019-07-24 stsp const struct got_error *err;
10110 0ebf8283 2019-07-24 stsp FILE *f = NULL;
10111 0ebf8283 2019-07-24 stsp char *path = NULL;
10112 0ebf8283 2019-07-24 stsp
10113 0ebf8283 2019-07-24 stsp err = got_opentemp_named(&path, &f, "got-histedit");
10114 0ebf8283 2019-07-24 stsp if (err)
10115 0ebf8283 2019-07-24 stsp return err;
10116 0ebf8283 2019-07-24 stsp
10117 514f2ffe 2020-01-29 stsp err = write_cmd_list(f, branch_name, commits);
10118 0ebf8283 2019-07-24 stsp if (err)
10119 0ebf8283 2019-07-24 stsp goto done;
10120 0ebf8283 2019-07-24 stsp
10121 466785b9 2020-12-10 jrick err = histedit_write_commit_list(commits, f, edit_logmsg_only,
10122 b93c7142 2021-10-01 stsp fold_only, edit_only, repo);
10123 0ebf8283 2019-07-24 stsp if (err)
10124 0ebf8283 2019-07-24 stsp goto done;
10125 0ebf8283 2019-07-24 stsp
10126 b93c7142 2021-10-01 stsp if (edit_logmsg_only || fold_only || edit_only) {
10127 083957f4 2020-02-24 stsp rewind(f);
10128 083957f4 2020-02-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
10129 083957f4 2020-02-24 stsp } else {
10130 56b63ca4 2021-01-22 stsp if (fclose(f) == EOF) {
10131 083957f4 2020-02-24 stsp err = got_error_from_errno("fclose");
10132 0ebf8283 2019-07-24 stsp goto done;
10133 083957f4 2020-02-24 stsp }
10134 083957f4 2020-02-24 stsp f = NULL;
10135 083957f4 2020-02-24 stsp err = histedit_run_editor(histedit_cmds, path, commits, repo);
10136 083957f4 2020-02-24 stsp if (err) {
10137 083957f4 2020-02-24 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
10138 083957f4 2020-02-24 stsp err->code != GOT_ERR_HISTEDIT_CMD)
10139 083957f4 2020-02-24 stsp goto done;
10140 083957f4 2020-02-24 stsp err = histedit_edit_list_retry(histedit_cmds, err,
10141 083957f4 2020-02-24 stsp commits, path, branch_name, repo);
10142 083957f4 2020-02-24 stsp }
10143 0ebf8283 2019-07-24 stsp }
10144 0ebf8283 2019-07-24 stsp done:
10145 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
10146 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
10147 0ebf8283 2019-07-24 stsp if (path && unlink(path) != 0 && err == NULL)
10148 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", path);
10149 0ebf8283 2019-07-24 stsp free(path);
10150 0ebf8283 2019-07-24 stsp return err;
10151 0ebf8283 2019-07-24 stsp }
10152 0ebf8283 2019-07-24 stsp
10153 0ebf8283 2019-07-24 stsp static const struct got_error *
10154 0ebf8283 2019-07-24 stsp histedit_save_list(struct got_histedit_list *histedit_cmds,
10155 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
10156 0ebf8283 2019-07-24 stsp {
10157 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
10158 0ebf8283 2019-07-24 stsp char *path = NULL;
10159 0ebf8283 2019-07-24 stsp FILE *f = NULL;
10160 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
10161 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
10162 0ebf8283 2019-07-24 stsp
10163 c3022ba5 2019-07-27 stsp err = got_worktree_get_histedit_script_path(&path, worktree);
10164 0ebf8283 2019-07-24 stsp if (err)
10165 0ebf8283 2019-07-24 stsp return err;
10166 0ebf8283 2019-07-24 stsp
10167 00fe21f2 2021-12-31 stsp f = fopen(path, "we");
10168 0ebf8283 2019-07-24 stsp if (f == NULL) {
10169 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
10170 0ebf8283 2019-07-24 stsp goto done;
10171 0ebf8283 2019-07-24 stsp }
10172 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
10173 0ebf8283 2019-07-24 stsp err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
10174 0ebf8283 2019-07-24 stsp repo);
10175 0ebf8283 2019-07-24 stsp if (err)
10176 0ebf8283 2019-07-24 stsp break;
10177 0ebf8283 2019-07-24 stsp
10178 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
10179 0ebf8283 2019-07-24 stsp int n = fprintf(f, "%c %s\n",
10180 0ebf8283 2019-07-24 stsp GOT_HISTEDIT_MESG, hle->logmsg);
10181 0ebf8283 2019-07-24 stsp if (n < 0) {
10182 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
10183 0ebf8283 2019-07-24 stsp break;
10184 0ebf8283 2019-07-24 stsp }
10185 0ebf8283 2019-07-24 stsp }
10186 0ebf8283 2019-07-24 stsp }
10187 0ebf8283 2019-07-24 stsp done:
10188 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
10189 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
10190 0ebf8283 2019-07-24 stsp free(path);
10191 0ebf8283 2019-07-24 stsp if (commit)
10192 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10193 0ebf8283 2019-07-24 stsp return err;
10194 0ebf8283 2019-07-24 stsp }
10195 0ebf8283 2019-07-24 stsp
10196 bfce7f83 2019-07-27 stsp void
10197 bfce7f83 2019-07-27 stsp histedit_free_list(struct got_histedit_list *histedit_cmds)
10198 bfce7f83 2019-07-27 stsp {
10199 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
10200 bfce7f83 2019-07-27 stsp
10201 bfce7f83 2019-07-27 stsp while ((hle = TAILQ_FIRST(histedit_cmds))) {
10202 bfce7f83 2019-07-27 stsp TAILQ_REMOVE(histedit_cmds, hle, entry);
10203 bfce7f83 2019-07-27 stsp free(hle);
10204 bfce7f83 2019-07-27 stsp }
10205 bfce7f83 2019-07-27 stsp }
10206 bfce7f83 2019-07-27 stsp
10207 0ebf8283 2019-07-24 stsp static const struct got_error *
10208 0ebf8283 2019-07-24 stsp histedit_load_list(struct got_histedit_list *histedit_cmds,
10209 0ebf8283 2019-07-24 stsp const char *path, struct got_repository *repo)
10210 0ebf8283 2019-07-24 stsp {
10211 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
10212 0ebf8283 2019-07-24 stsp FILE *f = NULL;
10213 0ebf8283 2019-07-24 stsp
10214 00fe21f2 2021-12-31 stsp f = fopen(path, "re");
10215 0ebf8283 2019-07-24 stsp if (f == NULL) {
10216 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
10217 0ebf8283 2019-07-24 stsp goto done;
10218 0ebf8283 2019-07-24 stsp }
10219 0ebf8283 2019-07-24 stsp
10220 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
10221 0ebf8283 2019-07-24 stsp done:
10222 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
10223 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
10224 0ebf8283 2019-07-24 stsp return err;
10225 0ebf8283 2019-07-24 stsp }
10226 0ebf8283 2019-07-24 stsp
10227 0ebf8283 2019-07-24 stsp static const struct got_error *
10228 0ebf8283 2019-07-24 stsp histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
10229 bfce7f83 2019-07-27 stsp const struct got_error *edit_err, struct got_object_id_queue *commits,
10230 514f2ffe 2020-01-29 stsp const char *path, const char *branch_name, struct got_repository *repo)
10231 0ebf8283 2019-07-24 stsp {
10232 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL, *prev_err = edit_err;
10233 0ebf8283 2019-07-24 stsp int resp = ' ';
10234 0ebf8283 2019-07-24 stsp
10235 b006047e 2019-07-25 stsp while (resp != 'c' && resp != 'r' && resp != 'a') {
10236 0ebf8283 2019-07-24 stsp printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
10237 bfce7f83 2019-07-27 stsp "or (a)bort: ", getprogname(), prev_err->msg);
10238 0ebf8283 2019-07-24 stsp resp = getchar();
10239 a61a4414 2019-08-07 stsp if (resp == '\n')
10240 a61a4414 2019-08-07 stsp resp = getchar();
10241 426ebf2e 2019-07-25 stsp if (resp == 'c') {
10242 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
10243 bfce7f83 2019-07-27 stsp err = histedit_run_editor(histedit_cmds, path, commits,
10244 bfce7f83 2019-07-27 stsp repo);
10245 426ebf2e 2019-07-25 stsp if (err) {
10246 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
10247 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
10248 426ebf2e 2019-07-25 stsp break;
10249 bfce7f83 2019-07-27 stsp prev_err = err;
10250 426ebf2e 2019-07-25 stsp resp = ' ';
10251 426ebf2e 2019-07-25 stsp continue;
10252 426ebf2e 2019-07-25 stsp }
10253 bfce7f83 2019-07-27 stsp break;
10254 426ebf2e 2019-07-25 stsp } else if (resp == 'r') {
10255 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
10256 0ebf8283 2019-07-24 stsp err = histedit_edit_script(histedit_cmds,
10257 b93c7142 2021-10-01 stsp commits, branch_name, 0, 0, 0, repo);
10258 426ebf2e 2019-07-25 stsp if (err) {
10259 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
10260 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
10261 426ebf2e 2019-07-25 stsp break;
10262 bfce7f83 2019-07-27 stsp prev_err = err;
10263 426ebf2e 2019-07-25 stsp resp = ' ';
10264 426ebf2e 2019-07-25 stsp continue;
10265 426ebf2e 2019-07-25 stsp }
10266 bfce7f83 2019-07-27 stsp break;
10267 426ebf2e 2019-07-25 stsp } else if (resp == 'a') {
10268 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CANCEL);
10269 0ebf8283 2019-07-24 stsp break;
10270 426ebf2e 2019-07-25 stsp } else
10271 0ebf8283 2019-07-24 stsp printf("invalid response '%c'\n", resp);
10272 0ebf8283 2019-07-24 stsp }
10273 0ebf8283 2019-07-24 stsp
10274 0ebf8283 2019-07-24 stsp return err;
10275 0ebf8283 2019-07-24 stsp }
10276 0ebf8283 2019-07-24 stsp
10277 0ebf8283 2019-07-24 stsp static const struct got_error *
10278 0ebf8283 2019-07-24 stsp histedit_complete(struct got_worktree *worktree,
10279 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex, struct got_reference *tmp_branch,
10280 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_repository *repo)
10281 0ebf8283 2019-07-24 stsp {
10282 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
10283 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
10284 3e3a69f1 2019-07-25 stsp return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
10285 3e3a69f1 2019-07-25 stsp branch, repo);
10286 0ebf8283 2019-07-24 stsp }
10287 0ebf8283 2019-07-24 stsp
10288 0ebf8283 2019-07-24 stsp static const struct got_error *
10289 0ebf8283 2019-07-24 stsp show_histedit_progress(struct got_commit_object *commit,
10290 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle, struct got_object_id *new_id)
10291 0ebf8283 2019-07-24 stsp {
10292 0ebf8283 2019-07-24 stsp const struct got_error *err;
10293 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
10294 0ebf8283 2019-07-24 stsp
10295 0ebf8283 2019-07-24 stsp err = got_object_id_str(&old_id_str, hle->commit_id);
10296 0ebf8283 2019-07-24 stsp if (err)
10297 0ebf8283 2019-07-24 stsp goto done;
10298 0ebf8283 2019-07-24 stsp
10299 0ebf8283 2019-07-24 stsp if (new_id) {
10300 0ebf8283 2019-07-24 stsp err = got_object_id_str(&new_id_str, new_id);
10301 0ebf8283 2019-07-24 stsp if (err)
10302 0ebf8283 2019-07-24 stsp goto done;
10303 0ebf8283 2019-07-24 stsp }
10304 0ebf8283 2019-07-24 stsp
10305 0ebf8283 2019-07-24 stsp old_id_str[12] = '\0';
10306 0ebf8283 2019-07-24 stsp if (new_id_str)
10307 0ebf8283 2019-07-24 stsp new_id_str[12] = '\0';
10308 0ebf8283 2019-07-24 stsp
10309 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
10310 0ebf8283 2019-07-24 stsp logmsg = strdup(hle->logmsg);
10311 0ebf8283 2019-07-24 stsp if (logmsg == NULL) {
10312 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
10313 0ebf8283 2019-07-24 stsp goto done;
10314 0ebf8283 2019-07-24 stsp }
10315 0ebf8283 2019-07-24 stsp trim_logmsg(logmsg, 42);
10316 0ebf8283 2019-07-24 stsp } else {
10317 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
10318 0ebf8283 2019-07-24 stsp if (err)
10319 0ebf8283 2019-07-24 stsp goto done;
10320 0ebf8283 2019-07-24 stsp }
10321 0ebf8283 2019-07-24 stsp
10322 0ebf8283 2019-07-24 stsp switch (hle->cmd->code) {
10323 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_PICK:
10324 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_EDIT:
10325 0ebf8283 2019-07-24 stsp printf("%s -> %s: %s\n", old_id_str,
10326 0ebf8283 2019-07-24 stsp new_id_str ? new_id_str : "no-op change", logmsg);
10327 0ebf8283 2019-07-24 stsp break;
10328 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_DROP:
10329 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_FOLD:
10330 0ebf8283 2019-07-24 stsp printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
10331 0ebf8283 2019-07-24 stsp logmsg);
10332 0ebf8283 2019-07-24 stsp break;
10333 0ebf8283 2019-07-24 stsp default:
10334 0ebf8283 2019-07-24 stsp break;
10335 0ebf8283 2019-07-24 stsp }
10336 0ebf8283 2019-07-24 stsp done:
10337 0ebf8283 2019-07-24 stsp free(old_id_str);
10338 0ebf8283 2019-07-24 stsp free(new_id_str);
10339 0ebf8283 2019-07-24 stsp return err;
10340 0ebf8283 2019-07-24 stsp }
10341 0ebf8283 2019-07-24 stsp
10342 0ebf8283 2019-07-24 stsp static const struct got_error *
10343 0ebf8283 2019-07-24 stsp histedit_commit(struct got_pathlist_head *merged_paths,
10344 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
10345 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
10346 3e3a69f1 2019-07-25 stsp struct got_repository *repo)
10347 0ebf8283 2019-07-24 stsp {
10348 0ebf8283 2019-07-24 stsp const struct got_error *err;
10349 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
10350 0ebf8283 2019-07-24 stsp struct got_object_id *new_commit_id;
10351 0ebf8283 2019-07-24 stsp
10352 0ebf8283 2019-07-24 stsp if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
10353 0ebf8283 2019-07-24 stsp && hle->logmsg == NULL) {
10354 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
10355 0ebf8283 2019-07-24 stsp if (err)
10356 0ebf8283 2019-07-24 stsp return err;
10357 0ebf8283 2019-07-24 stsp }
10358 0ebf8283 2019-07-24 stsp
10359 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
10360 0ebf8283 2019-07-24 stsp if (err)
10361 0ebf8283 2019-07-24 stsp return err;
10362 0ebf8283 2019-07-24 stsp
10363 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
10364 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, hle->commit_id,
10365 3e3a69f1 2019-07-25 stsp hle->logmsg, repo);
10366 0ebf8283 2019-07-24 stsp if (err) {
10367 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
10368 0ebf8283 2019-07-24 stsp goto done;
10369 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, NULL);
10370 0ebf8283 2019-07-24 stsp } else {
10371 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, new_commit_id);
10372 0ebf8283 2019-07-24 stsp free(new_commit_id);
10373 0ebf8283 2019-07-24 stsp }
10374 0ebf8283 2019-07-24 stsp done:
10375 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10376 0ebf8283 2019-07-24 stsp return err;
10377 0ebf8283 2019-07-24 stsp }
10378 0ebf8283 2019-07-24 stsp
10379 0ebf8283 2019-07-24 stsp static const struct got_error *
10380 0ebf8283 2019-07-24 stsp histedit_skip_commit(struct got_histedit_list_entry *hle,
10381 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
10382 0ebf8283 2019-07-24 stsp {
10383 0ebf8283 2019-07-24 stsp const struct got_error *error;
10384 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
10385 0ebf8283 2019-07-24 stsp
10386 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
10387 0ebf8283 2019-07-24 stsp repo);
10388 0ebf8283 2019-07-24 stsp if (error)
10389 0ebf8283 2019-07-24 stsp return error;
10390 0ebf8283 2019-07-24 stsp
10391 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo, hle->commit_id);
10392 0ebf8283 2019-07-24 stsp if (error)
10393 0ebf8283 2019-07-24 stsp return error;
10394 0ebf8283 2019-07-24 stsp
10395 0ebf8283 2019-07-24 stsp error = show_histedit_progress(commit, hle, NULL);
10396 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10397 0ebf8283 2019-07-24 stsp return error;
10398 ab20a43a 2020-01-29 stsp }
10399 ab20a43a 2020-01-29 stsp
10400 ab20a43a 2020-01-29 stsp static const struct got_error *
10401 ab20a43a 2020-01-29 stsp check_local_changes(void *arg, unsigned char status,
10402 ab20a43a 2020-01-29 stsp unsigned char staged_status, const char *path,
10403 ab20a43a 2020-01-29 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
10404 ab20a43a 2020-01-29 stsp struct got_object_id *commit_id, int dirfd, const char *de_name)
10405 ab20a43a 2020-01-29 stsp {
10406 ab20a43a 2020-01-29 stsp int *have_local_changes = arg;
10407 ab20a43a 2020-01-29 stsp
10408 ab20a43a 2020-01-29 stsp switch (status) {
10409 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
10410 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
10411 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
10412 ab20a43a 2020-01-29 stsp case GOT_STATUS_CONFLICT:
10413 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
10414 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
10415 ab20a43a 2020-01-29 stsp default:
10416 ab20a43a 2020-01-29 stsp break;
10417 ab20a43a 2020-01-29 stsp }
10418 ab20a43a 2020-01-29 stsp
10419 ab20a43a 2020-01-29 stsp switch (staged_status) {
10420 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
10421 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
10422 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
10423 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
10424 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
10425 ab20a43a 2020-01-29 stsp default:
10426 ab20a43a 2020-01-29 stsp break;
10427 ab20a43a 2020-01-29 stsp }
10428 ab20a43a 2020-01-29 stsp
10429 ab20a43a 2020-01-29 stsp return NULL;
10430 0ebf8283 2019-07-24 stsp }
10431 0ebf8283 2019-07-24 stsp
10432 0ebf8283 2019-07-24 stsp static const struct got_error *
10433 0ebf8283 2019-07-24 stsp cmd_histedit(int argc, char *argv[])
10434 0ebf8283 2019-07-24 stsp {
10435 0ebf8283 2019-07-24 stsp const struct got_error *error = NULL;
10436 0ebf8283 2019-07-24 stsp struct got_worktree *worktree = NULL;
10437 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
10438 0ebf8283 2019-07-24 stsp struct got_repository *repo = NULL;
10439 0ebf8283 2019-07-24 stsp char *cwd = NULL;
10440 0ebf8283 2019-07-24 stsp struct got_reference *branch = NULL;
10441 0ebf8283 2019-07-24 stsp struct got_reference *tmp_branch = NULL;
10442 0ebf8283 2019-07-24 stsp struct got_object_id *resume_commit_id = NULL;
10443 0ebf8283 2019-07-24 stsp struct got_object_id *base_commit_id = NULL;
10444 0ebf8283 2019-07-24 stsp struct got_object_id *head_commit_id = NULL;
10445 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
10446 f259c4c1 2021-09-24 stsp int ch, rebase_in_progress = 0, merge_in_progress = 0;
10447 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
10448 0ebf8283 2019-07-24 stsp int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
10449 b93c7142 2021-10-01 stsp int edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
10450 643b85bc 2021-07-16 stsp int list_backups = 0, delete_backups = 0;
10451 0ebf8283 2019-07-24 stsp const char *edit_script_path = NULL;
10452 0ebf8283 2019-07-24 stsp struct got_object_id_queue commits;
10453 0ebf8283 2019-07-24 stsp struct got_pathlist_head merged_paths;
10454 0ebf8283 2019-07-24 stsp const struct got_object_id_queue *parent_ids;
10455 0ebf8283 2019-07-24 stsp struct got_object_qid *pid;
10456 0ebf8283 2019-07-24 stsp struct got_histedit_list histedit_cmds;
10457 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
10458 0ebf8283 2019-07-24 stsp
10459 dbdddfee 2021-06-23 naddy STAILQ_INIT(&commits);
10460 0ebf8283 2019-07-24 stsp TAILQ_INIT(&histedit_cmds);
10461 0ebf8283 2019-07-24 stsp TAILQ_INIT(&merged_paths);
10462 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
10463 0ebf8283 2019-07-24 stsp
10464 b93c7142 2021-10-01 stsp while ((ch = getopt(argc, argv, "acefF:mlX")) != -1) {
10465 0ebf8283 2019-07-24 stsp switch (ch) {
10466 0ebf8283 2019-07-24 stsp case 'a':
10467 0ebf8283 2019-07-24 stsp abort_edit = 1;
10468 0ebf8283 2019-07-24 stsp break;
10469 0ebf8283 2019-07-24 stsp case 'c':
10470 0ebf8283 2019-07-24 stsp continue_edit = 1;
10471 0ebf8283 2019-07-24 stsp break;
10472 b93c7142 2021-10-01 stsp case 'e':
10473 b93c7142 2021-10-01 stsp edit_only = 1;
10474 b93c7142 2021-10-01 stsp break;
10475 466785b9 2020-12-10 jrick case 'f':
10476 466785b9 2020-12-10 jrick fold_only = 1;
10477 466785b9 2020-12-10 jrick break;
10478 0ebf8283 2019-07-24 stsp case 'F':
10479 0ebf8283 2019-07-24 stsp edit_script_path = optarg;
10480 0ebf8283 2019-07-24 stsp break;
10481 083957f4 2020-02-24 stsp case 'm':
10482 083957f4 2020-02-24 stsp edit_logmsg_only = 1;
10483 083957f4 2020-02-24 stsp break;
10484 e600f124 2021-03-21 stsp case 'l':
10485 e600f124 2021-03-21 stsp list_backups = 1;
10486 e600f124 2021-03-21 stsp break;
10487 643b85bc 2021-07-16 stsp case 'X':
10488 643b85bc 2021-07-16 stsp delete_backups = 1;
10489 643b85bc 2021-07-16 stsp break;
10490 0ebf8283 2019-07-24 stsp default:
10491 0ebf8283 2019-07-24 stsp usage_histedit();
10492 0ebf8283 2019-07-24 stsp /* NOTREACHED */
10493 0ebf8283 2019-07-24 stsp }
10494 0ebf8283 2019-07-24 stsp }
10495 0ebf8283 2019-07-24 stsp
10496 0ebf8283 2019-07-24 stsp argc -= optind;
10497 0ebf8283 2019-07-24 stsp argv += optind;
10498 0ebf8283 2019-07-24 stsp
10499 0ebf8283 2019-07-24 stsp #ifndef PROFILE
10500 0ebf8283 2019-07-24 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10501 0ebf8283 2019-07-24 stsp "unveil", NULL) == -1)
10502 0ebf8283 2019-07-24 stsp err(1, "pledge");
10503 0ebf8283 2019-07-24 stsp #endif
10504 0ebf8283 2019-07-24 stsp if (abort_edit && continue_edit)
10505 ff69268e 2020-12-13 stsp option_conflict('a', 'c');
10506 083957f4 2020-02-24 stsp if (edit_script_path && edit_logmsg_only)
10507 ff69268e 2020-12-13 stsp option_conflict('F', 'm');
10508 083957f4 2020-02-24 stsp if (abort_edit && edit_logmsg_only)
10509 ff69268e 2020-12-13 stsp option_conflict('a', 'm');
10510 083957f4 2020-02-24 stsp if (continue_edit && edit_logmsg_only)
10511 ff69268e 2020-12-13 stsp option_conflict('c', 'm');
10512 466785b9 2020-12-10 jrick if (abort_edit && fold_only)
10513 ff69268e 2020-12-13 stsp option_conflict('a', 'f');
10514 ff69268e 2020-12-13 stsp if (continue_edit && fold_only)
10515 ff69268e 2020-12-13 stsp option_conflict('c', 'f');
10516 466785b9 2020-12-10 jrick if (fold_only && edit_logmsg_only)
10517 ff69268e 2020-12-13 stsp option_conflict('f', 'm');
10518 b3805337 2020-12-13 stsp if (edit_script_path && fold_only)
10519 b3805337 2020-12-13 stsp option_conflict('F', 'f');
10520 b93c7142 2021-10-01 stsp if (abort_edit && edit_only)
10521 b93c7142 2021-10-01 stsp option_conflict('a', 'e');
10522 b93c7142 2021-10-01 stsp if (continue_edit && edit_only)
10523 b93c7142 2021-10-01 stsp option_conflict('c', 'e');
10524 b93c7142 2021-10-01 stsp if (edit_only && edit_logmsg_only)
10525 b93c7142 2021-10-01 stsp option_conflict('e', 'm');
10526 b93c7142 2021-10-01 stsp if (edit_script_path && edit_only)
10527 b93c7142 2021-10-01 stsp option_conflict('F', 'e');
10528 e600f124 2021-03-21 stsp if (list_backups) {
10529 e600f124 2021-03-21 stsp if (abort_edit)
10530 e600f124 2021-03-21 stsp option_conflict('l', 'a');
10531 e600f124 2021-03-21 stsp if (continue_edit)
10532 e600f124 2021-03-21 stsp option_conflict('l', 'c');
10533 e600f124 2021-03-21 stsp if (edit_script_path)
10534 e600f124 2021-03-21 stsp option_conflict('l', 'F');
10535 e600f124 2021-03-21 stsp if (edit_logmsg_only)
10536 e600f124 2021-03-21 stsp option_conflict('l', 'm');
10537 e600f124 2021-03-21 stsp if (fold_only)
10538 e600f124 2021-03-21 stsp option_conflict('l', 'f');
10539 b93c7142 2021-10-01 stsp if (edit_only)
10540 b93c7142 2021-10-01 stsp option_conflict('l', 'e');
10541 643b85bc 2021-07-16 stsp if (delete_backups)
10542 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
10543 e600f124 2021-03-21 stsp if (argc != 0 && argc != 1)
10544 e600f124 2021-03-21 stsp usage_histedit();
10545 643b85bc 2021-07-16 stsp } else if (delete_backups) {
10546 643b85bc 2021-07-16 stsp if (abort_edit)
10547 643b85bc 2021-07-16 stsp option_conflict('X', 'a');
10548 643b85bc 2021-07-16 stsp if (continue_edit)
10549 643b85bc 2021-07-16 stsp option_conflict('X', 'c');
10550 643b85bc 2021-07-16 stsp if (edit_script_path)
10551 643b85bc 2021-07-16 stsp option_conflict('X', 'F');
10552 643b85bc 2021-07-16 stsp if (edit_logmsg_only)
10553 643b85bc 2021-07-16 stsp option_conflict('X', 'm');
10554 643b85bc 2021-07-16 stsp if (fold_only)
10555 643b85bc 2021-07-16 stsp option_conflict('X', 'f');
10556 b93c7142 2021-10-01 stsp if (edit_only)
10557 b93c7142 2021-10-01 stsp option_conflict('X', 'e');
10558 643b85bc 2021-07-16 stsp if (list_backups)
10559 643b85bc 2021-07-16 stsp option_conflict('X', 'l');
10560 643b85bc 2021-07-16 stsp if (argc != 0 && argc != 1)
10561 643b85bc 2021-07-16 stsp usage_histedit();
10562 e600f124 2021-03-21 stsp } else if (argc != 0)
10563 0ebf8283 2019-07-24 stsp usage_histedit();
10564 0ebf8283 2019-07-24 stsp
10565 0ebf8283 2019-07-24 stsp /*
10566 0ebf8283 2019-07-24 stsp * This command cannot apply unveil(2) in all cases because the
10567 0ebf8283 2019-07-24 stsp * user may choose to run an editor to edit the histedit script
10568 0ebf8283 2019-07-24 stsp * and to edit individual commit log messages.
10569 0ebf8283 2019-07-24 stsp * unveil(2) traverses exec(2); if an editor is used we have to
10570 0ebf8283 2019-07-24 stsp * apply unveil after edit script and log messages have been written.
10571 0ebf8283 2019-07-24 stsp * XXX TODO: Make use of unveil(2) where possible.
10572 0ebf8283 2019-07-24 stsp */
10573 0ebf8283 2019-07-24 stsp
10574 0ebf8283 2019-07-24 stsp cwd = getcwd(NULL, 0);
10575 0ebf8283 2019-07-24 stsp if (cwd == NULL) {
10576 0ebf8283 2019-07-24 stsp error = got_error_from_errno("getcwd");
10577 0ebf8283 2019-07-24 stsp goto done;
10578 0ebf8283 2019-07-24 stsp }
10579 0ebf8283 2019-07-24 stsp error = got_worktree_open(&worktree, cwd);
10580 fa51e947 2020-03-27 stsp if (error) {
10581 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
10582 e600f124 2021-03-21 stsp if (error->code != GOT_ERR_NOT_WORKTREE)
10583 e600f124 2021-03-21 stsp goto done;
10584 e600f124 2021-03-21 stsp } else {
10585 e600f124 2021-03-21 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
10586 e600f124 2021-03-21 stsp error = wrap_not_worktree_error(error,
10587 e600f124 2021-03-21 stsp "histedit", cwd);
10588 e600f124 2021-03-21 stsp goto done;
10589 e600f124 2021-03-21 stsp }
10590 e600f124 2021-03-21 stsp }
10591 e600f124 2021-03-21 stsp
10592 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
10593 e600f124 2021-03-21 stsp error = got_repo_open(&repo,
10594 e600f124 2021-03-21 stsp worktree ? got_worktree_get_repo_path(worktree) : cwd,
10595 e600f124 2021-03-21 stsp NULL);
10596 e600f124 2021-03-21 stsp if (error != NULL)
10597 e600f124 2021-03-21 stsp goto done;
10598 e600f124 2021-03-21 stsp error = apply_unveil(got_repo_get_path(repo), 0,
10599 e600f124 2021-03-21 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
10600 e600f124 2021-03-21 stsp if (error)
10601 e600f124 2021-03-21 stsp goto done;
10602 643b85bc 2021-07-16 stsp error = process_backup_refs(
10603 e600f124 2021-03-21 stsp GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
10604 643b85bc 2021-07-16 stsp argc == 1 ? argv[0] : NULL, delete_backups, repo);
10605 e600f124 2021-03-21 stsp goto done; /* nothing else to do */
10606 fa51e947 2020-03-27 stsp }
10607 0ebf8283 2019-07-24 stsp
10608 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
10609 c9956ddf 2019-09-08 stsp NULL);
10610 0ebf8283 2019-07-24 stsp if (error != NULL)
10611 0ebf8283 2019-07-24 stsp goto done;
10612 0ebf8283 2019-07-24 stsp
10613 0ebf8283 2019-07-24 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
10614 0ebf8283 2019-07-24 stsp if (error)
10615 0ebf8283 2019-07-24 stsp goto done;
10616 0ebf8283 2019-07-24 stsp if (rebase_in_progress) {
10617 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_REBASING);
10618 f259c4c1 2021-09-24 stsp goto done;
10619 f259c4c1 2021-09-24 stsp }
10620 f259c4c1 2021-09-24 stsp
10621 f259c4c1 2021-09-24 stsp error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
10622 f259c4c1 2021-09-24 stsp repo);
10623 f259c4c1 2021-09-24 stsp if (error)
10624 f259c4c1 2021-09-24 stsp goto done;
10625 f259c4c1 2021-09-24 stsp if (merge_in_progress) {
10626 f259c4c1 2021-09-24 stsp error = got_error(GOT_ERR_MERGE_BUSY);
10627 0ebf8283 2019-07-24 stsp goto done;
10628 0ebf8283 2019-07-24 stsp }
10629 0ebf8283 2019-07-24 stsp
10630 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
10631 0ebf8283 2019-07-24 stsp if (error)
10632 0ebf8283 2019-07-24 stsp goto done;
10633 0ebf8283 2019-07-24 stsp
10634 083957f4 2020-02-24 stsp if (edit_in_progress && edit_logmsg_only) {
10635 083957f4 2020-02-24 stsp error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
10636 083957f4 2020-02-24 stsp "histedit operation is in progress in this "
10637 083957f4 2020-02-24 stsp "work tree and must be continued or aborted "
10638 083957f4 2020-02-24 stsp "before the -m option can be used");
10639 083957f4 2020-02-24 stsp goto done;
10640 083957f4 2020-02-24 stsp }
10641 466785b9 2020-12-10 jrick if (edit_in_progress && fold_only) {
10642 466785b9 2020-12-10 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
10643 466785b9 2020-12-10 jrick "histedit operation is in progress in this "
10644 466785b9 2020-12-10 jrick "work tree and must be continued or aborted "
10645 466785b9 2020-12-10 jrick "before the -f option can be used");
10646 466785b9 2020-12-10 jrick goto done;
10647 466785b9 2020-12-10 jrick }
10648 b93c7142 2021-10-01 stsp if (edit_in_progress && edit_only) {
10649 b93c7142 2021-10-01 stsp error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
10650 b93c7142 2021-10-01 stsp "histedit operation is in progress in this "
10651 b93c7142 2021-10-01 stsp "work tree and must be continued or aborted "
10652 b93c7142 2021-10-01 stsp "before the -e option can be used");
10653 b93c7142 2021-10-01 stsp goto done;
10654 b93c7142 2021-10-01 stsp }
10655 083957f4 2020-02-24 stsp
10656 0ebf8283 2019-07-24 stsp if (edit_in_progress && abort_edit) {
10657 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
10658 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
10659 3e3a69f1 2019-07-25 stsp worktree, repo);
10660 0ebf8283 2019-07-24 stsp if (error)
10661 0ebf8283 2019-07-24 stsp goto done;
10662 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
10663 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
10664 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_abort(worktree, fileindex, repo,
10665 41f061b2 2021-10-05 stsp branch, base_commit_id, abort_progress, &upa);
10666 0ebf8283 2019-07-24 stsp if (error)
10667 0ebf8283 2019-07-24 stsp goto done;
10668 0ebf8283 2019-07-24 stsp printf("Histedit of %s aborted\n",
10669 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
10670 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
10671 0ebf8283 2019-07-24 stsp goto done; /* nothing else to do */
10672 0ebf8283 2019-07-24 stsp } else if (abort_edit) {
10673 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
10674 0ebf8283 2019-07-24 stsp goto done;
10675 0ebf8283 2019-07-24 stsp }
10676 0ebf8283 2019-07-24 stsp
10677 0ebf8283 2019-07-24 stsp if (continue_edit) {
10678 0ebf8283 2019-07-24 stsp char *path;
10679 0ebf8283 2019-07-24 stsp
10680 0ebf8283 2019-07-24 stsp if (!edit_in_progress) {
10681 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
10682 0ebf8283 2019-07-24 stsp goto done;
10683 0ebf8283 2019-07-24 stsp }
10684 0ebf8283 2019-07-24 stsp
10685 c3022ba5 2019-07-27 stsp error = got_worktree_get_histedit_script_path(&path, worktree);
10686 0ebf8283 2019-07-24 stsp if (error)
10687 0ebf8283 2019-07-24 stsp goto done;
10688 0ebf8283 2019-07-24 stsp
10689 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds, path, repo);
10690 0ebf8283 2019-07-24 stsp free(path);
10691 0ebf8283 2019-07-24 stsp if (error)
10692 0ebf8283 2019-07-24 stsp goto done;
10693 0ebf8283 2019-07-24 stsp
10694 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
10695 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
10696 3e3a69f1 2019-07-25 stsp worktree, repo);
10697 0ebf8283 2019-07-24 stsp if (error)
10698 0ebf8283 2019-07-24 stsp goto done;
10699 0ebf8283 2019-07-24 stsp
10700 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
10701 0ebf8283 2019-07-24 stsp if (error)
10702 0ebf8283 2019-07-24 stsp goto done;
10703 0ebf8283 2019-07-24 stsp
10704 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10705 0ebf8283 2019-07-24 stsp head_commit_id);
10706 0ebf8283 2019-07-24 stsp if (error)
10707 0ebf8283 2019-07-24 stsp goto done;
10708 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10709 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10710 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
10711 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10712 3aac7cf7 2019-07-25 stsp goto done;
10713 3aac7cf7 2019-07-25 stsp }
10714 d7b5a0e8 2022-04-20 stsp error = collect_commits(&commits, head_commit_id, &pid->id,
10715 8ca9bd68 2019-07-25 stsp base_commit_id, got_worktree_get_path_prefix(worktree),
10716 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
10717 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10718 0ebf8283 2019-07-24 stsp commit = NULL;
10719 0ebf8283 2019-07-24 stsp if (error)
10720 0ebf8283 2019-07-24 stsp goto done;
10721 0ebf8283 2019-07-24 stsp } else {
10722 0ebf8283 2019-07-24 stsp if (edit_in_progress) {
10723 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
10724 0ebf8283 2019-07-24 stsp goto done;
10725 0ebf8283 2019-07-24 stsp }
10726 0ebf8283 2019-07-24 stsp
10727 0ebf8283 2019-07-24 stsp error = got_ref_open(&branch, repo,
10728 0ebf8283 2019-07-24 stsp got_worktree_get_head_ref_name(worktree), 0);
10729 0ebf8283 2019-07-24 stsp if (error != NULL)
10730 0ebf8283 2019-07-24 stsp goto done;
10731 0ebf8283 2019-07-24 stsp
10732 c7d20a3f 2019-07-30 stsp if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
10733 c7d20a3f 2019-07-30 stsp error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
10734 c7d20a3f 2019-07-30 stsp "will not edit commit history of a branch outside "
10735 c7d20a3f 2019-07-30 stsp "the \"refs/heads/\" reference namespace");
10736 c7d20a3f 2019-07-30 stsp goto done;
10737 c7d20a3f 2019-07-30 stsp }
10738 c7d20a3f 2019-07-30 stsp
10739 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
10740 bfce7f83 2019-07-27 stsp got_ref_close(branch);
10741 bfce7f83 2019-07-27 stsp branch = NULL;
10742 0ebf8283 2019-07-24 stsp if (error)
10743 0ebf8283 2019-07-24 stsp goto done;
10744 0ebf8283 2019-07-24 stsp
10745 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10746 0ebf8283 2019-07-24 stsp head_commit_id);
10747 0ebf8283 2019-07-24 stsp if (error)
10748 0ebf8283 2019-07-24 stsp goto done;
10749 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10750 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10751 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
10752 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10753 3aac7cf7 2019-07-25 stsp goto done;
10754 3aac7cf7 2019-07-25 stsp }
10755 d7b5a0e8 2022-04-20 stsp error = collect_commits(&commits, head_commit_id, &pid->id,
10756 8ca9bd68 2019-07-25 stsp got_worktree_get_base_commit_id(worktree),
10757 8ca9bd68 2019-07-25 stsp got_worktree_get_path_prefix(worktree),
10758 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
10759 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10760 0ebf8283 2019-07-24 stsp commit = NULL;
10761 0ebf8283 2019-07-24 stsp if (error)
10762 0ebf8283 2019-07-24 stsp goto done;
10763 0ebf8283 2019-07-24 stsp
10764 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(&commits)) {
10765 c5996fff 2020-01-29 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10766 c5996fff 2020-01-29 stsp goto done;
10767 c5996fff 2020-01-29 stsp }
10768 c5996fff 2020-01-29 stsp
10769 bfce7f83 2019-07-27 stsp error = got_worktree_histedit_prepare(&tmp_branch, &branch,
10770 bfce7f83 2019-07-27 stsp &base_commit_id, &fileindex, worktree, repo);
10771 bfce7f83 2019-07-27 stsp if (error)
10772 bfce7f83 2019-07-27 stsp goto done;
10773 bfce7f83 2019-07-27 stsp
10774 0ebf8283 2019-07-24 stsp if (edit_script_path) {
10775 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds,
10776 0ebf8283 2019-07-24 stsp edit_script_path, repo);
10777 6ba2bea2 2019-07-27 stsp if (error) {
10778 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10779 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10780 41f061b2 2021-10-05 stsp abort_progress, &upa);
10781 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
10782 0ebf8283 2019-07-24 stsp goto done;
10783 6ba2bea2 2019-07-27 stsp }
10784 0ebf8283 2019-07-24 stsp } else {
10785 514f2ffe 2020-01-29 stsp const char *branch_name;
10786 514f2ffe 2020-01-29 stsp branch_name = got_ref_get_symref_target(branch);
10787 514f2ffe 2020-01-29 stsp if (strncmp(branch_name, "refs/heads/", 11) == 0)
10788 514f2ffe 2020-01-29 stsp branch_name += 11;
10789 0ebf8283 2019-07-24 stsp error = histedit_edit_script(&histedit_cmds, &commits,
10790 b93c7142 2021-10-01 stsp branch_name, edit_logmsg_only, fold_only,
10791 b93c7142 2021-10-01 stsp edit_only, repo);
10792 6ba2bea2 2019-07-27 stsp if (error) {
10793 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10794 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10795 41f061b2 2021-10-05 stsp abort_progress, &upa);
10796 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
10797 0ebf8283 2019-07-24 stsp goto done;
10798 6ba2bea2 2019-07-27 stsp }
10799 0ebf8283 2019-07-24 stsp
10800 0ebf8283 2019-07-24 stsp }
10801 0ebf8283 2019-07-24 stsp
10802 0ebf8283 2019-07-24 stsp error = histedit_save_list(&histedit_cmds, worktree,
10803 0ebf8283 2019-07-24 stsp repo);
10804 6ba2bea2 2019-07-27 stsp if (error) {
10805 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10806 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10807 41f061b2 2021-10-05 stsp abort_progress, &upa);
10808 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
10809 0ebf8283 2019-07-24 stsp goto done;
10810 6ba2bea2 2019-07-27 stsp }
10811 0ebf8283 2019-07-24 stsp
10812 0ebf8283 2019-07-24 stsp }
10813 0ebf8283 2019-07-24 stsp
10814 4ec14e60 2019-08-28 hiltjo error = histedit_check_script(&histedit_cmds, &commits, repo);
10815 4ec14e60 2019-08-28 hiltjo if (error)
10816 0ebf8283 2019-07-24 stsp goto done;
10817 0ebf8283 2019-07-24 stsp
10818 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, &histedit_cmds, entry) {
10819 0ebf8283 2019-07-24 stsp if (resume_commit_id) {
10820 0ebf8283 2019-07-24 stsp if (got_object_id_cmp(hle->commit_id,
10821 0ebf8283 2019-07-24 stsp resume_commit_id) != 0)
10822 0ebf8283 2019-07-24 stsp continue;
10823 0ebf8283 2019-07-24 stsp
10824 0ebf8283 2019-07-24 stsp resume_commit_id = NULL;
10825 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP ||
10826 0ebf8283 2019-07-24 stsp hle->cmd->code == GOT_HISTEDIT_FOLD) {
10827 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree,
10828 62d463ca 2020-10-20 naddy repo);
10829 ab20a43a 2020-01-29 stsp if (error)
10830 ab20a43a 2020-01-29 stsp goto done;
10831 0ebf8283 2019-07-24 stsp } else {
10832 ab20a43a 2020-01-29 stsp struct got_pathlist_head paths;
10833 ab20a43a 2020-01-29 stsp int have_changes = 0;
10834 ab20a43a 2020-01-29 stsp
10835 ab20a43a 2020-01-29 stsp TAILQ_INIT(&paths);
10836 ab20a43a 2020-01-29 stsp error = got_pathlist_append(&paths, "", NULL);
10837 ab20a43a 2020-01-29 stsp if (error)
10838 ab20a43a 2020-01-29 stsp goto done;
10839 ab20a43a 2020-01-29 stsp error = got_worktree_status(worktree, &paths,
10840 f6343036 2021-06-22 stsp repo, 0, check_local_changes, &have_changes,
10841 ab20a43a 2020-01-29 stsp check_cancelled, NULL);
10842 ab20a43a 2020-01-29 stsp got_pathlist_free(&paths);
10843 ab20a43a 2020-01-29 stsp if (error) {
10844 ab20a43a 2020-01-29 stsp if (error->code != GOT_ERR_CANCELLED)
10845 ab20a43a 2020-01-29 stsp goto done;
10846 ab20a43a 2020-01-29 stsp if (sigint_received || sigpipe_received)
10847 ab20a43a 2020-01-29 stsp goto done;
10848 ab20a43a 2020-01-29 stsp }
10849 ab20a43a 2020-01-29 stsp if (have_changes) {
10850 ab20a43a 2020-01-29 stsp error = histedit_commit(NULL, worktree,
10851 ab20a43a 2020-01-29 stsp fileindex, tmp_branch, hle, repo);
10852 ab20a43a 2020-01-29 stsp if (error)
10853 ab20a43a 2020-01-29 stsp goto done;
10854 ab20a43a 2020-01-29 stsp } else {
10855 ab20a43a 2020-01-29 stsp error = got_object_open_as_commit(
10856 ab20a43a 2020-01-29 stsp &commit, repo, hle->commit_id);
10857 ab20a43a 2020-01-29 stsp if (error)
10858 ab20a43a 2020-01-29 stsp goto done;
10859 ab20a43a 2020-01-29 stsp error = show_histedit_progress(commit,
10860 ab20a43a 2020-01-29 stsp hle, NULL);
10861 ab20a43a 2020-01-29 stsp got_object_commit_close(commit);
10862 ab20a43a 2020-01-29 stsp commit = NULL;
10863 ab20a43a 2020-01-29 stsp if (error)
10864 ab20a43a 2020-01-29 stsp goto done;
10865 ab20a43a 2020-01-29 stsp }
10866 0ebf8283 2019-07-24 stsp }
10867 0ebf8283 2019-07-24 stsp continue;
10868 0ebf8283 2019-07-24 stsp }
10869 0ebf8283 2019-07-24 stsp
10870 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP) {
10871 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
10872 0ebf8283 2019-07-24 stsp if (error)
10873 0ebf8283 2019-07-24 stsp goto done;
10874 0ebf8283 2019-07-24 stsp continue;
10875 0ebf8283 2019-07-24 stsp }
10876 0ebf8283 2019-07-24 stsp
10877 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10878 0ebf8283 2019-07-24 stsp hle->commit_id);
10879 0ebf8283 2019-07-24 stsp if (error)
10880 0ebf8283 2019-07-24 stsp goto done;
10881 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10882 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10883 0ebf8283 2019-07-24 stsp
10884 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_merge_files(&merged_paths,
10885 d7b5a0e8 2022-04-20 stsp worktree, fileindex, &pid->id, hle->commit_id, repo,
10886 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
10887 0ebf8283 2019-07-24 stsp if (error)
10888 0ebf8283 2019-07-24 stsp goto done;
10889 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10890 0ebf8283 2019-07-24 stsp commit = NULL;
10891 0ebf8283 2019-07-24 stsp
10892 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
10893 cd33da48 2021-09-28 stsp if (upa.conflicts > 0 || upa.missing > 0 ||
10894 cd33da48 2021-09-28 stsp upa.not_deleted > 0 || upa.unversioned > 0) {
10895 cd33da48 2021-09-28 stsp if (upa.conflicts > 0) {
10896 cd33da48 2021-09-28 stsp error = show_rebase_merge_conflict(
10897 cd33da48 2021-09-28 stsp hle->commit_id, repo);
10898 cd33da48 2021-09-28 stsp if (error)
10899 cd33da48 2021-09-28 stsp goto done;
10900 cd33da48 2021-09-28 stsp }
10901 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10902 0ebf8283 2019-07-24 stsp break;
10903 0ebf8283 2019-07-24 stsp }
10904 0ebf8283 2019-07-24 stsp
10905 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
10906 0ebf8283 2019-07-24 stsp char *id_str;
10907 0ebf8283 2019-07-24 stsp error = got_object_id_str(&id_str, hle->commit_id);
10908 0ebf8283 2019-07-24 stsp if (error)
10909 0ebf8283 2019-07-24 stsp goto done;
10910 0ebf8283 2019-07-24 stsp printf("Stopping histedit for amending commit %s\n",
10911 0ebf8283 2019-07-24 stsp id_str);
10912 0ebf8283 2019-07-24 stsp free(id_str);
10913 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10914 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree,
10915 3e3a69f1 2019-07-25 stsp fileindex);
10916 0ebf8283 2019-07-24 stsp goto done;
10917 0ebf8283 2019-07-24 stsp }
10918 0ebf8283 2019-07-24 stsp
10919 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
10920 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
10921 0ebf8283 2019-07-24 stsp if (error)
10922 0ebf8283 2019-07-24 stsp goto done;
10923 0ebf8283 2019-07-24 stsp continue;
10924 0ebf8283 2019-07-24 stsp }
10925 0ebf8283 2019-07-24 stsp
10926 3e3a69f1 2019-07-25 stsp error = histedit_commit(&merged_paths, worktree, fileindex,
10927 3e3a69f1 2019-07-25 stsp tmp_branch, hle, repo);
10928 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10929 0ebf8283 2019-07-24 stsp if (error)
10930 0ebf8283 2019-07-24 stsp goto done;
10931 0ebf8283 2019-07-24 stsp }
10932 0ebf8283 2019-07-24 stsp
10933 cd33da48 2021-09-28 stsp if (upa.conflicts > 0 || upa.missing > 0 ||
10934 cd33da48 2021-09-28 stsp upa.not_deleted > 0 || upa.unversioned > 0) {
10935 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree, fileindex);
10936 0ebf8283 2019-07-24 stsp if (error)
10937 0ebf8283 2019-07-24 stsp goto done;
10938 cd33da48 2021-09-28 stsp if (upa.conflicts > 0 && upa.missing == 0 &&
10939 cd33da48 2021-09-28 stsp upa.not_deleted == 0 && upa.unversioned == 0) {
10940 cd33da48 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
10941 cd33da48 2021-09-28 stsp "conflicts must be resolved before histedit "
10942 cd33da48 2021-09-28 stsp "can continue");
10943 cd33da48 2021-09-28 stsp } else if (upa.conflicts > 0) {
10944 cd33da48 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
10945 cd33da48 2021-09-28 stsp "conflicts must be resolved before histedit "
10946 cd33da48 2021-09-28 stsp "can continue; changes destined for some "
10947 cd33da48 2021-09-28 stsp "files were not yet merged and should be "
10948 cd33da48 2021-09-28 stsp "merged manually if required before the "
10949 cd33da48 2021-09-28 stsp "histedit operation is continued");
10950 cd33da48 2021-09-28 stsp } else {
10951 cd33da48 2021-09-28 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
10952 cd33da48 2021-09-28 stsp "changes destined for some files were not "
10953 cd33da48 2021-09-28 stsp "yet merged and should be merged manually "
10954 cd33da48 2021-09-28 stsp "if required before the histedit operation "
10955 cd33da48 2021-09-28 stsp "is continued");
10956 cd33da48 2021-09-28 stsp }
10957 0ebf8283 2019-07-24 stsp } else
10958 3e3a69f1 2019-07-25 stsp error = histedit_complete(worktree, fileindex, tmp_branch,
10959 3e3a69f1 2019-07-25 stsp branch, repo);
10960 0ebf8283 2019-07-24 stsp done:
10961 0ebf8283 2019-07-24 stsp got_object_id_queue_free(&commits);
10962 bfce7f83 2019-07-27 stsp histedit_free_list(&histedit_cmds);
10963 0ebf8283 2019-07-24 stsp free(head_commit_id);
10964 0ebf8283 2019-07-24 stsp free(base_commit_id);
10965 0ebf8283 2019-07-24 stsp free(resume_commit_id);
10966 0ebf8283 2019-07-24 stsp if (commit)
10967 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10968 0ebf8283 2019-07-24 stsp if (branch)
10969 0ebf8283 2019-07-24 stsp got_ref_close(branch);
10970 0ebf8283 2019-07-24 stsp if (tmp_branch)
10971 0ebf8283 2019-07-24 stsp got_ref_close(tmp_branch);
10972 0ebf8283 2019-07-24 stsp if (worktree)
10973 0ebf8283 2019-07-24 stsp got_worktree_close(worktree);
10974 1d0f4054 2021-06-17 stsp if (repo) {
10975 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
10976 1d0f4054 2021-06-17 stsp if (error == NULL)
10977 1d0f4054 2021-06-17 stsp error = close_err;
10978 1d0f4054 2021-06-17 stsp }
10979 2822a352 2019-10-15 stsp return error;
10980 2822a352 2019-10-15 stsp }
10981 2822a352 2019-10-15 stsp
10982 2822a352 2019-10-15 stsp __dead static void
10983 2822a352 2019-10-15 stsp usage_integrate(void)
10984 2822a352 2019-10-15 stsp {
10985 2822a352 2019-10-15 stsp fprintf(stderr, "usage: %s integrate branch\n", getprogname());
10986 2822a352 2019-10-15 stsp exit(1);
10987 2822a352 2019-10-15 stsp }
10988 2822a352 2019-10-15 stsp
10989 2822a352 2019-10-15 stsp static const struct got_error *
10990 2822a352 2019-10-15 stsp cmd_integrate(int argc, char *argv[])
10991 2822a352 2019-10-15 stsp {
10992 2822a352 2019-10-15 stsp const struct got_error *error = NULL;
10993 2822a352 2019-10-15 stsp struct got_repository *repo = NULL;
10994 2822a352 2019-10-15 stsp struct got_worktree *worktree = NULL;
10995 2822a352 2019-10-15 stsp char *cwd = NULL, *refname = NULL, *base_refname = NULL;
10996 2822a352 2019-10-15 stsp const char *branch_arg = NULL;
10997 2822a352 2019-10-15 stsp struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
10998 2822a352 2019-10-15 stsp struct got_fileindex *fileindex = NULL;
10999 2822a352 2019-10-15 stsp struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
11000 9627c110 2020-04-18 stsp int ch;
11001 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
11002 2822a352 2019-10-15 stsp
11003 2822a352 2019-10-15 stsp while ((ch = getopt(argc, argv, "")) != -1) {
11004 2822a352 2019-10-15 stsp switch (ch) {
11005 2822a352 2019-10-15 stsp default:
11006 2822a352 2019-10-15 stsp usage_integrate();
11007 2822a352 2019-10-15 stsp /* NOTREACHED */
11008 2822a352 2019-10-15 stsp }
11009 2822a352 2019-10-15 stsp }
11010 2822a352 2019-10-15 stsp
11011 2822a352 2019-10-15 stsp argc -= optind;
11012 2822a352 2019-10-15 stsp argv += optind;
11013 2822a352 2019-10-15 stsp
11014 2822a352 2019-10-15 stsp if (argc != 1)
11015 2822a352 2019-10-15 stsp usage_integrate();
11016 2822a352 2019-10-15 stsp branch_arg = argv[0];
11017 b08a0ccd 2020-09-24 stsp #ifndef PROFILE
11018 2822a352 2019-10-15 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11019 2822a352 2019-10-15 stsp "unveil", NULL) == -1)
11020 2822a352 2019-10-15 stsp err(1, "pledge");
11021 b08a0ccd 2020-09-24 stsp #endif
11022 2822a352 2019-10-15 stsp cwd = getcwd(NULL, 0);
11023 2822a352 2019-10-15 stsp if (cwd == NULL) {
11024 2822a352 2019-10-15 stsp error = got_error_from_errno("getcwd");
11025 2822a352 2019-10-15 stsp goto done;
11026 2822a352 2019-10-15 stsp }
11027 2822a352 2019-10-15 stsp
11028 2822a352 2019-10-15 stsp error = got_worktree_open(&worktree, cwd);
11029 fa51e947 2020-03-27 stsp if (error) {
11030 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11031 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "integrate",
11032 fa51e947 2020-03-27 stsp cwd);
11033 2822a352 2019-10-15 stsp goto done;
11034 fa51e947 2020-03-27 stsp }
11035 2822a352 2019-10-15 stsp
11036 2822a352 2019-10-15 stsp error = check_rebase_or_histedit_in_progress(worktree);
11037 2822a352 2019-10-15 stsp if (error)
11038 2822a352 2019-10-15 stsp goto done;
11039 2822a352 2019-10-15 stsp
11040 2822a352 2019-10-15 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
11041 2822a352 2019-10-15 stsp NULL);
11042 2822a352 2019-10-15 stsp if (error != NULL)
11043 2822a352 2019-10-15 stsp goto done;
11044 2822a352 2019-10-15 stsp
11045 2822a352 2019-10-15 stsp error = apply_unveil(got_repo_get_path(repo), 0,
11046 2822a352 2019-10-15 stsp got_worktree_get_root_path(worktree));
11047 2822a352 2019-10-15 stsp if (error)
11048 2822a352 2019-10-15 stsp goto done;
11049 2822a352 2019-10-15 stsp
11050 f259c4c1 2021-09-24 stsp error = check_merge_in_progress(worktree, repo);
11051 f259c4c1 2021-09-24 stsp if (error)
11052 f259c4c1 2021-09-24 stsp goto done;
11053 f259c4c1 2021-09-24 stsp
11054 2822a352 2019-10-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
11055 2822a352 2019-10-15 stsp error = got_error_from_errno("asprintf");
11056 2822a352 2019-10-15 stsp goto done;
11057 2822a352 2019-10-15 stsp }
11058 2822a352 2019-10-15 stsp
11059 2822a352 2019-10-15 stsp error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
11060 2822a352 2019-10-15 stsp &base_branch_ref, worktree, refname, repo);
11061 2822a352 2019-10-15 stsp if (error)
11062 2822a352 2019-10-15 stsp goto done;
11063 2822a352 2019-10-15 stsp
11064 2822a352 2019-10-15 stsp refname = strdup(got_ref_get_name(branch_ref));
11065 2822a352 2019-10-15 stsp if (refname == NULL) {
11066 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
11067 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
11068 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
11069 2822a352 2019-10-15 stsp goto done;
11070 2822a352 2019-10-15 stsp }
11071 2822a352 2019-10-15 stsp base_refname = strdup(got_ref_get_name(base_branch_ref));
11072 2822a352 2019-10-15 stsp if (base_refname == NULL) {
11073 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
11074 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
11075 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
11076 2822a352 2019-10-15 stsp goto done;
11077 2822a352 2019-10-15 stsp }
11078 2822a352 2019-10-15 stsp
11079 2822a352 2019-10-15 stsp error = got_ref_resolve(&commit_id, repo, branch_ref);
11080 2822a352 2019-10-15 stsp if (error)
11081 2822a352 2019-10-15 stsp goto done;
11082 2822a352 2019-10-15 stsp
11083 2822a352 2019-10-15 stsp error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
11084 2822a352 2019-10-15 stsp if (error)
11085 2822a352 2019-10-15 stsp goto done;
11086 2822a352 2019-10-15 stsp
11087 2822a352 2019-10-15 stsp if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
11088 2822a352 2019-10-15 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH,
11089 2822a352 2019-10-15 stsp "specified branch has already been integrated");
11090 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
11091 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
11092 2822a352 2019-10-15 stsp goto done;
11093 2822a352 2019-10-15 stsp }
11094 2822a352 2019-10-15 stsp
11095 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
11096 2822a352 2019-10-15 stsp if (error) {
11097 2822a352 2019-10-15 stsp if (error->code == GOT_ERR_ANCESTRY)
11098 2822a352 2019-10-15 stsp error = got_error(GOT_ERR_REBASE_REQUIRED);
11099 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
11100 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
11101 2822a352 2019-10-15 stsp goto done;
11102 2822a352 2019-10-15 stsp }
11103 2822a352 2019-10-15 stsp
11104 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
11105 2822a352 2019-10-15 stsp error = got_worktree_integrate_continue(worktree, fileindex, repo,
11106 9627c110 2020-04-18 stsp branch_ref, base_branch_ref, update_progress, &upa,
11107 2822a352 2019-10-15 stsp check_cancelled, NULL);
11108 2822a352 2019-10-15 stsp if (error)
11109 2822a352 2019-10-15 stsp goto done;
11110 2822a352 2019-10-15 stsp
11111 2822a352 2019-10-15 stsp printf("Integrated %s into %s\n", refname, base_refname);
11112 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
11113 2822a352 2019-10-15 stsp done:
11114 1d0f4054 2021-06-17 stsp if (repo) {
11115 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
11116 1d0f4054 2021-06-17 stsp if (error == NULL)
11117 1d0f4054 2021-06-17 stsp error = close_err;
11118 1d0f4054 2021-06-17 stsp }
11119 2822a352 2019-10-15 stsp if (worktree)
11120 2822a352 2019-10-15 stsp got_worktree_close(worktree);
11121 2822a352 2019-10-15 stsp free(cwd);
11122 2822a352 2019-10-15 stsp free(base_commit_id);
11123 2822a352 2019-10-15 stsp free(commit_id);
11124 2822a352 2019-10-15 stsp free(refname);
11125 2822a352 2019-10-15 stsp free(base_refname);
11126 f259c4c1 2021-09-24 stsp return error;
11127 f259c4c1 2021-09-24 stsp }
11128 f259c4c1 2021-09-24 stsp
11129 f259c4c1 2021-09-24 stsp __dead static void
11130 f259c4c1 2021-09-24 stsp usage_merge(void)
11131 f259c4c1 2021-09-24 stsp {
11132 088449d3 2021-09-26 stsp fprintf(stderr, "usage: %s merge [-a] [-c] [-n] [branch]\n",
11133 f259c4c1 2021-09-24 stsp getprogname());
11134 f259c4c1 2021-09-24 stsp exit(1);
11135 f259c4c1 2021-09-24 stsp }
11136 f259c4c1 2021-09-24 stsp
11137 f259c4c1 2021-09-24 stsp static const struct got_error *
11138 f259c4c1 2021-09-24 stsp cmd_merge(int argc, char *argv[])
11139 f259c4c1 2021-09-24 stsp {
11140 f259c4c1 2021-09-24 stsp const struct got_error *error = NULL;
11141 f259c4c1 2021-09-24 stsp struct got_worktree *worktree = NULL;
11142 f259c4c1 2021-09-24 stsp struct got_repository *repo = NULL;
11143 f259c4c1 2021-09-24 stsp struct got_fileindex *fileindex = NULL;
11144 f259c4c1 2021-09-24 stsp char *cwd = NULL, *id_str = NULL, *author = NULL;
11145 f259c4c1 2021-09-24 stsp struct got_reference *branch = NULL, *wt_branch = NULL;
11146 f259c4c1 2021-09-24 stsp struct got_object_id *branch_tip = NULL, *yca_id = NULL;
11147 f259c4c1 2021-09-24 stsp struct got_object_id *wt_branch_tip = NULL;
11148 f259c4c1 2021-09-24 stsp int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
11149 088449d3 2021-09-26 stsp int interrupt_merge = 0;
11150 f259c4c1 2021-09-24 stsp struct got_update_progress_arg upa;
11151 f259c4c1 2021-09-24 stsp struct got_object_id *merge_commit_id = NULL;
11152 f259c4c1 2021-09-24 stsp char *branch_name = NULL;
11153 f259c4c1 2021-09-24 stsp
11154 f259c4c1 2021-09-24 stsp memset(&upa, 0, sizeof(upa));
11155 f259c4c1 2021-09-24 stsp
11156 088449d3 2021-09-26 stsp while ((ch = getopt(argc, argv, "acn")) != -1) {
11157 f259c4c1 2021-09-24 stsp switch (ch) {
11158 f259c4c1 2021-09-24 stsp case 'a':
11159 f259c4c1 2021-09-24 stsp abort_merge = 1;
11160 f259c4c1 2021-09-24 stsp break;
11161 f259c4c1 2021-09-24 stsp case 'c':
11162 f259c4c1 2021-09-24 stsp continue_merge = 1;
11163 f259c4c1 2021-09-24 stsp break;
11164 088449d3 2021-09-26 stsp case 'n':
11165 088449d3 2021-09-26 stsp interrupt_merge = 1;
11166 088449d3 2021-09-26 stsp break;
11167 f259c4c1 2021-09-24 stsp default:
11168 f259c4c1 2021-09-24 stsp usage_rebase();
11169 f259c4c1 2021-09-24 stsp /* NOTREACHED */
11170 f259c4c1 2021-09-24 stsp }
11171 f259c4c1 2021-09-24 stsp }
11172 f259c4c1 2021-09-24 stsp
11173 f259c4c1 2021-09-24 stsp argc -= optind;
11174 f259c4c1 2021-09-24 stsp argv += optind;
11175 f259c4c1 2021-09-24 stsp
11176 f259c4c1 2021-09-24 stsp #ifndef PROFILE
11177 f259c4c1 2021-09-24 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11178 f259c4c1 2021-09-24 stsp "unveil", NULL) == -1)
11179 f259c4c1 2021-09-24 stsp err(1, "pledge");
11180 f259c4c1 2021-09-24 stsp #endif
11181 f259c4c1 2021-09-24 stsp
11182 f259c4c1 2021-09-24 stsp if (abort_merge && continue_merge)
11183 f259c4c1 2021-09-24 stsp option_conflict('a', 'c');
11184 f259c4c1 2021-09-24 stsp if (abort_merge || continue_merge) {
11185 f259c4c1 2021-09-24 stsp if (argc != 0)
11186 f259c4c1 2021-09-24 stsp usage_merge();
11187 f259c4c1 2021-09-24 stsp } else if (argc != 1)
11188 f259c4c1 2021-09-24 stsp usage_merge();
11189 f259c4c1 2021-09-24 stsp
11190 f259c4c1 2021-09-24 stsp cwd = getcwd(NULL, 0);
11191 f259c4c1 2021-09-24 stsp if (cwd == NULL) {
11192 f259c4c1 2021-09-24 stsp error = got_error_from_errno("getcwd");
11193 f259c4c1 2021-09-24 stsp goto done;
11194 f259c4c1 2021-09-24 stsp }
11195 f259c4c1 2021-09-24 stsp
11196 f259c4c1 2021-09-24 stsp error = got_worktree_open(&worktree, cwd);
11197 f259c4c1 2021-09-24 stsp if (error) {
11198 f259c4c1 2021-09-24 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11199 f259c4c1 2021-09-24 stsp error = wrap_not_worktree_error(error,
11200 f259c4c1 2021-09-24 stsp "merge", cwd);
11201 f259c4c1 2021-09-24 stsp goto done;
11202 f259c4c1 2021-09-24 stsp }
11203 f259c4c1 2021-09-24 stsp
11204 f259c4c1 2021-09-24 stsp error = got_repo_open(&repo,
11205 f259c4c1 2021-09-24 stsp worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL);
11206 f259c4c1 2021-09-24 stsp if (error != NULL)
11207 f259c4c1 2021-09-24 stsp goto done;
11208 f259c4c1 2021-09-24 stsp
11209 f259c4c1 2021-09-24 stsp error = apply_unveil(got_repo_get_path(repo), 0,
11210 f259c4c1 2021-09-24 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
11211 f259c4c1 2021-09-24 stsp if (error)
11212 f259c4c1 2021-09-24 stsp goto done;
11213 f259c4c1 2021-09-24 stsp
11214 f259c4c1 2021-09-24 stsp error = check_rebase_or_histedit_in_progress(worktree);
11215 f259c4c1 2021-09-24 stsp if (error)
11216 f259c4c1 2021-09-24 stsp goto done;
11217 f259c4c1 2021-09-24 stsp
11218 f259c4c1 2021-09-24 stsp error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
11219 f259c4c1 2021-09-24 stsp repo);
11220 f259c4c1 2021-09-24 stsp if (error)
11221 f259c4c1 2021-09-24 stsp goto done;
11222 f259c4c1 2021-09-24 stsp
11223 f259c4c1 2021-09-24 stsp if (abort_merge) {
11224 f259c4c1 2021-09-24 stsp if (!merge_in_progress) {
11225 f259c4c1 2021-09-24 stsp error = got_error(GOT_ERR_NOT_MERGING);
11226 f259c4c1 2021-09-24 stsp goto done;
11227 f259c4c1 2021-09-24 stsp }
11228 f259c4c1 2021-09-24 stsp error = got_worktree_merge_continue(&branch_name,
11229 f259c4c1 2021-09-24 stsp &branch_tip, &fileindex, worktree, repo);
11230 f259c4c1 2021-09-24 stsp if (error)
11231 f259c4c1 2021-09-24 stsp goto done;
11232 f259c4c1 2021-09-24 stsp error = got_worktree_merge_abort(worktree, fileindex, repo,
11233 41f061b2 2021-10-05 stsp abort_progress, &upa);
11234 f259c4c1 2021-09-24 stsp if (error)
11235 f259c4c1 2021-09-24 stsp goto done;
11236 f259c4c1 2021-09-24 stsp printf("Merge of %s aborted\n", branch_name);
11237 f259c4c1 2021-09-24 stsp goto done; /* nothing else to do */
11238 f259c4c1 2021-09-24 stsp }
11239 f259c4c1 2021-09-24 stsp
11240 f259c4c1 2021-09-24 stsp error = get_author(&author, repo, worktree);
11241 f259c4c1 2021-09-24 stsp if (error)
11242 f259c4c1 2021-09-24 stsp goto done;
11243 f259c4c1 2021-09-24 stsp
11244 f259c4c1 2021-09-24 stsp if (continue_merge) {
11245 f259c4c1 2021-09-24 stsp if (!merge_in_progress) {
11246 f259c4c1 2021-09-24 stsp error = got_error(GOT_ERR_NOT_MERGING);
11247 f259c4c1 2021-09-24 stsp goto done;
11248 f259c4c1 2021-09-24 stsp }
11249 f259c4c1 2021-09-24 stsp error = got_worktree_merge_continue(&branch_name,
11250 f259c4c1 2021-09-24 stsp &branch_tip, &fileindex, worktree, repo);
11251 f259c4c1 2021-09-24 stsp if (error)
11252 f259c4c1 2021-09-24 stsp goto done;
11253 f259c4c1 2021-09-24 stsp } else {
11254 f259c4c1 2021-09-24 stsp error = got_ref_open(&branch, repo, argv[0], 0);
11255 f259c4c1 2021-09-24 stsp if (error != NULL)
11256 f259c4c1 2021-09-24 stsp goto done;
11257 f259c4c1 2021-09-24 stsp branch_name = strdup(got_ref_get_name(branch));
11258 f259c4c1 2021-09-24 stsp if (branch_name == NULL) {
11259 f259c4c1 2021-09-24 stsp error = got_error_from_errno("strdup");
11260 f259c4c1 2021-09-24 stsp goto done;
11261 f259c4c1 2021-09-24 stsp }
11262 f259c4c1 2021-09-24 stsp error = got_ref_resolve(&branch_tip, repo, branch);
11263 f259c4c1 2021-09-24 stsp if (error)
11264 f259c4c1 2021-09-24 stsp goto done;
11265 f259c4c1 2021-09-24 stsp }
11266 f259c4c1 2021-09-24 stsp
11267 f259c4c1 2021-09-24 stsp error = got_ref_open(&wt_branch, repo,
11268 f259c4c1 2021-09-24 stsp got_worktree_get_head_ref_name(worktree), 0);
11269 f259c4c1 2021-09-24 stsp if (error)
11270 f259c4c1 2021-09-24 stsp goto done;
11271 f259c4c1 2021-09-24 stsp error = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
11272 f259c4c1 2021-09-24 stsp if (error)
11273 f259c4c1 2021-09-24 stsp goto done;
11274 f259c4c1 2021-09-24 stsp error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
11275 4e91ef15 2021-09-26 stsp wt_branch_tip, branch_tip, 0, repo,
11276 f259c4c1 2021-09-24 stsp check_cancelled, NULL);
11277 4e91ef15 2021-09-26 stsp if (error && error->code != GOT_ERR_ANCESTRY)
11278 f259c4c1 2021-09-24 stsp goto done;
11279 f259c4c1 2021-09-24 stsp
11280 f259c4c1 2021-09-24 stsp if (!continue_merge) {
11281 f259c4c1 2021-09-24 stsp error = check_path_prefix(wt_branch_tip, branch_tip,
11282 f259c4c1 2021-09-24 stsp got_worktree_get_path_prefix(worktree),
11283 f259c4c1 2021-09-24 stsp GOT_ERR_MERGE_PATH, repo);
11284 f259c4c1 2021-09-24 stsp if (error)
11285 f259c4c1 2021-09-24 stsp goto done;
11286 4e91ef15 2021-09-26 stsp if (yca_id) {
11287 4e91ef15 2021-09-26 stsp error = check_same_branch(wt_branch_tip, branch,
11288 4e91ef15 2021-09-26 stsp yca_id, repo);
11289 4e91ef15 2021-09-26 stsp if (error) {
11290 4e91ef15 2021-09-26 stsp if (error->code != GOT_ERR_ANCESTRY)
11291 4e91ef15 2021-09-26 stsp goto done;
11292 4e91ef15 2021-09-26 stsp error = NULL;
11293 4e91ef15 2021-09-26 stsp } else {
11294 4e91ef15 2021-09-26 stsp static char msg[512];
11295 4e91ef15 2021-09-26 stsp snprintf(msg, sizeof(msg),
11296 4e91ef15 2021-09-26 stsp "cannot create a merge commit because "
11297 4e91ef15 2021-09-26 stsp "%s is based on %s; %s can be integrated "
11298 4e91ef15 2021-09-26 stsp "with 'got integrate' instead", branch_name,
11299 4e91ef15 2021-09-26 stsp got_worktree_get_head_ref_name(worktree),
11300 4e91ef15 2021-09-26 stsp branch_name);
11301 4e91ef15 2021-09-26 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH, msg);
11302 f259c4c1 2021-09-24 stsp goto done;
11303 4e91ef15 2021-09-26 stsp }
11304 f259c4c1 2021-09-24 stsp }
11305 f259c4c1 2021-09-24 stsp error = got_worktree_merge_prepare(&fileindex, worktree,
11306 f259c4c1 2021-09-24 stsp branch, repo);
11307 f259c4c1 2021-09-24 stsp if (error)
11308 f259c4c1 2021-09-24 stsp goto done;
11309 f259c4c1 2021-09-24 stsp
11310 f259c4c1 2021-09-24 stsp error = got_worktree_merge_branch(worktree, fileindex,
11311 f259c4c1 2021-09-24 stsp yca_id, branch_tip, repo, update_progress, &upa,
11312 f259c4c1 2021-09-24 stsp check_cancelled, NULL);
11313 f259c4c1 2021-09-24 stsp if (error)
11314 f259c4c1 2021-09-24 stsp goto done;
11315 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
11316 4e91ef15 2021-09-26 stsp if (!upa.did_something) {
11317 4e91ef15 2021-09-26 stsp error = got_worktree_merge_abort(worktree, fileindex,
11318 41f061b2 2021-10-05 stsp repo, abort_progress, &upa);
11319 4e91ef15 2021-09-26 stsp if (error)
11320 4e91ef15 2021-09-26 stsp goto done;
11321 4e91ef15 2021-09-26 stsp printf("Already up-to-date\n");
11322 4e91ef15 2021-09-26 stsp goto done;
11323 4e91ef15 2021-09-26 stsp }
11324 f259c4c1 2021-09-24 stsp }
11325 f259c4c1 2021-09-24 stsp
11326 088449d3 2021-09-26 stsp if (interrupt_merge) {
11327 f259c4c1 2021-09-24 stsp error = got_worktree_merge_postpone(worktree, fileindex);
11328 f259c4c1 2021-09-24 stsp if (error)
11329 f259c4c1 2021-09-24 stsp goto done;
11330 088449d3 2021-09-26 stsp printf("Merge of %s interrupted on request\n", branch_name);
11331 c1b05723 2021-09-28 stsp } else if (upa.conflicts > 0 || upa.missing > 0 ||
11332 c1b05723 2021-09-28 stsp upa.not_deleted > 0 || upa.unversioned > 0) {
11333 088449d3 2021-09-26 stsp error = got_worktree_merge_postpone(worktree, fileindex);
11334 088449d3 2021-09-26 stsp if (error)
11335 088449d3 2021-09-26 stsp goto done;
11336 c1b05723 2021-09-28 stsp if (upa.conflicts > 0 && upa.missing == 0 &&
11337 c1b05723 2021-09-28 stsp upa.not_deleted == 0 && upa.unversioned == 0) {
11338 f259c4c1 2021-09-24 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
11339 f259c4c1 2021-09-24 stsp "conflicts must be resolved before merging "
11340 f259c4c1 2021-09-24 stsp "can continue");
11341 f259c4c1 2021-09-24 stsp } else if (upa.conflicts > 0) {
11342 f259c4c1 2021-09-24 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
11343 f259c4c1 2021-09-24 stsp "conflicts must be resolved before merging "
11344 c1b05723 2021-09-28 stsp "can continue; changes destined for some "
11345 1acd48bc 2021-09-24 stsp "files were not yet merged and "
11346 f259c4c1 2021-09-24 stsp "should be merged manually if required before the "
11347 f259c4c1 2021-09-24 stsp "merge operation is continued");
11348 f259c4c1 2021-09-24 stsp } else {
11349 f259c4c1 2021-09-24 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
11350 c1b05723 2021-09-28 stsp "changes destined for some "
11351 f259c4c1 2021-09-24 stsp "files were not yet merged and should be "
11352 f259c4c1 2021-09-24 stsp "merged manually if required before the "
11353 f259c4c1 2021-09-24 stsp "merge operation is continued");
11354 f259c4c1 2021-09-24 stsp }
11355 f259c4c1 2021-09-24 stsp goto done;
11356 f259c4c1 2021-09-24 stsp } else {
11357 f259c4c1 2021-09-24 stsp error = got_worktree_merge_commit(&merge_commit_id, worktree,
11358 0ff8d236 2021-09-28 stsp fileindex, author, NULL, 1, branch_tip, branch_name,
11359 0ff8d236 2021-09-28 stsp repo, continue_merge ? print_status : NULL, NULL);
11360 f259c4c1 2021-09-24 stsp if (error)
11361 f259c4c1 2021-09-24 stsp goto done;
11362 f259c4c1 2021-09-24 stsp error = got_worktree_merge_complete(worktree, fileindex, repo);
11363 f259c4c1 2021-09-24 stsp if (error)
11364 f259c4c1 2021-09-24 stsp goto done;
11365 f259c4c1 2021-09-24 stsp error = got_object_id_str(&id_str, merge_commit_id);
11366 f259c4c1 2021-09-24 stsp if (error)
11367 f259c4c1 2021-09-24 stsp goto done;
11368 f259c4c1 2021-09-24 stsp printf("Merged %s into %s: %s\n", branch_name,
11369 f259c4c1 2021-09-24 stsp got_worktree_get_head_ref_name(worktree),
11370 f259c4c1 2021-09-24 stsp id_str);
11371 f259c4c1 2021-09-24 stsp
11372 f259c4c1 2021-09-24 stsp }
11373 f259c4c1 2021-09-24 stsp done:
11374 f259c4c1 2021-09-24 stsp free(id_str);
11375 f259c4c1 2021-09-24 stsp free(merge_commit_id);
11376 f259c4c1 2021-09-24 stsp free(author);
11377 f259c4c1 2021-09-24 stsp free(branch_tip);
11378 f259c4c1 2021-09-24 stsp free(branch_name);
11379 f259c4c1 2021-09-24 stsp free(yca_id);
11380 f259c4c1 2021-09-24 stsp if (branch)
11381 f259c4c1 2021-09-24 stsp got_ref_close(branch);
11382 f259c4c1 2021-09-24 stsp if (wt_branch)
11383 f259c4c1 2021-09-24 stsp got_ref_close(wt_branch);
11384 f259c4c1 2021-09-24 stsp if (worktree)
11385 f259c4c1 2021-09-24 stsp got_worktree_close(worktree);
11386 f259c4c1 2021-09-24 stsp if (repo) {
11387 f259c4c1 2021-09-24 stsp const struct got_error *close_err = got_repo_close(repo);
11388 f259c4c1 2021-09-24 stsp if (error == NULL)
11389 f259c4c1 2021-09-24 stsp error = close_err;
11390 f259c4c1 2021-09-24 stsp }
11391 715dc77e 2019-08-03 stsp return error;
11392 715dc77e 2019-08-03 stsp }
11393 715dc77e 2019-08-03 stsp
11394 715dc77e 2019-08-03 stsp __dead static void
11395 715dc77e 2019-08-03 stsp usage_stage(void)
11396 715dc77e 2019-08-03 stsp {
11397 f3055044 2019-08-07 stsp fprintf(stderr, "usage: %s stage [-l] | [-p] [-F response-script] "
11398 35213c7c 2020-07-23 stsp "[-S] [file-path ...]\n",
11399 715dc77e 2019-08-03 stsp getprogname());
11400 715dc77e 2019-08-03 stsp exit(1);
11401 715dc77e 2019-08-03 stsp }
11402 715dc77e 2019-08-03 stsp
11403 715dc77e 2019-08-03 stsp static const struct got_error *
11404 408b4ebc 2019-08-03 stsp print_stage(void *arg, unsigned char status, unsigned char staged_status,
11405 408b4ebc 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
11406 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
11407 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
11408 408b4ebc 2019-08-03 stsp {
11409 408b4ebc 2019-08-03 stsp const struct got_error *err = NULL;
11410 408b4ebc 2019-08-03 stsp char *id_str = NULL;
11411 408b4ebc 2019-08-03 stsp
11412 408b4ebc 2019-08-03 stsp if (staged_status != GOT_STATUS_ADD &&
11413 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_MODIFY &&
11414 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
11415 408b4ebc 2019-08-03 stsp return NULL;
11416 408b4ebc 2019-08-03 stsp
11417 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
11418 408b4ebc 2019-08-03 stsp staged_status == GOT_STATUS_MODIFY)
11419 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, staged_blob_id);
11420 408b4ebc 2019-08-03 stsp else
11421 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, blob_id);
11422 408b4ebc 2019-08-03 stsp if (err)
11423 408b4ebc 2019-08-03 stsp return err;
11424 408b4ebc 2019-08-03 stsp
11425 408b4ebc 2019-08-03 stsp printf("%s %c %s\n", id_str, staged_status, path);
11426 408b4ebc 2019-08-03 stsp free(id_str);
11427 dc424a06 2019-08-07 stsp return NULL;
11428 dc424a06 2019-08-07 stsp }
11429 2e1f37b0 2019-08-08 stsp
11430 dc424a06 2019-08-07 stsp static const struct got_error *
11431 715dc77e 2019-08-03 stsp cmd_stage(int argc, char *argv[])
11432 715dc77e 2019-08-03 stsp {
11433 715dc77e 2019-08-03 stsp const struct got_error *error = NULL;
11434 715dc77e 2019-08-03 stsp struct got_repository *repo = NULL;
11435 715dc77e 2019-08-03 stsp struct got_worktree *worktree = NULL;
11436 715dc77e 2019-08-03 stsp char *cwd = NULL;
11437 715dc77e 2019-08-03 stsp struct got_pathlist_head paths;
11438 715dc77e 2019-08-03 stsp struct got_pathlist_entry *pe;
11439 35213c7c 2020-07-23 stsp int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
11440 dc424a06 2019-08-07 stsp FILE *patch_script_file = NULL;
11441 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
11442 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
11443 715dc77e 2019-08-03 stsp
11444 715dc77e 2019-08-03 stsp TAILQ_INIT(&paths);
11445 715dc77e 2019-08-03 stsp
11446 35213c7c 2020-07-23 stsp while ((ch = getopt(argc, argv, "lpF:S")) != -1) {
11447 715dc77e 2019-08-03 stsp switch (ch) {
11448 408b4ebc 2019-08-03 stsp case 'l':
11449 408b4ebc 2019-08-03 stsp list_stage = 1;
11450 408b4ebc 2019-08-03 stsp break;
11451 dc424a06 2019-08-07 stsp case 'p':
11452 dc424a06 2019-08-07 stsp pflag = 1;
11453 dc424a06 2019-08-07 stsp break;
11454 dc424a06 2019-08-07 stsp case 'F':
11455 dc424a06 2019-08-07 stsp patch_script_path = optarg;
11456 dc424a06 2019-08-07 stsp break;
11457 35213c7c 2020-07-23 stsp case 'S':
11458 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
11459 35213c7c 2020-07-23 stsp break;
11460 715dc77e 2019-08-03 stsp default:
11461 715dc77e 2019-08-03 stsp usage_stage();
11462 715dc77e 2019-08-03 stsp /* NOTREACHED */
11463 715dc77e 2019-08-03 stsp }
11464 715dc77e 2019-08-03 stsp }
11465 715dc77e 2019-08-03 stsp
11466 715dc77e 2019-08-03 stsp argc -= optind;
11467 715dc77e 2019-08-03 stsp argv += optind;
11468 715dc77e 2019-08-03 stsp
11469 715dc77e 2019-08-03 stsp #ifndef PROFILE
11470 715dc77e 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11471 715dc77e 2019-08-03 stsp "unveil", NULL) == -1)
11472 715dc77e 2019-08-03 stsp err(1, "pledge");
11473 715dc77e 2019-08-03 stsp #endif
11474 2db2652d 2019-08-07 stsp if (list_stage && (pflag || patch_script_path))
11475 2db2652d 2019-08-07 stsp errx(1, "-l option cannot be used with other options");
11476 dc424a06 2019-08-07 stsp if (patch_script_path && !pflag)
11477 dc424a06 2019-08-07 stsp errx(1, "-F option can only be used together with -p option");
11478 715dc77e 2019-08-03 stsp
11479 715dc77e 2019-08-03 stsp cwd = getcwd(NULL, 0);
11480 715dc77e 2019-08-03 stsp if (cwd == NULL) {
11481 715dc77e 2019-08-03 stsp error = got_error_from_errno("getcwd");
11482 715dc77e 2019-08-03 stsp goto done;
11483 715dc77e 2019-08-03 stsp }
11484 715dc77e 2019-08-03 stsp
11485 715dc77e 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
11486 fa51e947 2020-03-27 stsp if (error) {
11487 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11488 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "stage", cwd);
11489 715dc77e 2019-08-03 stsp goto done;
11490 fa51e947 2020-03-27 stsp }
11491 715dc77e 2019-08-03 stsp
11492 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
11493 c9956ddf 2019-09-08 stsp NULL);
11494 715dc77e 2019-08-03 stsp if (error != NULL)
11495 715dc77e 2019-08-03 stsp goto done;
11496 715dc77e 2019-08-03 stsp
11497 dc424a06 2019-08-07 stsp if (patch_script_path) {
11498 00fe21f2 2021-12-31 stsp patch_script_file = fopen(patch_script_path, "re");
11499 dc424a06 2019-08-07 stsp if (patch_script_file == NULL) {
11500 dc424a06 2019-08-07 stsp error = got_error_from_errno2("fopen",
11501 dc424a06 2019-08-07 stsp patch_script_path);
11502 dc424a06 2019-08-07 stsp goto done;
11503 dc424a06 2019-08-07 stsp }
11504 dc424a06 2019-08-07 stsp }
11505 9fd7cd22 2019-08-30 stsp error = apply_unveil(got_repo_get_path(repo), 0,
11506 715dc77e 2019-08-03 stsp got_worktree_get_root_path(worktree));
11507 715dc77e 2019-08-03 stsp if (error)
11508 715dc77e 2019-08-03 stsp goto done;
11509 715dc77e 2019-08-03 stsp
11510 f259c4c1 2021-09-24 stsp error = check_merge_in_progress(worktree, repo);
11511 f259c4c1 2021-09-24 stsp if (error)
11512 f259c4c1 2021-09-24 stsp goto done;
11513 f259c4c1 2021-09-24 stsp
11514 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
11515 6d022e97 2019-08-04 stsp if (error)
11516 6d022e97 2019-08-04 stsp goto done;
11517 715dc77e 2019-08-03 stsp
11518 6d022e97 2019-08-04 stsp if (list_stage)
11519 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, 0,
11520 408b4ebc 2019-08-03 stsp print_stage, NULL, check_cancelled, NULL);
11521 2e1f37b0 2019-08-08 stsp else {
11522 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
11523 2e1f37b0 2019-08-08 stsp cpa.action = "stage";
11524 dc424a06 2019-08-07 stsp error = got_worktree_stage(worktree, &paths,
11525 dc424a06 2019-08-07 stsp pflag ? NULL : print_status, NULL,
11526 35213c7c 2020-07-23 stsp pflag ? choose_patch : NULL, &cpa,
11527 35213c7c 2020-07-23 stsp allow_bad_symlinks, repo);
11528 2e1f37b0 2019-08-08 stsp }
11529 ad493afc 2019-08-03 stsp done:
11530 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
11531 2e1f37b0 2019-08-08 stsp error == NULL)
11532 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
11533 1d0f4054 2021-06-17 stsp if (repo) {
11534 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
11535 1d0f4054 2021-06-17 stsp if (error == NULL)
11536 1d0f4054 2021-06-17 stsp error = close_err;
11537 1d0f4054 2021-06-17 stsp }
11538 ad493afc 2019-08-03 stsp if (worktree)
11539 ad493afc 2019-08-03 stsp got_worktree_close(worktree);
11540 ad493afc 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
11541 ad493afc 2019-08-03 stsp free((char *)pe->path);
11542 ad493afc 2019-08-03 stsp got_pathlist_free(&paths);
11543 ad493afc 2019-08-03 stsp free(cwd);
11544 ad493afc 2019-08-03 stsp return error;
11545 ad493afc 2019-08-03 stsp }
11546 ad493afc 2019-08-03 stsp
11547 ad493afc 2019-08-03 stsp __dead static void
11548 ad493afc 2019-08-03 stsp usage_unstage(void)
11549 ad493afc 2019-08-03 stsp {
11550 2e1f37b0 2019-08-08 stsp fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
11551 2e1f37b0 2019-08-08 stsp "[file-path ...]\n",
11552 ad493afc 2019-08-03 stsp getprogname());
11553 ad493afc 2019-08-03 stsp exit(1);
11554 ad493afc 2019-08-03 stsp }
11555 ad493afc 2019-08-03 stsp
11556 ad493afc 2019-08-03 stsp
11557 ad493afc 2019-08-03 stsp static const struct got_error *
11558 ad493afc 2019-08-03 stsp cmd_unstage(int argc, char *argv[])
11559 ad493afc 2019-08-03 stsp {
11560 ad493afc 2019-08-03 stsp const struct got_error *error = NULL;
11561 ad493afc 2019-08-03 stsp struct got_repository *repo = NULL;
11562 ad493afc 2019-08-03 stsp struct got_worktree *worktree = NULL;
11563 ad493afc 2019-08-03 stsp char *cwd = NULL;
11564 ad493afc 2019-08-03 stsp struct got_pathlist_head paths;
11565 ad493afc 2019-08-03 stsp struct got_pathlist_entry *pe;
11566 9627c110 2020-04-18 stsp int ch, pflag = 0;
11567 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
11568 2e1f37b0 2019-08-08 stsp FILE *patch_script_file = NULL;
11569 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
11570 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
11571 ad493afc 2019-08-03 stsp
11572 ad493afc 2019-08-03 stsp TAILQ_INIT(&paths);
11573 ad493afc 2019-08-03 stsp
11574 2e1f37b0 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:")) != -1) {
11575 ad493afc 2019-08-03 stsp switch (ch) {
11576 2e1f37b0 2019-08-08 stsp case 'p':
11577 2e1f37b0 2019-08-08 stsp pflag = 1;
11578 2e1f37b0 2019-08-08 stsp break;
11579 2e1f37b0 2019-08-08 stsp case 'F':
11580 2e1f37b0 2019-08-08 stsp patch_script_path = optarg;
11581 2e1f37b0 2019-08-08 stsp break;
11582 ad493afc 2019-08-03 stsp default:
11583 ad493afc 2019-08-03 stsp usage_unstage();
11584 ad493afc 2019-08-03 stsp /* NOTREACHED */
11585 ad493afc 2019-08-03 stsp }
11586 ad493afc 2019-08-03 stsp }
11587 ad493afc 2019-08-03 stsp
11588 ad493afc 2019-08-03 stsp argc -= optind;
11589 ad493afc 2019-08-03 stsp argv += optind;
11590 ad493afc 2019-08-03 stsp
11591 ad493afc 2019-08-03 stsp #ifndef PROFILE
11592 ad493afc 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11593 ad493afc 2019-08-03 stsp "unveil", NULL) == -1)
11594 ad493afc 2019-08-03 stsp err(1, "pledge");
11595 ad493afc 2019-08-03 stsp #endif
11596 2e1f37b0 2019-08-08 stsp if (patch_script_path && !pflag)
11597 2e1f37b0 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
11598 2e1f37b0 2019-08-08 stsp
11599 ad493afc 2019-08-03 stsp cwd = getcwd(NULL, 0);
11600 ad493afc 2019-08-03 stsp if (cwd == NULL) {
11601 ad493afc 2019-08-03 stsp error = got_error_from_errno("getcwd");
11602 ad493afc 2019-08-03 stsp goto done;
11603 ad493afc 2019-08-03 stsp }
11604 ad493afc 2019-08-03 stsp
11605 ad493afc 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
11606 fa51e947 2020-03-27 stsp if (error) {
11607 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11608 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "unstage", cwd);
11609 ad493afc 2019-08-03 stsp goto done;
11610 fa51e947 2020-03-27 stsp }
11611 ad493afc 2019-08-03 stsp
11612 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
11613 c9956ddf 2019-09-08 stsp NULL);
11614 ad493afc 2019-08-03 stsp if (error != NULL)
11615 ad493afc 2019-08-03 stsp goto done;
11616 ad493afc 2019-08-03 stsp
11617 2e1f37b0 2019-08-08 stsp if (patch_script_path) {
11618 00fe21f2 2021-12-31 stsp patch_script_file = fopen(patch_script_path, "re");
11619 2e1f37b0 2019-08-08 stsp if (patch_script_file == NULL) {
11620 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fopen",
11621 2e1f37b0 2019-08-08 stsp patch_script_path);
11622 2e1f37b0 2019-08-08 stsp goto done;
11623 2e1f37b0 2019-08-08 stsp }
11624 2e1f37b0 2019-08-08 stsp }
11625 2e1f37b0 2019-08-08 stsp
11626 00f36e47 2019-09-06 stsp error = apply_unveil(got_repo_get_path(repo), 0,
11627 ad493afc 2019-08-03 stsp got_worktree_get_root_path(worktree));
11628 ad493afc 2019-08-03 stsp if (error)
11629 ad493afc 2019-08-03 stsp goto done;
11630 ad493afc 2019-08-03 stsp
11631 ad493afc 2019-08-03 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
11632 ad493afc 2019-08-03 stsp if (error)
11633 ad493afc 2019-08-03 stsp goto done;
11634 ad493afc 2019-08-03 stsp
11635 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
11636 2e1f37b0 2019-08-08 stsp cpa.action = "unstage";
11637 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
11638 ad493afc 2019-08-03 stsp error = got_worktree_unstage(worktree, &paths, update_progress,
11639 9627c110 2020-04-18 stsp &upa, pflag ? choose_patch : NULL, &cpa, repo);
11640 9627c110 2020-04-18 stsp if (!error)
11641 35ca1db7 2021-09-28 stsp print_merge_progress_stats(&upa);
11642 715dc77e 2019-08-03 stsp done:
11643 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
11644 2e1f37b0 2019-08-08 stsp error == NULL)
11645 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
11646 1d0f4054 2021-06-17 stsp if (repo) {
11647 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
11648 1d0f4054 2021-06-17 stsp if (error == NULL)
11649 1d0f4054 2021-06-17 stsp error = close_err;
11650 1d0f4054 2021-06-17 stsp }
11651 715dc77e 2019-08-03 stsp if (worktree)
11652 715dc77e 2019-08-03 stsp got_worktree_close(worktree);
11653 715dc77e 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
11654 715dc77e 2019-08-03 stsp free((char *)pe->path);
11655 715dc77e 2019-08-03 stsp got_pathlist_free(&paths);
11656 715dc77e 2019-08-03 stsp free(cwd);
11657 01073a5d 2019-08-22 stsp return error;
11658 01073a5d 2019-08-22 stsp }
11659 01073a5d 2019-08-22 stsp
11660 01073a5d 2019-08-22 stsp __dead static void
11661 01073a5d 2019-08-22 stsp usage_cat(void)
11662 01073a5d 2019-08-22 stsp {
11663 896e9b6f 2019-08-26 stsp fprintf(stderr, "usage: %s cat [-r repository ] [ -c commit ] [ -P ] "
11664 896e9b6f 2019-08-26 stsp "arg1 [arg2 ...]\n", getprogname());
11665 01073a5d 2019-08-22 stsp exit(1);
11666 01073a5d 2019-08-22 stsp }
11667 01073a5d 2019-08-22 stsp
11668 01073a5d 2019-08-22 stsp static const struct got_error *
11669 01073a5d 2019-08-22 stsp cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11670 01073a5d 2019-08-22 stsp {
11671 01073a5d 2019-08-22 stsp const struct got_error *err;
11672 01073a5d 2019-08-22 stsp struct got_blob_object *blob;
11673 01073a5d 2019-08-22 stsp
11674 01073a5d 2019-08-22 stsp err = got_object_open_as_blob(&blob, repo, id, 8192);
11675 01073a5d 2019-08-22 stsp if (err)
11676 01073a5d 2019-08-22 stsp return err;
11677 01073a5d 2019-08-22 stsp
11678 01073a5d 2019-08-22 stsp err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob);
11679 01073a5d 2019-08-22 stsp got_object_blob_close(blob);
11680 01073a5d 2019-08-22 stsp return err;
11681 01073a5d 2019-08-22 stsp }
11682 01073a5d 2019-08-22 stsp
11683 01073a5d 2019-08-22 stsp static const struct got_error *
11684 01073a5d 2019-08-22 stsp cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11685 01073a5d 2019-08-22 stsp {
11686 01073a5d 2019-08-22 stsp const struct got_error *err;
11687 01073a5d 2019-08-22 stsp struct got_tree_object *tree;
11688 56e0773d 2019-11-28 stsp int nentries, i;
11689 01073a5d 2019-08-22 stsp
11690 01073a5d 2019-08-22 stsp err = got_object_open_as_tree(&tree, repo, id);
11691 01073a5d 2019-08-22 stsp if (err)
11692 01073a5d 2019-08-22 stsp return err;
11693 01073a5d 2019-08-22 stsp
11694 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
11695 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
11696 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
11697 01073a5d 2019-08-22 stsp char *id_str;
11698 01073a5d 2019-08-22 stsp if (sigint_received || sigpipe_received)
11699 01073a5d 2019-08-22 stsp break;
11700 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
11701 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
11702 01073a5d 2019-08-22 stsp if (err)
11703 01073a5d 2019-08-22 stsp break;
11704 56e0773d 2019-11-28 stsp fprintf(outfile, "%s %.7o %s\n", id_str,
11705 56e0773d 2019-11-28 stsp got_tree_entry_get_mode(te),
11706 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te));
11707 01073a5d 2019-08-22 stsp free(id_str);
11708 01073a5d 2019-08-22 stsp }
11709 01073a5d 2019-08-22 stsp
11710 01073a5d 2019-08-22 stsp got_object_tree_close(tree);
11711 01073a5d 2019-08-22 stsp return err;
11712 01073a5d 2019-08-22 stsp }
11713 01073a5d 2019-08-22 stsp
11714 bdc78ba6 2022-02-16 jrick static void
11715 bdc78ba6 2022-02-16 jrick format_gmtoff(char *buf, size_t sz, time_t gmtoff)
11716 bdc78ba6 2022-02-16 jrick {
11717 bdc78ba6 2022-02-16 jrick long long h, m;
11718 bdc78ba6 2022-02-16 jrick char sign = '+';
11719 e546352c 2022-02-16 jrick
11720 bdc78ba6 2022-02-16 jrick if (gmtoff < 0) {
11721 bdc78ba6 2022-02-16 jrick sign = '-';
11722 bdc78ba6 2022-02-16 jrick gmtoff = -gmtoff;
11723 bdc78ba6 2022-02-16 jrick }
11724 bdc78ba6 2022-02-16 jrick
11725 bdc78ba6 2022-02-16 jrick h = (long long)gmtoff / 3600;
11726 bdc78ba6 2022-02-16 jrick m = ((long long)gmtoff - h*3600) / 60;
11727 bdc78ba6 2022-02-16 jrick snprintf(buf, sz, "%c%02lld%02lld", sign, h, m);
11728 bdc78ba6 2022-02-16 jrick }
11729 bdc78ba6 2022-02-16 jrick
11730 01073a5d 2019-08-22 stsp static const struct got_error *
11731 01073a5d 2019-08-22 stsp cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11732 01073a5d 2019-08-22 stsp {
11733 01073a5d 2019-08-22 stsp const struct got_error *err;
11734 01073a5d 2019-08-22 stsp struct got_commit_object *commit;
11735 01073a5d 2019-08-22 stsp const struct got_object_id_queue *parent_ids;
11736 01073a5d 2019-08-22 stsp struct got_object_qid *pid;
11737 01073a5d 2019-08-22 stsp char *id_str = NULL;
11738 24ea5512 2019-08-22 stsp const char *logmsg = NULL;
11739 bdc78ba6 2022-02-16 jrick char gmtoff[6];
11740 01073a5d 2019-08-22 stsp
11741 01073a5d 2019-08-22 stsp err = got_object_open_as_commit(&commit, repo, id);
11742 01073a5d 2019-08-22 stsp if (err)
11743 01073a5d 2019-08-22 stsp return err;
11744 01073a5d 2019-08-22 stsp
11745 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
11746 01073a5d 2019-08-22 stsp if (err)
11747 01073a5d 2019-08-22 stsp goto done;
11748 01073a5d 2019-08-22 stsp
11749 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str);
11750 01073a5d 2019-08-22 stsp parent_ids = got_object_commit_get_parent_ids(commit);
11751 8aa93786 2019-08-22 stsp fprintf(outfile, "numparents %d\n",
11752 01073a5d 2019-08-22 stsp got_object_commit_get_nparents(commit));
11753 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(pid, parent_ids, entry) {
11754 01073a5d 2019-08-22 stsp char *pid_str;
11755 d7b5a0e8 2022-04-20 stsp err = got_object_id_str(&pid_str, &pid->id);
11756 01073a5d 2019-08-22 stsp if (err)
11757 01073a5d 2019-08-22 stsp goto done;
11758 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str);
11759 01073a5d 2019-08-22 stsp free(pid_str);
11760 01073a5d 2019-08-22 stsp }
11761 bdc78ba6 2022-02-16 jrick format_gmtoff(gmtoff, sizeof(gmtoff),
11762 bdc78ba6 2022-02-16 jrick got_object_commit_get_author_gmtoff(commit));
11763 bdc78ba6 2022-02-16 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR,
11764 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
11765 bdc78ba6 2022-02-16 jrick (long long)got_object_commit_get_author_time(commit),
11766 bdc78ba6 2022-02-16 jrick gmtoff);
11767 01073a5d 2019-08-22 stsp
11768 bdc78ba6 2022-02-16 jrick format_gmtoff(gmtoff, sizeof(gmtoff),
11769 bdc78ba6 2022-02-16 jrick got_object_commit_get_committer_gmtoff(commit));
11770 bdc78ba6 2022-02-16 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER,
11771 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
11772 bdc78ba6 2022-02-16 jrick (long long)got_object_commit_get_committer_time(commit),
11773 bdc78ba6 2022-02-16 jrick gmtoff);
11774 01073a5d 2019-08-22 stsp
11775 24ea5512 2019-08-22 stsp logmsg = got_object_commit_get_logmsg_raw(commit);
11776 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
11777 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", logmsg);
11778 01073a5d 2019-08-22 stsp done:
11779 01073a5d 2019-08-22 stsp free(id_str);
11780 01073a5d 2019-08-22 stsp got_object_commit_close(commit);
11781 01073a5d 2019-08-22 stsp return err;
11782 01073a5d 2019-08-22 stsp }
11783 01073a5d 2019-08-22 stsp
11784 01073a5d 2019-08-22 stsp static const struct got_error *
11785 01073a5d 2019-08-22 stsp cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11786 01073a5d 2019-08-22 stsp {
11787 01073a5d 2019-08-22 stsp const struct got_error *err;
11788 01073a5d 2019-08-22 stsp struct got_tag_object *tag;
11789 01073a5d 2019-08-22 stsp char *id_str = NULL;
11790 01073a5d 2019-08-22 stsp const char *tagmsg = NULL;
11791 bdc78ba6 2022-02-16 jrick char gmtoff[6];
11792 01073a5d 2019-08-22 stsp
11793 01073a5d 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
11794 01073a5d 2019-08-22 stsp if (err)
11795 01073a5d 2019-08-22 stsp return err;
11796 01073a5d 2019-08-22 stsp
11797 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
11798 01073a5d 2019-08-22 stsp if (err)
11799 01073a5d 2019-08-22 stsp goto done;
11800 01073a5d 2019-08-22 stsp
11801 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str);
11802 e15d5241 2019-08-22 stsp
11803 01073a5d 2019-08-22 stsp switch (got_object_tag_get_object_type(tag)) {
11804 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
11805 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11806 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_BLOB);
11807 01073a5d 2019-08-22 stsp break;
11808 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
11809 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11810 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TREE);
11811 01073a5d 2019-08-22 stsp break;
11812 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
11813 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11814 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_COMMIT);
11815 01073a5d 2019-08-22 stsp break;
11816 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
11817 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11818 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TAG);
11819 01073a5d 2019-08-22 stsp break;
11820 01073a5d 2019-08-22 stsp default:
11821 01073a5d 2019-08-22 stsp break;
11822 01073a5d 2019-08-22 stsp }
11823 01073a5d 2019-08-22 stsp
11824 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG,
11825 e15d5241 2019-08-22 stsp got_object_tag_get_name(tag));
11826 e15d5241 2019-08-22 stsp
11827 bdc78ba6 2022-02-16 jrick format_gmtoff(gmtoff, sizeof(gmtoff),
11828 bdc78ba6 2022-02-16 jrick got_object_tag_get_tagger_gmtoff(tag));
11829 bdc78ba6 2022-02-16 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER,
11830 8aa93786 2019-08-22 stsp got_object_tag_get_tagger(tag),
11831 bdc78ba6 2022-02-16 jrick (long long)got_object_tag_get_tagger_time(tag),
11832 bdc78ba6 2022-02-16 jrick gmtoff);
11833 01073a5d 2019-08-22 stsp
11834 01073a5d 2019-08-22 stsp tagmsg = got_object_tag_get_message(tag);
11835 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
11836 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", tagmsg);
11837 01073a5d 2019-08-22 stsp done:
11838 01073a5d 2019-08-22 stsp free(id_str);
11839 01073a5d 2019-08-22 stsp got_object_tag_close(tag);
11840 01073a5d 2019-08-22 stsp return err;
11841 01073a5d 2019-08-22 stsp }
11842 01073a5d 2019-08-22 stsp
11843 01073a5d 2019-08-22 stsp static const struct got_error *
11844 01073a5d 2019-08-22 stsp cmd_cat(int argc, char *argv[])
11845 01073a5d 2019-08-22 stsp {
11846 01073a5d 2019-08-22 stsp const struct got_error *error;
11847 01073a5d 2019-08-22 stsp struct got_repository *repo = NULL;
11848 01073a5d 2019-08-22 stsp struct got_worktree *worktree = NULL;
11849 01073a5d 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *label = NULL;
11850 896e9b6f 2019-08-26 stsp const char *commit_id_str = NULL;
11851 896e9b6f 2019-08-26 stsp struct got_object_id *id = NULL, *commit_id = NULL;
11852 a44927cc 2022-04-07 stsp struct got_commit_object *commit = NULL;
11853 896e9b6f 2019-08-26 stsp int ch, obj_type, i, force_path = 0;
11854 84de9106 2020-12-26 stsp struct got_reflist_head refs;
11855 84de9106 2020-12-26 stsp
11856 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
11857 01073a5d 2019-08-22 stsp
11858 01073a5d 2019-08-22 stsp #ifndef PROFILE
11859 01073a5d 2019-08-22 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
11860 01073a5d 2019-08-22 stsp NULL) == -1)
11861 01073a5d 2019-08-22 stsp err(1, "pledge");
11862 01073a5d 2019-08-22 stsp #endif
11863 01073a5d 2019-08-22 stsp
11864 896e9b6f 2019-08-26 stsp while ((ch = getopt(argc, argv, "c:r:P")) != -1) {
11865 01073a5d 2019-08-22 stsp switch (ch) {
11866 896e9b6f 2019-08-26 stsp case 'c':
11867 896e9b6f 2019-08-26 stsp commit_id_str = optarg;
11868 896e9b6f 2019-08-26 stsp break;
11869 01073a5d 2019-08-22 stsp case 'r':
11870 01073a5d 2019-08-22 stsp repo_path = realpath(optarg, NULL);
11871 01073a5d 2019-08-22 stsp if (repo_path == NULL)
11872 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
11873 9ba1d308 2019-10-21 stsp optarg);
11874 01073a5d 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
11875 01073a5d 2019-08-22 stsp break;
11876 896e9b6f 2019-08-26 stsp case 'P':
11877 896e9b6f 2019-08-26 stsp force_path = 1;
11878 896e9b6f 2019-08-26 stsp break;
11879 01073a5d 2019-08-22 stsp default:
11880 01073a5d 2019-08-22 stsp usage_cat();
11881 01073a5d 2019-08-22 stsp /* NOTREACHED */
11882 01073a5d 2019-08-22 stsp }
11883 01073a5d 2019-08-22 stsp }
11884 01073a5d 2019-08-22 stsp
11885 01073a5d 2019-08-22 stsp argc -= optind;
11886 01073a5d 2019-08-22 stsp argv += optind;
11887 01073a5d 2019-08-22 stsp
11888 01073a5d 2019-08-22 stsp cwd = getcwd(NULL, 0);
11889 01073a5d 2019-08-22 stsp if (cwd == NULL) {
11890 01073a5d 2019-08-22 stsp error = got_error_from_errno("getcwd");
11891 01073a5d 2019-08-22 stsp goto done;
11892 01073a5d 2019-08-22 stsp }
11893 a091f71a 2022-04-09 stsp
11894 a091f71a 2022-04-09 stsp if (repo_path == NULL) {
11895 a091f71a 2022-04-09 stsp error = got_worktree_open(&worktree, cwd);
11896 a091f71a 2022-04-09 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
11897 a091f71a 2022-04-09 stsp goto done;
11898 a091f71a 2022-04-09 stsp if (worktree) {
11899 01073a5d 2019-08-22 stsp repo_path = strdup(
11900 01073a5d 2019-08-22 stsp got_worktree_get_repo_path(worktree));
11901 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
11902 01073a5d 2019-08-22 stsp error = got_error_from_errno("strdup");
11903 01073a5d 2019-08-22 stsp goto done;
11904 01073a5d 2019-08-22 stsp }
11905 f7fce2e2 2022-03-12 stsp
11906 a091f71a 2022-04-09 stsp /* Release work tree lock. */
11907 a091f71a 2022-04-09 stsp got_worktree_close(worktree);
11908 a091f71a 2022-04-09 stsp worktree = NULL;
11909 a091f71a 2022-04-09 stsp }
11910 01073a5d 2019-08-22 stsp }
11911 01073a5d 2019-08-22 stsp
11912 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
11913 a091f71a 2022-04-09 stsp repo_path = strdup(cwd);
11914 01073a5d 2019-08-22 stsp if (repo_path == NULL)
11915 a091f71a 2022-04-09 stsp return got_error_from_errno("strdup");
11916 01073a5d 2019-08-22 stsp }
11917 01073a5d 2019-08-22 stsp
11918 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
11919 01073a5d 2019-08-22 stsp free(repo_path);
11920 01073a5d 2019-08-22 stsp if (error != NULL)
11921 01073a5d 2019-08-22 stsp goto done;
11922 01073a5d 2019-08-22 stsp
11923 01073a5d 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
11924 896e9b6f 2019-08-26 stsp if (error)
11925 896e9b6f 2019-08-26 stsp goto done;
11926 896e9b6f 2019-08-26 stsp
11927 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
11928 84de9106 2020-12-26 stsp if (error)
11929 84de9106 2020-12-26 stsp goto done;
11930 84de9106 2020-12-26 stsp
11931 896e9b6f 2019-08-26 stsp if (commit_id_str == NULL)
11932 896e9b6f 2019-08-26 stsp commit_id_str = GOT_REF_HEAD;
11933 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
11934 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
11935 01073a5d 2019-08-22 stsp if (error)
11936 01073a5d 2019-08-22 stsp goto done;
11937 01073a5d 2019-08-22 stsp
11938 a44927cc 2022-04-07 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
11939 a44927cc 2022-04-07 stsp if (error)
11940 a44927cc 2022-04-07 stsp goto done;
11941 a44927cc 2022-04-07 stsp
11942 01073a5d 2019-08-22 stsp for (i = 0; i < argc; i++) {
11943 896e9b6f 2019-08-26 stsp if (force_path) {
11944 a44927cc 2022-04-07 stsp error = got_object_id_by_path(&id, repo, commit,
11945 896e9b6f 2019-08-26 stsp argv[i]);
11946 896e9b6f 2019-08-26 stsp if (error)
11947 896e9b6f 2019-08-26 stsp break;
11948 896e9b6f 2019-08-26 stsp } else {
11949 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id, &label, argv[i],
11950 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */,
11951 84de9106 2020-12-26 stsp repo);
11952 896e9b6f 2019-08-26 stsp if (error) {
11953 896e9b6f 2019-08-26 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR &&
11954 896e9b6f 2019-08-26 stsp error->code != GOT_ERR_NOT_REF)
11955 896e9b6f 2019-08-26 stsp break;
11956 896e9b6f 2019-08-26 stsp error = got_object_id_by_path(&id, repo,
11957 a44927cc 2022-04-07 stsp commit, argv[i]);
11958 896e9b6f 2019-08-26 stsp if (error)
11959 896e9b6f 2019-08-26 stsp break;
11960 896e9b6f 2019-08-26 stsp }
11961 896e9b6f 2019-08-26 stsp }
11962 01073a5d 2019-08-22 stsp
11963 01073a5d 2019-08-22 stsp error = got_object_get_type(&obj_type, repo, id);
11964 01073a5d 2019-08-22 stsp if (error)
11965 01073a5d 2019-08-22 stsp break;
11966 01073a5d 2019-08-22 stsp
11967 01073a5d 2019-08-22 stsp switch (obj_type) {
11968 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
11969 01073a5d 2019-08-22 stsp error = cat_blob(id, repo, stdout);
11970 01073a5d 2019-08-22 stsp break;
11971 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
11972 01073a5d 2019-08-22 stsp error = cat_tree(id, repo, stdout);
11973 01073a5d 2019-08-22 stsp break;
11974 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
11975 01073a5d 2019-08-22 stsp error = cat_commit(id, repo, stdout);
11976 01073a5d 2019-08-22 stsp break;
11977 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
11978 01073a5d 2019-08-22 stsp error = cat_tag(id, repo, stdout);
11979 01073a5d 2019-08-22 stsp break;
11980 01073a5d 2019-08-22 stsp default:
11981 01073a5d 2019-08-22 stsp error = got_error(GOT_ERR_OBJ_TYPE);
11982 01073a5d 2019-08-22 stsp break;
11983 01073a5d 2019-08-22 stsp }
11984 01073a5d 2019-08-22 stsp if (error)
11985 01073a5d 2019-08-22 stsp break;
11986 01073a5d 2019-08-22 stsp free(label);
11987 01073a5d 2019-08-22 stsp label = NULL;
11988 01073a5d 2019-08-22 stsp free(id);
11989 01073a5d 2019-08-22 stsp id = NULL;
11990 01073a5d 2019-08-22 stsp }
11991 01073a5d 2019-08-22 stsp done:
11992 01073a5d 2019-08-22 stsp free(label);
11993 01073a5d 2019-08-22 stsp free(id);
11994 896e9b6f 2019-08-26 stsp free(commit_id);
11995 a44927cc 2022-04-07 stsp if (commit)
11996 a44927cc 2022-04-07 stsp got_object_commit_close(commit);
11997 01073a5d 2019-08-22 stsp if (worktree)
11998 01073a5d 2019-08-22 stsp got_worktree_close(worktree);
11999 01073a5d 2019-08-22 stsp if (repo) {
12000 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
12001 01073a5d 2019-08-22 stsp if (error == NULL)
12002 1d0f4054 2021-06-17 stsp error = close_err;
12003 b2118c49 2020-07-28 stsp }
12004 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
12005 b2118c49 2020-07-28 stsp return error;
12006 b2118c49 2020-07-28 stsp }
12007 b2118c49 2020-07-28 stsp
12008 b2118c49 2020-07-28 stsp __dead static void
12009 b2118c49 2020-07-28 stsp usage_info(void)
12010 b2118c49 2020-07-28 stsp {
12011 b2118c49 2020-07-28 stsp fprintf(stderr, "usage: %s info [path ...]\n",
12012 b2118c49 2020-07-28 stsp getprogname());
12013 b2118c49 2020-07-28 stsp exit(1);
12014 b2118c49 2020-07-28 stsp }
12015 b2118c49 2020-07-28 stsp
12016 b2118c49 2020-07-28 stsp static const struct got_error *
12017 b2118c49 2020-07-28 stsp print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
12018 b2118c49 2020-07-28 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
12019 b2118c49 2020-07-28 stsp struct got_object_id *commit_id)
12020 b2118c49 2020-07-28 stsp {
12021 b2118c49 2020-07-28 stsp const struct got_error *err = NULL;
12022 b2118c49 2020-07-28 stsp char *id_str = NULL;
12023 b2118c49 2020-07-28 stsp char datebuf[128];
12024 b2118c49 2020-07-28 stsp struct tm mytm, *tm;
12025 b2118c49 2020-07-28 stsp struct got_pathlist_head *paths = arg;
12026 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
12027 b2118c49 2020-07-28 stsp
12028 b2118c49 2020-07-28 stsp /*
12029 b2118c49 2020-07-28 stsp * Clear error indication from any of the path arguments which
12030 b2118c49 2020-07-28 stsp * would cause this file index entry to be displayed.
12031 b2118c49 2020-07-28 stsp */
12032 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, paths, entry) {
12033 b2118c49 2020-07-28 stsp if (got_path_cmp(path, pe->path, strlen(path),
12034 b2118c49 2020-07-28 stsp pe->path_len) == 0 ||
12035 b2118c49 2020-07-28 stsp got_path_is_child(path, pe->path, pe->path_len))
12036 b2118c49 2020-07-28 stsp pe->data = NULL; /* no error */
12037 b2118c49 2020-07-28 stsp }
12038 b2118c49 2020-07-28 stsp
12039 b2118c49 2020-07-28 stsp printf(GOT_COMMIT_SEP_STR);
12040 b2118c49 2020-07-28 stsp if (S_ISLNK(mode))
12041 b2118c49 2020-07-28 stsp printf("symlink: %s\n", path);
12042 b2118c49 2020-07-28 stsp else if (S_ISREG(mode)) {
12043 b2118c49 2020-07-28 stsp printf("file: %s\n", path);
12044 b2118c49 2020-07-28 stsp printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO));
12045 b2118c49 2020-07-28 stsp } else if (S_ISDIR(mode))
12046 b2118c49 2020-07-28 stsp printf("directory: %s\n", path);
12047 b2118c49 2020-07-28 stsp else
12048 b2118c49 2020-07-28 stsp printf("something: %s\n", path);
12049 b2118c49 2020-07-28 stsp
12050 b2118c49 2020-07-28 stsp tm = localtime_r(&mtime, &mytm);
12051 b2118c49 2020-07-28 stsp if (tm == NULL)
12052 b2118c49 2020-07-28 stsp return NULL;
12053 ec6d1a36 2021-03-21 jrick if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0)
12054 b2118c49 2020-07-28 stsp return got_error(GOT_ERR_NO_SPACE);
12055 b2118c49 2020-07-28 stsp printf("timestamp: %s\n", datebuf);
12056 b2118c49 2020-07-28 stsp
12057 b2118c49 2020-07-28 stsp if (blob_id) {
12058 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, blob_id);
12059 b2118c49 2020-07-28 stsp if (err)
12060 b2118c49 2020-07-28 stsp return err;
12061 b2118c49 2020-07-28 stsp printf("based on blob: %s\n", id_str);
12062 b2118c49 2020-07-28 stsp free(id_str);
12063 b2118c49 2020-07-28 stsp }
12064 b2118c49 2020-07-28 stsp
12065 b2118c49 2020-07-28 stsp if (staged_blob_id) {
12066 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, staged_blob_id);
12067 b2118c49 2020-07-28 stsp if (err)
12068 b2118c49 2020-07-28 stsp return err;
12069 b2118c49 2020-07-28 stsp printf("based on staged blob: %s\n", id_str);
12070 b2118c49 2020-07-28 stsp free(id_str);
12071 b2118c49 2020-07-28 stsp }
12072 b2118c49 2020-07-28 stsp
12073 b2118c49 2020-07-28 stsp if (commit_id) {
12074 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, commit_id);
12075 b2118c49 2020-07-28 stsp if (err)
12076 b2118c49 2020-07-28 stsp return err;
12077 b2118c49 2020-07-28 stsp printf("based on commit: %s\n", id_str);
12078 b2118c49 2020-07-28 stsp free(id_str);
12079 b2118c49 2020-07-28 stsp }
12080 b2118c49 2020-07-28 stsp
12081 b2118c49 2020-07-28 stsp return NULL;
12082 b2118c49 2020-07-28 stsp }
12083 b2118c49 2020-07-28 stsp
12084 b2118c49 2020-07-28 stsp static const struct got_error *
12085 b2118c49 2020-07-28 stsp cmd_info(int argc, char *argv[])
12086 b2118c49 2020-07-28 stsp {
12087 b2118c49 2020-07-28 stsp const struct got_error *error = NULL;
12088 b2118c49 2020-07-28 stsp struct got_worktree *worktree = NULL;
12089 b2118c49 2020-07-28 stsp char *cwd = NULL, *id_str = NULL;
12090 b2118c49 2020-07-28 stsp struct got_pathlist_head paths;
12091 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
12092 b2118c49 2020-07-28 stsp char *uuidstr = NULL;
12093 b2118c49 2020-07-28 stsp int ch, show_files = 0;
12094 b2118c49 2020-07-28 stsp
12095 b2118c49 2020-07-28 stsp TAILQ_INIT(&paths);
12096 b2118c49 2020-07-28 stsp
12097 b2118c49 2020-07-28 stsp while ((ch = getopt(argc, argv, "")) != -1) {
12098 b2118c49 2020-07-28 stsp switch (ch) {
12099 b2118c49 2020-07-28 stsp default:
12100 b2118c49 2020-07-28 stsp usage_info();
12101 b2118c49 2020-07-28 stsp /* NOTREACHED */
12102 b2118c49 2020-07-28 stsp }
12103 01073a5d 2019-08-22 stsp }
12104 b2118c49 2020-07-28 stsp
12105 b2118c49 2020-07-28 stsp argc -= optind;
12106 b2118c49 2020-07-28 stsp argv += optind;
12107 b2118c49 2020-07-28 stsp
12108 b2118c49 2020-07-28 stsp #ifndef PROFILE
12109 b2118c49 2020-07-28 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
12110 b2118c49 2020-07-28 stsp NULL) == -1)
12111 b2118c49 2020-07-28 stsp err(1, "pledge");
12112 b2118c49 2020-07-28 stsp #endif
12113 b2118c49 2020-07-28 stsp cwd = getcwd(NULL, 0);
12114 b2118c49 2020-07-28 stsp if (cwd == NULL) {
12115 b2118c49 2020-07-28 stsp error = got_error_from_errno("getcwd");
12116 b2118c49 2020-07-28 stsp goto done;
12117 b2118c49 2020-07-28 stsp }
12118 b2118c49 2020-07-28 stsp
12119 b2118c49 2020-07-28 stsp error = got_worktree_open(&worktree, cwd);
12120 b2118c49 2020-07-28 stsp if (error) {
12121 b2118c49 2020-07-28 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
12122 8ea5c997 2021-02-07 naddy error = wrap_not_worktree_error(error, "info", cwd);
12123 b2118c49 2020-07-28 stsp goto done;
12124 b2118c49 2020-07-28 stsp }
12125 b2118c49 2020-07-28 stsp
12126 b2118c49 2020-07-28 stsp error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree));
12127 b2118c49 2020-07-28 stsp if (error)
12128 b2118c49 2020-07-28 stsp goto done;
12129 b2118c49 2020-07-28 stsp
12130 b2118c49 2020-07-28 stsp if (argc >= 1) {
12131 b2118c49 2020-07-28 stsp error = get_worktree_paths_from_argv(&paths, argc, argv,
12132 b2118c49 2020-07-28 stsp worktree);
12133 b2118c49 2020-07-28 stsp if (error)
12134 b2118c49 2020-07-28 stsp goto done;
12135 b2118c49 2020-07-28 stsp show_files = 1;
12136 b2118c49 2020-07-28 stsp }
12137 b2118c49 2020-07-28 stsp
12138 b2118c49 2020-07-28 stsp error = got_object_id_str(&id_str,
12139 b2118c49 2020-07-28 stsp got_worktree_get_base_commit_id(worktree));
12140 b2118c49 2020-07-28 stsp if (error)
12141 b2118c49 2020-07-28 stsp goto done;
12142 b2118c49 2020-07-28 stsp
12143 b2118c49 2020-07-28 stsp error = got_worktree_get_uuid(&uuidstr, worktree);
12144 b2118c49 2020-07-28 stsp if (error)
12145 b2118c49 2020-07-28 stsp goto done;
12146 b2118c49 2020-07-28 stsp
12147 b2118c49 2020-07-28 stsp printf("work tree: %s\n", got_worktree_get_root_path(worktree));
12148 b2118c49 2020-07-28 stsp printf("work tree base commit: %s\n", id_str);
12149 b2118c49 2020-07-28 stsp printf("work tree path prefix: %s\n",
12150 b2118c49 2020-07-28 stsp got_worktree_get_path_prefix(worktree));
12151 b2118c49 2020-07-28 stsp printf("work tree branch reference: %s\n",
12152 b2118c49 2020-07-28 stsp got_worktree_get_head_ref_name(worktree));
12153 b2118c49 2020-07-28 stsp printf("work tree UUID: %s\n", uuidstr);
12154 b2118c49 2020-07-28 stsp printf("repository: %s\n", got_worktree_get_repo_path(worktree));
12155 b2118c49 2020-07-28 stsp
12156 b2118c49 2020-07-28 stsp if (show_files) {
12157 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
12158 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
12159 b2118c49 2020-07-28 stsp if (pe->path_len == 0)
12160 b2118c49 2020-07-28 stsp continue;
12161 b2118c49 2020-07-28 stsp /*
12162 b2118c49 2020-07-28 stsp * Assume this path will fail. This will be corrected
12163 b2118c49 2020-07-28 stsp * in print_path_info() in case the path does suceeed.
12164 b2118c49 2020-07-28 stsp */
12165 b2118c49 2020-07-28 stsp pe->data = (void *)got_error_path(pe->path,
12166 b2118c49 2020-07-28 stsp GOT_ERR_BAD_PATH);
12167 b2118c49 2020-07-28 stsp }
12168 b2118c49 2020-07-28 stsp error = got_worktree_path_info(worktree, &paths,
12169 b2118c49 2020-07-28 stsp print_path_info, &paths, check_cancelled, NULL);
12170 b2118c49 2020-07-28 stsp if (error)
12171 b2118c49 2020-07-28 stsp goto done;
12172 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
12173 b2118c49 2020-07-28 stsp if (pe->data != NULL) {
12174 b2118c49 2020-07-28 stsp error = pe->data; /* bad path */
12175 b2118c49 2020-07-28 stsp break;
12176 b2118c49 2020-07-28 stsp }
12177 b2118c49 2020-07-28 stsp }
12178 b2118c49 2020-07-28 stsp }
12179 b2118c49 2020-07-28 stsp done:
12180 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry)
12181 b2118c49 2020-07-28 stsp free((char *)pe->path);
12182 b2118c49 2020-07-28 stsp got_pathlist_free(&paths);
12183 b2118c49 2020-07-28 stsp free(cwd);
12184 b2118c49 2020-07-28 stsp free(id_str);
12185 b2118c49 2020-07-28 stsp free(uuidstr);
12186 0ebf8283 2019-07-24 stsp return error;
12187 0ebf8283 2019-07-24 stsp }