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 c0768b0f 2018-06-10 stsp #include <sys/types.h>
20 5de5890b 2018-10-18 stsp #include <sys/stat.h>
21 33ad4cbe 2019-05-12 jcs #include <sys/wait.h>
22 f42b1b34 2018-03-12 stsp
23 5c860e29 2018-03-12 stsp #include <err.h>
24 5c860e29 2018-03-12 stsp #include <errno.h>
25 12463d8b 2019-12-13 stsp #include <fcntl.h>
26 12ce7a6c 2019-08-12 stsp #include <limits.h>
27 5c860e29 2018-03-12 stsp #include <locale.h>
28 818c7501 2019-07-11 stsp #include <ctype.h>
29 99437157 2018-11-11 stsp #include <signal.h>
30 5c860e29 2018-03-12 stsp #include <stdio.h>
31 5c860e29 2018-03-12 stsp #include <stdlib.h>
32 5c860e29 2018-03-12 stsp #include <string.h>
33 5c860e29 2018-03-12 stsp #include <unistd.h>
34 c09a553d 2018-03-12 stsp #include <libgen.h>
35 c0768b0f 2018-06-10 stsp #include <time.h>
36 33ad4cbe 2019-05-12 jcs #include <paths.h>
37 6841bf13 2019-11-29 kn #include <regex.h>
38 83cd27f8 2020-01-13 stsp #include <getopt.h>
39 dd038bc6 2021-09-21 thomas.ad
40 dd038bc6 2021-09-21 thomas.ad #include "got_compat.h"
41 5c860e29 2018-03-12 stsp
42 53ccebc2 2019-07-30 stsp #include "got_version.h"
43 f42b1b34 2018-03-12 stsp #include "got_error.h"
44 f42b1b34 2018-03-12 stsp #include "got_object.h"
45 5261c201 2018-04-01 stsp #include "got_reference.h"
46 f42b1b34 2018-03-12 stsp #include "got_repository.h"
47 1dd54920 2019-05-11 stsp #include "got_path.h"
48 e6209546 2019-08-22 stsp #include "got_cancel.h"
49 c09a553d 2018-03-12 stsp #include "got_worktree.h"
50 79109fed 2018-03-27 stsp #include "got_diff.h"
51 372ccdbb 2018-06-10 stsp #include "got_commit_graph.h"
52 6f23baec 2020-03-18 stsp #include "got_fetch.h"
53 f8a36e22 2021-08-26 stsp #include "got_send.h"
54 404c43c4 2018-06-21 stsp #include "got_blame.h"
55 63219cd2 2019-01-04 stsp #include "got_privsep.h"
56 793c30b5 2019-05-13 stsp #include "got_opentemp.h"
57 50b0790e 2020-09-11 stsp #include "got_gotconfig.h"
58 d65a88a2 2021-09-05 stsp #include "got_dial.h"
59 5c860e29 2018-03-12 stsp
60 5c860e29 2018-03-12 stsp #ifndef nitems
61 5c860e29 2018-03-12 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
62 5c860e29 2018-03-12 stsp #endif
63 99437157 2018-11-11 stsp
64 99437157 2018-11-11 stsp static volatile sig_atomic_t sigint_received;
65 99437157 2018-11-11 stsp static volatile sig_atomic_t sigpipe_received;
66 99437157 2018-11-11 stsp
67 99437157 2018-11-11 stsp static void
68 99437157 2018-11-11 stsp catch_sigint(int signo)
69 99437157 2018-11-11 stsp {
70 99437157 2018-11-11 stsp sigint_received = 1;
71 99437157 2018-11-11 stsp }
72 99437157 2018-11-11 stsp
73 99437157 2018-11-11 stsp static void
74 99437157 2018-11-11 stsp catch_sigpipe(int signo)
75 99437157 2018-11-11 stsp {
76 99437157 2018-11-11 stsp sigpipe_received = 1;
77 99437157 2018-11-11 stsp }
78 5c860e29 2018-03-12 stsp
79 99437157 2018-11-11 stsp
80 8cfb4057 2019-07-09 stsp struct got_cmd {
81 820059fa 2020-09-25 stsp const char *cmd_name;
82 d7d4f210 2018-03-12 stsp const struct got_error *(*cmd_main)(int, char *[]);
83 1b6b95a8 2018-03-12 stsp void (*cmd_usage)(void);
84 97b3a7be 2019-07-09 stsp const char *cmd_alias;
85 5c860e29 2018-03-12 stsp };
86 5c860e29 2018-03-12 stsp
87 6879ba42 2020-10-01 naddy __dead static void usage(int, int);
88 2c7829a4 2019-06-17 stsp __dead static void usage_init(void);
89 3ce1b845 2019-07-15 stsp __dead static void usage_import(void);
90 93658fb9 2020-03-18 stsp __dead static void usage_clone(void);
91 7848a0e1 2020-03-19 stsp __dead static void usage_fetch(void);
92 2ab43947 2020-03-18 stsp __dead static void usage_checkout(void);
93 507dc3bb 2018-12-29 stsp __dead static void usage_update(void);
94 4ed7e80c 2018-05-20 stsp __dead static void usage_log(void);
95 4ed7e80c 2018-05-20 stsp __dead static void usage_diff(void);
96 404c43c4 2018-06-21 stsp __dead static void usage_blame(void);
97 5de5890b 2018-10-18 stsp __dead static void usage_tree(void);
98 6bad629b 2019-02-04 stsp __dead static void usage_status(void);
99 d0eebce4 2019-03-11 stsp __dead static void usage_ref(void);
100 4e759de4 2019-06-26 stsp __dead static void usage_branch(void);
101 8e7bd50a 2019-08-22 stsp __dead static void usage_tag(void);
102 d00136be 2019-03-26 stsp __dead static void usage_add(void);
103 648e4ef7 2019-07-09 stsp __dead static void usage_remove(void);
104 a129376b 2019-03-28 stsp __dead static void usage_revert(void);
105 c4296144 2019-05-09 stsp __dead static void usage_commit(void);
106 f8a36e22 2021-08-26 stsp __dead static void usage_send(void);
107 234035bc 2019-06-01 stsp __dead static void usage_cherrypick(void);
108 5ef14e63 2019-06-02 stsp __dead static void usage_backout(void);
109 818c7501 2019-07-11 stsp __dead static void usage_rebase(void);
110 0ebf8283 2019-07-24 stsp __dead static void usage_histedit(void);
111 2822a352 2019-10-15 stsp __dead static void usage_integrate(void);
112 10604dce 2021-09-24 thomas __dead static void usage_merge(void);
113 715dc77e 2019-08-03 stsp __dead static void usage_stage(void);
114 ad493afc 2019-08-03 stsp __dead static void usage_unstage(void);
115 01073a5d 2019-08-22 stsp __dead static void usage_cat(void);
116 b2118c49 2020-07-28 stsp __dead static void usage_info(void);
117 5c860e29 2018-03-12 stsp
118 2c7829a4 2019-06-17 stsp static const struct got_error* cmd_init(int, char *[]);
119 3ce1b845 2019-07-15 stsp static const struct got_error* cmd_import(int, char *[]);
120 93658fb9 2020-03-18 stsp static const struct got_error* cmd_clone(int, char *[]);
121 7848a0e1 2020-03-19 stsp static const struct got_error* cmd_fetch(int, char *[]);
122 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_checkout(int, char *[]);
123 507dc3bb 2018-12-29 stsp static const struct got_error* cmd_update(int, char *[]);
124 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_log(int, char *[]);
125 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_diff(int, char *[]);
126 404c43c4 2018-06-21 stsp static const struct got_error* cmd_blame(int, char *[]);
127 5de5890b 2018-10-18 stsp static const struct got_error* cmd_tree(int, char *[]);
128 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_status(int, char *[]);
129 d0eebce4 2019-03-11 stsp static const struct got_error* cmd_ref(int, char *[]);
130 4e759de4 2019-06-26 stsp static const struct got_error* cmd_branch(int, char *[]);
131 8e7bd50a 2019-08-22 stsp static const struct got_error* cmd_tag(int, char *[]);
132 d00136be 2019-03-26 stsp static const struct got_error* cmd_add(int, char *[]);
133 648e4ef7 2019-07-09 stsp static const struct got_error* cmd_remove(int, char *[]);
134 a129376b 2019-03-28 stsp static const struct got_error* cmd_revert(int, char *[]);
135 c4296144 2019-05-09 stsp static const struct got_error* cmd_commit(int, char *[]);
136 f8a36e22 2021-08-26 stsp static const struct got_error* cmd_send(int, char *[]);
137 234035bc 2019-06-01 stsp static const struct got_error* cmd_cherrypick(int, char *[]);
138 5ef14e63 2019-06-02 stsp static const struct got_error* cmd_backout(int, char *[]);
139 818c7501 2019-07-11 stsp static const struct got_error* cmd_rebase(int, char *[]);
140 0ebf8283 2019-07-24 stsp static const struct got_error* cmd_histedit(int, char *[]);
141 2822a352 2019-10-15 stsp static const struct got_error* cmd_integrate(int, char *[]);
142 10604dce 2021-09-24 thomas static const struct got_error* cmd_merge(int, char *[]);
143 715dc77e 2019-08-03 stsp static const struct got_error* cmd_stage(int, char *[]);
144 ad493afc 2019-08-03 stsp static const struct got_error* cmd_unstage(int, char *[]);
145 01073a5d 2019-08-22 stsp static const struct got_error* cmd_cat(int, char *[]);
146 b2118c49 2020-07-28 stsp static const struct got_error* cmd_info(int, char *[]);
147 5c860e29 2018-03-12 stsp
148 8cfb4057 2019-07-09 stsp static struct got_cmd got_commands[] = {
149 b2118c49 2020-07-28 stsp { "init", cmd_init, usage_init, "" },
150 bc26cce8 2019-08-04 stsp { "import", cmd_import, usage_import, "im" },
151 93658fb9 2020-03-18 stsp { "clone", cmd_clone, usage_clone, "cl" },
152 7848a0e1 2020-03-19 stsp { "fetch", cmd_fetch, usage_fetch, "fe" },
153 2ab43947 2020-03-18 stsp { "checkout", cmd_checkout, usage_checkout, "co" },
154 97b3a7be 2019-07-09 stsp { "update", cmd_update, usage_update, "up" },
155 97b3a7be 2019-07-09 stsp { "log", cmd_log, usage_log, "" },
156 bc26cce8 2019-08-04 stsp { "diff", cmd_diff, usage_diff, "di" },
157 bc26cce8 2019-08-04 stsp { "blame", cmd_blame, usage_blame, "bl" },
158 bc26cce8 2019-08-04 stsp { "tree", cmd_tree, usage_tree, "tr" },
159 97b3a7be 2019-07-09 stsp { "status", cmd_status, usage_status, "st" },
160 97b3a7be 2019-07-09 stsp { "ref", cmd_ref, usage_ref, "" },
161 97b3a7be 2019-07-09 stsp { "branch", cmd_branch, usage_branch, "br" },
162 8e7bd50a 2019-08-22 stsp { "tag", cmd_tag, usage_tag, "" },
163 97b3a7be 2019-07-09 stsp { "add", cmd_add, usage_add, "" },
164 648e4ef7 2019-07-09 stsp { "remove", cmd_remove, usage_remove, "rm" },
165 97b3a7be 2019-07-09 stsp { "revert", cmd_revert, usage_revert, "rv" },
166 97b3a7be 2019-07-09 stsp { "commit", cmd_commit, usage_commit, "ci" },
167 f8a36e22 2021-08-26 stsp { "send", cmd_send, usage_send, "se" },
168 016477fd 2019-07-09 stsp { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
169 97b3a7be 2019-07-09 stsp { "backout", cmd_backout, usage_backout, "bo" },
170 818c7501 2019-07-11 stsp { "rebase", cmd_rebase, usage_rebase, "rb" },
171 0ebf8283 2019-07-24 stsp { "histedit", cmd_histedit, usage_histedit, "he" },
172 2822a352 2019-10-15 stsp { "integrate", cmd_integrate, usage_integrate,"ig" },
173 10604dce 2021-09-24 thomas { "merge", cmd_merge, usage_merge, "mg" },
174 715dc77e 2019-08-03 stsp { "stage", cmd_stage, usage_stage, "sg" },
175 ad493afc 2019-08-03 stsp { "unstage", cmd_unstage, usage_unstage, "ug" },
176 01073a5d 2019-08-22 stsp { "cat", cmd_cat, usage_cat, "" },
177 b2118c49 2020-07-28 stsp { "info", cmd_info, usage_info, "" },
178 5c860e29 2018-03-12 stsp };
179 ce5b7c56 2019-07-09 stsp
180 ce5b7c56 2019-07-09 stsp static void
181 6879ba42 2020-10-01 naddy list_commands(FILE *fp)
182 ce5b7c56 2019-07-09 stsp {
183 6059809a 2020-12-17 stsp size_t i;
184 ce5b7c56 2019-07-09 stsp
185 6879ba42 2020-10-01 naddy fprintf(fp, "commands:");
186 ce5b7c56 2019-07-09 stsp for (i = 0; i < nitems(got_commands); i++) {
187 ce5b7c56 2019-07-09 stsp struct got_cmd *cmd = &got_commands[i];
188 6879ba42 2020-10-01 naddy fprintf(fp, " %s", cmd->cmd_name);
189 ce5b7c56 2019-07-09 stsp }
190 6879ba42 2020-10-01 naddy fputc('\n', fp);
191 ce5b7c56 2019-07-09 stsp }
192 5c860e29 2018-03-12 stsp
193 ff69268e 2020-12-13 stsp __dead static void
194 ff69268e 2020-12-13 stsp option_conflict(char a, char b)
195 ff69268e 2020-12-13 stsp {
196 ff69268e 2020-12-13 stsp errx(1, "-%c and -%c options are mutually exclusive", a, b);
197 ff69268e 2020-12-13 stsp }
198 ff69268e 2020-12-13 stsp
199 5c860e29 2018-03-12 stsp int
200 5c860e29 2018-03-12 stsp main(int argc, char *argv[])
201 5c860e29 2018-03-12 stsp {
202 8cfb4057 2019-07-09 stsp struct got_cmd *cmd;
203 6059809a 2020-12-17 stsp size_t i;
204 5c860e29 2018-03-12 stsp int ch;
205 53ccebc2 2019-07-30 stsp int hflag = 0, Vflag = 0;
206 83cd27f8 2020-01-13 stsp static struct option longopts[] = {
207 62d463ca 2020-10-20 naddy { "version", no_argument, NULL, 'V' },
208 62d463ca 2020-10-20 naddy { NULL, 0, NULL, 0 }
209 83cd27f8 2020-01-13 stsp };
210 5c860e29 2018-03-12 stsp
211 289e3cbf 2019-02-04 stsp setlocale(LC_CTYPE, "");
212 5c860e29 2018-03-12 stsp
213 6586ea88 2020-01-13 stsp while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
214 5c860e29 2018-03-12 stsp switch (ch) {
215 1b6b95a8 2018-03-12 stsp case 'h':
216 1b6b95a8 2018-03-12 stsp hflag = 1;
217 53ccebc2 2019-07-30 stsp break;
218 53ccebc2 2019-07-30 stsp case 'V':
219 53ccebc2 2019-07-30 stsp Vflag = 1;
220 1b6b95a8 2018-03-12 stsp break;
221 5c860e29 2018-03-12 stsp default:
222 6879ba42 2020-10-01 naddy usage(hflag, 1);
223 5c860e29 2018-03-12 stsp /* NOTREACHED */
224 5c860e29 2018-03-12 stsp }
225 5c860e29 2018-03-12 stsp }
226 5c860e29 2018-03-12 stsp
227 5c860e29 2018-03-12 stsp argc -= optind;
228 5c860e29 2018-03-12 stsp argv += optind;
229 9814e6a3 2020-09-27 naddy optind = 1;
230 9814e6a3 2020-09-27 naddy optreset = 1;
231 53ccebc2 2019-07-30 stsp
232 53ccebc2 2019-07-30 stsp if (Vflag) {
233 53ccebc2 2019-07-30 stsp got_version_print_str();
234 6879ba42 2020-10-01 naddy return 0;
235 53ccebc2 2019-07-30 stsp }
236 5c860e29 2018-03-12 stsp
237 5c860e29 2018-03-12 stsp if (argc <= 0)
238 6879ba42 2020-10-01 naddy usage(hflag, hflag ? 0 : 1);
239 5c860e29 2018-03-12 stsp
240 99437157 2018-11-11 stsp signal(SIGINT, catch_sigint);
241 99437157 2018-11-11 stsp signal(SIGPIPE, catch_sigpipe);
242 99437157 2018-11-11 stsp
243 5c860e29 2018-03-12 stsp for (i = 0; i < nitems(got_commands); i++) {
244 d7d4f210 2018-03-12 stsp const struct got_error *error;
245 d7d4f210 2018-03-12 stsp
246 5c860e29 2018-03-12 stsp cmd = &got_commands[i];
247 5c860e29 2018-03-12 stsp
248 97b3a7be 2019-07-09 stsp if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
249 97b3a7be 2019-07-09 stsp strcmp(cmd->cmd_alias, argv[0]) != 0)
250 5c860e29 2018-03-12 stsp continue;
251 5c860e29 2018-03-12 stsp
252 1b6b95a8 2018-03-12 stsp if (hflag)
253 1b6b95a8 2018-03-12 stsp got_commands[i].cmd_usage();
254 1b6b95a8 2018-03-12 stsp
255 d7d4f210 2018-03-12 stsp error = got_commands[i].cmd_main(argc, argv);
256 f8afbdc8 2019-11-08 stsp if (error && error->code != GOT_ERR_CANCELLED &&
257 f8afbdc8 2019-11-08 stsp error->code != GOT_ERR_PRIVSEP_EXIT &&
258 f8afbdc8 2019-11-08 stsp !(sigpipe_received &&
259 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
260 70015d7a 2019-11-08 stsp !(sigint_received &&
261 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EINTR)) {
262 d7d4f210 2018-03-12 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
263 d7d4f210 2018-03-12 stsp return 1;
264 d7d4f210 2018-03-12 stsp }
265 d7d4f210 2018-03-12 stsp
266 d7d4f210 2018-03-12 stsp return 0;
267 5c860e29 2018-03-12 stsp }
268 5c860e29 2018-03-12 stsp
269 20ecf764 2018-03-12 stsp fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
270 6879ba42 2020-10-01 naddy list_commands(stderr);
271 5c860e29 2018-03-12 stsp return 1;
272 5c860e29 2018-03-12 stsp }
273 5c860e29 2018-03-12 stsp
274 4ed7e80c 2018-05-20 stsp __dead static void
275 6879ba42 2020-10-01 naddy usage(int hflag, int status)
276 5c860e29 2018-03-12 stsp {
277 6879ba42 2020-10-01 naddy FILE *fp = (status == 0) ? stdout : stderr;
278 6879ba42 2020-10-01 naddy
279 6879ba42 2020-10-01 naddy fprintf(fp, "usage: %s [-h] [-V | --version] command [arg ...]\n",
280 53ccebc2 2019-07-30 stsp getprogname());
281 ce5b7c56 2019-07-09 stsp if (hflag)
282 6879ba42 2020-10-01 naddy list_commands(fp);
283 6879ba42 2020-10-01 naddy exit(status);
284 5c860e29 2018-03-12 stsp }
285 5c860e29 2018-03-12 stsp
286 0266afb7 2019-01-04 stsp static const struct got_error *
287 0ee7065d 2019-05-13 stsp get_editor(char **abspath)
288 e2ba3d07 2019-05-13 stsp {
289 0ee7065d 2019-05-13 stsp const struct got_error *err = NULL;
290 e2ba3d07 2019-05-13 stsp const char *editor;
291 8920fa04 2019-08-18 stsp
292 8920fa04 2019-08-18 stsp *abspath = NULL;
293 e2ba3d07 2019-05-13 stsp
294 e2ba3d07 2019-05-13 stsp editor = getenv("VISUAL");
295 e2ba3d07 2019-05-13 stsp if (editor == NULL)
296 e2ba3d07 2019-05-13 stsp editor = getenv("EDITOR");
297 e2ba3d07 2019-05-13 stsp
298 0ee7065d 2019-05-13 stsp if (editor) {
299 0ee7065d 2019-05-13 stsp err = got_path_find_prog(abspath, editor);
300 0ee7065d 2019-05-13 stsp if (err)
301 0ee7065d 2019-05-13 stsp return err;
302 0ee7065d 2019-05-13 stsp }
303 e2ba3d07 2019-05-13 stsp
304 0ee7065d 2019-05-13 stsp if (*abspath == NULL) {
305 0ee7065d 2019-05-13 stsp *abspath = strdup("/bin/ed");
306 0ee7065d 2019-05-13 stsp if (*abspath == NULL)
307 0ee7065d 2019-05-13 stsp return got_error_from_errno("strdup");
308 0ee7065d 2019-05-13 stsp }
309 0ee7065d 2019-05-13 stsp
310 e2ba3d07 2019-05-13 stsp return NULL;
311 e2ba3d07 2019-05-13 stsp }
312 e2ba3d07 2019-05-13 stsp
313 e2ba3d07 2019-05-13 stsp static const struct got_error *
314 d0eebce4 2019-03-11 stsp apply_unveil(const char *repo_path, int repo_read_only,
315 c530dc23 2019-07-23 stsp const char *worktree_path)
316 0266afb7 2019-01-04 stsp {
317 163ce85a 2019-05-13 stsp const struct got_error *err;
318 0266afb7 2019-01-04 stsp
319 37c06ea4 2019-07-15 stsp #ifdef PROFILE
320 37c06ea4 2019-07-15 stsp if (unveil("gmon.out", "rwc") != 0)
321 37c06ea4 2019-07-15 stsp return got_error_from_errno2("unveil", "gmon.out");
322 37c06ea4 2019-07-15 stsp #endif
323 d0eebce4 2019-03-11 stsp if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
324 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", repo_path);
325 0266afb7 2019-01-04 stsp
326 0266afb7 2019-01-04 stsp if (worktree_path && unveil(worktree_path, "rwc") != 0)
327 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", worktree_path);
328 0266afb7 2019-01-04 stsp
329 bb63914a 2020-02-17 stsp if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
330 bb63914a 2020-02-17 stsp return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
331 0266afb7 2019-01-04 stsp
332 163ce85a 2019-05-13 stsp err = got_privsep_unveil_exec_helpers();
333 163ce85a 2019-05-13 stsp if (err != NULL)
334 163ce85a 2019-05-13 stsp return err;
335 0266afb7 2019-01-04 stsp
336 0266afb7 2019-01-04 stsp if (unveil(NULL, NULL) != 0)
337 638f9024 2019-05-13 stsp return got_error_from_errno("unveil");
338 0266afb7 2019-01-04 stsp
339 0266afb7 2019-01-04 stsp return NULL;
340 2c7829a4 2019-06-17 stsp }
341 2c7829a4 2019-06-17 stsp
342 2c7829a4 2019-06-17 stsp __dead static void
343 2c7829a4 2019-06-17 stsp usage_init(void)
344 2c7829a4 2019-06-17 stsp {
345 09ea71ba 2019-07-27 stsp fprintf(stderr, "usage: %s init repository-path\n", getprogname());
346 2c7829a4 2019-06-17 stsp exit(1);
347 2c7829a4 2019-06-17 stsp }
348 2c7829a4 2019-06-17 stsp
349 2c7829a4 2019-06-17 stsp static const struct got_error *
350 2c7829a4 2019-06-17 stsp cmd_init(int argc, char *argv[])
351 2c7829a4 2019-06-17 stsp {
352 2c7829a4 2019-06-17 stsp const struct got_error *error = NULL;
353 2c7829a4 2019-06-17 stsp char *repo_path = NULL;
354 2c7829a4 2019-06-17 stsp int ch;
355 2c7829a4 2019-06-17 stsp
356 2c7829a4 2019-06-17 stsp while ((ch = getopt(argc, argv, "")) != -1) {
357 2c7829a4 2019-06-17 stsp switch (ch) {
358 2c7829a4 2019-06-17 stsp default:
359 2c7829a4 2019-06-17 stsp usage_init();
360 2c7829a4 2019-06-17 stsp /* NOTREACHED */
361 2c7829a4 2019-06-17 stsp }
362 2c7829a4 2019-06-17 stsp }
363 2c7829a4 2019-06-17 stsp
364 2c7829a4 2019-06-17 stsp argc -= optind;
365 2c7829a4 2019-06-17 stsp argv += optind;
366 2c7829a4 2019-06-17 stsp
367 2c7829a4 2019-06-17 stsp #ifndef PROFILE
368 2c7829a4 2019-06-17 stsp if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
369 2c7829a4 2019-06-17 stsp err(1, "pledge");
370 2c7829a4 2019-06-17 stsp #endif
371 2c7829a4 2019-06-17 stsp if (argc != 1)
372 bc20e173 2019-06-17 stsp usage_init();
373 2c7829a4 2019-06-17 stsp
374 2c7829a4 2019-06-17 stsp repo_path = strdup(argv[0]);
375 2c7829a4 2019-06-17 stsp if (repo_path == NULL)
376 2c7829a4 2019-06-17 stsp return got_error_from_errno("strdup");
377 2c7829a4 2019-06-17 stsp
378 2c7829a4 2019-06-17 stsp got_path_strip_trailing_slashes(repo_path);
379 2c7829a4 2019-06-17 stsp
380 2c7829a4 2019-06-17 stsp error = got_path_mkdir(repo_path);
381 2c7829a4 2019-06-17 stsp if (error &&
382 2c7829a4 2019-06-17 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
383 2c7829a4 2019-06-17 stsp goto done;
384 2c7829a4 2019-06-17 stsp
385 c530dc23 2019-07-23 stsp error = apply_unveil(repo_path, 0, NULL);
386 2c7829a4 2019-06-17 stsp if (error)
387 2c7829a4 2019-06-17 stsp goto done;
388 2c7829a4 2019-06-17 stsp
389 2c7829a4 2019-06-17 stsp error = got_repo_init(repo_path);
390 3ce1b845 2019-07-15 stsp done:
391 3ce1b845 2019-07-15 stsp free(repo_path);
392 3ce1b845 2019-07-15 stsp return error;
393 3ce1b845 2019-07-15 stsp }
394 3ce1b845 2019-07-15 stsp
395 3ce1b845 2019-07-15 stsp __dead static void
396 3ce1b845 2019-07-15 stsp usage_import(void)
397 3ce1b845 2019-07-15 stsp {
398 3ce1b845 2019-07-15 stsp fprintf(stderr, "usage: %s import [-b branch] [-m message] "
399 3ce1b845 2019-07-15 stsp "[-r repository-path] [-I pattern] path\n", getprogname());
400 3ce1b845 2019-07-15 stsp exit(1);
401 3ce1b845 2019-07-15 stsp }
402 3ce1b845 2019-07-15 stsp
403 3ce1b845 2019-07-15 stsp int
404 3ce1b845 2019-07-15 stsp spawn_editor(const char *editor, const char *file)
405 3ce1b845 2019-07-15 stsp {
406 3ce1b845 2019-07-15 stsp pid_t pid;
407 3ce1b845 2019-07-15 stsp sig_t sighup, sigint, sigquit;
408 3ce1b845 2019-07-15 stsp int st = -1;
409 3ce1b845 2019-07-15 stsp
410 3ce1b845 2019-07-15 stsp sighup = signal(SIGHUP, SIG_IGN);
411 3ce1b845 2019-07-15 stsp sigint = signal(SIGINT, SIG_IGN);
412 3ce1b845 2019-07-15 stsp sigquit = signal(SIGQUIT, SIG_IGN);
413 3ce1b845 2019-07-15 stsp
414 3ce1b845 2019-07-15 stsp switch (pid = fork()) {
415 3ce1b845 2019-07-15 stsp case -1:
416 3ce1b845 2019-07-15 stsp goto doneediting;
417 3ce1b845 2019-07-15 stsp case 0:
418 3ce1b845 2019-07-15 stsp execl(editor, editor, file, (char *)NULL);
419 3ce1b845 2019-07-15 stsp _exit(127);
420 3ce1b845 2019-07-15 stsp }
421 3ce1b845 2019-07-15 stsp
422 3ce1b845 2019-07-15 stsp while (waitpid(pid, &st, 0) == -1)
423 3ce1b845 2019-07-15 stsp if (errno != EINTR)
424 3ce1b845 2019-07-15 stsp break;
425 3ce1b845 2019-07-15 stsp
426 3ce1b845 2019-07-15 stsp doneediting:
427 3ce1b845 2019-07-15 stsp (void)signal(SIGHUP, sighup);
428 3ce1b845 2019-07-15 stsp (void)signal(SIGINT, sigint);
429 3ce1b845 2019-07-15 stsp (void)signal(SIGQUIT, sigquit);
430 3ce1b845 2019-07-15 stsp
431 3ce1b845 2019-07-15 stsp if (!WIFEXITED(st)) {
432 3ce1b845 2019-07-15 stsp errno = EINTR;
433 3ce1b845 2019-07-15 stsp return -1;
434 3ce1b845 2019-07-15 stsp }
435 3ce1b845 2019-07-15 stsp
436 3ce1b845 2019-07-15 stsp return WEXITSTATUS(st);
437 3ce1b845 2019-07-15 stsp }
438 3ce1b845 2019-07-15 stsp
439 3ce1b845 2019-07-15 stsp static const struct got_error *
440 3ce1b845 2019-07-15 stsp edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
441 28cf319f 2021-01-28 stsp const char *initial_content, size_t initial_content_len,
442 28cf319f 2021-01-28 stsp int require_modification)
443 3ce1b845 2019-07-15 stsp {
444 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
445 bfa12d5e 2020-09-26 stsp char *line = NULL;
446 bfa12d5e 2020-09-26 stsp size_t linesize = 0;
447 bfa12d5e 2020-09-26 stsp ssize_t linelen;
448 3ce1b845 2019-07-15 stsp struct stat st, st2;
449 bfa12d5e 2020-09-26 stsp FILE *fp = NULL;
450 bfa12d5e 2020-09-26 stsp size_t len, logmsg_len;
451 bfa12d5e 2020-09-26 stsp char *initial_content_stripped = NULL, *buf = NULL, *s;
452 3ce1b845 2019-07-15 stsp
453 3ce1b845 2019-07-15 stsp *logmsg = NULL;
454 3ce1b845 2019-07-15 stsp
455 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st) == -1)
456 3ce1b845 2019-07-15 stsp return got_error_from_errno2("stat", logmsg_path);
457 3ce1b845 2019-07-15 stsp
458 3ce1b845 2019-07-15 stsp if (spawn_editor(editor, logmsg_path) == -1)
459 3ce1b845 2019-07-15 stsp return got_error_from_errno("failed spawning editor");
460 3ce1b845 2019-07-15 stsp
461 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st2) == -1)
462 3ce1b845 2019-07-15 stsp return got_error_from_errno("stat");
463 3ce1b845 2019-07-15 stsp
464 28cf319f 2021-01-28 stsp if (require_modification &&
465 28cf319f 2021-01-28 stsp st.st_mtime == st2.st_mtime && st.st_size == st2.st_size)
466 3ce1b845 2019-07-15 stsp return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
467 3ce1b845 2019-07-15 stsp "no changes made to commit message, aborting");
468 3ce1b845 2019-07-15 stsp
469 bfa12d5e 2020-09-26 stsp /*
470 bfa12d5e 2020-09-26 stsp * Set up a stripped version of the initial content without comments
471 bfa12d5e 2020-09-26 stsp * and blank lines. We need this in order to check if the message
472 bfa12d5e 2020-09-26 stsp * has in fact been edited.
473 bfa12d5e 2020-09-26 stsp */
474 bfa12d5e 2020-09-26 stsp initial_content_stripped = malloc(initial_content_len + 1);
475 bfa12d5e 2020-09-26 stsp if (initial_content_stripped == NULL)
476 bfa12d5e 2020-09-26 stsp return got_error_from_errno("malloc");
477 bfa12d5e 2020-09-26 stsp initial_content_stripped[0] = '\0';
478 bfa12d5e 2020-09-26 stsp
479 bfa12d5e 2020-09-26 stsp buf = strdup(initial_content);
480 bfa12d5e 2020-09-26 stsp if (buf == NULL) {
481 bfa12d5e 2020-09-26 stsp err = got_error_from_errno("strdup");
482 bfa12d5e 2020-09-26 stsp goto done;
483 bfa12d5e 2020-09-26 stsp }
484 bfa12d5e 2020-09-26 stsp s = buf;
485 bfa12d5e 2020-09-26 stsp len = 0;
486 bfa12d5e 2020-09-26 stsp while ((line = strsep(&s, "\n")) != NULL) {
487 bfa12d5e 2020-09-26 stsp if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
488 bfa12d5e 2020-09-26 stsp continue; /* remove comments and leading empty lines */
489 bfa12d5e 2020-09-26 stsp len = strlcat(initial_content_stripped, line,
490 bfa12d5e 2020-09-26 stsp initial_content_len + 1);
491 bfa12d5e 2020-09-26 stsp if (len >= initial_content_len + 1) {
492 bfa12d5e 2020-09-26 stsp err = got_error(GOT_ERR_NO_SPACE);
493 bfa12d5e 2020-09-26 stsp goto done;
494 bfa12d5e 2020-09-26 stsp }
495 bfa12d5e 2020-09-26 stsp }
496 bfa12d5e 2020-09-26 stsp while (len > 0 && initial_content_stripped[len - 1] == '\n') {
497 bfa12d5e 2020-09-26 stsp initial_content_stripped[len - 1] = '\0';
498 bfa12d5e 2020-09-26 stsp len--;
499 bfa12d5e 2020-09-26 stsp }
500 bfa12d5e 2020-09-26 stsp
501 bfa12d5e 2020-09-26 stsp logmsg_len = st2.st_size;
502 bfa12d5e 2020-09-26 stsp *logmsg = malloc(logmsg_len + 1);
503 3ce1b845 2019-07-15 stsp if (*logmsg == NULL)
504 3ce1b845 2019-07-15 stsp return got_error_from_errno("malloc");
505 3ce1b845 2019-07-15 stsp (*logmsg)[0] = '\0';
506 3ce1b845 2019-07-15 stsp
507 3ce1b845 2019-07-15 stsp fp = fopen(logmsg_path, "r");
508 3ce1b845 2019-07-15 stsp if (fp == NULL) {
509 3ce1b845 2019-07-15 stsp err = got_error_from_errno("fopen");
510 3ce1b845 2019-07-15 stsp goto done;
511 3ce1b845 2019-07-15 stsp }
512 bfa12d5e 2020-09-26 stsp
513 bfa12d5e 2020-09-26 stsp len = 0;
514 bfa12d5e 2020-09-26 stsp while ((linelen = getline(&line, &linesize, fp)) != -1) {
515 bfa12d5e 2020-09-26 stsp if ((line[0] == '#' || (len == 0 && line[0] == '\n')))
516 3ce1b845 2019-07-15 stsp continue; /* remove comments and leading empty lines */
517 bfa12d5e 2020-09-26 stsp len = strlcat(*logmsg, line, logmsg_len + 1);
518 bfa12d5e 2020-09-26 stsp if (len >= logmsg_len + 1) {
519 bfa12d5e 2020-09-26 stsp err = got_error(GOT_ERR_NO_SPACE);
520 bfa12d5e 2020-09-26 stsp goto done;
521 bfa12d5e 2020-09-26 stsp }
522 3ce1b845 2019-07-15 stsp }
523 bfa12d5e 2020-09-26 stsp free(line);
524 bfa12d5e 2020-09-26 stsp if (ferror(fp)) {
525 bfa12d5e 2020-09-26 stsp err = got_ferror(fp, GOT_ERR_IO);
526 bfa12d5e 2020-09-26 stsp goto done;
527 bfa12d5e 2020-09-26 stsp }
528 3ce1b845 2019-07-15 stsp while (len > 0 && (*logmsg)[len - 1] == '\n') {
529 3ce1b845 2019-07-15 stsp (*logmsg)[len - 1] = '\0';
530 3ce1b845 2019-07-15 stsp len--;
531 3ce1b845 2019-07-15 stsp }
532 3ce1b845 2019-07-15 stsp
533 bfa12d5e 2020-09-26 stsp if (len == 0) {
534 3ce1b845 2019-07-15 stsp err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
535 3ce1b845 2019-07-15 stsp "commit message cannot be empty, aborting");
536 bfa12d5e 2020-09-26 stsp goto done;
537 bfa12d5e 2020-09-26 stsp }
538 28cf319f 2021-01-28 stsp if (require_modification &&
539 28cf319f 2021-01-28 stsp strcmp(*logmsg, initial_content_stripped) == 0)
540 bfa12d5e 2020-09-26 stsp err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
541 bfa12d5e 2020-09-26 stsp "no changes made to commit message, aborting");
542 3ce1b845 2019-07-15 stsp done:
543 bfa12d5e 2020-09-26 stsp free(initial_content_stripped);
544 bfa12d5e 2020-09-26 stsp free(buf);
545 bfa12d5e 2020-09-26 stsp if (fp && fclose(fp) == EOF && err == NULL)
546 bfa12d5e 2020-09-26 stsp err = got_error_from_errno("fclose");
547 3ce1b845 2019-07-15 stsp if (err) {
548 3ce1b845 2019-07-15 stsp free(*logmsg);
549 3ce1b845 2019-07-15 stsp *logmsg = NULL;
550 3ce1b845 2019-07-15 stsp }
551 3ce1b845 2019-07-15 stsp return err;
552 3ce1b845 2019-07-15 stsp }
553 3ce1b845 2019-07-15 stsp
554 3ce1b845 2019-07-15 stsp static const struct got_error *
555 ef293bdd 2019-10-21 stsp collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
556 ef293bdd 2019-10-21 stsp const char *path_dir, const char *branch_name)
557 3ce1b845 2019-07-15 stsp {
558 ef293bdd 2019-10-21 stsp char *initial_content = NULL;
559 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
560 1601cb9f 2020-09-11 naddy int initial_content_len;
561 97972933 2020-09-11 stsp int fd = -1;
562 3ce1b845 2019-07-15 stsp
563 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
564 3ce1b845 2019-07-15 stsp "\n# %s to be imported to branch %s\n", path_dir,
565 1601cb9f 2020-09-11 naddy branch_name);
566 1601cb9f 2020-09-11 naddy if (initial_content_len == -1)
567 3ce1b845 2019-07-15 stsp return got_error_from_errno("asprintf");
568 3ce1b845 2019-07-15 stsp
569 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(logmsg_path, &fd,
570 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-importmsg");
571 3ce1b845 2019-07-15 stsp if (err)
572 3ce1b845 2019-07-15 stsp goto done;
573 3ce1b845 2019-07-15 stsp
574 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
575 97972933 2020-09-11 stsp err = got_error_from_errno2("write", *logmsg_path);
576 97972933 2020-09-11 stsp goto done;
577 97972933 2020-09-11 stsp }
578 3ce1b845 2019-07-15 stsp
579 bfa12d5e 2020-09-26 stsp err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
580 0d5bb276 2020-12-15 stsp initial_content_len, 1);
581 3ce1b845 2019-07-15 stsp done:
582 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
583 97972933 2020-09-11 stsp err = got_error_from_errno2("close", *logmsg_path);
584 3ce1b845 2019-07-15 stsp free(initial_content);
585 59f86c76 2020-09-11 stsp if (err) {
586 59f86c76 2020-09-11 stsp free(*logmsg_path);
587 59f86c76 2020-09-11 stsp *logmsg_path = NULL;
588 59f86c76 2020-09-11 stsp }
589 3ce1b845 2019-07-15 stsp return err;
590 3ce1b845 2019-07-15 stsp }
591 3ce1b845 2019-07-15 stsp
592 3ce1b845 2019-07-15 stsp static const struct got_error *
593 3ce1b845 2019-07-15 stsp import_progress(void *arg, const char *path)
594 3ce1b845 2019-07-15 stsp {
595 3ce1b845 2019-07-15 stsp printf("A %s\n", path);
596 3ce1b845 2019-07-15 stsp return NULL;
597 3ce1b845 2019-07-15 stsp }
598 3ce1b845 2019-07-15 stsp
599 3ce1b845 2019-07-15 stsp static const struct got_error *
600 50b0790e 2020-09-11 stsp get_author(char **author, struct got_repository *repo,
601 50b0790e 2020-09-11 stsp struct got_worktree *worktree)
602 84792843 2019-08-09 stsp {
603 aba9c984 2019-09-08 stsp const struct got_error *err = NULL;
604 50b0790e 2020-09-11 stsp const char *got_author = NULL, *name, *email;
605 50b0790e 2020-09-11 stsp const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
606 84792843 2019-08-09 stsp
607 84792843 2019-08-09 stsp *author = NULL;
608 aba9c984 2019-09-08 stsp
609 50b0790e 2020-09-11 stsp if (worktree)
610 50b0790e 2020-09-11 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
611 50b0790e 2020-09-11 stsp repo_conf = got_repo_get_gotconfig(repo);
612 50b0790e 2020-09-11 stsp
613 50b0790e 2020-09-11 stsp /*
614 50b0790e 2020-09-11 stsp * Priority of potential author information sources, from most
615 50b0790e 2020-09-11 stsp * significant to least significant:
616 50b0790e 2020-09-11 stsp * 1) work tree's .got/got.conf file
617 50b0790e 2020-09-11 stsp * 2) repository's got.conf file
618 50b0790e 2020-09-11 stsp * 3) repository's git config file
619 50b0790e 2020-09-11 stsp * 4) environment variables
620 50b0790e 2020-09-11 stsp * 5) global git config files (in user's home directory or /etc)
621 50b0790e 2020-09-11 stsp */
622 50b0790e 2020-09-11 stsp
623 50b0790e 2020-09-11 stsp if (worktree_conf)
624 50b0790e 2020-09-11 stsp got_author = got_gotconfig_get_author(worktree_conf);
625 50b0790e 2020-09-11 stsp if (got_author == NULL)
626 50b0790e 2020-09-11 stsp got_author = got_gotconfig_get_author(repo_conf);
627 84792843 2019-08-09 stsp if (got_author == NULL) {
628 257add31 2020-09-09 stsp name = got_repo_get_gitconfig_author_name(repo);
629 257add31 2020-09-09 stsp email = got_repo_get_gitconfig_author_email(repo);
630 c9956ddf 2019-09-08 stsp if (name && email) {
631 c9956ddf 2019-09-08 stsp if (asprintf(author, "%s <%s>", name, email) == -1)
632 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
633 c9956ddf 2019-09-08 stsp return NULL;
634 c9956ddf 2019-09-08 stsp }
635 257add31 2020-09-09 stsp
636 257add31 2020-09-09 stsp got_author = getenv("GOT_AUTHOR");
637 257add31 2020-09-09 stsp if (got_author == NULL) {
638 257add31 2020-09-09 stsp name = got_repo_get_global_gitconfig_author_name(repo);
639 257add31 2020-09-09 stsp email = got_repo_get_global_gitconfig_author_email(
640 257add31 2020-09-09 stsp repo);
641 257add31 2020-09-09 stsp if (name && email) {
642 257add31 2020-09-09 stsp if (asprintf(author, "%s <%s>", name, email)
643 257add31 2020-09-09 stsp == -1)
644 257add31 2020-09-09 stsp return got_error_from_errno("asprintf");
645 257add31 2020-09-09 stsp return NULL;
646 257add31 2020-09-09 stsp }
647 257add31 2020-09-09 stsp /* TODO: Look up user in password database? */
648 257add31 2020-09-09 stsp return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
649 257add31 2020-09-09 stsp }
650 84792843 2019-08-09 stsp }
651 84792843 2019-08-09 stsp
652 aba9c984 2019-09-08 stsp *author = strdup(got_author);
653 aba9c984 2019-09-08 stsp if (*author == NULL)
654 aba9c984 2019-09-08 stsp return got_error_from_errno("strdup");
655 84792843 2019-08-09 stsp
656 84792843 2019-08-09 stsp /*
657 84792843 2019-08-09 stsp * Really dumb email address check; we're only doing this to
658 84792843 2019-08-09 stsp * avoid git's object parser breaking on commits we create.
659 84792843 2019-08-09 stsp */
660 84792843 2019-08-09 stsp while (*got_author && *got_author != '<')
661 84792843 2019-08-09 stsp got_author++;
662 aba9c984 2019-09-08 stsp if (*got_author != '<') {
663 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
664 aba9c984 2019-09-08 stsp goto done;
665 aba9c984 2019-09-08 stsp }
666 84792843 2019-08-09 stsp while (*got_author && *got_author != '@')
667 84792843 2019-08-09 stsp got_author++;
668 aba9c984 2019-09-08 stsp if (*got_author != '@') {
669 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
670 aba9c984 2019-09-08 stsp goto done;
671 aba9c984 2019-09-08 stsp }
672 84792843 2019-08-09 stsp while (*got_author && *got_author != '>')
673 84792843 2019-08-09 stsp got_author++;
674 84792843 2019-08-09 stsp if (*got_author != '>')
675 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
676 aba9c984 2019-09-08 stsp done:
677 aba9c984 2019-09-08 stsp if (err) {
678 aba9c984 2019-09-08 stsp free(*author);
679 aba9c984 2019-09-08 stsp *author = NULL;
680 aba9c984 2019-09-08 stsp }
681 aba9c984 2019-09-08 stsp return err;
682 c9956ddf 2019-09-08 stsp }
683 c9956ddf 2019-09-08 stsp
684 c9956ddf 2019-09-08 stsp static const struct got_error *
685 c9956ddf 2019-09-08 stsp get_gitconfig_path(char **gitconfig_path)
686 c9956ddf 2019-09-08 stsp {
687 c9956ddf 2019-09-08 stsp const char *homedir = getenv("HOME");
688 c9956ddf 2019-09-08 stsp
689 c9956ddf 2019-09-08 stsp *gitconfig_path = NULL;
690 c9956ddf 2019-09-08 stsp if (homedir) {
691 c9956ddf 2019-09-08 stsp if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
692 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
693 c9956ddf 2019-09-08 stsp
694 c9956ddf 2019-09-08 stsp }
695 c9956ddf 2019-09-08 stsp return NULL;
696 84792843 2019-08-09 stsp }
697 84792843 2019-08-09 stsp
698 84792843 2019-08-09 stsp static const struct got_error *
699 3ce1b845 2019-07-15 stsp cmd_import(int argc, char *argv[])
700 3ce1b845 2019-07-15 stsp {
701 3ce1b845 2019-07-15 stsp const struct got_error *error = NULL;
702 3ce1b845 2019-07-15 stsp char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
703 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
704 5d67f40d 2019-11-08 stsp const char *branch_name = "main";
705 ef293bdd 2019-10-21 stsp char *refname = NULL, *id_str = NULL, *logmsg_path = NULL;
706 3ce1b845 2019-07-15 stsp struct got_repository *repo = NULL;
707 3ce1b845 2019-07-15 stsp struct got_reference *branch_ref = NULL, *head_ref = NULL;
708 3ce1b845 2019-07-15 stsp struct got_object_id *new_commit_id = NULL;
709 3ce1b845 2019-07-15 stsp int ch;
710 3ce1b845 2019-07-15 stsp struct got_pathlist_head ignores;
711 3ce1b845 2019-07-15 stsp struct got_pathlist_entry *pe;
712 ef293bdd 2019-10-21 stsp int preserve_logmsg = 0;
713 3ce1b845 2019-07-15 stsp
714 3ce1b845 2019-07-15 stsp TAILQ_INIT(&ignores);
715 3ce1b845 2019-07-15 stsp
716 3ce1b845 2019-07-15 stsp while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
717 3ce1b845 2019-07-15 stsp switch (ch) {
718 3ce1b845 2019-07-15 stsp case 'b':
719 3ce1b845 2019-07-15 stsp branch_name = optarg;
720 3ce1b845 2019-07-15 stsp break;
721 3ce1b845 2019-07-15 stsp case 'm':
722 3ce1b845 2019-07-15 stsp logmsg = strdup(optarg);
723 3ce1b845 2019-07-15 stsp if (logmsg == NULL) {
724 3ce1b845 2019-07-15 stsp error = got_error_from_errno("strdup");
725 3ce1b845 2019-07-15 stsp goto done;
726 3ce1b845 2019-07-15 stsp }
727 3ce1b845 2019-07-15 stsp break;
728 3ce1b845 2019-07-15 stsp case 'r':
729 3ce1b845 2019-07-15 stsp repo_path = realpath(optarg, NULL);
730 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
731 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath",
732 9ba1d308 2019-10-21 stsp optarg);
733 3ce1b845 2019-07-15 stsp goto done;
734 3ce1b845 2019-07-15 stsp }
735 3ce1b845 2019-07-15 stsp break;
736 3ce1b845 2019-07-15 stsp case 'I':
737 3ce1b845 2019-07-15 stsp if (optarg[0] == '\0')
738 3ce1b845 2019-07-15 stsp break;
739 3ce1b845 2019-07-15 stsp error = got_pathlist_insert(&pe, &ignores, optarg,
740 3ce1b845 2019-07-15 stsp NULL);
741 3ce1b845 2019-07-15 stsp if (error)
742 3ce1b845 2019-07-15 stsp goto done;
743 3ce1b845 2019-07-15 stsp break;
744 3ce1b845 2019-07-15 stsp default:
745 b2b65d18 2019-08-22 stsp usage_import();
746 3ce1b845 2019-07-15 stsp /* NOTREACHED */
747 3ce1b845 2019-07-15 stsp }
748 3ce1b845 2019-07-15 stsp }
749 3ce1b845 2019-07-15 stsp
750 3ce1b845 2019-07-15 stsp argc -= optind;
751 3ce1b845 2019-07-15 stsp argv += optind;
752 3ce1b845 2019-07-15 stsp
753 3ce1b845 2019-07-15 stsp #ifndef PROFILE
754 aba9c984 2019-09-08 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
755 aba9c984 2019-09-08 stsp "unveil",
756 3ce1b845 2019-07-15 stsp NULL) == -1)
757 3ce1b845 2019-07-15 stsp err(1, "pledge");
758 3ce1b845 2019-07-15 stsp #endif
759 3ce1b845 2019-07-15 stsp if (argc != 1)
760 3ce1b845 2019-07-15 stsp usage_import();
761 2c7829a4 2019-06-17 stsp
762 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
763 3ce1b845 2019-07-15 stsp repo_path = getcwd(NULL, 0);
764 3ce1b845 2019-07-15 stsp if (repo_path == NULL)
765 3ce1b845 2019-07-15 stsp return got_error_from_errno("getcwd");
766 3ce1b845 2019-07-15 stsp }
767 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(repo_path);
768 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
769 c9956ddf 2019-09-08 stsp if (error)
770 c9956ddf 2019-09-08 stsp goto done;
771 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
772 3ce1b845 2019-07-15 stsp if (error)
773 3ce1b845 2019-07-15 stsp goto done;
774 aba9c984 2019-09-08 stsp
775 50b0790e 2020-09-11 stsp error = get_author(&author, repo, NULL);
776 aba9c984 2019-09-08 stsp if (error)
777 aba9c984 2019-09-08 stsp return error;
778 e560b7e0 2019-11-28 stsp
779 e560b7e0 2019-11-28 stsp /*
780 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
781 e560b7e0 2019-11-28 stsp * While technically a valid reference name, this case is usually
782 e560b7e0 2019-11-28 stsp * an unintended typo.
783 e560b7e0 2019-11-28 stsp */
784 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
785 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
786 3ce1b845 2019-07-15 stsp
787 3ce1b845 2019-07-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
788 3ce1b845 2019-07-15 stsp error = got_error_from_errno("asprintf");
789 3ce1b845 2019-07-15 stsp goto done;
790 3ce1b845 2019-07-15 stsp }
791 3ce1b845 2019-07-15 stsp
792 3ce1b845 2019-07-15 stsp error = got_ref_open(&branch_ref, repo, refname, 0);
793 3ce1b845 2019-07-15 stsp if (error) {
794 3ce1b845 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
795 3ce1b845 2019-07-15 stsp goto done;
796 3ce1b845 2019-07-15 stsp } else {
797 3ce1b845 2019-07-15 stsp error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
798 3ce1b845 2019-07-15 stsp "import target branch already exists");
799 3ce1b845 2019-07-15 stsp goto done;
800 3ce1b845 2019-07-15 stsp }
801 3ce1b845 2019-07-15 stsp
802 3ce1b845 2019-07-15 stsp path_dir = realpath(argv[0], NULL);
803 3ce1b845 2019-07-15 stsp if (path_dir == NULL) {
804 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath", argv[0]);
805 3ce1b845 2019-07-15 stsp goto done;
806 3ce1b845 2019-07-15 stsp }
807 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(path_dir);
808 3ce1b845 2019-07-15 stsp
809 3ce1b845 2019-07-15 stsp /*
810 3ce1b845 2019-07-15 stsp * unveil(2) traverses exec(2); if an editor is used we have
811 3ce1b845 2019-07-15 stsp * to apply unveil after the log message has been written.
812 3ce1b845 2019-07-15 stsp */
813 3ce1b845 2019-07-15 stsp if (logmsg == NULL || strlen(logmsg) == 0) {
814 3ce1b845 2019-07-15 stsp error = get_editor(&editor);
815 3ce1b845 2019-07-15 stsp if (error)
816 3ce1b845 2019-07-15 stsp goto done;
817 8e158b01 2019-09-22 stsp free(logmsg);
818 ef293bdd 2019-10-21 stsp error = collect_import_msg(&logmsg, &logmsg_path, editor,
819 ef293bdd 2019-10-21 stsp path_dir, refname);
820 ef293bdd 2019-10-21 stsp if (error) {
821 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
822 ef293bdd 2019-10-21 stsp logmsg_path != NULL)
823 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
824 3ce1b845 2019-07-15 stsp goto done;
825 ef293bdd 2019-10-21 stsp }
826 3ce1b845 2019-07-15 stsp }
827 3ce1b845 2019-07-15 stsp
828 ef293bdd 2019-10-21 stsp if (unveil(path_dir, "r") != 0) {
829 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unveil", path_dir);
830 ef293bdd 2019-10-21 stsp if (logmsg_path)
831 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
832 3ce1b845 2019-07-15 stsp goto done;
833 ef293bdd 2019-10-21 stsp }
834 3ce1b845 2019-07-15 stsp
835 ef293bdd 2019-10-21 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
836 ef293bdd 2019-10-21 stsp if (error) {
837 ef293bdd 2019-10-21 stsp if (logmsg_path)
838 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
839 ef293bdd 2019-10-21 stsp goto done;
840 ef293bdd 2019-10-21 stsp }
841 ef293bdd 2019-10-21 stsp
842 3ce1b845 2019-07-15 stsp error = got_repo_import(&new_commit_id, path_dir, logmsg,
843 84792843 2019-08-09 stsp author, &ignores, repo, import_progress, NULL);
844 ef293bdd 2019-10-21 stsp if (error) {
845 ef293bdd 2019-10-21 stsp if (logmsg_path)
846 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
847 3ce1b845 2019-07-15 stsp goto done;
848 ef293bdd 2019-10-21 stsp }
849 3ce1b845 2019-07-15 stsp
850 3ce1b845 2019-07-15 stsp error = got_ref_alloc(&branch_ref, refname, new_commit_id);
851 ef293bdd 2019-10-21 stsp if (error) {
852 ef293bdd 2019-10-21 stsp if (logmsg_path)
853 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
854 3ce1b845 2019-07-15 stsp goto done;
855 ef293bdd 2019-10-21 stsp }
856 3ce1b845 2019-07-15 stsp
857 3ce1b845 2019-07-15 stsp error = got_ref_write(branch_ref, repo);
858 ef293bdd 2019-10-21 stsp if (error) {
859 ef293bdd 2019-10-21 stsp if (logmsg_path)
860 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
861 3ce1b845 2019-07-15 stsp goto done;
862 ef293bdd 2019-10-21 stsp }
863 3ce1b845 2019-07-15 stsp
864 3ce1b845 2019-07-15 stsp error = got_object_id_str(&id_str, new_commit_id);
865 ef293bdd 2019-10-21 stsp if (error) {
866 ef293bdd 2019-10-21 stsp if (logmsg_path)
867 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
868 3ce1b845 2019-07-15 stsp goto done;
869 ef293bdd 2019-10-21 stsp }
870 3ce1b845 2019-07-15 stsp
871 3ce1b845 2019-07-15 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
872 3ce1b845 2019-07-15 stsp if (error) {
873 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_NOT_REF) {
874 ef293bdd 2019-10-21 stsp if (logmsg_path)
875 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
876 3ce1b845 2019-07-15 stsp goto done;
877 ef293bdd 2019-10-21 stsp }
878 3ce1b845 2019-07-15 stsp
879 3ce1b845 2019-07-15 stsp error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
880 3ce1b845 2019-07-15 stsp branch_ref);
881 ef293bdd 2019-10-21 stsp if (error) {
882 ef293bdd 2019-10-21 stsp if (logmsg_path)
883 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
884 3ce1b845 2019-07-15 stsp goto done;
885 ef293bdd 2019-10-21 stsp }
886 3ce1b845 2019-07-15 stsp
887 3ce1b845 2019-07-15 stsp error = got_ref_write(head_ref, repo);
888 ef293bdd 2019-10-21 stsp if (error) {
889 ef293bdd 2019-10-21 stsp if (logmsg_path)
890 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
891 3ce1b845 2019-07-15 stsp goto done;
892 ef293bdd 2019-10-21 stsp }
893 3ce1b845 2019-07-15 stsp }
894 3ce1b845 2019-07-15 stsp
895 3ce1b845 2019-07-15 stsp printf("Created branch %s with commit %s\n",
896 3ce1b845 2019-07-15 stsp got_ref_get_name(branch_ref), id_str);
897 2c7829a4 2019-06-17 stsp done:
898 ef293bdd 2019-10-21 stsp if (preserve_logmsg) {
899 ef293bdd 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
900 ef293bdd 2019-10-21 stsp getprogname(), logmsg_path);
901 ef293bdd 2019-10-21 stsp } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
902 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unlink", logmsg_path);
903 8e158b01 2019-09-22 stsp free(logmsg);
904 ef293bdd 2019-10-21 stsp free(logmsg_path);
905 2c7829a4 2019-06-17 stsp free(repo_path);
906 3ce1b845 2019-07-15 stsp free(editor);
907 3ce1b845 2019-07-15 stsp free(refname);
908 3ce1b845 2019-07-15 stsp free(new_commit_id);
909 3ce1b845 2019-07-15 stsp free(id_str);
910 aba9c984 2019-09-08 stsp free(author);
911 c9956ddf 2019-09-08 stsp free(gitconfig_path);
912 3ce1b845 2019-07-15 stsp if (branch_ref)
913 3ce1b845 2019-07-15 stsp got_ref_close(branch_ref);
914 3ce1b845 2019-07-15 stsp if (head_ref)
915 3ce1b845 2019-07-15 stsp got_ref_close(head_ref);
916 2c7829a4 2019-06-17 stsp return error;
917 93658fb9 2020-03-18 stsp }
918 93658fb9 2020-03-18 stsp
919 93658fb9 2020-03-18 stsp __dead static void
920 93658fb9 2020-03-18 stsp usage_clone(void)
921 93658fb9 2020-03-18 stsp {
922 13f12b09 2020-03-21 stsp fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
923 0e4002ca 2020-03-21 stsp "[-R reference] repository-url [directory]\n", getprogname());
924 93658fb9 2020-03-18 stsp exit(1);
925 93658fb9 2020-03-18 stsp }
926 892ac3b6 2020-03-18 stsp
927 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg {
928 892ac3b6 2020-03-18 stsp char last_scaled_size[FMT_SCALED_STRSIZE];
929 892ac3b6 2020-03-18 stsp int last_p_indexed;
930 892ac3b6 2020-03-18 stsp int last_p_resolved;
931 68999b92 2020-03-18 stsp int verbosity;
932 04d9a9ec 2020-09-24 stsp
933 04d9a9ec 2020-09-24 stsp struct got_repository *repo;
934 04d9a9ec 2020-09-24 stsp
935 04d9a9ec 2020-09-24 stsp int create_configs;
936 04d9a9ec 2020-09-24 stsp int configs_created;
937 04d9a9ec 2020-09-24 stsp struct {
938 04d9a9ec 2020-09-24 stsp struct got_pathlist_head *symrefs;
939 04d9a9ec 2020-09-24 stsp struct got_pathlist_head *wanted_branches;
940 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs;
941 04d9a9ec 2020-09-24 stsp const char *proto;
942 04d9a9ec 2020-09-24 stsp const char *host;
943 04d9a9ec 2020-09-24 stsp const char *port;
944 04d9a9ec 2020-09-24 stsp const char *remote_repo_path;
945 04d9a9ec 2020-09-24 stsp const char *git_url;
946 04d9a9ec 2020-09-24 stsp int fetch_all_branches;
947 04d9a9ec 2020-09-24 stsp int mirror_references;
948 04d9a9ec 2020-09-24 stsp } config_info;
949 892ac3b6 2020-03-18 stsp };
950 93658fb9 2020-03-18 stsp
951 04d9a9ec 2020-09-24 stsp /* XXX forward declaration */
952 93658fb9 2020-03-18 stsp static const struct got_error *
953 04d9a9ec 2020-09-24 stsp create_config_files(const char *proto, const char *host, const char *port,
954 04d9a9ec 2020-09-24 stsp const char *remote_repo_path, const char *git_url, int fetch_all_branches,
955 04d9a9ec 2020-09-24 stsp int mirror_references, struct got_pathlist_head *symrefs,
956 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_branches,
957 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, struct got_repository *repo);
958 04d9a9ec 2020-09-24 stsp
959 04d9a9ec 2020-09-24 stsp static const struct got_error *
960 baa9fea0 2020-03-18 stsp fetch_progress(void *arg, const char *message, off_t packfile_size,
961 668a20f6 2020-03-18 stsp int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
962 531c3985 2020-03-18 stsp {
963 04d9a9ec 2020-09-24 stsp const struct got_error *err = NULL;
964 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg *a = arg;
965 892ac3b6 2020-03-18 stsp char scaled_size[FMT_SCALED_STRSIZE];
966 892ac3b6 2020-03-18 stsp int p_indexed, p_resolved;
967 892ac3b6 2020-03-18 stsp int print_size = 0, print_indexed = 0, print_resolved = 0;
968 04d9a9ec 2020-09-24 stsp
969 04d9a9ec 2020-09-24 stsp /*
970 04d9a9ec 2020-09-24 stsp * In order to allow a failed clone to be resumed with 'got fetch'
971 04d9a9ec 2020-09-24 stsp * we try to create configuration files as soon as possible.
972 04d9a9ec 2020-09-24 stsp * Once the server has sent information about its default branch
973 04d9a9ec 2020-09-24 stsp * we have all required information.
974 04d9a9ec 2020-09-24 stsp */
975 04d9a9ec 2020-09-24 stsp if (a->create_configs && !a->configs_created &&
976 04d9a9ec 2020-09-24 stsp !TAILQ_EMPTY(a->config_info.symrefs)) {
977 04d9a9ec 2020-09-24 stsp err = create_config_files(a->config_info.proto,
978 62d463ca 2020-10-20 naddy a->config_info.host, a->config_info.port,
979 62d463ca 2020-10-20 naddy a->config_info.remote_repo_path,
980 62d463ca 2020-10-20 naddy a->config_info.git_url,
981 62d463ca 2020-10-20 naddy a->config_info.fetch_all_branches,
982 62d463ca 2020-10-20 naddy a->config_info.mirror_references,
983 62d463ca 2020-10-20 naddy a->config_info.symrefs,
984 99495ddb 2021-01-10 stsp a->config_info.wanted_branches,
985 99495ddb 2021-01-10 stsp a->config_info.wanted_refs, a->repo);
986 04d9a9ec 2020-09-24 stsp if (err)
987 04d9a9ec 2020-09-24 stsp return err;
988 04d9a9ec 2020-09-24 stsp a->configs_created = 1;
989 04d9a9ec 2020-09-24 stsp }
990 b2409d58 2020-03-18 stsp
991 68999b92 2020-03-18 stsp if (a->verbosity < 0)
992 68999b92 2020-03-18 stsp return NULL;
993 68999b92 2020-03-18 stsp
994 fd843b58 2020-03-18 stsp if (message && message[0] != '\0') {
995 d2cdc636 2020-03-18 stsp printf("\rserver: %s", message);
996 892ac3b6 2020-03-18 stsp fflush(stdout);
997 12d1281e 2020-03-19 stsp return NULL;
998 b2409d58 2020-03-18 stsp }
999 b2409d58 2020-03-18 stsp
1000 b2409d58 2020-03-18 stsp if (packfile_size > 0 || nobj_indexed > 0) {
1001 892ac3b6 2020-03-18 stsp if (fmt_scaled(packfile_size, scaled_size) == 0 &&
1002 892ac3b6 2020-03-18 stsp (a->last_scaled_size[0] == '\0' ||
1003 892ac3b6 2020-03-18 stsp strcmp(scaled_size, a->last_scaled_size)) != 0) {
1004 892ac3b6 2020-03-18 stsp print_size = 1;
1005 892ac3b6 2020-03-18 stsp if (strlcpy(a->last_scaled_size, scaled_size,
1006 892ac3b6 2020-03-18 stsp FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
1007 892ac3b6 2020-03-18 stsp return got_error(GOT_ERR_NO_SPACE);
1008 892ac3b6 2020-03-18 stsp }
1009 61cc1a7a 2020-03-18 stsp if (nobj_indexed > 0) {
1010 892ac3b6 2020-03-18 stsp p_indexed = (nobj_indexed * 100) / nobj_total;
1011 892ac3b6 2020-03-18 stsp if (p_indexed != a->last_p_indexed) {
1012 892ac3b6 2020-03-18 stsp a->last_p_indexed = p_indexed;
1013 892ac3b6 2020-03-18 stsp print_indexed = 1;
1014 892ac3b6 2020-03-18 stsp print_size = 1;
1015 892ac3b6 2020-03-18 stsp }
1016 61cc1a7a 2020-03-18 stsp }
1017 61cc1a7a 2020-03-18 stsp if (nobj_resolved > 0) {
1018 892ac3b6 2020-03-18 stsp p_resolved = (nobj_resolved * 100) /
1019 892ac3b6 2020-03-18 stsp (nobj_total - nobj_loose);
1020 892ac3b6 2020-03-18 stsp if (p_resolved != a->last_p_resolved) {
1021 892ac3b6 2020-03-18 stsp a->last_p_resolved = p_resolved;
1022 892ac3b6 2020-03-18 stsp print_resolved = 1;
1023 892ac3b6 2020-03-18 stsp print_indexed = 1;
1024 892ac3b6 2020-03-18 stsp print_size = 1;
1025 892ac3b6 2020-03-18 stsp }
1026 61cc1a7a 2020-03-18 stsp }
1027 3168e5da 2020-09-10 stsp
1028 d2cdc636 2020-03-18 stsp }
1029 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
1030 892ac3b6 2020-03-18 stsp printf("\r");
1031 892ac3b6 2020-03-18 stsp if (print_size)
1032 892ac3b6 2020-03-18 stsp printf("%*s fetched", FMT_SCALED_STRSIZE, scaled_size);
1033 d715f13e 2020-03-19 stsp if (print_indexed)
1034 892ac3b6 2020-03-18 stsp printf("; indexing %d%%", p_indexed);
1035 d715f13e 2020-03-19 stsp if (print_resolved)
1036 892ac3b6 2020-03-18 stsp printf("; resolving deltas %d%%", p_resolved);
1037 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
1038 892ac3b6 2020-03-18 stsp fflush(stdout);
1039 892ac3b6 2020-03-18 stsp
1040 531c3985 2020-03-18 stsp return NULL;
1041 531c3985 2020-03-18 stsp }
1042 531c3985 2020-03-18 stsp
1043 531c3985 2020-03-18 stsp static const struct got_error *
1044 04d9a9ec 2020-09-24 stsp create_symref(const char *refname, struct got_reference *target_ref,
1045 04d9a9ec 2020-09-24 stsp int verbosity, struct got_repository *repo)
1046 4ba14133 2020-03-20 stsp {
1047 4ba14133 2020-03-20 stsp const struct got_error *err;
1048 04d9a9ec 2020-09-24 stsp struct got_reference *head_symref;
1049 4ba14133 2020-03-20 stsp
1050 04d9a9ec 2020-09-24 stsp err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1051 4ba14133 2020-03-20 stsp if (err)
1052 4ba14133 2020-03-20 stsp return err;
1053 4ba14133 2020-03-20 stsp
1054 04d9a9ec 2020-09-24 stsp err = got_ref_write(head_symref, repo);
1055 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity > 0) {
1056 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", GOT_REF_HEAD,
1057 6338a6a1 2020-03-21 stsp got_ref_get_name(target_ref));
1058 6338a6a1 2020-03-21 stsp }
1059 04d9a9ec 2020-09-24 stsp got_ref_close(head_symref);
1060 4ba14133 2020-03-20 stsp return err;
1061 4ba14133 2020-03-20 stsp }
1062 4ba14133 2020-03-20 stsp
1063 4ba14133 2020-03-20 stsp static const struct got_error *
1064 41b0de12 2020-03-21 stsp list_remote_refs(struct got_pathlist_head *symrefs,
1065 41b0de12 2020-03-21 stsp struct got_pathlist_head *refs)
1066 41b0de12 2020-03-21 stsp {
1067 41b0de12 2020-03-21 stsp const struct got_error *err;
1068 41b0de12 2020-03-21 stsp struct got_pathlist_entry *pe;
1069 41b0de12 2020-03-21 stsp
1070 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, symrefs, entry) {
1071 41b0de12 2020-03-21 stsp const char *refname = pe->path;
1072 41b0de12 2020-03-21 stsp const char *targetref = pe->data;
1073 41b0de12 2020-03-21 stsp
1074 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, targetref);
1075 41b0de12 2020-03-21 stsp }
1076 41b0de12 2020-03-21 stsp
1077 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, refs, entry) {
1078 41b0de12 2020-03-21 stsp const char *refname = pe->path;
1079 41b0de12 2020-03-21 stsp struct got_object_id *id = pe->data;
1080 41b0de12 2020-03-21 stsp char *id_str;
1081 41b0de12 2020-03-21 stsp
1082 41b0de12 2020-03-21 stsp err = got_object_id_str(&id_str, id);
1083 41b0de12 2020-03-21 stsp if (err)
1084 41b0de12 2020-03-21 stsp return err;
1085 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, id_str);
1086 41b0de12 2020-03-21 stsp free(id_str);
1087 41b0de12 2020-03-21 stsp }
1088 41b0de12 2020-03-21 stsp
1089 41b0de12 2020-03-21 stsp return NULL;
1090 6338a6a1 2020-03-21 stsp }
1091 6338a6a1 2020-03-21 stsp
1092 6338a6a1 2020-03-21 stsp static const struct got_error *
1093 6338a6a1 2020-03-21 stsp create_ref(const char *refname, struct got_object_id *id,
1094 6338a6a1 2020-03-21 stsp int verbosity, struct got_repository *repo)
1095 6338a6a1 2020-03-21 stsp {
1096 6338a6a1 2020-03-21 stsp const struct got_error *err = NULL;
1097 6338a6a1 2020-03-21 stsp struct got_reference *ref;
1098 6338a6a1 2020-03-21 stsp char *id_str;
1099 6338a6a1 2020-03-21 stsp
1100 6338a6a1 2020-03-21 stsp err = got_object_id_str(&id_str, id);
1101 6338a6a1 2020-03-21 stsp if (err)
1102 6338a6a1 2020-03-21 stsp return err;
1103 6338a6a1 2020-03-21 stsp
1104 6338a6a1 2020-03-21 stsp err = got_ref_alloc(&ref, refname, id);
1105 6338a6a1 2020-03-21 stsp if (err)
1106 6338a6a1 2020-03-21 stsp goto done;
1107 6338a6a1 2020-03-21 stsp
1108 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
1109 6338a6a1 2020-03-21 stsp got_ref_close(ref);
1110 6338a6a1 2020-03-21 stsp
1111 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity >= 0)
1112 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", refname, id_str);
1113 6338a6a1 2020-03-21 stsp done:
1114 6338a6a1 2020-03-21 stsp free(id_str);
1115 6338a6a1 2020-03-21 stsp return err;
1116 0e4002ca 2020-03-21 stsp }
1117 0e4002ca 2020-03-21 stsp
1118 0e4002ca 2020-03-21 stsp static int
1119 0e4002ca 2020-03-21 stsp match_wanted_ref(const char *refname, const char *wanted_ref)
1120 0e4002ca 2020-03-21 stsp {
1121 0e4002ca 2020-03-21 stsp if (strncmp(refname, "refs/", 5) != 0)
1122 0e4002ca 2020-03-21 stsp return 0;
1123 0e4002ca 2020-03-21 stsp refname += 5;
1124 0e4002ca 2020-03-21 stsp
1125 0e4002ca 2020-03-21 stsp /*
1126 0e4002ca 2020-03-21 stsp * Prevent fetching of references that won't make any
1127 0e4002ca 2020-03-21 stsp * sense outside of the remote repository's context.
1128 0e4002ca 2020-03-21 stsp */
1129 0e4002ca 2020-03-21 stsp if (strncmp(refname, "got/", 4) == 0)
1130 0e4002ca 2020-03-21 stsp return 0;
1131 0e4002ca 2020-03-21 stsp if (strncmp(refname, "remotes/", 8) == 0)
1132 0e4002ca 2020-03-21 stsp return 0;
1133 0e4002ca 2020-03-21 stsp
1134 0e4002ca 2020-03-21 stsp if (strncmp(wanted_ref, "refs/", 5) == 0)
1135 0e4002ca 2020-03-21 stsp wanted_ref += 5;
1136 0e4002ca 2020-03-21 stsp
1137 0e4002ca 2020-03-21 stsp /* Allow prefix match. */
1138 0e4002ca 2020-03-21 stsp if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1139 0e4002ca 2020-03-21 stsp return 1;
1140 0e4002ca 2020-03-21 stsp
1141 0e4002ca 2020-03-21 stsp /* Allow exact match. */
1142 0e4002ca 2020-03-21 stsp return (strcmp(refname, wanted_ref) == 0);
1143 41b0de12 2020-03-21 stsp }
1144 41b0de12 2020-03-21 stsp
1145 0e4002ca 2020-03-21 stsp static int
1146 0e4002ca 2020-03-21 stsp is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1147 0e4002ca 2020-03-21 stsp {
1148 0e4002ca 2020-03-21 stsp struct got_pathlist_entry *pe;
1149 0e4002ca 2020-03-21 stsp
1150 0e4002ca 2020-03-21 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1151 0e4002ca 2020-03-21 stsp if (match_wanted_ref(refname, pe->path))
1152 0e4002ca 2020-03-21 stsp return 1;
1153 0e4002ca 2020-03-21 stsp }
1154 0e4002ca 2020-03-21 stsp
1155 0e4002ca 2020-03-21 stsp return 0;
1156 0e4002ca 2020-03-21 stsp }
1157 0e4002ca 2020-03-21 stsp
1158 41b0de12 2020-03-21 stsp static const struct got_error *
1159 0e4002ca 2020-03-21 stsp create_wanted_ref(const char *refname, struct got_object_id *id,
1160 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
1161 0e4002ca 2020-03-21 stsp {
1162 0e4002ca 2020-03-21 stsp const struct got_error *err;
1163 0e4002ca 2020-03-21 stsp char *remote_refname;
1164 0e4002ca 2020-03-21 stsp
1165 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
1166 0e4002ca 2020-03-21 stsp refname += 5;
1167 0e4002ca 2020-03-21 stsp
1168 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1169 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
1170 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
1171 0e4002ca 2020-03-21 stsp
1172 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
1173 0e4002ca 2020-03-21 stsp free(remote_refname);
1174 7c0b7f42 2020-09-24 stsp return err;
1175 7c0b7f42 2020-09-24 stsp }
1176 7c0b7f42 2020-09-24 stsp
1177 7c0b7f42 2020-09-24 stsp static const struct got_error *
1178 7c0b7f42 2020-09-24 stsp create_gotconfig(const char *proto, const char *host, const char *port,
1179 15d3c221 2021-01-05 stsp const char *remote_repo_path, const char *default_branch,
1180 0c8b29c5 2021-01-05 stsp int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1181 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, int mirror_references,
1182 99495ddb 2021-01-10 stsp struct got_repository *repo)
1183 7c0b7f42 2020-09-24 stsp {
1184 7c0b7f42 2020-09-24 stsp const struct got_error *err = NULL;
1185 7c0b7f42 2020-09-24 stsp char *gotconfig_path = NULL;
1186 7c0b7f42 2020-09-24 stsp char *gotconfig = NULL;
1187 7c0b7f42 2020-09-24 stsp FILE *gotconfig_file = NULL;
1188 15d3c221 2021-01-05 stsp const char *branchname = NULL;
1189 99495ddb 2021-01-10 stsp char *branches = NULL, *refs = NULL;
1190 7c0b7f42 2020-09-24 stsp ssize_t n;
1191 7c0b7f42 2020-09-24 stsp
1192 0c8b29c5 2021-01-05 stsp if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
1193 132af4a5 2021-01-05 stsp struct got_pathlist_entry *pe;
1194 132af4a5 2021-01-05 stsp TAILQ_FOREACH(pe, wanted_branches, entry) {
1195 132af4a5 2021-01-05 stsp char *s;
1196 132af4a5 2021-01-05 stsp branchname = pe->path;
1197 132af4a5 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1198 132af4a5 2021-01-05 stsp branchname += 11;
1199 132af4a5 2021-01-05 stsp if (asprintf(&s, "%s\"%s\" ",
1200 132af4a5 2021-01-05 stsp branches ? branches : "", branchname) == -1) {
1201 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1202 132af4a5 2021-01-05 stsp goto done;
1203 132af4a5 2021-01-05 stsp }
1204 132af4a5 2021-01-05 stsp free(branches);
1205 132af4a5 2021-01-05 stsp branches = s;
1206 132af4a5 2021-01-05 stsp }
1207 0c8b29c5 2021-01-05 stsp } else if (!fetch_all_branches && default_branch) {
1208 15d3c221 2021-01-05 stsp branchname = default_branch;
1209 15d3c221 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1210 15d3c221 2021-01-05 stsp branchname += 11;
1211 132af4a5 2021-01-05 stsp if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1212 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1213 132af4a5 2021-01-05 stsp goto done;
1214 99495ddb 2021-01-10 stsp }
1215 99495ddb 2021-01-10 stsp }
1216 99495ddb 2021-01-10 stsp if (!TAILQ_EMPTY(wanted_refs)) {
1217 99495ddb 2021-01-10 stsp struct got_pathlist_entry *pe;
1218 99495ddb 2021-01-10 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1219 99495ddb 2021-01-10 stsp char *s;
1220 99495ddb 2021-01-10 stsp const char *refname = pe->path;
1221 99495ddb 2021-01-10 stsp if (strncmp(refname, "refs/", 5) == 0)
1222 99495ddb 2021-01-10 stsp branchname += 5;
1223 99495ddb 2021-01-10 stsp if (asprintf(&s, "%s\"%s\" ",
1224 99495ddb 2021-01-10 stsp refs ? refs : "", refname) == -1) {
1225 99495ddb 2021-01-10 stsp err = got_error_from_errno("asprintf");
1226 99495ddb 2021-01-10 stsp goto done;
1227 99495ddb 2021-01-10 stsp }
1228 99495ddb 2021-01-10 stsp free(refs);
1229 99495ddb 2021-01-10 stsp refs = s;
1230 132af4a5 2021-01-05 stsp }
1231 15d3c221 2021-01-05 stsp }
1232 15d3c221 2021-01-05 stsp
1233 7c0b7f42 2020-09-24 stsp /* Create got.conf(5). */
1234 7c0b7f42 2020-09-24 stsp gotconfig_path = got_repo_get_path_gotconfig(repo);
1235 7c0b7f42 2020-09-24 stsp if (gotconfig_path == NULL) {
1236 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("got_repo_get_path_gotconfig");
1237 7c0b7f42 2020-09-24 stsp goto done;
1238 7c0b7f42 2020-09-24 stsp }
1239 7c0b7f42 2020-09-24 stsp gotconfig_file = fopen(gotconfig_path, "a");
1240 7c0b7f42 2020-09-24 stsp if (gotconfig_file == NULL) {
1241 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fopen", gotconfig_path);
1242 7c0b7f42 2020-09-24 stsp goto done;
1243 7c0b7f42 2020-09-24 stsp }
1244 7c0b7f42 2020-09-24 stsp if (asprintf(&gotconfig,
1245 7c0b7f42 2020-09-24 stsp "remote \"%s\" {\n"
1246 7c0b7f42 2020-09-24 stsp "\tserver %s\n"
1247 7c0b7f42 2020-09-24 stsp "\tprotocol %s\n"
1248 7c0b7f42 2020-09-24 stsp "%s%s%s"
1249 7c0b7f42 2020-09-24 stsp "\trepository \"%s\"\n"
1250 15d3c221 2021-01-05 stsp "%s%s%s"
1251 99495ddb 2021-01-10 stsp "%s%s%s"
1252 7c0b7f42 2020-09-24 stsp "%s"
1253 0c8b29c5 2021-01-05 stsp "%s"
1254 7c0b7f42 2020-09-24 stsp "}\n",
1255 7c0b7f42 2020-09-24 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
1256 7c0b7f42 2020-09-24 stsp port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1257 132af4a5 2021-01-05 stsp remote_repo_path, branches ? "\tbranch { " : "",
1258 132af4a5 2021-01-05 stsp branches ? branches : "", branches ? "}\n" : "",
1259 99495ddb 2021-01-10 stsp refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1260 0c8b29c5 2021-01-05 stsp mirror_references ? "\tmirror-references yes\n" : "",
1261 0c8b29c5 2021-01-05 stsp fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) {
1262 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1263 7c0b7f42 2020-09-24 stsp goto done;
1264 7c0b7f42 2020-09-24 stsp }
1265 7c0b7f42 2020-09-24 stsp n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1266 7c0b7f42 2020-09-24 stsp if (n != strlen(gotconfig)) {
1267 7c0b7f42 2020-09-24 stsp err = got_ferror(gotconfig_file, GOT_ERR_IO);
1268 7c0b7f42 2020-09-24 stsp goto done;
1269 7c0b7f42 2020-09-24 stsp }
1270 7c0b7f42 2020-09-24 stsp
1271 7c0b7f42 2020-09-24 stsp done:
1272 7c0b7f42 2020-09-24 stsp if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
1273 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fclose", gotconfig_path);
1274 7c0b7f42 2020-09-24 stsp free(gotconfig_path);
1275 132af4a5 2021-01-05 stsp free(branches);
1276 7c0b7f42 2020-09-24 stsp return err;
1277 7c0b7f42 2020-09-24 stsp }
1278 7c0b7f42 2020-09-24 stsp
1279 7c0b7f42 2020-09-24 stsp static const struct got_error *
1280 04d9a9ec 2020-09-24 stsp create_gitconfig(const char *git_url, const char *default_branch,
1281 132af4a5 2021-01-05 stsp int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1282 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, int mirror_references,
1283 99495ddb 2021-01-10 stsp struct got_repository *repo)
1284 7c0b7f42 2020-09-24 stsp {
1285 7c0b7f42 2020-09-24 stsp const struct got_error *err = NULL;
1286 7c0b7f42 2020-09-24 stsp char *gitconfig_path = NULL;
1287 7c0b7f42 2020-09-24 stsp char *gitconfig = NULL;
1288 7c0b7f42 2020-09-24 stsp FILE *gitconfig_file = NULL;
1289 99495ddb 2021-01-10 stsp char *branches = NULL, *refs = NULL;
1290 56d0a753 2021-01-20 stsp const char *branchname;
1291 7c0b7f42 2020-09-24 stsp ssize_t n;
1292 7c0b7f42 2020-09-24 stsp
1293 7c0b7f42 2020-09-24 stsp /* Create a config file Git can understand. */
1294 7c0b7f42 2020-09-24 stsp gitconfig_path = got_repo_get_path_gitconfig(repo);
1295 7c0b7f42 2020-09-24 stsp if (gitconfig_path == NULL) {
1296 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("got_repo_get_path_gitconfig");
1297 7c0b7f42 2020-09-24 stsp goto done;
1298 7c0b7f42 2020-09-24 stsp }
1299 7c0b7f42 2020-09-24 stsp gitconfig_file = fopen(gitconfig_path, "a");
1300 7c0b7f42 2020-09-24 stsp if (gitconfig_file == NULL) {
1301 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fopen", gitconfig_path);
1302 7c0b7f42 2020-09-24 stsp goto done;
1303 7c0b7f42 2020-09-24 stsp }
1304 56d0a753 2021-01-20 stsp if (fetch_all_branches) {
1305 56d0a753 2021-01-20 stsp if (mirror_references) {
1306 56d0a753 2021-01-20 stsp if (asprintf(&branches,
1307 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1308 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1309 56d0a753 2021-01-20 stsp goto done;
1310 56d0a753 2021-01-20 stsp }
1311 56d0a753 2021-01-20 stsp } else if (asprintf(&branches,
1312 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1313 7c0b7f42 2020-09-24 stsp GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1314 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1315 7c0b7f42 2020-09-24 stsp goto done;
1316 132af4a5 2021-01-05 stsp }
1317 132af4a5 2021-01-05 stsp } else if (!TAILQ_EMPTY(wanted_branches)) {
1318 132af4a5 2021-01-05 stsp struct got_pathlist_entry *pe;
1319 132af4a5 2021-01-05 stsp TAILQ_FOREACH(pe, wanted_branches, entry) {
1320 132af4a5 2021-01-05 stsp char *s;
1321 132af4a5 2021-01-05 stsp branchname = pe->path;
1322 132af4a5 2021-01-05 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1323 132af4a5 2021-01-05 stsp branchname += 11;
1324 56d0a753 2021-01-20 stsp if (mirror_references) {
1325 56d0a753 2021-01-20 stsp if (asprintf(&s,
1326 56d0a753 2021-01-20 stsp "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1327 56d0a753 2021-01-20 stsp branches ? branches : "",
1328 56d0a753 2021-01-20 stsp branchname, branchname) == -1) {
1329 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1330 56d0a753 2021-01-20 stsp goto done;
1331 56d0a753 2021-01-20 stsp }
1332 56d0a753 2021-01-20 stsp } else if (asprintf(&s,
1333 56d0a753 2021-01-20 stsp "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1334 132af4a5 2021-01-05 stsp branches ? branches : "",
1335 132af4a5 2021-01-05 stsp branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1336 132af4a5 2021-01-05 stsp branchname) == -1) {
1337 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1338 132af4a5 2021-01-05 stsp goto done;
1339 132af4a5 2021-01-05 stsp }
1340 132af4a5 2021-01-05 stsp free(branches);
1341 132af4a5 2021-01-05 stsp branches = s;
1342 7c0b7f42 2020-09-24 stsp }
1343 7c0b7f42 2020-09-24 stsp } else {
1344 7c0b7f42 2020-09-24 stsp /*
1345 7c0b7f42 2020-09-24 stsp * If the server specified a default branch, use just that one.
1346 7c0b7f42 2020-09-24 stsp * Otherwise fall back to fetching all branches on next fetch.
1347 7c0b7f42 2020-09-24 stsp */
1348 04d9a9ec 2020-09-24 stsp if (default_branch) {
1349 04d9a9ec 2020-09-24 stsp branchname = default_branch;
1350 7c0b7f42 2020-09-24 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1351 7c0b7f42 2020-09-24 stsp branchname += 11;
1352 7c0b7f42 2020-09-24 stsp } else
1353 7c0b7f42 2020-09-24 stsp branchname = "*"; /* fall back to all branches */
1354 56d0a753 2021-01-20 stsp if (mirror_references) {
1355 56d0a753 2021-01-20 stsp if (asprintf(&branches,
1356 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/%s:refs/heads/%s\n",
1357 56d0a753 2021-01-20 stsp branchname, branchname) == -1) {
1358 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1359 56d0a753 2021-01-20 stsp goto done;
1360 56d0a753 2021-01-20 stsp }
1361 56d0a753 2021-01-20 stsp } else if (asprintf(&branches,
1362 56d0a753 2021-01-20 stsp "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1363 7c0b7f42 2020-09-24 stsp branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1364 7c0b7f42 2020-09-24 stsp branchname) == -1) {
1365 7c0b7f42 2020-09-24 stsp err = got_error_from_errno("asprintf");
1366 7c0b7f42 2020-09-24 stsp goto done;
1367 99495ddb 2021-01-10 stsp }
1368 99495ddb 2021-01-10 stsp }
1369 56d0a753 2021-01-20 stsp if (!TAILQ_EMPTY(wanted_refs)) {
1370 99495ddb 2021-01-10 stsp struct got_pathlist_entry *pe;
1371 99495ddb 2021-01-10 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
1372 99495ddb 2021-01-10 stsp char *s;
1373 99495ddb 2021-01-10 stsp const char *refname = pe->path;
1374 99495ddb 2021-01-10 stsp if (strncmp(refname, "refs/", 5) == 0)
1375 99495ddb 2021-01-10 stsp refname += 5;
1376 56d0a753 2021-01-20 stsp if (mirror_references) {
1377 56d0a753 2021-01-20 stsp if (asprintf(&s,
1378 56d0a753 2021-01-20 stsp "%s\tfetch = refs/%s:refs/%s\n",
1379 56d0a753 2021-01-20 stsp refs ? refs : "", refname, refname) == -1) {
1380 56d0a753 2021-01-20 stsp err = got_error_from_errno("asprintf");
1381 56d0a753 2021-01-20 stsp goto done;
1382 56d0a753 2021-01-20 stsp }
1383 56d0a753 2021-01-20 stsp } else if (asprintf(&s,
1384 56d0a753 2021-01-20 stsp "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1385 99495ddb 2021-01-10 stsp refs ? refs : "",
1386 99495ddb 2021-01-10 stsp refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1387 99495ddb 2021-01-10 stsp refname) == -1) {
1388 99495ddb 2021-01-10 stsp err = got_error_from_errno("asprintf");
1389 99495ddb 2021-01-10 stsp goto done;
1390 99495ddb 2021-01-10 stsp }
1391 99495ddb 2021-01-10 stsp free(refs);
1392 99495ddb 2021-01-10 stsp refs = s;
1393 7c0b7f42 2020-09-24 stsp }
1394 132af4a5 2021-01-05 stsp }
1395 99495ddb 2021-01-10 stsp
1396 132af4a5 2021-01-05 stsp if (asprintf(&gitconfig,
1397 132af4a5 2021-01-05 stsp "[remote \"%s\"]\n"
1398 132af4a5 2021-01-05 stsp "\turl = %s\n"
1399 132af4a5 2021-01-05 stsp "%s"
1400 99495ddb 2021-01-10 stsp "%s"
1401 56d0a753 2021-01-20 stsp "\tfetch = refs/tags/*:refs/tags/*\n",
1402 132af4a5 2021-01-05 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
1403 56d0a753 2021-01-20 stsp refs ? refs : "") == -1) {
1404 132af4a5 2021-01-05 stsp err = got_error_from_errno("asprintf");
1405 132af4a5 2021-01-05 stsp goto done;
1406 7c0b7f42 2020-09-24 stsp }
1407 7c0b7f42 2020-09-24 stsp n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1408 7c0b7f42 2020-09-24 stsp if (n != strlen(gitconfig)) {
1409 7c0b7f42 2020-09-24 stsp err = got_ferror(gitconfig_file, GOT_ERR_IO);
1410 7c0b7f42 2020-09-24 stsp goto done;
1411 7c0b7f42 2020-09-24 stsp }
1412 7c0b7f42 2020-09-24 stsp done:
1413 7c0b7f42 2020-09-24 stsp if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
1414 7c0b7f42 2020-09-24 stsp err = got_error_from_errno2("fclose", gitconfig_path);
1415 7c0b7f42 2020-09-24 stsp free(gitconfig_path);
1416 132af4a5 2021-01-05 stsp free(branches);
1417 0e4002ca 2020-03-21 stsp return err;
1418 0e4002ca 2020-03-21 stsp }
1419 0e4002ca 2020-03-21 stsp
1420 0e4002ca 2020-03-21 stsp static const struct got_error *
1421 04d9a9ec 2020-09-24 stsp create_config_files(const char *proto, const char *host, const char *port,
1422 04d9a9ec 2020-09-24 stsp const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1423 04d9a9ec 2020-09-24 stsp int mirror_references, struct got_pathlist_head *symrefs,
1424 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_branches,
1425 99495ddb 2021-01-10 stsp struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1426 04d9a9ec 2020-09-24 stsp {
1427 04d9a9ec 2020-09-24 stsp const struct got_error *err = NULL;
1428 04d9a9ec 2020-09-24 stsp const char *default_branch = NULL;
1429 04d9a9ec 2020-09-24 stsp struct got_pathlist_entry *pe;
1430 04d9a9ec 2020-09-24 stsp
1431 04d9a9ec 2020-09-24 stsp /*
1432 04d9a9ec 2020-09-24 stsp * If we asked for a set of wanted branches then use the first
1433 04d9a9ec 2020-09-24 stsp * one of those.
1434 04d9a9ec 2020-09-24 stsp */
1435 62d463ca 2020-10-20 naddy if (!TAILQ_EMPTY(wanted_branches)) {
1436 04d9a9ec 2020-09-24 stsp pe = TAILQ_FIRST(wanted_branches);
1437 04d9a9ec 2020-09-24 stsp default_branch = pe->path;
1438 04d9a9ec 2020-09-24 stsp } else {
1439 04d9a9ec 2020-09-24 stsp /* First HEAD ref listed by server is the default branch. */
1440 04d9a9ec 2020-09-24 stsp TAILQ_FOREACH(pe, symrefs, entry) {
1441 04d9a9ec 2020-09-24 stsp const char *refname = pe->path;
1442 04d9a9ec 2020-09-24 stsp const char *target = pe->data;
1443 04d9a9ec 2020-09-24 stsp
1444 04d9a9ec 2020-09-24 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
1445 04d9a9ec 2020-09-24 stsp continue;
1446 04d9a9ec 2020-09-24 stsp
1447 04d9a9ec 2020-09-24 stsp default_branch = target;
1448 04d9a9ec 2020-09-24 stsp break;
1449 04d9a9ec 2020-09-24 stsp }
1450 04d9a9ec 2020-09-24 stsp }
1451 04d9a9ec 2020-09-24 stsp
1452 04d9a9ec 2020-09-24 stsp /* Create got.conf(5). */
1453 04d9a9ec 2020-09-24 stsp err = create_gotconfig(proto, host, port, remote_repo_path,
1454 0c8b29c5 2021-01-05 stsp default_branch, fetch_all_branches, wanted_branches,
1455 99495ddb 2021-01-10 stsp wanted_refs, mirror_references, repo);
1456 04d9a9ec 2020-09-24 stsp if (err)
1457 04d9a9ec 2020-09-24 stsp return err;
1458 04d9a9ec 2020-09-24 stsp
1459 04d9a9ec 2020-09-24 stsp /* Create a config file Git can understand. */
1460 04d9a9ec 2020-09-24 stsp return create_gitconfig(git_url, default_branch, fetch_all_branches,
1461 99495ddb 2021-01-10 stsp wanted_branches, wanted_refs, mirror_references, repo);
1462 04d9a9ec 2020-09-24 stsp }
1463 04d9a9ec 2020-09-24 stsp
1464 04d9a9ec 2020-09-24 stsp static const struct got_error *
1465 93658fb9 2020-03-18 stsp cmd_clone(int argc, char *argv[])
1466 93658fb9 2020-03-18 stsp {
1467 39c64a6a 2020-03-18 stsp const struct got_error *error = NULL;
1468 9df6f38b 2020-03-18 stsp const char *uri, *dirname;
1469 09838ffc 2020-03-18 stsp char *proto, *host, *port, *repo_name, *server_path;
1470 d9b4d0c0 2020-03-18 stsp char *default_destdir = NULL, *id_str = NULL;
1471 a9c2d4c2 2020-09-24 stsp const char *repo_path;
1472 bb64b798 2020-03-18 stsp struct got_repository *repo = NULL;
1473 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1474 d9b4d0c0 2020-03-18 stsp struct got_pathlist_entry *pe;
1475 d9b4d0c0 2020-03-18 stsp struct got_object_id *pack_hash = NULL;
1476 9c52365f 2020-03-21 stsp int ch, fetchfd = -1, fetchstatus;
1477 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
1478 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg fpa;
1479 b46f3e71 2020-03-18 stsp char *git_url = NULL;
1480 659e7fbd 2020-03-20 stsp int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1481 41b0de12 2020-03-21 stsp int list_refs_only = 0;
1482 93658fb9 2020-03-18 stsp
1483 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&refs);
1484 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&symrefs);
1485 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
1486 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
1487 d9b4d0c0 2020-03-18 stsp
1488 0e4002ca 2020-03-21 stsp while ((ch = getopt(argc, argv, "ab:lmvqR:")) != -1) {
1489 93658fb9 2020-03-18 stsp switch (ch) {
1490 659e7fbd 2020-03-20 stsp case 'a':
1491 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
1492 4ba14133 2020-03-20 stsp break;
1493 4ba14133 2020-03-20 stsp case 'b':
1494 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
1495 4ba14133 2020-03-20 stsp optarg, NULL);
1496 4ba14133 2020-03-20 stsp if (error)
1497 4ba14133 2020-03-20 stsp return error;
1498 659e7fbd 2020-03-20 stsp break;
1499 41b0de12 2020-03-21 stsp case 'l':
1500 41b0de12 2020-03-21 stsp list_refs_only = 1;
1501 41b0de12 2020-03-21 stsp break;
1502 469dd726 2020-03-20 stsp case 'm':
1503 469dd726 2020-03-20 stsp mirror_references = 1;
1504 469dd726 2020-03-20 stsp break;
1505 68999b92 2020-03-18 stsp case 'v':
1506 68999b92 2020-03-18 stsp if (verbosity < 0)
1507 68999b92 2020-03-18 stsp verbosity = 0;
1508 68999b92 2020-03-18 stsp else if (verbosity < 3)
1509 68999b92 2020-03-18 stsp verbosity++;
1510 68999b92 2020-03-18 stsp break;
1511 68999b92 2020-03-18 stsp case 'q':
1512 68999b92 2020-03-18 stsp verbosity = -1;
1513 68999b92 2020-03-18 stsp break;
1514 0e4002ca 2020-03-21 stsp case 'R':
1515 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
1516 0e4002ca 2020-03-21 stsp optarg, NULL);
1517 0e4002ca 2020-03-21 stsp if (error)
1518 0e4002ca 2020-03-21 stsp return error;
1519 0e4002ca 2020-03-21 stsp break;
1520 93658fb9 2020-03-18 stsp default:
1521 93658fb9 2020-03-18 stsp usage_clone();
1522 93658fb9 2020-03-18 stsp break;
1523 93658fb9 2020-03-18 stsp }
1524 93658fb9 2020-03-18 stsp }
1525 93658fb9 2020-03-18 stsp argc -= optind;
1526 93658fb9 2020-03-18 stsp argv += optind;
1527 39c64a6a 2020-03-18 stsp
1528 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1529 ff69268e 2020-12-13 stsp option_conflict('a', 'b');
1530 41b0de12 2020-03-21 stsp if (list_refs_only) {
1531 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
1532 ff69268e 2020-12-13 stsp option_conflict('l', 'b');
1533 41b0de12 2020-03-21 stsp if (fetch_all_branches)
1534 ff69268e 2020-12-13 stsp option_conflict('l', 'a');
1535 41b0de12 2020-03-21 stsp if (mirror_references)
1536 ff69268e 2020-12-13 stsp option_conflict('l', 'm');
1537 0e4002ca 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_refs))
1538 ff69268e 2020-12-13 stsp option_conflict('l', 'R');
1539 41b0de12 2020-03-21 stsp }
1540 4ba14133 2020-03-20 stsp
1541 93658fb9 2020-03-18 stsp uri = argv[0];
1542 9df6f38b 2020-03-18 stsp
1543 9df6f38b 2020-03-18 stsp if (argc == 1)
1544 93658fb9 2020-03-18 stsp dirname = NULL;
1545 9df6f38b 2020-03-18 stsp else if (argc == 2)
1546 93658fb9 2020-03-18 stsp dirname = argv[1];
1547 93658fb9 2020-03-18 stsp else
1548 93658fb9 2020-03-18 stsp usage_clone();
1549 09838ffc 2020-03-18 stsp
1550 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
1551 4dbec0a8 2020-08-27 stsp &repo_name, uri);
1552 39c64a6a 2020-03-18 stsp if (error)
1553 09f63084 2020-03-20 stsp goto done;
1554 09f63084 2020-03-20 stsp
1555 09f63084 2020-03-20 stsp if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1556 09f63084 2020-03-20 stsp host, port ? ":" : "", port ? port : "",
1557 09f63084 2020-03-20 stsp server_path[0] != '/' ? "/" : "", server_path) == -1) {
1558 09f63084 2020-03-20 stsp error = got_error_from_errno("asprintf");
1559 09838ffc 2020-03-18 stsp goto done;
1560 09f63084 2020-03-20 stsp }
1561 09838ffc 2020-03-18 stsp
1562 39c64a6a 2020-03-18 stsp if (strcmp(proto, "git") == 0) {
1563 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1564 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1565 39c64a6a 2020-03-18 stsp "sendfd dns inet unveil", NULL) == -1)
1566 39c64a6a 2020-03-18 stsp err(1, "pledge");
1567 b46f3e71 2020-03-18 stsp #endif
1568 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
1569 39c64a6a 2020-03-18 stsp strcmp(proto, "ssh") == 0) {
1570 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1571 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1572 39c64a6a 2020-03-18 stsp "sendfd unveil", NULL) == -1)
1573 39c64a6a 2020-03-18 stsp err(1, "pledge");
1574 b46f3e71 2020-03-18 stsp #endif
1575 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "http") == 0 ||
1576 39c64a6a 2020-03-18 stsp strcmp(proto, "git+http") == 0) {
1577 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1578 39c64a6a 2020-03-18 stsp goto done;
1579 39c64a6a 2020-03-18 stsp } else {
1580 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1581 39c64a6a 2020-03-18 stsp goto done;
1582 39c64a6a 2020-03-18 stsp }
1583 bb64b798 2020-03-18 stsp if (dirname == NULL) {
1584 bb64b798 2020-03-18 stsp if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1585 39c64a6a 2020-03-18 stsp error = got_error_from_errno("asprintf");
1586 bb64b798 2020-03-18 stsp goto done;
1587 bb64b798 2020-03-18 stsp }
1588 bb64b798 2020-03-18 stsp repo_path = default_destdir;
1589 bb64b798 2020-03-18 stsp } else
1590 bb64b798 2020-03-18 stsp repo_path = dirname;
1591 bb64b798 2020-03-18 stsp
1592 41b0de12 2020-03-21 stsp if (!list_refs_only) {
1593 41b0de12 2020-03-21 stsp error = got_path_mkdir(repo_path);
1594 2751fe64 2020-09-24 stsp if (error &&
1595 2751fe64 2020-09-24 stsp (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
1596 2751fe64 2020-09-24 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST)))
1597 41b0de12 2020-03-21 stsp goto done;
1598 2751fe64 2020-09-24 stsp if (!got_path_dir_is_empty(repo_path)) {
1599 2751fe64 2020-09-24 stsp error = got_error_path(repo_path,
1600 2751fe64 2020-09-24 stsp GOT_ERR_DIR_NOT_EMPTY);
1601 41b0de12 2020-03-21 stsp goto done;
1602 2751fe64 2020-09-24 stsp }
1603 41b0de12 2020-03-21 stsp }
1604 bb64b798 2020-03-18 stsp
1605 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
1606 d65a88a2 2021-09-05 stsp if (error)
1607 d65a88a2 2021-09-05 stsp goto done;
1608 d65a88a2 2021-09-05 stsp
1609 f535bcd4 2020-09-30 stsp error = apply_unveil(repo_path, 0, NULL);
1610 ee448f5f 2020-03-18 stsp if (error)
1611 ee448f5f 2020-03-18 stsp goto done;
1612 f79e6490 2020-04-19 stsp
1613 f79e6490 2020-04-19 stsp if (verbosity >= 0)
1614 f79e6490 2020-04-19 stsp printf("Connecting to %s%s%s\n", host,
1615 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
1616 ee448f5f 2020-03-18 stsp
1617 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1618 9c52365f 2020-03-21 stsp server_path, verbosity);
1619 39c64a6a 2020-03-18 stsp if (error)
1620 bb64b798 2020-03-18 stsp goto done;
1621 bb64b798 2020-03-18 stsp
1622 2751fe64 2020-09-24 stsp if (!list_refs_only) {
1623 2751fe64 2020-09-24 stsp error = got_repo_init(repo_path);
1624 2751fe64 2020-09-24 stsp if (error)
1625 2751fe64 2020-09-24 stsp goto done;
1626 2751fe64 2020-09-24 stsp error = got_repo_open(&repo, repo_path, NULL);
1627 2751fe64 2020-09-24 stsp if (error)
1628 2751fe64 2020-09-24 stsp goto done;
1629 2751fe64 2020-09-24 stsp }
1630 2751fe64 2020-09-24 stsp
1631 892ac3b6 2020-03-18 stsp fpa.last_scaled_size[0] = '\0';
1632 892ac3b6 2020-03-18 stsp fpa.last_p_indexed = -1;
1633 892ac3b6 2020-03-18 stsp fpa.last_p_resolved = -1;
1634 68999b92 2020-03-18 stsp fpa.verbosity = verbosity;
1635 04d9a9ec 2020-09-24 stsp fpa.create_configs = 1;
1636 04d9a9ec 2020-09-24 stsp fpa.configs_created = 0;
1637 04d9a9ec 2020-09-24 stsp fpa.repo = repo;
1638 04d9a9ec 2020-09-24 stsp fpa.config_info.symrefs = &symrefs;
1639 04d9a9ec 2020-09-24 stsp fpa.config_info.wanted_branches = &wanted_branches;
1640 99495ddb 2021-01-10 stsp fpa.config_info.wanted_refs = &wanted_refs;
1641 04d9a9ec 2020-09-24 stsp fpa.config_info.proto = proto;
1642 04d9a9ec 2020-09-24 stsp fpa.config_info.host = host;
1643 04d9a9ec 2020-09-24 stsp fpa.config_info.port = port;
1644 04d9a9ec 2020-09-24 stsp fpa.config_info.remote_repo_path = server_path;
1645 04d9a9ec 2020-09-24 stsp fpa.config_info.git_url = git_url;
1646 04d9a9ec 2020-09-24 stsp fpa.config_info.fetch_all_branches = fetch_all_branches;
1647 04d9a9ec 2020-09-24 stsp fpa.config_info.mirror_references = mirror_references;
1648 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1649 469dd726 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1650 0e4002ca 2020-03-21 stsp fetch_all_branches, &wanted_branches, &wanted_refs,
1651 0e4002ca 2020-03-21 stsp list_refs_only, verbosity, fetchfd, repo,
1652 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
1653 39c64a6a 2020-03-18 stsp if (error)
1654 d9b4d0c0 2020-03-18 stsp goto done;
1655 d9b4d0c0 2020-03-18 stsp
1656 41b0de12 2020-03-21 stsp if (list_refs_only) {
1657 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
1658 41b0de12 2020-03-21 stsp goto done;
1659 41b0de12 2020-03-21 stsp }
1660 41b0de12 2020-03-21 stsp
1661 39c64a6a 2020-03-18 stsp error = got_object_id_str(&id_str, pack_hash);
1662 39c64a6a 2020-03-18 stsp if (error)
1663 d9b4d0c0 2020-03-18 stsp goto done;
1664 68999b92 2020-03-18 stsp if (verbosity >= 0)
1665 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
1666 d9b4d0c0 2020-03-18 stsp free(id_str);
1667 d9b4d0c0 2020-03-18 stsp
1668 d9b4d0c0 2020-03-18 stsp /* Set up references provided with the pack file. */
1669 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1670 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1671 d9b4d0c0 2020-03-18 stsp struct got_object_id *id = pe->data;
1672 7ebc0570 2020-03-18 stsp char *remote_refname;
1673 0e4002ca 2020-03-21 stsp
1674 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
1675 0e4002ca 2020-03-21 stsp !mirror_references) {
1676 0e4002ca 2020-03-21 stsp error = create_wanted_ref(refname, id,
1677 0e4002ca 2020-03-21 stsp GOT_FETCH_DEFAULT_REMOTE_NAME,
1678 0e4002ca 2020-03-21 stsp verbosity - 1, repo);
1679 0e4002ca 2020-03-21 stsp if (error)
1680 0e4002ca 2020-03-21 stsp goto done;
1681 0e4002ca 2020-03-21 stsp continue;
1682 0e4002ca 2020-03-21 stsp }
1683 668a20f6 2020-03-18 stsp
1684 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity - 1, repo);
1685 39c64a6a 2020-03-18 stsp if (error)
1686 d9b4d0c0 2020-03-18 stsp goto done;
1687 d9b4d0c0 2020-03-18 stsp
1688 469dd726 2020-03-20 stsp if (mirror_references)
1689 469dd726 2020-03-20 stsp continue;
1690 469dd726 2020-03-20 stsp
1691 7ebc0570 2020-03-18 stsp if (strncmp("refs/heads/", refname, 11) != 0)
1692 7ebc0570 2020-03-18 stsp continue;
1693 7ebc0570 2020-03-18 stsp
1694 7ebc0570 2020-03-18 stsp if (asprintf(&remote_refname,
1695 7ebc0570 2020-03-18 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1696 7ebc0570 2020-03-18 stsp refname + 11) == -1) {
1697 7ebc0570 2020-03-18 stsp error = got_error_from_errno("asprintf");
1698 7ebc0570 2020-03-18 stsp goto done;
1699 7ebc0570 2020-03-18 stsp }
1700 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id, verbosity - 1, repo);
1701 f298ae0f 2020-03-25 stsp free(remote_refname);
1702 39c64a6a 2020-03-18 stsp if (error)
1703 d9b4d0c0 2020-03-18 stsp goto done;
1704 d9b4d0c0 2020-03-18 stsp }
1705 d9b4d0c0 2020-03-18 stsp
1706 d9b4d0c0 2020-03-18 stsp /* Set the HEAD reference if the server provided one. */
1707 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1708 659e7fbd 2020-03-20 stsp struct got_reference *target_ref;
1709 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1710 d9b4d0c0 2020-03-18 stsp const char *target = pe->data;
1711 f298ae0f 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
1712 d9b4d0c0 2020-03-18 stsp
1713 d9b4d0c0 2020-03-18 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
1714 d9b4d0c0 2020-03-18 stsp continue;
1715 d9b4d0c0 2020-03-18 stsp
1716 39c64a6a 2020-03-18 stsp error = got_ref_open(&target_ref, repo, target, 0);
1717 39c64a6a 2020-03-18 stsp if (error) {
1718 55330abe 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1719 55330abe 2020-03-20 stsp error = NULL;
1720 d9b4d0c0 2020-03-18 stsp continue;
1721 55330abe 2020-03-20 stsp }
1722 d9b4d0c0 2020-03-18 stsp goto done;
1723 d9b4d0c0 2020-03-18 stsp }
1724 d9b4d0c0 2020-03-18 stsp
1725 04d9a9ec 2020-09-24 stsp error = create_symref(refname, target_ref, verbosity, repo);
1726 f298ae0f 2020-03-25 stsp got_ref_close(target_ref);
1727 f298ae0f 2020-03-25 stsp if (error)
1728 f298ae0f 2020-03-25 stsp goto done;
1729 f298ae0f 2020-03-25 stsp
1730 f298ae0f 2020-03-25 stsp if (mirror_references)
1731 f298ae0f 2020-03-25 stsp continue;
1732 f298ae0f 2020-03-25 stsp
1733 f298ae0f 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
1734 f298ae0f 2020-03-25 stsp continue;
1735 f298ae0f 2020-03-25 stsp
1736 f298ae0f 2020-03-25 stsp if (asprintf(&remote_refname,
1737 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1738 f298ae0f 2020-03-25 stsp refname) == -1) {
1739 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1740 f298ae0f 2020-03-25 stsp goto done;
1741 f298ae0f 2020-03-25 stsp }
1742 f298ae0f 2020-03-25 stsp if (asprintf(&remote_target,
1743 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1744 f298ae0f 2020-03-25 stsp target + 11) == -1) {
1745 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1746 f298ae0f 2020-03-25 stsp free(remote_refname);
1747 f298ae0f 2020-03-25 stsp goto done;
1748 f298ae0f 2020-03-25 stsp }
1749 f298ae0f 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target, 0);
1750 f298ae0f 2020-03-25 stsp if (error) {
1751 f298ae0f 2020-03-25 stsp free(remote_refname);
1752 f298ae0f 2020-03-25 stsp free(remote_target);
1753 f298ae0f 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
1754 f298ae0f 2020-03-25 stsp error = NULL;
1755 f298ae0f 2020-03-25 stsp continue;
1756 f298ae0f 2020-03-25 stsp }
1757 f298ae0f 2020-03-25 stsp goto done;
1758 f298ae0f 2020-03-25 stsp }
1759 04d9a9ec 2020-09-24 stsp error = create_symref(remote_refname, target_ref,
1760 04d9a9ec 2020-09-24 stsp verbosity - 1, repo);
1761 f298ae0f 2020-03-25 stsp free(remote_refname);
1762 f298ae0f 2020-03-25 stsp free(remote_target);
1763 d9b4d0c0 2020-03-18 stsp got_ref_close(target_ref);
1764 39c64a6a 2020-03-18 stsp if (error)
1765 d9b4d0c0 2020-03-18 stsp goto done;
1766 4ba14133 2020-03-20 stsp }
1767 4ba14133 2020-03-20 stsp if (pe == NULL) {
1768 4ba14133 2020-03-20 stsp /*
1769 4ba14133 2020-03-20 stsp * We failed to set the HEAD reference. If we asked for
1770 4ba14133 2020-03-20 stsp * a set of wanted branches use the first of one of those
1771 4ba14133 2020-03-20 stsp * which could be fetched instead.
1772 4ba14133 2020-03-20 stsp */
1773 62d463ca 2020-10-20 naddy TAILQ_FOREACH(pe, &wanted_branches, entry) {
1774 4ba14133 2020-03-20 stsp const char *target = pe->path;
1775 4ba14133 2020-03-20 stsp struct got_reference *target_ref;
1776 d9b4d0c0 2020-03-18 stsp
1777 4ba14133 2020-03-20 stsp error = got_ref_open(&target_ref, repo, target, 0);
1778 4ba14133 2020-03-20 stsp if (error) {
1779 4ba14133 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1780 4ba14133 2020-03-20 stsp error = NULL;
1781 4ba14133 2020-03-20 stsp continue;
1782 4ba14133 2020-03-20 stsp }
1783 4ba14133 2020-03-20 stsp goto done;
1784 4ba14133 2020-03-20 stsp }
1785 4ba14133 2020-03-20 stsp
1786 04d9a9ec 2020-09-24 stsp error = create_symref(GOT_REF_HEAD, target_ref,
1787 04d9a9ec 2020-09-24 stsp verbosity, repo);
1788 4ba14133 2020-03-20 stsp got_ref_close(target_ref);
1789 4ba14133 2020-03-20 stsp if (error)
1790 4ba14133 2020-03-20 stsp goto done;
1791 4ba14133 2020-03-20 stsp break;
1792 4ba14133 2020-03-20 stsp }
1793 659e7fbd 2020-03-20 stsp }
1794 659e7fbd 2020-03-20 stsp
1795 d715f13e 2020-03-19 stsp if (verbosity >= 0)
1796 469dd726 2020-03-20 stsp printf("Created %s repository '%s'\n",
1797 469dd726 2020-03-20 stsp mirror_references ? "mirrored" : "cloned", repo_path);
1798 09838ffc 2020-03-18 stsp done:
1799 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
1800 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
1801 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
1802 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1803 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
1804 9c52365f 2020-03-21 stsp }
1805 39c64a6a 2020-03-18 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1806 39c64a6a 2020-03-18 stsp error = got_error_from_errno("close");
1807 1d0f4054 2021-06-17 stsp if (repo) {
1808 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
1809 1d0f4054 2021-06-17 stsp if (error == NULL)
1810 1d0f4054 2021-06-17 stsp error = close_err;
1811 1d0f4054 2021-06-17 stsp }
1812 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1813 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1814 d9b4d0c0 2020-03-18 stsp free(pe->data);
1815 d9b4d0c0 2020-03-18 stsp }
1816 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&refs);
1817 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1818 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1819 d9b4d0c0 2020-03-18 stsp free(pe->data);
1820 d9b4d0c0 2020-03-18 stsp }
1821 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&symrefs);
1822 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
1823 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
1824 d9b4d0c0 2020-03-18 stsp free(pack_hash);
1825 09838ffc 2020-03-18 stsp free(proto);
1826 09838ffc 2020-03-18 stsp free(host);
1827 09838ffc 2020-03-18 stsp free(port);
1828 09838ffc 2020-03-18 stsp free(server_path);
1829 09838ffc 2020-03-18 stsp free(repo_name);
1830 bb64b798 2020-03-18 stsp free(default_destdir);
1831 b46f3e71 2020-03-18 stsp free(git_url);
1832 39c64a6a 2020-03-18 stsp return error;
1833 7848a0e1 2020-03-19 stsp }
1834 7848a0e1 2020-03-19 stsp
1835 7848a0e1 2020-03-19 stsp static const struct got_error *
1836 7848a0e1 2020-03-19 stsp update_ref(struct got_reference *ref, struct got_object_id *new_id,
1837 db6d8ad8 2020-03-21 stsp int replace_tags, int verbosity, struct got_repository *repo)
1838 7848a0e1 2020-03-19 stsp {
1839 7848a0e1 2020-03-19 stsp const struct got_error *err = NULL;
1840 7848a0e1 2020-03-19 stsp char *new_id_str = NULL;
1841 7848a0e1 2020-03-19 stsp struct got_object_id *old_id = NULL;
1842 7848a0e1 2020-03-19 stsp
1843 7848a0e1 2020-03-19 stsp err = got_object_id_str(&new_id_str, new_id);
1844 7848a0e1 2020-03-19 stsp if (err)
1845 7848a0e1 2020-03-19 stsp goto done;
1846 7848a0e1 2020-03-19 stsp
1847 db6d8ad8 2020-03-21 stsp if (!replace_tags &&
1848 db6d8ad8 2020-03-21 stsp strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1849 88609724 2020-03-21 stsp err = got_ref_resolve(&old_id, repo, ref);
1850 88609724 2020-03-21 stsp if (err)
1851 88609724 2020-03-21 stsp goto done;
1852 88609724 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1853 88609724 2020-03-21 stsp goto done;
1854 db6d8ad8 2020-03-21 stsp if (verbosity >= 0) {
1855 db6d8ad8 2020-03-21 stsp printf("Rejecting update of existing tag %s: %s\n",
1856 db6d8ad8 2020-03-21 stsp got_ref_get_name(ref), new_id_str);
1857 db6d8ad8 2020-03-21 stsp }
1858 db6d8ad8 2020-03-21 stsp goto done;
1859 db6d8ad8 2020-03-21 stsp }
1860 db6d8ad8 2020-03-21 stsp
1861 7848a0e1 2020-03-19 stsp if (got_ref_is_symbolic(ref)) {
1862 688f11b3 2020-03-21 stsp if (verbosity >= 0) {
1863 e8a967e0 2020-03-21 stsp printf("Replacing reference %s: %s\n",
1864 6338a6a1 2020-03-21 stsp got_ref_get_name(ref),
1865 6338a6a1 2020-03-21 stsp got_ref_get_symref_target(ref));
1866 688f11b3 2020-03-21 stsp }
1867 e8a967e0 2020-03-21 stsp err = got_ref_change_symref_to_ref(ref, new_id);
1868 7848a0e1 2020-03-19 stsp if (err)
1869 7848a0e1 2020-03-19 stsp goto done;
1870 e8a967e0 2020-03-21 stsp err = got_ref_write(ref, repo);
1871 e8a967e0 2020-03-21 stsp if (err)
1872 e8a967e0 2020-03-21 stsp goto done;
1873 7848a0e1 2020-03-19 stsp } else {
1874 7848a0e1 2020-03-19 stsp err = got_ref_resolve(&old_id, repo, ref);
1875 7848a0e1 2020-03-19 stsp if (err)
1876 7848a0e1 2020-03-19 stsp goto done;
1877 6338a6a1 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1878 6338a6a1 2020-03-21 stsp goto done;
1879 6338a6a1 2020-03-21 stsp
1880 6338a6a1 2020-03-21 stsp err = got_ref_change_ref(ref, new_id);
1881 6338a6a1 2020-03-21 stsp if (err)
1882 6338a6a1 2020-03-21 stsp goto done;
1883 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
1884 6338a6a1 2020-03-21 stsp if (err)
1885 6338a6a1 2020-03-21 stsp goto done;
1886 7848a0e1 2020-03-19 stsp }
1887 6338a6a1 2020-03-21 stsp
1888 6338a6a1 2020-03-21 stsp if (verbosity >= 0)
1889 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(ref),
1890 6338a6a1 2020-03-21 stsp new_id_str);
1891 7848a0e1 2020-03-19 stsp done:
1892 7848a0e1 2020-03-19 stsp free(old_id);
1893 7848a0e1 2020-03-19 stsp free(new_id_str);
1894 7848a0e1 2020-03-19 stsp return err;
1895 2ab43947 2020-03-18 stsp }
1896 f1bcca34 2020-03-25 stsp
1897 f1bcca34 2020-03-25 stsp static const struct got_error *
1898 f1bcca34 2020-03-25 stsp update_symref(const char *refname, struct got_reference *target_ref,
1899 f1bcca34 2020-03-25 stsp int verbosity, struct got_repository *repo)
1900 f1bcca34 2020-03-25 stsp {
1901 f1bcca34 2020-03-25 stsp const struct got_error *err = NULL, *unlock_err;
1902 f1bcca34 2020-03-25 stsp struct got_reference *symref;
1903 bcf34b0e 2020-03-26 stsp int symref_is_locked = 0;
1904 f1bcca34 2020-03-25 stsp
1905 f1bcca34 2020-03-25 stsp err = got_ref_open(&symref, repo, refname, 1);
1906 bcf34b0e 2020-03-26 stsp if (err) {
1907 bcf34b0e 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
1908 bcf34b0e 2020-03-26 stsp return err;
1909 bcf34b0e 2020-03-26 stsp err = got_ref_alloc_symref(&symref, refname, target_ref);
1910 bcf34b0e 2020-03-26 stsp if (err)
1911 bcf34b0e 2020-03-26 stsp goto done;
1912 2ab43947 2020-03-18 stsp
1913 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1914 bcf34b0e 2020-03-26 stsp if (err)
1915 bcf34b0e 2020-03-26 stsp goto done;
1916 f1bcca34 2020-03-25 stsp
1917 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1918 bcf34b0e 2020-03-26 stsp printf("Created reference %s: %s\n",
1919 bcf34b0e 2020-03-26 stsp got_ref_get_name(symref),
1920 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1921 bcf34b0e 2020-03-26 stsp } else {
1922 bcf34b0e 2020-03-26 stsp symref_is_locked = 1;
1923 f1bcca34 2020-03-25 stsp
1924 bcf34b0e 2020-03-26 stsp if (strcmp(got_ref_get_symref_target(symref),
1925 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref)) == 0)
1926 bcf34b0e 2020-03-26 stsp goto done;
1927 bcf34b0e 2020-03-26 stsp
1928 bcf34b0e 2020-03-26 stsp err = got_ref_change_symref(symref,
1929 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref));
1930 bcf34b0e 2020-03-26 stsp if (err)
1931 bcf34b0e 2020-03-26 stsp goto done;
1932 bcf34b0e 2020-03-26 stsp
1933 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1934 bcf34b0e 2020-03-26 stsp if (err)
1935 bcf34b0e 2020-03-26 stsp goto done;
1936 bcf34b0e 2020-03-26 stsp
1937 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1938 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(symref),
1939 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1940 bcf34b0e 2020-03-26 stsp
1941 bcf34b0e 2020-03-26 stsp }
1942 f1bcca34 2020-03-25 stsp done:
1943 bcf34b0e 2020-03-26 stsp if (symref_is_locked) {
1944 bcf34b0e 2020-03-26 stsp unlock_err = got_ref_unlock(symref);
1945 bcf34b0e 2020-03-26 stsp if (unlock_err && err == NULL)
1946 bcf34b0e 2020-03-26 stsp err = unlock_err;
1947 bcf34b0e 2020-03-26 stsp }
1948 f1bcca34 2020-03-25 stsp got_ref_close(symref);
1949 f1bcca34 2020-03-25 stsp return err;
1950 f1bcca34 2020-03-25 stsp }
1951 f1bcca34 2020-03-25 stsp
1952 2ab43947 2020-03-18 stsp __dead static void
1953 7848a0e1 2020-03-19 stsp usage_fetch(void)
1954 7848a0e1 2020-03-19 stsp {
1955 f21ec2f0 2020-03-21 stsp fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
1956 161728eb 2021-07-24 stsp "[-r repository-path] [-t] [-q] [-v] [-R reference] [-X] "
1957 0e4002ca 2020-03-21 stsp "[remote-repository-name]\n",
1958 13f12b09 2020-03-21 stsp getprogname());
1959 7848a0e1 2020-03-19 stsp exit(1);
1960 7848a0e1 2020-03-19 stsp }
1961 7848a0e1 2020-03-19 stsp
1962 7848a0e1 2020-03-19 stsp static const struct got_error *
1963 3789fd73 2020-03-26 stsp delete_missing_ref(struct got_reference *ref,
1964 688f11b3 2020-03-21 stsp int verbosity, struct got_repository *repo)
1965 f21ec2f0 2020-03-21 stsp {
1966 f21ec2f0 2020-03-21 stsp const struct got_error *err = NULL;
1967 3789fd73 2020-03-26 stsp struct got_object_id *id = NULL;
1968 3789fd73 2020-03-26 stsp char *id_str = NULL;
1969 3789fd73 2020-03-26 stsp
1970 3789fd73 2020-03-26 stsp if (got_ref_is_symbolic(ref)) {
1971 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1972 3789fd73 2020-03-26 stsp if (err)
1973 3789fd73 2020-03-26 stsp return err;
1974 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
1975 f9d54ee6 2021-07-16 stsp printf("Deleted %s: %s\n",
1976 3789fd73 2020-03-26 stsp got_ref_get_name(ref),
1977 3789fd73 2020-03-26 stsp got_ref_get_symref_target(ref));
1978 3789fd73 2020-03-26 stsp }
1979 3789fd73 2020-03-26 stsp } else {
1980 3789fd73 2020-03-26 stsp err = got_ref_resolve(&id, repo, ref);
1981 3789fd73 2020-03-26 stsp if (err)
1982 3789fd73 2020-03-26 stsp return err;
1983 3789fd73 2020-03-26 stsp err = got_object_id_str(&id_str, id);
1984 3789fd73 2020-03-26 stsp if (err)
1985 3789fd73 2020-03-26 stsp goto done;
1986 3168e5da 2020-09-10 stsp
1987 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1988 3789fd73 2020-03-26 stsp if (err)
1989 3789fd73 2020-03-26 stsp goto done;
1990 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
1991 f9d54ee6 2021-07-16 stsp printf("Deleted %s: %s\n",
1992 3789fd73 2020-03-26 stsp got_ref_get_name(ref), id_str);
1993 3789fd73 2020-03-26 stsp }
1994 3789fd73 2020-03-26 stsp }
1995 3789fd73 2020-03-26 stsp done:
1996 3789fd73 2020-03-26 stsp free(id);
1997 3789fd73 2020-03-26 stsp free(id_str);
1998 3789fd73 2020-03-26 stsp return NULL;
1999 3789fd73 2020-03-26 stsp }
2000 3789fd73 2020-03-26 stsp
2001 3789fd73 2020-03-26 stsp static const struct got_error *
2002 3789fd73 2020-03-26 stsp delete_missing_refs(struct got_pathlist_head *their_refs,
2003 50b0790e 2020-09-11 stsp struct got_pathlist_head *their_symrefs,
2004 50b0790e 2020-09-11 stsp const struct got_remote_repo *remote,
2005 3789fd73 2020-03-26 stsp int verbosity, struct got_repository *repo)
2006 3789fd73 2020-03-26 stsp {
2007 3789fd73 2020-03-26 stsp const struct got_error *err = NULL, *unlock_err;
2008 f21ec2f0 2020-03-21 stsp struct got_reflist_head my_refs;
2009 f21ec2f0 2020-03-21 stsp struct got_reflist_entry *re;
2010 f21ec2f0 2020-03-21 stsp struct got_pathlist_entry *pe;
2011 3789fd73 2020-03-26 stsp char *remote_namespace = NULL;
2012 3789fd73 2020-03-26 stsp char *local_refname = NULL;
2013 f21ec2f0 2020-03-21 stsp
2014 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&my_refs);
2015 f21ec2f0 2020-03-21 stsp
2016 3789fd73 2020-03-26 stsp if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
2017 3789fd73 2020-03-26 stsp == -1)
2018 3789fd73 2020-03-26 stsp return got_error_from_errno("asprintf");
2019 3789fd73 2020-03-26 stsp
2020 f21ec2f0 2020-03-21 stsp err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
2021 f21ec2f0 2020-03-21 stsp if (err)
2022 3789fd73 2020-03-26 stsp goto done;
2023 f21ec2f0 2020-03-21 stsp
2024 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &my_refs, entry) {
2025 f21ec2f0 2020-03-21 stsp const char *refname = got_ref_get_name(re->ref);
2026 1b796c3f 2021-09-11 stsp const char *their_refname;
2027 f21ec2f0 2020-03-21 stsp
2028 1b796c3f 2021-09-11 stsp if (remote->mirror_references) {
2029 1b796c3f 2021-09-11 stsp their_refname = refname;
2030 1b796c3f 2021-09-11 stsp } else {
2031 3789fd73 2020-03-26 stsp if (strncmp(refname, remote_namespace,
2032 3789fd73 2020-03-26 stsp strlen(remote_namespace)) == 0) {
2033 3789fd73 2020-03-26 stsp if (strcmp(refname + strlen(remote_namespace),
2034 3789fd73 2020-03-26 stsp GOT_REF_HEAD) == 0)
2035 3789fd73 2020-03-26 stsp continue;
2036 3789fd73 2020-03-26 stsp if (asprintf(&local_refname, "refs/heads/%s",
2037 3789fd73 2020-03-26 stsp refname + strlen(remote_namespace)) == -1) {
2038 3789fd73 2020-03-26 stsp err = got_error_from_errno("asprintf");
2039 3789fd73 2020-03-26 stsp goto done;
2040 3789fd73 2020-03-26 stsp }
2041 3789fd73 2020-03-26 stsp } else if (strncmp(refname, "refs/tags/", 10) != 0)
2042 3789fd73 2020-03-26 stsp continue;
2043 f21ec2f0 2020-03-21 stsp
2044 1b796c3f 2021-09-11 stsp their_refname = local_refname;
2045 1b796c3f 2021-09-11 stsp }
2046 1b796c3f 2021-09-11 stsp
2047 f21ec2f0 2020-03-21 stsp TAILQ_FOREACH(pe, their_refs, entry) {
2048 1b796c3f 2021-09-11 stsp if (strcmp(their_refname, pe->path) == 0)
2049 f21ec2f0 2020-03-21 stsp break;
2050 f21ec2f0 2020-03-21 stsp }
2051 f21ec2f0 2020-03-21 stsp if (pe != NULL)
2052 f21ec2f0 2020-03-21 stsp continue;
2053 f21ec2f0 2020-03-21 stsp
2054 3789fd73 2020-03-26 stsp TAILQ_FOREACH(pe, their_symrefs, entry) {
2055 1b796c3f 2021-09-11 stsp if (strcmp(their_refname, pe->path) == 0)
2056 3789fd73 2020-03-26 stsp break;
2057 3789fd73 2020-03-26 stsp }
2058 3789fd73 2020-03-26 stsp if (pe != NULL)
2059 3789fd73 2020-03-26 stsp continue;
2060 f21ec2f0 2020-03-21 stsp
2061 3789fd73 2020-03-26 stsp err = delete_missing_ref(re->ref, verbosity, repo);
2062 f21ec2f0 2020-03-21 stsp if (err)
2063 f21ec2f0 2020-03-21 stsp break;
2064 3789fd73 2020-03-26 stsp
2065 3789fd73 2020-03-26 stsp if (local_refname) {
2066 3789fd73 2020-03-26 stsp struct got_reference *ref;
2067 3789fd73 2020-03-26 stsp err = got_ref_open(&ref, repo, local_refname, 1);
2068 3789fd73 2020-03-26 stsp if (err) {
2069 3789fd73 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
2070 3789fd73 2020-03-26 stsp break;
2071 3789fd73 2020-03-26 stsp free(local_refname);
2072 3789fd73 2020-03-26 stsp local_refname = NULL;
2073 3789fd73 2020-03-26 stsp continue;
2074 3789fd73 2020-03-26 stsp }
2075 3789fd73 2020-03-26 stsp err = delete_missing_ref(ref, verbosity, repo);
2076 3789fd73 2020-03-26 stsp if (err)
2077 3789fd73 2020-03-26 stsp break;
2078 3789fd73 2020-03-26 stsp unlock_err = got_ref_unlock(ref);
2079 3789fd73 2020-03-26 stsp got_ref_close(ref);
2080 3789fd73 2020-03-26 stsp if (unlock_err && err == NULL) {
2081 3789fd73 2020-03-26 stsp err = unlock_err;
2082 3789fd73 2020-03-26 stsp break;
2083 3789fd73 2020-03-26 stsp }
2084 3789fd73 2020-03-26 stsp
2085 3789fd73 2020-03-26 stsp free(local_refname);
2086 3789fd73 2020-03-26 stsp local_refname = NULL;
2087 6338a6a1 2020-03-21 stsp }
2088 f21ec2f0 2020-03-21 stsp }
2089 3789fd73 2020-03-26 stsp done:
2090 3789fd73 2020-03-26 stsp free(remote_namespace);
2091 3789fd73 2020-03-26 stsp free(local_refname);
2092 0e4002ca 2020-03-21 stsp return err;
2093 0e4002ca 2020-03-21 stsp }
2094 0e4002ca 2020-03-21 stsp
2095 0e4002ca 2020-03-21 stsp static const struct got_error *
2096 0e4002ca 2020-03-21 stsp update_wanted_ref(const char *refname, struct got_object_id *id,
2097 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
2098 0e4002ca 2020-03-21 stsp {
2099 9f142382 2020-03-21 stsp const struct got_error *err, *unlock_err;
2100 0e4002ca 2020-03-21 stsp char *remote_refname;
2101 0e4002ca 2020-03-21 stsp struct got_reference *ref;
2102 0e4002ca 2020-03-21 stsp
2103 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
2104 0e4002ca 2020-03-21 stsp refname += 5;
2105 0e4002ca 2020-03-21 stsp
2106 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2107 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
2108 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
2109 f21ec2f0 2020-03-21 stsp
2110 9f142382 2020-03-21 stsp err = got_ref_open(&ref, repo, remote_refname, 1);
2111 0e4002ca 2020-03-21 stsp if (err) {
2112 0e4002ca 2020-03-21 stsp if (err->code != GOT_ERR_NOT_REF)
2113 0e4002ca 2020-03-21 stsp goto done;
2114 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
2115 0e4002ca 2020-03-21 stsp } else {
2116 0e4002ca 2020-03-21 stsp err = update_ref(ref, id, 0, verbosity, repo);
2117 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2118 9f142382 2020-03-21 stsp if (unlock_err && err == NULL)
2119 9f142382 2020-03-21 stsp err = unlock_err;
2120 0e4002ca 2020-03-21 stsp got_ref_close(ref);
2121 0e4002ca 2020-03-21 stsp }
2122 0e4002ca 2020-03-21 stsp done:
2123 0e4002ca 2020-03-21 stsp free(remote_refname);
2124 161728eb 2021-07-24 stsp return err;
2125 161728eb 2021-07-24 stsp }
2126 161728eb 2021-07-24 stsp
2127 161728eb 2021-07-24 stsp static const struct got_error *
2128 161728eb 2021-07-24 stsp delete_ref(struct got_repository *repo, struct got_reference *ref)
2129 161728eb 2021-07-24 stsp {
2130 161728eb 2021-07-24 stsp const struct got_error *err = NULL;
2131 161728eb 2021-07-24 stsp struct got_object_id *id = NULL;
2132 161728eb 2021-07-24 stsp char *id_str = NULL;
2133 161728eb 2021-07-24 stsp const char *target;
2134 161728eb 2021-07-24 stsp
2135 161728eb 2021-07-24 stsp if (got_ref_is_symbolic(ref)) {
2136 161728eb 2021-07-24 stsp target = got_ref_get_symref_target(ref);
2137 161728eb 2021-07-24 stsp } else {
2138 161728eb 2021-07-24 stsp err = got_ref_resolve(&id, repo, ref);
2139 161728eb 2021-07-24 stsp if (err)
2140 161728eb 2021-07-24 stsp goto done;
2141 161728eb 2021-07-24 stsp err = got_object_id_str(&id_str, id);
2142 161728eb 2021-07-24 stsp if (err)
2143 161728eb 2021-07-24 stsp goto done;
2144 161728eb 2021-07-24 stsp target = id_str;
2145 161728eb 2021-07-24 stsp }
2146 161728eb 2021-07-24 stsp
2147 161728eb 2021-07-24 stsp err = got_ref_delete(ref, repo);
2148 161728eb 2021-07-24 stsp if (err)
2149 161728eb 2021-07-24 stsp goto done;
2150 161728eb 2021-07-24 stsp
2151 161728eb 2021-07-24 stsp printf("Deleted %s: %s\n", got_ref_get_name(ref), target);
2152 161728eb 2021-07-24 stsp done:
2153 161728eb 2021-07-24 stsp free(id);
2154 161728eb 2021-07-24 stsp free(id_str);
2155 f21ec2f0 2020-03-21 stsp return err;
2156 f21ec2f0 2020-03-21 stsp }
2157 f21ec2f0 2020-03-21 stsp
2158 f21ec2f0 2020-03-21 stsp static const struct got_error *
2159 161728eb 2021-07-24 stsp delete_refs_for_remote(struct got_repository *repo, const char *remote_name)
2160 161728eb 2021-07-24 stsp {
2161 161728eb 2021-07-24 stsp const struct got_error *err = NULL;
2162 161728eb 2021-07-24 stsp struct got_reflist_head refs;
2163 161728eb 2021-07-24 stsp struct got_reflist_entry *re;
2164 161728eb 2021-07-24 stsp char *prefix;
2165 161728eb 2021-07-24 stsp
2166 161728eb 2021-07-24 stsp TAILQ_INIT(&refs);
2167 161728eb 2021-07-24 stsp
2168 161728eb 2021-07-24 stsp if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) {
2169 161728eb 2021-07-24 stsp err = got_error_from_errno("asprintf");
2170 161728eb 2021-07-24 stsp goto done;
2171 161728eb 2021-07-24 stsp }
2172 161728eb 2021-07-24 stsp err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL);
2173 161728eb 2021-07-24 stsp if (err)
2174 161728eb 2021-07-24 stsp goto done;
2175 161728eb 2021-07-24 stsp
2176 161728eb 2021-07-24 stsp TAILQ_FOREACH(re, &refs, entry)
2177 161728eb 2021-07-24 stsp delete_ref(repo, re->ref);
2178 161728eb 2021-07-24 stsp done:
2179 161728eb 2021-07-24 stsp got_ref_list_free(&refs);
2180 161728eb 2021-07-24 stsp return err;
2181 161728eb 2021-07-24 stsp }
2182 161728eb 2021-07-24 stsp
2183 161728eb 2021-07-24 stsp static const struct got_error *
2184 7848a0e1 2020-03-19 stsp cmd_fetch(int argc, char *argv[])
2185 7848a0e1 2020-03-19 stsp {
2186 9f142382 2020-03-21 stsp const struct got_error *error = NULL, *unlock_err;
2187 7848a0e1 2020-03-19 stsp char *cwd = NULL, *repo_path = NULL;
2188 7848a0e1 2020-03-19 stsp const char *remote_name;
2189 7848a0e1 2020-03-19 stsp char *proto = NULL, *host = NULL, *port = NULL;
2190 7848a0e1 2020-03-19 stsp char *repo_name = NULL, *server_path = NULL;
2191 50b0790e 2020-09-11 stsp const struct got_remote_repo *remotes, *remote = NULL;
2192 7848a0e1 2020-03-19 stsp int nremotes;
2193 7848a0e1 2020-03-19 stsp char *id_str = NULL;
2194 7848a0e1 2020-03-19 stsp struct got_repository *repo = NULL;
2195 7848a0e1 2020-03-19 stsp struct got_worktree *worktree = NULL;
2196 50b0790e 2020-09-11 stsp const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
2197 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
2198 7848a0e1 2020-03-19 stsp struct got_pathlist_entry *pe;
2199 7848a0e1 2020-03-19 stsp struct got_object_id *pack_hash = NULL;
2200 9c52365f 2020-03-21 stsp int i, ch, fetchfd = -1, fetchstatus;
2201 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
2202 7848a0e1 2020-03-19 stsp struct got_fetch_progress_arg fpa;
2203 41b0de12 2020-03-21 stsp int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
2204 161728eb 2021-07-24 stsp int delete_refs = 0, replace_tags = 0, delete_remote = 0;
2205 7848a0e1 2020-03-19 stsp
2206 7848a0e1 2020-03-19 stsp TAILQ_INIT(&refs);
2207 7848a0e1 2020-03-19 stsp TAILQ_INIT(&symrefs);
2208 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
2209 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
2210 7848a0e1 2020-03-19 stsp
2211 161728eb 2021-07-24 stsp while ((ch = getopt(argc, argv, "ab:dlr:tvqR:X")) != -1) {
2212 7848a0e1 2020-03-19 stsp switch (ch) {
2213 659e7fbd 2020-03-20 stsp case 'a':
2214 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
2215 4ba14133 2020-03-20 stsp break;
2216 4ba14133 2020-03-20 stsp case 'b':
2217 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
2218 4ba14133 2020-03-20 stsp optarg, NULL);
2219 4ba14133 2020-03-20 stsp if (error)
2220 4ba14133 2020-03-20 stsp return error;
2221 41b0de12 2020-03-21 stsp break;
2222 f21ec2f0 2020-03-21 stsp case 'd':
2223 f21ec2f0 2020-03-21 stsp delete_refs = 1;
2224 f21ec2f0 2020-03-21 stsp break;
2225 41b0de12 2020-03-21 stsp case 'l':
2226 41b0de12 2020-03-21 stsp list_refs_only = 1;
2227 659e7fbd 2020-03-20 stsp break;
2228 7848a0e1 2020-03-19 stsp case 'r':
2229 7848a0e1 2020-03-19 stsp repo_path = realpath(optarg, NULL);
2230 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
2231 7848a0e1 2020-03-19 stsp return got_error_from_errno2("realpath",
2232 7848a0e1 2020-03-19 stsp optarg);
2233 7848a0e1 2020-03-19 stsp got_path_strip_trailing_slashes(repo_path);
2234 7848a0e1 2020-03-19 stsp break;
2235 db6d8ad8 2020-03-21 stsp case 't':
2236 db6d8ad8 2020-03-21 stsp replace_tags = 1;
2237 db6d8ad8 2020-03-21 stsp break;
2238 7848a0e1 2020-03-19 stsp case 'v':
2239 7848a0e1 2020-03-19 stsp if (verbosity < 0)
2240 7848a0e1 2020-03-19 stsp verbosity = 0;
2241 7848a0e1 2020-03-19 stsp else if (verbosity < 3)
2242 7848a0e1 2020-03-19 stsp verbosity++;
2243 7848a0e1 2020-03-19 stsp break;
2244 7848a0e1 2020-03-19 stsp case 'q':
2245 7848a0e1 2020-03-19 stsp verbosity = -1;
2246 7848a0e1 2020-03-19 stsp break;
2247 0e4002ca 2020-03-21 stsp case 'R':
2248 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
2249 0e4002ca 2020-03-21 stsp optarg, NULL);
2250 0e4002ca 2020-03-21 stsp if (error)
2251 0e4002ca 2020-03-21 stsp return error;
2252 0e4002ca 2020-03-21 stsp break;
2253 161728eb 2021-07-24 stsp case 'X':
2254 161728eb 2021-07-24 stsp delete_remote = 1;
2255 161728eb 2021-07-24 stsp break;
2256 7848a0e1 2020-03-19 stsp default:
2257 7848a0e1 2020-03-19 stsp usage_fetch();
2258 7848a0e1 2020-03-19 stsp break;
2259 7848a0e1 2020-03-19 stsp }
2260 7848a0e1 2020-03-19 stsp }
2261 7848a0e1 2020-03-19 stsp argc -= optind;
2262 7848a0e1 2020-03-19 stsp argv += optind;
2263 7848a0e1 2020-03-19 stsp
2264 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
2265 ff69268e 2020-12-13 stsp option_conflict('a', 'b');
2266 41b0de12 2020-03-21 stsp if (list_refs_only) {
2267 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
2268 ff69268e 2020-12-13 stsp option_conflict('l', 'b');
2269 ff69268e 2020-12-13 stsp if (fetch_all_branches)
2270 ff69268e 2020-12-13 stsp option_conflict('l', 'a');
2271 f21ec2f0 2020-03-21 stsp if (delete_refs)
2272 ff69268e 2020-12-13 stsp option_conflict('l', 'd');
2273 161728eb 2021-07-24 stsp if (delete_remote)
2274 161728eb 2021-07-24 stsp option_conflict('l', 'X');
2275 41b0de12 2020-03-21 stsp }
2276 161728eb 2021-07-24 stsp if (delete_remote) {
2277 161728eb 2021-07-24 stsp if (fetch_all_branches)
2278 161728eb 2021-07-24 stsp option_conflict('X', 'a');
2279 161728eb 2021-07-24 stsp if (!TAILQ_EMPTY(&wanted_branches))
2280 161728eb 2021-07-24 stsp option_conflict('X', 'b');
2281 161728eb 2021-07-24 stsp if (delete_refs)
2282 161728eb 2021-07-24 stsp option_conflict('X', 'd');
2283 161728eb 2021-07-24 stsp if (replace_tags)
2284 161728eb 2021-07-24 stsp option_conflict('X', 't');
2285 161728eb 2021-07-24 stsp if (!TAILQ_EMPTY(&wanted_refs))
2286 161728eb 2021-07-24 stsp option_conflict('X', 'R');
2287 161728eb 2021-07-24 stsp }
2288 161728eb 2021-07-24 stsp
2289 161728eb 2021-07-24 stsp if (argc == 0) {
2290 161728eb 2021-07-24 stsp if (delete_remote)
2291 161728eb 2021-07-24 stsp errx(1, "-X option requires a remote name");
2292 7848a0e1 2020-03-19 stsp remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
2293 161728eb 2021-07-24 stsp } else if (argc == 1)
2294 7848a0e1 2020-03-19 stsp remote_name = argv[0];
2295 7848a0e1 2020-03-19 stsp else
2296 7848a0e1 2020-03-19 stsp usage_fetch();
2297 7848a0e1 2020-03-19 stsp
2298 7848a0e1 2020-03-19 stsp cwd = getcwd(NULL, 0);
2299 7848a0e1 2020-03-19 stsp if (cwd == NULL) {
2300 7848a0e1 2020-03-19 stsp error = got_error_from_errno("getcwd");
2301 7848a0e1 2020-03-19 stsp goto done;
2302 7848a0e1 2020-03-19 stsp }
2303 7848a0e1 2020-03-19 stsp
2304 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
2305 7848a0e1 2020-03-19 stsp error = got_worktree_open(&worktree, cwd);
2306 7848a0e1 2020-03-19 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
2307 7848a0e1 2020-03-19 stsp goto done;
2308 7848a0e1 2020-03-19 stsp else
2309 7848a0e1 2020-03-19 stsp error = NULL;
2310 7848a0e1 2020-03-19 stsp if (worktree) {
2311 7848a0e1 2020-03-19 stsp repo_path =
2312 7848a0e1 2020-03-19 stsp strdup(got_worktree_get_repo_path(worktree));
2313 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
2314 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
2315 7848a0e1 2020-03-19 stsp if (error)
2316 7848a0e1 2020-03-19 stsp goto done;
2317 7848a0e1 2020-03-19 stsp } else {
2318 7848a0e1 2020-03-19 stsp repo_path = strdup(cwd);
2319 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
2320 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
2321 7848a0e1 2020-03-19 stsp goto done;
2322 7848a0e1 2020-03-19 stsp }
2323 7848a0e1 2020-03-19 stsp }
2324 7848a0e1 2020-03-19 stsp }
2325 7848a0e1 2020-03-19 stsp
2326 7848a0e1 2020-03-19 stsp error = got_repo_open(&repo, repo_path, NULL);
2327 7848a0e1 2020-03-19 stsp if (error)
2328 7848a0e1 2020-03-19 stsp goto done;
2329 7848a0e1 2020-03-19 stsp
2330 161728eb 2021-07-24 stsp if (delete_remote) {
2331 161728eb 2021-07-24 stsp error = delete_refs_for_remote(repo, remote_name);
2332 161728eb 2021-07-24 stsp goto done; /* nothing else to do */
2333 161728eb 2021-07-24 stsp }
2334 161728eb 2021-07-24 stsp
2335 50b0790e 2020-09-11 stsp if (worktree) {
2336 50b0790e 2020-09-11 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
2337 50b0790e 2020-09-11 stsp if (worktree_conf) {
2338 50b0790e 2020-09-11 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
2339 50b0790e 2020-09-11 stsp worktree_conf);
2340 50b0790e 2020-09-11 stsp for (i = 0; i < nremotes; i++) {
2341 54eb00d5 2020-10-20 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
2342 54eb00d5 2020-10-20 stsp remote = &remotes[i];
2343 50b0790e 2020-09-11 stsp break;
2344 54eb00d5 2020-10-20 stsp }
2345 50b0790e 2020-09-11 stsp }
2346 50b0790e 2020-09-11 stsp }
2347 7848a0e1 2020-03-19 stsp }
2348 50b0790e 2020-09-11 stsp if (remote == NULL) {
2349 50b0790e 2020-09-11 stsp repo_conf = got_repo_get_gotconfig(repo);
2350 50b0790e 2020-09-11 stsp if (repo_conf) {
2351 50b0790e 2020-09-11 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
2352 50b0790e 2020-09-11 stsp repo_conf);
2353 50b0790e 2020-09-11 stsp for (i = 0; i < nremotes; i++) {
2354 54eb00d5 2020-10-20 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
2355 54eb00d5 2020-10-20 stsp remote = &remotes[i];
2356 50b0790e 2020-09-11 stsp break;
2357 54eb00d5 2020-10-20 stsp }
2358 50b0790e 2020-09-11 stsp }
2359 50b0790e 2020-09-11 stsp }
2360 50b0790e 2020-09-11 stsp }
2361 50b0790e 2020-09-11 stsp if (remote == NULL) {
2362 257add31 2020-09-09 stsp got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
2363 257add31 2020-09-09 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 257add31 2020-09-09 stsp break;
2367 54eb00d5 2020-10-20 stsp }
2368 257add31 2020-09-09 stsp }
2369 7848a0e1 2020-03-19 stsp }
2370 50b0790e 2020-09-11 stsp if (remote == NULL) {
2371 50b0790e 2020-09-11 stsp error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
2372 50b0790e 2020-09-11 stsp goto done;
2373 b8adfa55 2020-09-25 stsp }
2374 b8adfa55 2020-09-25 stsp
2375 0c8b29c5 2021-01-05 stsp if (TAILQ_EMPTY(&wanted_branches)) {
2376 0c8b29c5 2021-01-05 stsp if (!fetch_all_branches)
2377 0c8b29c5 2021-01-05 stsp fetch_all_branches = remote->fetch_all_branches;
2378 6480c871 2021-08-30 stsp for (i = 0; i < remote->nfetch_branches; i++) {
2379 b8adfa55 2020-09-25 stsp got_pathlist_append(&wanted_branches,
2380 6480c871 2021-08-30 stsp remote->fetch_branches[i], NULL);
2381 99495ddb 2021-01-10 stsp }
2382 99495ddb 2021-01-10 stsp }
2383 99495ddb 2021-01-10 stsp if (TAILQ_EMPTY(&wanted_refs)) {
2384 6480c871 2021-08-30 stsp for (i = 0; i < remote->nfetch_refs; i++) {
2385 99495ddb 2021-01-10 stsp got_pathlist_append(&wanted_refs,
2386 6480c871 2021-08-30 stsp remote->fetch_refs[i], NULL);
2387 b8adfa55 2020-09-25 stsp }
2388 50b0790e 2020-09-11 stsp }
2389 7848a0e1 2020-03-19 stsp
2390 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
2391 6480c871 2021-08-30 stsp &repo_name, remote->fetch_url);
2392 7848a0e1 2020-03-19 stsp if (error)
2393 7848a0e1 2020-03-19 stsp goto done;
2394 7848a0e1 2020-03-19 stsp
2395 7848a0e1 2020-03-19 stsp if (strcmp(proto, "git") == 0) {
2396 7848a0e1 2020-03-19 stsp #ifndef PROFILE
2397 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2398 7848a0e1 2020-03-19 stsp "sendfd dns inet unveil", NULL) == -1)
2399 7848a0e1 2020-03-19 stsp err(1, "pledge");
2400 7848a0e1 2020-03-19 stsp #endif
2401 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
2402 7848a0e1 2020-03-19 stsp strcmp(proto, "ssh") == 0) {
2403 7848a0e1 2020-03-19 stsp #ifndef PROFILE
2404 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2405 7848a0e1 2020-03-19 stsp "sendfd unveil", NULL) == -1)
2406 7848a0e1 2020-03-19 stsp err(1, "pledge");
2407 7848a0e1 2020-03-19 stsp #endif
2408 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "http") == 0 ||
2409 7848a0e1 2020-03-19 stsp strcmp(proto, "git+http") == 0) {
2410 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
2411 7848a0e1 2020-03-19 stsp goto done;
2412 7848a0e1 2020-03-19 stsp } else {
2413 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
2414 7848a0e1 2020-03-19 stsp goto done;
2415 7848a0e1 2020-03-19 stsp }
2416 7848a0e1 2020-03-19 stsp
2417 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
2418 d65a88a2 2021-09-05 stsp if (error)
2419 d65a88a2 2021-09-05 stsp goto done;
2420 d65a88a2 2021-09-05 stsp
2421 7848a0e1 2020-03-19 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
2422 7848a0e1 2020-03-19 stsp if (error)
2423 7848a0e1 2020-03-19 stsp goto done;
2424 f79e6490 2020-04-19 stsp
2425 f79e6490 2020-04-19 stsp if (verbosity >= 0)
2426 f79e6490 2020-04-19 stsp printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
2427 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
2428 7848a0e1 2020-03-19 stsp
2429 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
2430 9c52365f 2020-03-21 stsp server_path, verbosity);
2431 7848a0e1 2020-03-19 stsp if (error)
2432 7848a0e1 2020-03-19 stsp goto done;
2433 7848a0e1 2020-03-19 stsp
2434 7848a0e1 2020-03-19 stsp fpa.last_scaled_size[0] = '\0';
2435 7848a0e1 2020-03-19 stsp fpa.last_p_indexed = -1;
2436 7848a0e1 2020-03-19 stsp fpa.last_p_resolved = -1;
2437 7848a0e1 2020-03-19 stsp fpa.verbosity = verbosity;
2438 04d9a9ec 2020-09-24 stsp fpa.repo = repo;
2439 04d9a9ec 2020-09-24 stsp fpa.create_configs = 0;
2440 04d9a9ec 2020-09-24 stsp fpa.configs_created = 0;
2441 04d9a9ec 2020-09-24 stsp memset(&fpa.config_info, 0, sizeof(fpa.config_info));
2442 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
2443 4ba14133 2020-03-20 stsp remote->mirror_references, fetch_all_branches, &wanted_branches,
2444 0e4002ca 2020-03-21 stsp &wanted_refs, list_refs_only, verbosity, fetchfd, repo,
2445 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
2446 7848a0e1 2020-03-19 stsp if (error)
2447 7848a0e1 2020-03-19 stsp goto done;
2448 7848a0e1 2020-03-19 stsp
2449 41b0de12 2020-03-21 stsp if (list_refs_only) {
2450 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
2451 41b0de12 2020-03-21 stsp goto done;
2452 41b0de12 2020-03-21 stsp }
2453 41b0de12 2020-03-21 stsp
2454 7848a0e1 2020-03-19 stsp if (pack_hash == NULL) {
2455 7848a0e1 2020-03-19 stsp if (verbosity >= 0)
2456 7848a0e1 2020-03-19 stsp printf("Already up-to-date\n");
2457 bcf34b0e 2020-03-26 stsp } else if (verbosity >= 0) {
2458 984065c8 2020-03-19 stsp error = got_object_id_str(&id_str, pack_hash);
2459 984065c8 2020-03-19 stsp if (error)
2460 984065c8 2020-03-19 stsp goto done;
2461 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
2462 984065c8 2020-03-19 stsp free(id_str);
2463 984065c8 2020-03-19 stsp id_str = NULL;
2464 984065c8 2020-03-19 stsp }
2465 7848a0e1 2020-03-19 stsp
2466 7848a0e1 2020-03-19 stsp /* Update references provided with the pack file. */
2467 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
2468 7848a0e1 2020-03-19 stsp const char *refname = pe->path;
2469 7848a0e1 2020-03-19 stsp struct got_object_id *id = pe->data;
2470 7848a0e1 2020-03-19 stsp struct got_reference *ref;
2471 7848a0e1 2020-03-19 stsp char *remote_refname;
2472 7848a0e1 2020-03-19 stsp
2473 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
2474 0e4002ca 2020-03-21 stsp !remote->mirror_references) {
2475 0e4002ca 2020-03-21 stsp error = update_wanted_ref(refname, id,
2476 0e4002ca 2020-03-21 stsp remote->name, verbosity, repo);
2477 0e4002ca 2020-03-21 stsp if (error)
2478 0e4002ca 2020-03-21 stsp goto done;
2479 0e4002ca 2020-03-21 stsp continue;
2480 0e4002ca 2020-03-21 stsp }
2481 0e4002ca 2020-03-21 stsp
2482 1510c839 2020-03-20 stsp if (remote->mirror_references ||
2483 1510c839 2020-03-20 stsp strncmp("refs/tags/", refname, 10) == 0) {
2484 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
2485 7848a0e1 2020-03-19 stsp if (error) {
2486 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
2487 7848a0e1 2020-03-19 stsp goto done;
2488 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
2489 6338a6a1 2020-03-21 stsp repo);
2490 7848a0e1 2020-03-19 stsp if (error)
2491 7848a0e1 2020-03-19 stsp goto done;
2492 7848a0e1 2020-03-19 stsp } else {
2493 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
2494 db6d8ad8 2020-03-21 stsp verbosity, repo);
2495 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2496 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2497 9f142382 2020-03-21 stsp error = unlock_err;
2498 7848a0e1 2020-03-19 stsp got_ref_close(ref);
2499 7848a0e1 2020-03-19 stsp if (error)
2500 7848a0e1 2020-03-19 stsp goto done;
2501 7848a0e1 2020-03-19 stsp }
2502 7848a0e1 2020-03-19 stsp } else if (strncmp("refs/heads/", refname, 11) == 0) {
2503 7848a0e1 2020-03-19 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2504 7848a0e1 2020-03-19 stsp remote_name, refname + 11) == -1) {
2505 7848a0e1 2020-03-19 stsp error = got_error_from_errno("asprintf");
2506 7848a0e1 2020-03-19 stsp goto done;
2507 7848a0e1 2020-03-19 stsp }
2508 7848a0e1 2020-03-19 stsp
2509 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, remote_refname, 1);
2510 7848a0e1 2020-03-19 stsp if (error) {
2511 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
2512 7848a0e1 2020-03-19 stsp goto done;
2513 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id,
2514 688f11b3 2020-03-21 stsp verbosity, repo);
2515 7848a0e1 2020-03-19 stsp if (error)
2516 7848a0e1 2020-03-19 stsp goto done;
2517 7848a0e1 2020-03-19 stsp } else {
2518 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
2519 db6d8ad8 2020-03-21 stsp verbosity, repo);
2520 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2521 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2522 9f142382 2020-03-21 stsp error = unlock_err;
2523 7848a0e1 2020-03-19 stsp got_ref_close(ref);
2524 7848a0e1 2020-03-19 stsp if (error)
2525 7848a0e1 2020-03-19 stsp goto done;
2526 7848a0e1 2020-03-19 stsp }
2527 2ec30c80 2020-03-20 stsp
2528 2ec30c80 2020-03-20 stsp /* Also create a local branch if none exists yet. */
2529 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
2530 2ec30c80 2020-03-20 stsp if (error) {
2531 2ec30c80 2020-03-20 stsp if (error->code != GOT_ERR_NOT_REF)
2532 2ec30c80 2020-03-20 stsp goto done;
2533 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
2534 6338a6a1 2020-03-21 stsp repo);
2535 2ec30c80 2020-03-20 stsp if (error)
2536 2ec30c80 2020-03-20 stsp goto done;
2537 9f142382 2020-03-21 stsp } else {
2538 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2539 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2540 9f142382 2020-03-21 stsp error = unlock_err;
2541 2ec30c80 2020-03-20 stsp got_ref_close(ref);
2542 9f142382 2020-03-21 stsp }
2543 7848a0e1 2020-03-19 stsp }
2544 7848a0e1 2020-03-19 stsp }
2545 f1bcca34 2020-03-25 stsp if (delete_refs) {
2546 3789fd73 2020-03-26 stsp error = delete_missing_refs(&refs, &symrefs, remote,
2547 3789fd73 2020-03-26 stsp verbosity, repo);
2548 f1bcca34 2020-03-25 stsp if (error)
2549 f1bcca34 2020-03-25 stsp goto done;
2550 f1bcca34 2020-03-25 stsp }
2551 f1bcca34 2020-03-25 stsp
2552 f1bcca34 2020-03-25 stsp if (!remote->mirror_references) {
2553 f1bcca34 2020-03-25 stsp /* Update remote HEAD reference if the server provided one. */
2554 f1bcca34 2020-03-25 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2555 f1bcca34 2020-03-25 stsp struct got_reference *target_ref;
2556 f1bcca34 2020-03-25 stsp const char *refname = pe->path;
2557 f1bcca34 2020-03-25 stsp const char *target = pe->data;
2558 f1bcca34 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
2559 f1bcca34 2020-03-25 stsp
2560 f1bcca34 2020-03-25 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
2561 f1bcca34 2020-03-25 stsp continue;
2562 f1bcca34 2020-03-25 stsp
2563 f1bcca34 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
2564 f1bcca34 2020-03-25 stsp continue;
2565 f1bcca34 2020-03-25 stsp
2566 f1bcca34 2020-03-25 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2567 f1bcca34 2020-03-25 stsp remote->name, refname) == -1) {
2568 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2569 f1bcca34 2020-03-25 stsp goto done;
2570 f1bcca34 2020-03-25 stsp }
2571 f1bcca34 2020-03-25 stsp if (asprintf(&remote_target, "refs/remotes/%s/%s",
2572 f1bcca34 2020-03-25 stsp remote->name, target + 11) == -1) {
2573 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2574 f1bcca34 2020-03-25 stsp free(remote_refname);
2575 f1bcca34 2020-03-25 stsp goto done;
2576 f1bcca34 2020-03-25 stsp }
2577 f1bcca34 2020-03-25 stsp
2578 f1bcca34 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target,
2579 f1bcca34 2020-03-25 stsp 0);
2580 f1bcca34 2020-03-25 stsp if (error) {
2581 f1bcca34 2020-03-25 stsp free(remote_refname);
2582 f1bcca34 2020-03-25 stsp free(remote_target);
2583 f1bcca34 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
2584 f1bcca34 2020-03-25 stsp error = NULL;
2585 f1bcca34 2020-03-25 stsp continue;
2586 f1bcca34 2020-03-25 stsp }
2587 f1bcca34 2020-03-25 stsp goto done;
2588 f1bcca34 2020-03-25 stsp }
2589 f1bcca34 2020-03-25 stsp error = update_symref(remote_refname, target_ref,
2590 f1bcca34 2020-03-25 stsp verbosity, repo);
2591 f1bcca34 2020-03-25 stsp free(remote_refname);
2592 f1bcca34 2020-03-25 stsp free(remote_target);
2593 f1bcca34 2020-03-25 stsp got_ref_close(target_ref);
2594 f1bcca34 2020-03-25 stsp if (error)
2595 f1bcca34 2020-03-25 stsp goto done;
2596 f1bcca34 2020-03-25 stsp }
2597 f1bcca34 2020-03-25 stsp }
2598 7848a0e1 2020-03-19 stsp done:
2599 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
2600 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
2601 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
2602 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
2603 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
2604 9c52365f 2020-03-21 stsp }
2605 7848a0e1 2020-03-19 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
2606 7848a0e1 2020-03-19 stsp error = got_error_from_errno("close");
2607 1d0f4054 2021-06-17 stsp if (repo) {
2608 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
2609 1d0f4054 2021-06-17 stsp if (error == NULL)
2610 1d0f4054 2021-06-17 stsp error = close_err;
2611 1d0f4054 2021-06-17 stsp }
2612 7848a0e1 2020-03-19 stsp if (worktree)
2613 7848a0e1 2020-03-19 stsp got_worktree_close(worktree);
2614 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
2615 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2616 7848a0e1 2020-03-19 stsp free(pe->data);
2617 7848a0e1 2020-03-19 stsp }
2618 7848a0e1 2020-03-19 stsp got_pathlist_free(&refs);
2619 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2620 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2621 7848a0e1 2020-03-19 stsp free(pe->data);
2622 7848a0e1 2020-03-19 stsp }
2623 7848a0e1 2020-03-19 stsp got_pathlist_free(&symrefs);
2624 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
2625 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
2626 7848a0e1 2020-03-19 stsp free(id_str);
2627 7848a0e1 2020-03-19 stsp free(cwd);
2628 7848a0e1 2020-03-19 stsp free(repo_path);
2629 7848a0e1 2020-03-19 stsp free(pack_hash);
2630 7848a0e1 2020-03-19 stsp free(proto);
2631 7848a0e1 2020-03-19 stsp free(host);
2632 7848a0e1 2020-03-19 stsp free(port);
2633 7848a0e1 2020-03-19 stsp free(server_path);
2634 7848a0e1 2020-03-19 stsp free(repo_name);
2635 7848a0e1 2020-03-19 stsp return error;
2636 7848a0e1 2020-03-19 stsp }
2637 7848a0e1 2020-03-19 stsp
2638 7848a0e1 2020-03-19 stsp
2639 7848a0e1 2020-03-19 stsp __dead static void
2640 2ab43947 2020-03-18 stsp usage_checkout(void)
2641 2ab43947 2020-03-18 stsp {
2642 2ab43947 2020-03-18 stsp fprintf(stderr, "usage: %s checkout [-E] [-b branch] [-c commit] "
2643 4ad4a1ec 2021-09-13 tracey "[-p prefix] [-q] repository-path [worktree-path]\n",
2644 4ad4a1ec 2021-09-13 tracey getprogname());
2645 2ab43947 2020-03-18 stsp exit(1);
2646 2ab43947 2020-03-18 stsp }
2647 2ab43947 2020-03-18 stsp
2648 2ab43947 2020-03-18 stsp static void
2649 2ab43947 2020-03-18 stsp show_worktree_base_ref_warning(void)
2650 2ab43947 2020-03-18 stsp {
2651 2ab43947 2020-03-18 stsp fprintf(stderr, "%s: warning: could not create a reference "
2652 2ab43947 2020-03-18 stsp "to the work tree's base commit; the commit could be "
2653 e6786710 2021-07-03 stsp "garbage-collected by Git or 'gotadmin cleanup'; making the "
2654 e6786710 2021-07-03 stsp "repository writable and running 'got update' will prevent this\n",
2655 2ab43947 2020-03-18 stsp getprogname());
2656 2ab43947 2020-03-18 stsp }
2657 2ab43947 2020-03-18 stsp
2658 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg {
2659 2ab43947 2020-03-18 stsp const char *worktree_path;
2660 2ab43947 2020-03-18 stsp int had_base_commit_ref_error;
2661 4ad4a1ec 2021-09-13 tracey int verbosity;
2662 2ab43947 2020-03-18 stsp };
2663 2ab43947 2020-03-18 stsp
2664 2ab43947 2020-03-18 stsp static const struct got_error *
2665 2ab43947 2020-03-18 stsp checkout_progress(void *arg, unsigned char status, const char *path)
2666 2ab43947 2020-03-18 stsp {
2667 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg *a = arg;
2668 2ab43947 2020-03-18 stsp
2669 2ab43947 2020-03-18 stsp /* Base commit bump happens silently. */
2670 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BUMP_BASE)
2671 2ab43947 2020-03-18 stsp return NULL;
2672 2ab43947 2020-03-18 stsp
2673 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BASE_REF_ERR) {
2674 2ab43947 2020-03-18 stsp a->had_base_commit_ref_error = 1;
2675 2ab43947 2020-03-18 stsp return NULL;
2676 2ab43947 2020-03-18 stsp }
2677 2ab43947 2020-03-18 stsp
2678 2ab43947 2020-03-18 stsp while (path[0] == '/')
2679 2ab43947 2020-03-18 stsp path++;
2680 2ab43947 2020-03-18 stsp
2681 4ad4a1ec 2021-09-13 tracey if (a->verbosity >= 0)
2682 4ad4a1ec 2021-09-13 tracey printf("%c %s/%s\n", status, a->worktree_path, path);
2683 4ad4a1ec 2021-09-13 tracey
2684 2ab43947 2020-03-18 stsp return NULL;
2685 2ab43947 2020-03-18 stsp }
2686 2ab43947 2020-03-18 stsp
2687 2ab43947 2020-03-18 stsp static const struct got_error *
2688 2ab43947 2020-03-18 stsp check_cancelled(void *arg)
2689 2ab43947 2020-03-18 stsp {
2690 2ab43947 2020-03-18 stsp if (sigint_received || sigpipe_received)
2691 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_CANCELLED);
2692 2ab43947 2020-03-18 stsp return NULL;
2693 2ab43947 2020-03-18 stsp }
2694 2ab43947 2020-03-18 stsp
2695 2ab43947 2020-03-18 stsp static const struct got_error *
2696 2ab43947 2020-03-18 stsp check_linear_ancestry(struct got_object_id *commit_id,
2697 2ab43947 2020-03-18 stsp struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2698 2ab43947 2020-03-18 stsp struct got_repository *repo)
2699 2ab43947 2020-03-18 stsp {
2700 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2701 2ab43947 2020-03-18 stsp struct got_object_id *yca_id;
2702 2ab43947 2020-03-18 stsp
2703 2ab43947 2020-03-18 stsp err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2704 2ab43947 2020-03-18 stsp commit_id, base_commit_id, repo, check_cancelled, NULL);
2705 2ab43947 2020-03-18 stsp if (err)
2706 2ab43947 2020-03-18 stsp return err;
2707 2ab43947 2020-03-18 stsp
2708 2ab43947 2020-03-18 stsp if (yca_id == NULL)
2709 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2710 2ab43947 2020-03-18 stsp
2711 2ab43947 2020-03-18 stsp /*
2712 2ab43947 2020-03-18 stsp * Require a straight line of history between the target commit
2713 2ab43947 2020-03-18 stsp * and the work tree's base commit.
2714 2ab43947 2020-03-18 stsp *
2715 2ab43947 2020-03-18 stsp * Non-linear situations such as this require a rebase:
2716 2ab43947 2020-03-18 stsp *
2717 2ab43947 2020-03-18 stsp * (commit) D F (base_commit)
2718 2ab43947 2020-03-18 stsp * \ /
2719 2ab43947 2020-03-18 stsp * C E
2720 2ab43947 2020-03-18 stsp * \ /
2721 2ab43947 2020-03-18 stsp * B (yca)
2722 2ab43947 2020-03-18 stsp * |
2723 2ab43947 2020-03-18 stsp * A
2724 2ab43947 2020-03-18 stsp *
2725 2ab43947 2020-03-18 stsp * 'got update' only handles linear cases:
2726 2ab43947 2020-03-18 stsp * Update forwards in time: A (base/yca) - B - C - D (commit)
2727 2ab43947 2020-03-18 stsp * Update backwards in time: D (base) - C - B - A (commit/yca)
2728 2ab43947 2020-03-18 stsp */
2729 2ab43947 2020-03-18 stsp if (allow_forwards_in_time_only) {
2730 2ab43947 2020-03-18 stsp if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2731 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2732 2ab43947 2020-03-18 stsp } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2733 2ab43947 2020-03-18 stsp got_object_id_cmp(base_commit_id, yca_id) != 0)
2734 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2735 2ab43947 2020-03-18 stsp
2736 2ab43947 2020-03-18 stsp free(yca_id);
2737 2ab43947 2020-03-18 stsp return NULL;
2738 2ab43947 2020-03-18 stsp }
2739 2ab43947 2020-03-18 stsp
2740 2ab43947 2020-03-18 stsp static const struct got_error *
2741 2ab43947 2020-03-18 stsp check_same_branch(struct got_object_id *commit_id,
2742 2ab43947 2020-03-18 stsp struct got_reference *head_ref, struct got_object_id *yca_id,
2743 2ab43947 2020-03-18 stsp struct got_repository *repo)
2744 2ab43947 2020-03-18 stsp {
2745 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2746 2ab43947 2020-03-18 stsp struct got_commit_graph *graph = NULL;
2747 2ab43947 2020-03-18 stsp struct got_object_id *head_commit_id = NULL;
2748 2ab43947 2020-03-18 stsp int is_same_branch = 0;
2749 2ab43947 2020-03-18 stsp
2750 2ab43947 2020-03-18 stsp err = got_ref_resolve(&head_commit_id, repo, head_ref);
2751 2ab43947 2020-03-18 stsp if (err)
2752 2ab43947 2020-03-18 stsp goto done;
2753 2ab43947 2020-03-18 stsp
2754 2ab43947 2020-03-18 stsp if (got_object_id_cmp(head_commit_id, commit_id) == 0) {
2755 2ab43947 2020-03-18 stsp is_same_branch = 1;
2756 2ab43947 2020-03-18 stsp goto done;
2757 2ab43947 2020-03-18 stsp }
2758 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(commit_id, yca_id) == 0) {
2759 2ab43947 2020-03-18 stsp is_same_branch = 1;
2760 2ab43947 2020-03-18 stsp goto done;
2761 2ab43947 2020-03-18 stsp }
2762 2ab43947 2020-03-18 stsp
2763 2ab43947 2020-03-18 stsp err = got_commit_graph_open(&graph, "/", 1);
2764 2ab43947 2020-03-18 stsp if (err)
2765 2ab43947 2020-03-18 stsp goto done;
2766 2ab43947 2020-03-18 stsp
2767 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2768 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2769 2ab43947 2020-03-18 stsp if (err)
2770 2ab43947 2020-03-18 stsp goto done;
2771 2ab43947 2020-03-18 stsp
2772 2ab43947 2020-03-18 stsp for (;;) {
2773 2ab43947 2020-03-18 stsp struct got_object_id *id;
2774 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_next(&id, graph, repo,
2775 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2776 2ab43947 2020-03-18 stsp if (err) {
2777 2ab43947 2020-03-18 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
2778 2ab43947 2020-03-18 stsp err = NULL;
2779 2ab43947 2020-03-18 stsp break;
2780 2ab43947 2020-03-18 stsp }
2781 2ab43947 2020-03-18 stsp
2782 2ab43947 2020-03-18 stsp if (id) {
2783 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(id, yca_id) == 0)
2784 2ab43947 2020-03-18 stsp break;
2785 2ab43947 2020-03-18 stsp if (got_object_id_cmp(id, commit_id) == 0) {
2786 2ab43947 2020-03-18 stsp is_same_branch = 1;
2787 2ab43947 2020-03-18 stsp break;
2788 2ab43947 2020-03-18 stsp }
2789 2ab43947 2020-03-18 stsp }
2790 2ab43947 2020-03-18 stsp }
2791 2ab43947 2020-03-18 stsp done:
2792 2ab43947 2020-03-18 stsp if (graph)
2793 2ab43947 2020-03-18 stsp got_commit_graph_close(graph);
2794 2ab43947 2020-03-18 stsp free(head_commit_id);
2795 2ab43947 2020-03-18 stsp if (!err && !is_same_branch)
2796 2ab43947 2020-03-18 stsp err = got_error(GOT_ERR_ANCESTRY);
2797 2ab43947 2020-03-18 stsp return err;
2798 a367ff0f 2019-05-14 stsp }
2799 8069f636 2019-01-12 stsp
2800 4ed7e80c 2018-05-20 stsp static const struct got_error *
2801 4b6c9460 2020-03-05 stsp checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2802 4b6c9460 2020-03-05 stsp {
2803 4b6c9460 2020-03-05 stsp static char msg[512];
2804 4b6c9460 2020-03-05 stsp const char *branch_name;
2805 4b6c9460 2020-03-05 stsp
2806 4b6c9460 2020-03-05 stsp if (got_ref_is_symbolic(ref))
2807 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_symref_target(ref);
2808 4b6c9460 2020-03-05 stsp else
2809 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_name(ref);
2810 4b6c9460 2020-03-05 stsp
2811 4b6c9460 2020-03-05 stsp if (strncmp("refs/heads/", branch_name, 11) == 0)
2812 4b6c9460 2020-03-05 stsp branch_name += 11;
2813 4b6c9460 2020-03-05 stsp
2814 4b6c9460 2020-03-05 stsp snprintf(msg, sizeof(msg),
2815 4b6c9460 2020-03-05 stsp "target commit is not contained in branch '%s'; "
2816 4b6c9460 2020-03-05 stsp "the branch to use must be specified with -b; "
2817 4b6c9460 2020-03-05 stsp "if necessary a new branch can be created for "
2818 4b6c9460 2020-03-05 stsp "this commit with 'got branch -c %s BRANCH_NAME'",
2819 4b6c9460 2020-03-05 stsp branch_name, commit_id_str);
2820 4b6c9460 2020-03-05 stsp
2821 4b6c9460 2020-03-05 stsp return got_error_msg(GOT_ERR_ANCESTRY, msg);
2822 4b6c9460 2020-03-05 stsp }
2823 4b6c9460 2020-03-05 stsp
2824 4b6c9460 2020-03-05 stsp static const struct got_error *
2825 c09a553d 2018-03-12 stsp cmd_checkout(int argc, char *argv[])
2826 c09a553d 2018-03-12 stsp {
2827 c09a553d 2018-03-12 stsp const struct got_error *error = NULL;
2828 c09a553d 2018-03-12 stsp struct got_repository *repo = NULL;
2829 08e5873e 2021-09-14 stsp struct got_reference *head_ref = NULL, *ref = NULL;
2830 c09a553d 2018-03-12 stsp struct got_worktree *worktree = NULL;
2831 c09a553d 2018-03-12 stsp char *repo_path = NULL;
2832 c09a553d 2018-03-12 stsp char *worktree_path = NULL;
2833 0bb8a95e 2018-03-12 stsp const char *path_prefix = "";
2834 08e5873e 2021-09-14 stsp const char *branch_name = GOT_REF_HEAD, *refname = NULL;
2835 8069f636 2019-01-12 stsp char *commit_id_str = NULL;
2836 08e5873e 2021-09-14 stsp struct got_object_id *commit_id = NULL;
2837 f0207f6a 2020-10-19 stsp char *cwd = NULL;
2838 4ad4a1ec 2021-09-13 tracey int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0;
2839 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
2840 7f47418f 2019-12-20 stsp struct got_checkout_progress_arg cpa;
2841 f2ea84fa 2019-07-27 stsp
2842 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
2843 c09a553d 2018-03-12 stsp
2844 4ad4a1ec 2021-09-13 tracey while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) {
2845 0bb8a95e 2018-03-12 stsp switch (ch) {
2846 08573d5b 2019-05-14 stsp case 'b':
2847 08573d5b 2019-05-14 stsp branch_name = optarg;
2848 08573d5b 2019-05-14 stsp break;
2849 8069f636 2019-01-12 stsp case 'c':
2850 8069f636 2019-01-12 stsp commit_id_str = strdup(optarg);
2851 8069f636 2019-01-12 stsp if (commit_id_str == NULL)
2852 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
2853 bb51a5b4 2020-01-13 stsp break;
2854 bb51a5b4 2020-01-13 stsp case 'E':
2855 bb51a5b4 2020-01-13 stsp allow_nonempty = 1;
2856 8069f636 2019-01-12 stsp break;
2857 0bb8a95e 2018-03-12 stsp case 'p':
2858 0bb8a95e 2018-03-12 stsp path_prefix = optarg;
2859 0bb8a95e 2018-03-12 stsp break;
2860 4ad4a1ec 2021-09-13 tracey case 'q':
2861 4ad4a1ec 2021-09-13 tracey verbosity = -1;
2862 4ad4a1ec 2021-09-13 tracey break;
2863 0bb8a95e 2018-03-12 stsp default:
2864 2deda0b9 2019-03-07 stsp usage_checkout();
2865 0bb8a95e 2018-03-12 stsp /* NOTREACHED */
2866 0bb8a95e 2018-03-12 stsp }
2867 0bb8a95e 2018-03-12 stsp }
2868 0bb8a95e 2018-03-12 stsp
2869 0bb8a95e 2018-03-12 stsp argc -= optind;
2870 0bb8a95e 2018-03-12 stsp argv += optind;
2871 0bb8a95e 2018-03-12 stsp
2872 6715a751 2018-03-16 stsp #ifndef PROFILE
2873 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2874 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
2875 c09a553d 2018-03-12 stsp err(1, "pledge");
2876 6715a751 2018-03-16 stsp #endif
2877 0bb8a95e 2018-03-12 stsp if (argc == 1) {
2878 c47340da 2020-09-20 stsp char *base, *dotgit;
2879 f0207f6a 2020-10-19 stsp const char *path;
2880 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2881 76089277 2018-04-01 stsp if (repo_path == NULL)
2882 638f9024 2019-05-13 stsp return got_error_from_errno2("realpath", argv[0]);
2883 c09a553d 2018-03-12 stsp cwd = getcwd(NULL, 0);
2884 76089277 2018-04-01 stsp if (cwd == NULL) {
2885 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
2886 76089277 2018-04-01 stsp goto done;
2887 76089277 2018-04-01 stsp }
2888 c47340da 2020-09-20 stsp if (path_prefix[0])
2889 f0207f6a 2020-10-19 stsp path = path_prefix;
2890 c47340da 2020-09-20 stsp else
2891 f0207f6a 2020-10-19 stsp path = repo_path;
2892 f0207f6a 2020-10-19 stsp error = got_path_basename(&base, path);
2893 f0207f6a 2020-10-19 stsp if (error)
2894 c47340da 2020-09-20 stsp goto done;
2895 c09a553d 2018-03-12 stsp dotgit = strstr(base, ".git");
2896 c09a553d 2018-03-12 stsp if (dotgit)
2897 c09a553d 2018-03-12 stsp *dotgit = '\0';
2898 c09a553d 2018-03-12 stsp if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2899 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
2900 f0207f6a 2020-10-19 stsp free(base);
2901 76089277 2018-04-01 stsp goto done;
2902 c09a553d 2018-03-12 stsp }
2903 f0207f6a 2020-10-19 stsp free(base);
2904 0bb8a95e 2018-03-12 stsp } else if (argc == 2) {
2905 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2906 76089277 2018-04-01 stsp if (repo_path == NULL) {
2907 638f9024 2019-05-13 stsp error = got_error_from_errno2("realpath", argv[0]);
2908 76089277 2018-04-01 stsp goto done;
2909 76089277 2018-04-01 stsp }
2910 f7b38925 2018-04-01 stsp worktree_path = realpath(argv[1], NULL);
2911 76089277 2018-04-01 stsp if (worktree_path == NULL) {
2912 b4b3a7dd 2019-07-22 stsp if (errno != ENOENT) {
2913 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno2("realpath",
2914 b4b3a7dd 2019-07-22 stsp argv[1]);
2915 b4b3a7dd 2019-07-22 stsp goto done;
2916 b4b3a7dd 2019-07-22 stsp }
2917 b4b3a7dd 2019-07-22 stsp worktree_path = strdup(argv[1]);
2918 b4b3a7dd 2019-07-22 stsp if (worktree_path == NULL) {
2919 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno("strdup");
2920 b4b3a7dd 2019-07-22 stsp goto done;
2921 b4b3a7dd 2019-07-22 stsp }
2922 76089277 2018-04-01 stsp }
2923 c09a553d 2018-03-12 stsp } else
2924 c09a553d 2018-03-12 stsp usage_checkout();
2925 c09a553d 2018-03-12 stsp
2926 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
2927 72151b04 2019-05-11 stsp got_path_strip_trailing_slashes(worktree_path);
2928 13bfb272 2019-05-10 jcs
2929 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
2930 c09a553d 2018-03-12 stsp if (error != NULL)
2931 c02c541e 2019-03-29 stsp goto done;
2932 c02c541e 2019-03-29 stsp
2933 c530dc23 2019-07-23 stsp /* Pre-create work tree path for unveil(2) */
2934 c530dc23 2019-07-23 stsp error = got_path_mkdir(worktree_path);
2935 c530dc23 2019-07-23 stsp if (error) {
2936 80c1b583 2019-08-07 stsp if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2937 80c1b583 2019-08-07 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2938 c530dc23 2019-07-23 stsp goto done;
2939 bb51a5b4 2020-01-13 stsp if (!allow_nonempty &&
2940 bb51a5b4 2020-01-13 stsp !got_path_dir_is_empty(worktree_path)) {
2941 c530dc23 2019-07-23 stsp error = got_error_path(worktree_path,
2942 c530dc23 2019-07-23 stsp GOT_ERR_DIR_NOT_EMPTY);
2943 c530dc23 2019-07-23 stsp goto done;
2944 c530dc23 2019-07-23 stsp }
2945 c530dc23 2019-07-23 stsp }
2946 c530dc23 2019-07-23 stsp
2947 c530dc23 2019-07-23 stsp error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2948 c02c541e 2019-03-29 stsp if (error)
2949 c09a553d 2018-03-12 stsp goto done;
2950 8069f636 2019-01-12 stsp
2951 08573d5b 2019-05-14 stsp error = got_ref_open(&head_ref, repo, branch_name, 0);
2952 c09a553d 2018-03-12 stsp if (error != NULL)
2953 c09a553d 2018-03-12 stsp goto done;
2954 c09a553d 2018-03-12 stsp
2955 0bb8a95e 2018-03-12 stsp error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2956 d70b8e30 2018-12-27 stsp if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2957 c09a553d 2018-03-12 stsp goto done;
2958 c09a553d 2018-03-12 stsp
2959 c09a553d 2018-03-12 stsp error = got_worktree_open(&worktree, worktree_path);
2960 c09a553d 2018-03-12 stsp if (error != NULL)
2961 c09a553d 2018-03-12 stsp goto done;
2962 c09a553d 2018-03-12 stsp
2963 e5dc7198 2018-12-29 stsp error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2964 e5dc7198 2018-12-29 stsp path_prefix);
2965 e5dc7198 2018-12-29 stsp if (error != NULL)
2966 e5dc7198 2018-12-29 stsp goto done;
2967 e5dc7198 2018-12-29 stsp if (!same_path_prefix) {
2968 49520a32 2018-12-29 stsp error = got_error(GOT_ERR_PATH_PREFIX);
2969 49520a32 2018-12-29 stsp goto done;
2970 49520a32 2018-12-29 stsp }
2971 49520a32 2018-12-29 stsp
2972 8069f636 2019-01-12 stsp if (commit_id_str) {
2973 84de9106 2020-12-26 stsp struct got_reflist_head refs;
2974 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
2975 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2976 84de9106 2020-12-26 stsp NULL);
2977 84de9106 2020-12-26 stsp if (error)
2978 84de9106 2020-12-26 stsp goto done;
2979 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
2980 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2981 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
2982 30837e32 2019-07-25 stsp if (error)
2983 8069f636 2019-01-12 stsp goto done;
2984 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
2985 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
2986 8069f636 2019-01-12 stsp if (error != NULL) {
2987 8069f636 2019-01-12 stsp free(commit_id);
2988 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
2989 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
2990 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
2991 4b6c9460 2020-03-05 stsp }
2992 8069f636 2019-01-12 stsp goto done;
2993 8069f636 2019-01-12 stsp }
2994 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
2995 4b6c9460 2020-03-05 stsp if (error) {
2996 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
2997 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
2998 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
2999 4b6c9460 2020-03-05 stsp }
3000 45d344f6 2019-05-14 stsp goto done;
3001 4b6c9460 2020-03-05 stsp }
3002 8069f636 2019-01-12 stsp error = got_worktree_set_base_commit_id(worktree, repo,
3003 8069f636 2019-01-12 stsp commit_id);
3004 8069f636 2019-01-12 stsp if (error)
3005 8069f636 2019-01-12 stsp goto done;
3006 08e5873e 2021-09-14 stsp /* Expand potentially abbreviated commit ID string. */
3007 08e5873e 2021-09-14 stsp free(commit_id_str);
3008 08e5873e 2021-09-14 stsp error = got_object_id_str(&commit_id_str, commit_id);
3009 08e5873e 2021-09-14 stsp if (error)
3010 08e5873e 2021-09-14 stsp goto done;
3011 08e5873e 2021-09-14 stsp } else {
3012 08e5873e 2021-09-14 stsp commit_id = got_object_id_dup(
3013 08e5873e 2021-09-14 stsp got_worktree_get_base_commit_id(worktree));
3014 08e5873e 2021-09-14 stsp if (commit_id == NULL) {
3015 08e5873e 2021-09-14 stsp error = got_error_from_errno("got_object_id_dup");
3016 08e5873e 2021-09-14 stsp goto done;
3017 08e5873e 2021-09-14 stsp }
3018 08e5873e 2021-09-14 stsp error = got_object_id_str(&commit_id_str, commit_id);
3019 08e5873e 2021-09-14 stsp if (error)
3020 08e5873e 2021-09-14 stsp goto done;
3021 8069f636 2019-01-12 stsp }
3022 8069f636 2019-01-12 stsp
3023 adc19d55 2019-07-28 stsp error = got_pathlist_append(&paths, "", NULL);
3024 f2ea84fa 2019-07-27 stsp if (error)
3025 f2ea84fa 2019-07-27 stsp goto done;
3026 7f47418f 2019-12-20 stsp cpa.worktree_path = worktree_path;
3027 7f47418f 2019-12-20 stsp cpa.had_base_commit_ref_error = 0;
3028 4ad4a1ec 2021-09-13 tracey cpa.verbosity = verbosity;
3029 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
3030 7f47418f 2019-12-20 stsp checkout_progress, &cpa, check_cancelled, NULL);
3031 c09a553d 2018-03-12 stsp if (error != NULL)
3032 c09a553d 2018-03-12 stsp goto done;
3033 c09a553d 2018-03-12 stsp
3034 08e5873e 2021-09-14 stsp if (got_ref_is_symbolic(head_ref)) {
3035 08e5873e 2021-09-14 stsp error = got_ref_resolve_symbolic(&ref, repo, head_ref);
3036 08e5873e 2021-09-14 stsp if (error)
3037 08e5873e 2021-09-14 stsp goto done;
3038 08e5873e 2021-09-14 stsp refname = got_ref_get_name(ref);
3039 08e5873e 2021-09-14 stsp } else
3040 08e5873e 2021-09-14 stsp refname = got_ref_get_name(head_ref);
3041 08e5873e 2021-09-14 stsp printf("Checked out %s: %s\n", refname, commit_id_str);
3042 b65ae19a 2018-04-24 stsp printf("Now shut up and hack\n");
3043 7f47418f 2019-12-20 stsp if (cpa.had_base_commit_ref_error)
3044 7f47418f 2019-12-20 stsp show_worktree_base_ref_warning();
3045 c09a553d 2018-03-12 stsp done:
3046 08e5873e 2021-09-14 stsp if (head_ref)
3047 08e5873e 2021-09-14 stsp got_ref_close(head_ref);
3048 08e5873e 2021-09-14 stsp if (ref)
3049 08e5873e 2021-09-14 stsp got_ref_close(ref);
3050 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
3051 8069f636 2019-01-12 stsp free(commit_id_str);
3052 08e5873e 2021-09-14 stsp free(commit_id);
3053 76089277 2018-04-01 stsp free(repo_path);
3054 507dc3bb 2018-12-29 stsp free(worktree_path);
3055 c47340da 2020-09-20 stsp free(cwd);
3056 507dc3bb 2018-12-29 stsp return error;
3057 9627c110 2020-04-18 stsp }
3058 9627c110 2020-04-18 stsp
3059 9627c110 2020-04-18 stsp struct got_update_progress_arg {
3060 9627c110 2020-04-18 stsp int did_something;
3061 9627c110 2020-04-18 stsp int conflicts;
3062 9627c110 2020-04-18 stsp int obstructed;
3063 9627c110 2020-04-18 stsp int not_updated;
3064 10604dce 2021-09-24 thomas int missing;
3065 4ad4a1ec 2021-09-13 tracey int verbosity;
3066 9627c110 2020-04-18 stsp };
3067 9627c110 2020-04-18 stsp
3068 9627c110 2020-04-18 stsp void
3069 9627c110 2020-04-18 stsp print_update_progress_stats(struct got_update_progress_arg *upa)
3070 9627c110 2020-04-18 stsp {
3071 9627c110 2020-04-18 stsp if (!upa->did_something)
3072 9627c110 2020-04-18 stsp return;
3073 9627c110 2020-04-18 stsp
3074 9627c110 2020-04-18 stsp if (upa->conflicts > 0)
3075 9627c110 2020-04-18 stsp printf("Files with new merge conflicts: %d\n", upa->conflicts);
3076 9627c110 2020-04-18 stsp if (upa->obstructed > 0)
3077 9627c110 2020-04-18 stsp printf("File paths obstructed by a non-regular file: %d\n",
3078 9627c110 2020-04-18 stsp upa->obstructed);
3079 9627c110 2020-04-18 stsp if (upa->not_updated > 0)
3080 9627c110 2020-04-18 stsp printf("Files not updated because of existing merge "
3081 9627c110 2020-04-18 stsp "conflicts: %d\n", upa->not_updated);
3082 507dc3bb 2018-12-29 stsp }
3083 507dc3bb 2018-12-29 stsp
3084 507dc3bb 2018-12-29 stsp __dead static void
3085 507dc3bb 2018-12-29 stsp usage_update(void)
3086 507dc3bb 2018-12-29 stsp {
3087 4ad4a1ec 2021-09-13 tracey fprintf(stderr, "usage: %s update [-b branch] [-c commit] [-q] "
3088 4ad4a1ec 2021-09-13 tracey "[path ...]\n",
3089 507dc3bb 2018-12-29 stsp getprogname());
3090 507dc3bb 2018-12-29 stsp exit(1);
3091 507dc3bb 2018-12-29 stsp }
3092 507dc3bb 2018-12-29 stsp
3093 1ee397ad 2019-07-12 stsp static const struct got_error *
3094 507dc3bb 2018-12-29 stsp update_progress(void *arg, unsigned char status, const char *path)
3095 507dc3bb 2018-12-29 stsp {
3096 9627c110 2020-04-18 stsp struct got_update_progress_arg *upa = arg;
3097 784955db 2019-01-12 stsp
3098 7f47418f 2019-12-20 stsp if (status == GOT_STATUS_EXISTS ||
3099 7f47418f 2019-12-20 stsp status == GOT_STATUS_BASE_REF_ERR)
3100 1ee397ad 2019-07-12 stsp return NULL;
3101 507dc3bb 2018-12-29 stsp
3102 9627c110 2020-04-18 stsp upa->did_something = 1;
3103 a484d721 2019-06-10 stsp
3104 a484d721 2019-06-10 stsp /* Base commit bump happens silently. */
3105 a484d721 2019-06-10 stsp if (status == GOT_STATUS_BUMP_BASE)
3106 1ee397ad 2019-07-12 stsp return NULL;
3107 a484d721 2019-06-10 stsp
3108 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CONFLICT)
3109 9627c110 2020-04-18 stsp upa->conflicts++;
3110 9627c110 2020-04-18 stsp if (status == GOT_STATUS_OBSTRUCTED)
3111 9627c110 2020-04-18 stsp upa->obstructed++;
3112 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CANNOT_UPDATE)
3113 9627c110 2020-04-18 stsp upa->not_updated++;
3114 10604dce 2021-09-24 thomas if (status == GOT_STATUS_MISSING)
3115 10604dce 2021-09-24 thomas upa->missing++;
3116 9627c110 2020-04-18 stsp
3117 507dc3bb 2018-12-29 stsp while (path[0] == '/')
3118 507dc3bb 2018-12-29 stsp path++;
3119 4ad4a1ec 2021-09-13 tracey if (upa->verbosity >= 0)
3120 4ad4a1ec 2021-09-13 tracey printf("%c %s\n", status, path);
3121 4ad4a1ec 2021-09-13 tracey
3122 1ee397ad 2019-07-12 stsp return NULL;
3123 be7061eb 2018-12-30 stsp }
3124 be7061eb 2018-12-30 stsp
3125 be7061eb 2018-12-30 stsp static const struct got_error *
3126 a1fb16d8 2019-05-24 stsp switch_head_ref(struct got_reference *head_ref,
3127 a1fb16d8 2019-05-24 stsp struct got_object_id *commit_id, struct got_worktree *worktree,
3128 a1fb16d8 2019-05-24 stsp struct got_repository *repo)
3129 a1fb16d8 2019-05-24 stsp {
3130 a1fb16d8 2019-05-24 stsp const struct got_error *err = NULL;
3131 a1fb16d8 2019-05-24 stsp char *base_id_str;
3132 a1fb16d8 2019-05-24 stsp int ref_has_moved = 0;
3133 a1fb16d8 2019-05-24 stsp
3134 a1fb16d8 2019-05-24 stsp /* Trivial case: switching between two different references. */
3135 a1fb16d8 2019-05-24 stsp if (strcmp(got_ref_get_name(head_ref),
3136 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree)) != 0) {
3137 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n",
3138 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree),
3139 a1fb16d8 2019-05-24 stsp got_ref_get_name(head_ref));
3140 a1fb16d8 2019-05-24 stsp return got_worktree_set_head_ref(worktree, head_ref);
3141 a1fb16d8 2019-05-24 stsp }
3142 a1fb16d8 2019-05-24 stsp
3143 a1fb16d8 2019-05-24 stsp err = check_linear_ancestry(commit_id,
3144 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
3145 a1fb16d8 2019-05-24 stsp if (err) {
3146 a1fb16d8 2019-05-24 stsp if (err->code != GOT_ERR_ANCESTRY)
3147 a1fb16d8 2019-05-24 stsp return err;
3148 a1fb16d8 2019-05-24 stsp ref_has_moved = 1;
3149 a1fb16d8 2019-05-24 stsp }
3150 a1fb16d8 2019-05-24 stsp if (!ref_has_moved)
3151 a1fb16d8 2019-05-24 stsp return NULL;
3152 a1fb16d8 2019-05-24 stsp
3153 a1fb16d8 2019-05-24 stsp /* Switching to a rebased branch with the same reference name. */
3154 a1fb16d8 2019-05-24 stsp err = got_object_id_str(&base_id_str,
3155 a1fb16d8 2019-05-24 stsp got_worktree_get_base_commit_id(worktree));
3156 a1fb16d8 2019-05-24 stsp if (err)
3157 a1fb16d8 2019-05-24 stsp return err;
3158 a1fb16d8 2019-05-24 stsp printf("Reference %s now points at a different branch\n",
3159 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
3160 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n", base_id_str,
3161 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
3162 0ebf8283 2019-07-24 stsp return NULL;
3163 0ebf8283 2019-07-24 stsp }
3164 0ebf8283 2019-07-24 stsp
3165 0ebf8283 2019-07-24 stsp static const struct got_error *
3166 0ebf8283 2019-07-24 stsp check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
3167 0ebf8283 2019-07-24 stsp {
3168 0ebf8283 2019-07-24 stsp const struct got_error *err;
3169 0ebf8283 2019-07-24 stsp int in_progress;
3170 0ebf8283 2019-07-24 stsp
3171 0ebf8283 2019-07-24 stsp err = got_worktree_rebase_in_progress(&in_progress, worktree);
3172 0ebf8283 2019-07-24 stsp if (err)
3173 0ebf8283 2019-07-24 stsp return err;
3174 0ebf8283 2019-07-24 stsp if (in_progress)
3175 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_REBASING);
3176 0ebf8283 2019-07-24 stsp
3177 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_in_progress(&in_progress, worktree);
3178 0ebf8283 2019-07-24 stsp if (err)
3179 0ebf8283 2019-07-24 stsp return err;
3180 0ebf8283 2019-07-24 stsp if (in_progress)
3181 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_BUSY);
3182 10604dce 2021-09-24 thomas
3183 10604dce 2021-09-24 thomas return NULL;
3184 10604dce 2021-09-24 thomas }
3185 10604dce 2021-09-24 thomas
3186 10604dce 2021-09-24 thomas static const struct got_error *
3187 10604dce 2021-09-24 thomas check_merge_in_progress(struct got_worktree *worktree,
3188 10604dce 2021-09-24 thomas struct got_repository *repo)
3189 10604dce 2021-09-24 thomas {
3190 10604dce 2021-09-24 thomas const struct got_error *err;
3191 10604dce 2021-09-24 thomas int in_progress;
3192 10604dce 2021-09-24 thomas
3193 10604dce 2021-09-24 thomas err = got_worktree_merge_in_progress(&in_progress, worktree, repo);
3194 10604dce 2021-09-24 thomas if (err)
3195 10604dce 2021-09-24 thomas return err;
3196 10604dce 2021-09-24 thomas if (in_progress)
3197 10604dce 2021-09-24 thomas return got_error(GOT_ERR_MERGE_BUSY);
3198 0ebf8283 2019-07-24 stsp
3199 a1fb16d8 2019-05-24 stsp return NULL;
3200 a5edda0a 2019-07-27 stsp }
3201 a5edda0a 2019-07-27 stsp
3202 a5edda0a 2019-07-27 stsp static const struct got_error *
3203 a5edda0a 2019-07-27 stsp get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
3204 a5edda0a 2019-07-27 stsp char *argv[], struct got_worktree *worktree)
3205 a5edda0a 2019-07-27 stsp {
3206 a0de39f3 2019-08-09 stsp const struct got_error *err = NULL;
3207 a5edda0a 2019-07-27 stsp char *path;
3208 a5edda0a 2019-07-27 stsp int i;
3209 a5edda0a 2019-07-27 stsp
3210 a5edda0a 2019-07-27 stsp if (argc == 0) {
3211 a5edda0a 2019-07-27 stsp path = strdup("");
3212 a5edda0a 2019-07-27 stsp if (path == NULL)
3213 a5edda0a 2019-07-27 stsp return got_error_from_errno("strdup");
3214 adc19d55 2019-07-28 stsp return got_pathlist_append(paths, path, NULL);
3215 a5edda0a 2019-07-27 stsp }
3216 a5edda0a 2019-07-27 stsp
3217 a5edda0a 2019-07-27 stsp for (i = 0; i < argc; i++) {
3218 a5edda0a 2019-07-27 stsp err = got_worktree_resolve_path(&path, worktree, argv[i]);
3219 a5edda0a 2019-07-27 stsp if (err)
3220 a5edda0a 2019-07-27 stsp break;
3221 adc19d55 2019-07-28 stsp err = got_pathlist_append(paths, path, NULL);
3222 a5edda0a 2019-07-27 stsp if (err) {
3223 a5edda0a 2019-07-27 stsp free(path);
3224 a5edda0a 2019-07-27 stsp break;
3225 a5edda0a 2019-07-27 stsp }
3226 a5edda0a 2019-07-27 stsp }
3227 a5edda0a 2019-07-27 stsp
3228 a5edda0a 2019-07-27 stsp return err;
3229 a1fb16d8 2019-05-24 stsp }
3230 a1fb16d8 2019-05-24 stsp
3231 a1fb16d8 2019-05-24 stsp static const struct got_error *
3232 fa51e947 2020-03-27 stsp wrap_not_worktree_error(const struct got_error *orig_err,
3233 fa51e947 2020-03-27 stsp const char *cmdname, const char *path)
3234 fa51e947 2020-03-27 stsp {
3235 fa51e947 2020-03-27 stsp const struct got_error *err;
3236 fa51e947 2020-03-27 stsp struct got_repository *repo;
3237 fa51e947 2020-03-27 stsp static char msg[512];
3238 fa51e947 2020-03-27 stsp
3239 fa51e947 2020-03-27 stsp err = got_repo_open(&repo, path, NULL);
3240 fa51e947 2020-03-27 stsp if (err)
3241 fa51e947 2020-03-27 stsp return orig_err;
3242 fa51e947 2020-03-27 stsp
3243 fa51e947 2020-03-27 stsp snprintf(msg, sizeof(msg),
3244 fa51e947 2020-03-27 stsp "'got %s' needs a work tree in addition to a git repository\n"
3245 fa51e947 2020-03-27 stsp "Work trees can be checked out from this Git repository with "
3246 fa51e947 2020-03-27 stsp "'got checkout'.\n"
3247 fa51e947 2020-03-27 stsp "The got(1) manual page contains more information.", cmdname);
3248 fa51e947 2020-03-27 stsp err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
3249 fa51e947 2020-03-27 stsp got_repo_close(repo);
3250 fa51e947 2020-03-27 stsp return err;
3251 fa51e947 2020-03-27 stsp }
3252 fa51e947 2020-03-27 stsp
3253 fa51e947 2020-03-27 stsp static const struct got_error *
3254 507dc3bb 2018-12-29 stsp cmd_update(int argc, char *argv[])
3255 507dc3bb 2018-12-29 stsp {
3256 507dc3bb 2018-12-29 stsp const struct got_error *error = NULL;
3257 507dc3bb 2018-12-29 stsp struct got_repository *repo = NULL;
3258 507dc3bb 2018-12-29 stsp struct got_worktree *worktree = NULL;
3259 f2ea84fa 2019-07-27 stsp char *worktree_path = NULL;
3260 507dc3bb 2018-12-29 stsp struct got_object_id *commit_id = NULL;
3261 9c4b8182 2019-01-02 stsp char *commit_id_str = NULL;
3262 024e9686 2019-05-14 stsp const char *branch_name = NULL;
3263 024e9686 2019-05-14 stsp struct got_reference *head_ref = NULL;
3264 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
3265 f2ea84fa 2019-07-27 stsp struct got_pathlist_entry *pe;
3266 4ad4a1ec 2021-09-13 tracey int ch, verbosity = 0;
3267 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
3268 507dc3bb 2018-12-29 stsp
3269 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
3270 f2ea84fa 2019-07-27 stsp
3271 4ad4a1ec 2021-09-13 tracey while ((ch = getopt(argc, argv, "b:c:q")) != -1) {
3272 507dc3bb 2018-12-29 stsp switch (ch) {
3273 024e9686 2019-05-14 stsp case 'b':
3274 024e9686 2019-05-14 stsp branch_name = optarg;
3275 024e9686 2019-05-14 stsp break;
3276 507dc3bb 2018-12-29 stsp case 'c':
3277 9c4b8182 2019-01-02 stsp commit_id_str = strdup(optarg);
3278 9c4b8182 2019-01-02 stsp if (commit_id_str == NULL)
3279 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
3280 4ad4a1ec 2021-09-13 tracey break;
3281 4ad4a1ec 2021-09-13 tracey case 'q':
3282 4ad4a1ec 2021-09-13 tracey verbosity = -1;
3283 507dc3bb 2018-12-29 stsp break;
3284 507dc3bb 2018-12-29 stsp default:
3285 2deda0b9 2019-03-07 stsp usage_update();
3286 507dc3bb 2018-12-29 stsp /* NOTREACHED */
3287 507dc3bb 2018-12-29 stsp }
3288 507dc3bb 2018-12-29 stsp }
3289 507dc3bb 2018-12-29 stsp
3290 507dc3bb 2018-12-29 stsp argc -= optind;
3291 507dc3bb 2018-12-29 stsp argv += optind;
3292 507dc3bb 2018-12-29 stsp
3293 507dc3bb 2018-12-29 stsp #ifndef PROFILE
3294 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3295 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
3296 507dc3bb 2018-12-29 stsp err(1, "pledge");
3297 507dc3bb 2018-12-29 stsp #endif
3298 c4cdcb68 2019-04-03 stsp worktree_path = getcwd(NULL, 0);
3299 c4cdcb68 2019-04-03 stsp if (worktree_path == NULL) {
3300 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
3301 c4cdcb68 2019-04-03 stsp goto done;
3302 c4cdcb68 2019-04-03 stsp }
3303 c4cdcb68 2019-04-03 stsp error = got_worktree_open(&worktree, worktree_path);
3304 fa51e947 2020-03-27 stsp if (error) {
3305 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
3306 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "update",
3307 fa51e947 2020-03-27 stsp worktree_path);
3308 7d5807f4 2019-07-11 stsp goto done;
3309 fa51e947 2020-03-27 stsp }
3310 7d5807f4 2019-07-11 stsp
3311 0ebf8283 2019-07-24 stsp error = check_rebase_or_histedit_in_progress(worktree);
3312 f2ea84fa 2019-07-27 stsp if (error)
3313 f2ea84fa 2019-07-27 stsp goto done;
3314 507dc3bb 2018-12-29 stsp
3315 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
3316 c9956ddf 2019-09-08 stsp NULL);
3317 507dc3bb 2018-12-29 stsp if (error != NULL)
3318 507dc3bb 2018-12-29 stsp goto done;
3319 507dc3bb 2018-12-29 stsp
3320 97430839 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
3321 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
3322 087fb88c 2019-08-04 stsp if (error)
3323 087fb88c 2019-08-04 stsp goto done;
3324 087fb88c 2019-08-04 stsp
3325 10604dce 2021-09-24 thomas error = check_merge_in_progress(worktree, repo);
3326 10604dce 2021-09-24 thomas if (error)
3327 10604dce 2021-09-24 thomas goto done;
3328 10604dce 2021-09-24 thomas
3329 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
3330 0266afb7 2019-01-04 stsp if (error)
3331 0266afb7 2019-01-04 stsp goto done;
3332 0266afb7 2019-01-04 stsp
3333 a1fb16d8 2019-05-24 stsp error = got_ref_open(&head_ref, repo, branch_name ? branch_name :
3334 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree), 0);
3335 024e9686 2019-05-14 stsp if (error != NULL)
3336 024e9686 2019-05-14 stsp goto done;
3337 507dc3bb 2018-12-29 stsp if (commit_id_str == NULL) {
3338 507dc3bb 2018-12-29 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
3339 9c4b8182 2019-01-02 stsp if (error != NULL)
3340 9c4b8182 2019-01-02 stsp goto done;
3341 9c4b8182 2019-01-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
3342 507dc3bb 2018-12-29 stsp if (error != NULL)
3343 507dc3bb 2018-12-29 stsp goto done;
3344 507dc3bb 2018-12-29 stsp } else {
3345 84de9106 2020-12-26 stsp struct got_reflist_head refs;
3346 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
3347 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
3348 84de9106 2020-12-26 stsp NULL);
3349 84de9106 2020-12-26 stsp if (error)
3350 84de9106 2020-12-26 stsp goto done;
3351 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
3352 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
3353 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
3354 04f57cb3 2019-07-25 stsp free(commit_id_str);
3355 bb787f09 2019-07-25 stsp commit_id_str = NULL;
3356 30837e32 2019-07-25 stsp if (error)
3357 a297e751 2019-07-11 stsp goto done;
3358 a297e751 2019-07-11 stsp error = got_object_id_str(&commit_id_str, commit_id);
3359 a297e751 2019-07-11 stsp if (error)
3360 507dc3bb 2018-12-29 stsp goto done;
3361 507dc3bb 2018-12-29 stsp }
3362 35c965b2 2018-12-29 stsp
3363 a1fb16d8 2019-05-24 stsp if (branch_name) {
3364 024e9686 2019-05-14 stsp struct got_object_id *head_commit_id;
3365 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry) {
3366 f2b16ada 2019-08-02 stsp if (pe->path_len == 0)
3367 f2ea84fa 2019-07-27 stsp continue;
3368 f2ea84fa 2019-07-27 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
3369 f2ea84fa 2019-07-27 stsp "switching between branches requires that "
3370 f2ea84fa 2019-07-27 stsp "the entire work tree gets updated");
3371 024e9686 2019-05-14 stsp goto done;
3372 024e9686 2019-05-14 stsp }
3373 024e9686 2019-05-14 stsp error = got_ref_resolve(&head_commit_id, repo, head_ref);
3374 024e9686 2019-05-14 stsp if (error)
3375 024e9686 2019-05-14 stsp goto done;
3376 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, head_commit_id, 0,
3377 3aef623b 2019-10-15 stsp repo);
3378 a367ff0f 2019-05-14 stsp free(head_commit_id);
3379 024e9686 2019-05-14 stsp if (error != NULL)
3380 024e9686 2019-05-14 stsp goto done;
3381 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
3382 a367ff0f 2019-05-14 stsp if (error)
3383 a367ff0f 2019-05-14 stsp goto done;
3384 a1fb16d8 2019-05-24 stsp error = switch_head_ref(head_ref, commit_id, worktree, repo);
3385 024e9686 2019-05-14 stsp if (error)
3386 024e9686 2019-05-14 stsp goto done;
3387 024e9686 2019-05-14 stsp } else {
3388 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
3389 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
3390 a367ff0f 2019-05-14 stsp if (error != NULL) {
3391 a367ff0f 2019-05-14 stsp if (error->code == GOT_ERR_ANCESTRY)
3392 a367ff0f 2019-05-14 stsp error = got_error(GOT_ERR_BRANCH_MOVED);
3393 024e9686 2019-05-14 stsp goto done;
3394 a367ff0f 2019-05-14 stsp }
3395 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
3396 a367ff0f 2019-05-14 stsp if (error)
3397 a367ff0f 2019-05-14 stsp goto done;
3398 024e9686 2019-05-14 stsp }
3399 507dc3bb 2018-12-29 stsp
3400 507dc3bb 2018-12-29 stsp if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
3401 507dc3bb 2018-12-29 stsp commit_id) != 0) {
3402 507dc3bb 2018-12-29 stsp error = got_worktree_set_base_commit_id(worktree, repo,
3403 507dc3bb 2018-12-29 stsp commit_id);
3404 507dc3bb 2018-12-29 stsp if (error)
3405 507dc3bb 2018-12-29 stsp goto done;
3406 507dc3bb 2018-12-29 stsp }
3407 507dc3bb 2018-12-29 stsp
3408 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
3409 4ad4a1ec 2021-09-13 tracey upa.verbosity = verbosity;
3410 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
3411 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
3412 507dc3bb 2018-12-29 stsp if (error != NULL)
3413 507dc3bb 2018-12-29 stsp goto done;
3414 9c4b8182 2019-01-02 stsp
3415 4f3c844b 2021-09-14 stsp if (upa.did_something) {
3416 4f3c844b 2021-09-14 stsp printf("Updated to %s: %s\n",
3417 4f3c844b 2021-09-14 stsp got_worktree_get_head_ref_name(worktree), commit_id_str);
3418 4f3c844b 2021-09-14 stsp } else
3419 784955db 2019-01-12 stsp printf("Already up-to-date\n");
3420 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
3421 507dc3bb 2018-12-29 stsp done:
3422 c09a553d 2018-03-12 stsp free(worktree_path);
3423 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
3424 f2ea84fa 2019-07-27 stsp free((char *)pe->path);
3425 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
3426 507dc3bb 2018-12-29 stsp free(commit_id);
3427 9c4b8182 2019-01-02 stsp free(commit_id_str);
3428 c09a553d 2018-03-12 stsp return error;
3429 c09a553d 2018-03-12 stsp }
3430 c09a553d 2018-03-12 stsp
3431 f42b1b34 2018-03-12 stsp static const struct got_error *
3432 44392932 2019-08-25 stsp diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3433 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
3434 64453f7e 2020-11-21 stsp int force_text_diff, struct got_repository *repo)
3435 5c860e29 2018-03-12 stsp {
3436 f42b1b34 2018-03-12 stsp const struct got_error *err = NULL;
3437 44392932 2019-08-25 stsp struct got_blob_object *blob1 = NULL, *blob2 = NULL;
3438 79109fed 2018-03-27 stsp
3439 44392932 2019-08-25 stsp if (blob_id1) {
3440 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192);
3441 44392932 2019-08-25 stsp if (err)
3442 44392932 2019-08-25 stsp goto done;
3443 44392932 2019-08-25 stsp }
3444 79109fed 2018-03-27 stsp
3445 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192);
3446 44392932 2019-08-25 stsp if (err)
3447 44392932 2019-08-25 stsp goto done;
3448 79109fed 2018-03-27 stsp
3449 44392932 2019-08-25 stsp while (path[0] == '/')
3450 44392932 2019-08-25 stsp path++;
3451 fe621944 2020-11-10 stsp err = got_diff_blob(NULL, NULL, blob1, blob2, path, path,
3452 64453f7e 2020-11-21 stsp diff_context, ignore_whitespace, force_text_diff, stdout);
3453 44392932 2019-08-25 stsp done:
3454 44392932 2019-08-25 stsp if (blob1)
3455 44392932 2019-08-25 stsp got_object_blob_close(blob1);
3456 44392932 2019-08-25 stsp got_object_blob_close(blob2);
3457 44392932 2019-08-25 stsp return err;
3458 44392932 2019-08-25 stsp }
3459 44392932 2019-08-25 stsp
3460 44392932 2019-08-25 stsp static const struct got_error *
3461 44392932 2019-08-25 stsp diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
3462 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
3463 64453f7e 2020-11-21 stsp int force_text_diff, struct got_repository *repo)
3464 44392932 2019-08-25 stsp {
3465 44392932 2019-08-25 stsp const struct got_error *err = NULL;
3466 44392932 2019-08-25 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3467 44392932 2019-08-25 stsp struct got_diff_blob_output_unidiff_arg arg;
3468 44392932 2019-08-25 stsp
3469 44392932 2019-08-25 stsp if (tree_id1) {
3470 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
3471 79109fed 2018-03-27 stsp if (err)
3472 44392932 2019-08-25 stsp goto done;
3473 79109fed 2018-03-27 stsp }
3474 79109fed 2018-03-27 stsp
3475 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
3476 0f2b3dca 2018-12-22 stsp if (err)
3477 0f2b3dca 2018-12-22 stsp goto done;
3478 0f2b3dca 2018-12-22 stsp
3479 aaa13589 2019-06-01 stsp arg.diff_context = diff_context;
3480 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
3481 64453f7e 2020-11-21 stsp arg.force_text_diff = force_text_diff;
3482 aaa13589 2019-06-01 stsp arg.outfile = stdout;
3483 fe621944 2020-11-10 stsp arg.line_offsets = NULL;
3484 fe621944 2020-11-10 stsp arg.nlines = 0;
3485 44392932 2019-08-25 stsp while (path[0] == '/')
3486 44392932 2019-08-25 stsp path++;
3487 44392932 2019-08-25 stsp err = got_diff_tree(tree1, tree2, path, path, repo,
3488 31b4484f 2019-07-27 stsp got_diff_blob_output_unidiff, &arg, 1);
3489 0f2b3dca 2018-12-22 stsp done:
3490 79109fed 2018-03-27 stsp if (tree1)
3491 79109fed 2018-03-27 stsp got_object_tree_close(tree1);
3492 366e0a5f 2019-10-10 stsp if (tree2)
3493 366e0a5f 2019-10-10 stsp got_object_tree_close(tree2);
3494 44392932 2019-08-25 stsp return err;
3495 44392932 2019-08-25 stsp }
3496 44392932 2019-08-25 stsp
3497 44392932 2019-08-25 stsp static const struct got_error *
3498 0208f208 2020-05-05 stsp get_changed_paths(struct got_pathlist_head *paths,
3499 0208f208 2020-05-05 stsp struct got_commit_object *commit, struct got_repository *repo)
3500 0208f208 2020-05-05 stsp {
3501 0208f208 2020-05-05 stsp const struct got_error *err = NULL;
3502 0208f208 2020-05-05 stsp struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3503 0208f208 2020-05-05 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3504 0208f208 2020-05-05 stsp struct got_object_qid *qid;
3505 0208f208 2020-05-05 stsp
3506 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3507 0208f208 2020-05-05 stsp if (qid != NULL) {
3508 0208f208 2020-05-05 stsp struct got_commit_object *pcommit;
3509 0208f208 2020-05-05 stsp err = got_object_open_as_commit(&pcommit, repo,
3510 0208f208 2020-05-05 stsp qid->id);
3511 0208f208 2020-05-05 stsp if (err)
3512 0208f208 2020-05-05 stsp return err;
3513 0208f208 2020-05-05 stsp
3514 aa8b5dd0 2021-08-01 stsp tree_id1 = got_object_id_dup(
3515 aa8b5dd0 2021-08-01 stsp got_object_commit_get_tree_id(pcommit));
3516 aa8b5dd0 2021-08-01 stsp if (tree_id1 == NULL) {
3517 aa8b5dd0 2021-08-01 stsp got_object_commit_close(pcommit);
3518 aa8b5dd0 2021-08-01 stsp return got_error_from_errno("got_object_id_dup");
3519 aa8b5dd0 2021-08-01 stsp }
3520 0208f208 2020-05-05 stsp got_object_commit_close(pcommit);
3521 0208f208 2020-05-05 stsp
3522 0208f208 2020-05-05 stsp }
3523 0208f208 2020-05-05 stsp
3524 0208f208 2020-05-05 stsp if (tree_id1) {
3525 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
3526 0208f208 2020-05-05 stsp if (err)
3527 0208f208 2020-05-05 stsp goto done;
3528 0208f208 2020-05-05 stsp }
3529 0208f208 2020-05-05 stsp
3530 0208f208 2020-05-05 stsp tree_id2 = got_object_commit_get_tree_id(commit);
3531 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
3532 0208f208 2020-05-05 stsp if (err)
3533 0208f208 2020-05-05 stsp goto done;
3534 0208f208 2020-05-05 stsp
3535 0208f208 2020-05-05 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
3536 0208f208 2020-05-05 stsp got_diff_tree_collect_changed_paths, paths, 0);
3537 0208f208 2020-05-05 stsp done:
3538 0208f208 2020-05-05 stsp if (tree1)
3539 0208f208 2020-05-05 stsp got_object_tree_close(tree1);
3540 0208f208 2020-05-05 stsp if (tree2)
3541 0208f208 2020-05-05 stsp got_object_tree_close(tree2);
3542 aa8b5dd0 2021-08-01 stsp free(tree_id1);
3543 0208f208 2020-05-05 stsp return err;
3544 0208f208 2020-05-05 stsp }
3545 0208f208 2020-05-05 stsp
3546 0208f208 2020-05-05 stsp static const struct got_error *
3547 44392932 2019-08-25 stsp print_patch(struct got_commit_object *commit, struct got_object_id *id,
3548 44392932 2019-08-25 stsp const char *path, int diff_context, struct got_repository *repo)
3549 44392932 2019-08-25 stsp {
3550 44392932 2019-08-25 stsp const struct got_error *err = NULL;
3551 44392932 2019-08-25 stsp struct got_commit_object *pcommit = NULL;
3552 44392932 2019-08-25 stsp char *id_str1 = NULL, *id_str2 = NULL;
3553 44392932 2019-08-25 stsp struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL;
3554 44392932 2019-08-25 stsp struct got_object_qid *qid;
3555 44392932 2019-08-25 stsp
3556 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3557 44392932 2019-08-25 stsp if (qid != NULL) {
3558 44392932 2019-08-25 stsp err = got_object_open_as_commit(&pcommit, repo,
3559 44392932 2019-08-25 stsp qid->id);
3560 44392932 2019-08-25 stsp if (err)
3561 44392932 2019-08-25 stsp return err;
3562 44392932 2019-08-25 stsp }
3563 44392932 2019-08-25 stsp
3564 44392932 2019-08-25 stsp if (path && path[0] != '\0') {
3565 44392932 2019-08-25 stsp int obj_type;
3566 44392932 2019-08-25 stsp err = got_object_id_by_path(&obj_id2, repo, id, path);
3567 44392932 2019-08-25 stsp if (err)
3568 44392932 2019-08-25 stsp goto done;
3569 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
3570 44392932 2019-08-25 stsp if (err) {
3571 44392932 2019-08-25 stsp free(obj_id2);
3572 44392932 2019-08-25 stsp goto done;
3573 44392932 2019-08-25 stsp }
3574 44392932 2019-08-25 stsp if (pcommit) {
3575 44392932 2019-08-25 stsp err = got_object_id_by_path(&obj_id1, repo,
3576 44392932 2019-08-25 stsp qid->id, path);
3577 44392932 2019-08-25 stsp if (err) {
3578 2e8c69d1 2020-05-04 stsp if (err->code != GOT_ERR_NO_TREE_ENTRY) {
3579 2e8c69d1 2020-05-04 stsp free(obj_id2);
3580 2e8c69d1 2020-05-04 stsp goto done;
3581 2e8c69d1 2020-05-04 stsp }
3582 2e8c69d1 2020-05-04 stsp } else {
3583 2e8c69d1 2020-05-04 stsp err = got_object_id_str(&id_str1, obj_id1);
3584 2e8c69d1 2020-05-04 stsp if (err) {
3585 2e8c69d1 2020-05-04 stsp free(obj_id2);
3586 2e8c69d1 2020-05-04 stsp goto done;
3587 2e8c69d1 2020-05-04 stsp }
3588 44392932 2019-08-25 stsp }
3589 44392932 2019-08-25 stsp }
3590 44392932 2019-08-25 stsp err = got_object_get_type(&obj_type, repo, obj_id2);
3591 44392932 2019-08-25 stsp if (err) {
3592 44392932 2019-08-25 stsp free(obj_id2);
3593 44392932 2019-08-25 stsp goto done;
3594 44392932 2019-08-25 stsp }
3595 44392932 2019-08-25 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3596 44392932 2019-08-25 stsp switch (obj_type) {
3597 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_BLOB:
3598 44392932 2019-08-25 stsp err = diff_blobs(obj_id1, obj_id2, path, diff_context,
3599 64453f7e 2020-11-21 stsp 0, 0, repo);
3600 44392932 2019-08-25 stsp break;
3601 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_TREE:
3602 44392932 2019-08-25 stsp err = diff_trees(obj_id1, obj_id2, path, diff_context,
3603 64453f7e 2020-11-21 stsp 0, 0, repo);
3604 44392932 2019-08-25 stsp break;
3605 44392932 2019-08-25 stsp default:
3606 44392932 2019-08-25 stsp err = got_error(GOT_ERR_OBJ_TYPE);
3607 44392932 2019-08-25 stsp break;
3608 44392932 2019-08-25 stsp }
3609 44392932 2019-08-25 stsp free(obj_id1);
3610 44392932 2019-08-25 stsp free(obj_id2);
3611 44392932 2019-08-25 stsp } else {
3612 44392932 2019-08-25 stsp obj_id2 = got_object_commit_get_tree_id(commit);
3613 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
3614 44392932 2019-08-25 stsp if (err)
3615 44392932 2019-08-25 stsp goto done;
3616 579bd556 2020-10-24 stsp if (pcommit) {
3617 579bd556 2020-10-24 stsp obj_id1 = got_object_commit_get_tree_id(pcommit);
3618 579bd556 2020-10-24 stsp err = got_object_id_str(&id_str1, obj_id1);
3619 579bd556 2020-10-24 stsp if (err)
3620 579bd556 2020-10-24 stsp goto done;
3621 579bd556 2020-10-24 stsp }
3622 64453f7e 2020-11-21 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null",
3623 64453f7e 2020-11-21 stsp id_str2);
3624 64453f7e 2020-11-21 stsp err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
3625 64453f7e 2020-11-21 stsp repo);
3626 44392932 2019-08-25 stsp }
3627 44392932 2019-08-25 stsp done:
3628 0f2b3dca 2018-12-22 stsp free(id_str1);
3629 0f2b3dca 2018-12-22 stsp free(id_str2);
3630 44392932 2019-08-25 stsp if (pcommit)
3631 44392932 2019-08-25 stsp got_object_commit_close(pcommit);
3632 79109fed 2018-03-27 stsp return err;
3633 79109fed 2018-03-27 stsp }
3634 79109fed 2018-03-27 stsp
3635 4bb494d5 2018-06-16 stsp static char *
3636 6c281f94 2018-06-11 stsp get_datestr(time_t *time, char *datebuf)
3637 6c281f94 2018-06-11 stsp {
3638 09867e48 2019-08-13 stsp struct tm mytm, *tm;
3639 09867e48 2019-08-13 stsp char *p, *s;
3640 09867e48 2019-08-13 stsp
3641 09867e48 2019-08-13 stsp tm = gmtime_r(time, &mytm);
3642 09867e48 2019-08-13 stsp if (tm == NULL)
3643 09867e48 2019-08-13 stsp return NULL;
3644 09867e48 2019-08-13 stsp s = asctime_r(tm, datebuf);
3645 09867e48 2019-08-13 stsp if (s == NULL)
3646 09867e48 2019-08-13 stsp return NULL;
3647 6c281f94 2018-06-11 stsp p = strchr(s, '\n');
3648 6c281f94 2018-06-11 stsp if (p)
3649 6c281f94 2018-06-11 stsp *p = '\0';
3650 6c281f94 2018-06-11 stsp return s;
3651 6c281f94 2018-06-11 stsp }
3652 dc424a06 2019-08-07 stsp
3653 6841bf13 2019-11-29 kn static const struct got_error *
3654 6841bf13 2019-11-29 kn match_logmsg(int *have_match, struct got_object_id *id,
3655 6841bf13 2019-11-29 kn struct got_commit_object *commit, regex_t *regex)
3656 6841bf13 2019-11-29 kn {
3657 6841bf13 2019-11-29 kn const struct got_error *err = NULL;
3658 6841bf13 2019-11-29 kn regmatch_t regmatch;
3659 6841bf13 2019-11-29 kn char *id_str = NULL, *logmsg = NULL;
3660 6841bf13 2019-11-29 kn
3661 6841bf13 2019-11-29 kn *have_match = 0;
3662 6841bf13 2019-11-29 kn
3663 6841bf13 2019-11-29 kn err = got_object_id_str(&id_str, id);
3664 6841bf13 2019-11-29 kn if (err)
3665 6841bf13 2019-11-29 kn return err;
3666 6841bf13 2019-11-29 kn
3667 6841bf13 2019-11-29 kn err = got_object_commit_get_logmsg(&logmsg, commit);
3668 6841bf13 2019-11-29 kn if (err)
3669 6841bf13 2019-11-29 kn goto done;
3670 6841bf13 2019-11-29 kn
3671 6841bf13 2019-11-29 kn if (regexec(regex, logmsg, 1, &regmatch, 0) == 0)
3672 6841bf13 2019-11-29 kn *have_match = 1;
3673 6841bf13 2019-11-29 kn done:
3674 6841bf13 2019-11-29 kn free(id_str);
3675 6841bf13 2019-11-29 kn free(logmsg);
3676 6841bf13 2019-11-29 kn return err;
3677 6841bf13 2019-11-29 kn }
3678 6841bf13 2019-11-29 kn
3679 0208f208 2020-05-05 stsp static void
3680 0208f208 2020-05-05 stsp match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3681 0208f208 2020-05-05 stsp regex_t *regex)
3682 0208f208 2020-05-05 stsp {
3683 0208f208 2020-05-05 stsp regmatch_t regmatch;
3684 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3685 0208f208 2020-05-05 stsp
3686 0208f208 2020-05-05 stsp *have_match = 0;
3687 0208f208 2020-05-05 stsp
3688 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3689 0208f208 2020-05-05 stsp if (regexec(regex, pe->path, 1, &regmatch, 0) == 0) {
3690 0208f208 2020-05-05 stsp *have_match = 1;
3691 0208f208 2020-05-05 stsp break;
3692 0208f208 2020-05-05 stsp }
3693 0208f208 2020-05-05 stsp }
3694 0208f208 2020-05-05 stsp }
3695 0208f208 2020-05-05 stsp
3696 dc424a06 2019-08-07 stsp #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3697 6c281f94 2018-06-11 stsp
3698 888b7d99 2020-12-26 stsp static const struct got_error*
3699 888b7d99 2020-12-26 stsp build_refs_str(char **refs_str, struct got_reflist_head *refs,
3700 888b7d99 2020-12-26 stsp struct got_object_id *id, struct got_repository *repo)
3701 888b7d99 2020-12-26 stsp {
3702 888b7d99 2020-12-26 stsp static const struct got_error *err = NULL;
3703 199a4027 2019-02-02 stsp struct got_reflist_entry *re;
3704 888b7d99 2020-12-26 stsp char *s;
3705 888b7d99 2020-12-26 stsp const char *name;
3706 5c860e29 2018-03-12 stsp
3707 888b7d99 2020-12-26 stsp *refs_str = NULL;
3708 888b7d99 2020-12-26 stsp
3709 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, refs, entry) {
3710 a436ad14 2019-08-13 stsp struct got_tag_object *tag = NULL;
3711 48cae60d 2020-09-22 stsp struct got_object_id *ref_id;
3712 a436ad14 2019-08-13 stsp int cmp;
3713 a436ad14 2019-08-13 stsp
3714 199a4027 2019-02-02 stsp name = got_ref_get_name(re->ref);
3715 d9498b20 2019-02-05 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
3716 d9498b20 2019-02-05 stsp continue;
3717 199a4027 2019-02-02 stsp if (strncmp(name, "refs/", 5) == 0)
3718 199a4027 2019-02-02 stsp name += 5;
3719 7143d404 2019-03-12 stsp if (strncmp(name, "got/", 4) == 0)
3720 7143d404 2019-03-12 stsp continue;
3721 e34f9ed6 2019-02-02 stsp if (strncmp(name, "heads/", 6) == 0)
3722 e34f9ed6 2019-02-02 stsp name += 6;
3723 4343a07f 2020-04-24 stsp if (strncmp(name, "remotes/", 8) == 0) {
3724 141c2bff 2019-02-04 stsp name += 8;
3725 4343a07f 2020-04-24 stsp s = strstr(name, "/" GOT_REF_HEAD);
3726 4343a07f 2020-04-24 stsp if (s != NULL && s[strlen(s)] == '\0')
3727 4343a07f 2020-04-24 stsp continue;
3728 4343a07f 2020-04-24 stsp }
3729 48cae60d 2020-09-22 stsp err = got_ref_resolve(&ref_id, repo, re->ref);
3730 48cae60d 2020-09-22 stsp if (err)
3731 888b7d99 2020-12-26 stsp break;
3732 a436ad14 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
3733 48cae60d 2020-09-22 stsp err = got_object_open_as_tag(&tag, repo, ref_id);
3734 5d844a1e 2019-08-13 stsp if (err) {
3735 48cae60d 2020-09-22 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
3736 48cae60d 2020-09-22 stsp free(ref_id);
3737 888b7d99 2020-12-26 stsp break;
3738 48cae60d 2020-09-22 stsp }
3739 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
3740 5d844a1e 2019-08-13 stsp err = NULL;
3741 5d844a1e 2019-08-13 stsp tag = NULL;
3742 5d844a1e 2019-08-13 stsp }
3743 a436ad14 2019-08-13 stsp }
3744 a436ad14 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
3745 48cae60d 2020-09-22 stsp got_object_tag_get_object_id(tag) : ref_id, id);
3746 48cae60d 2020-09-22 stsp free(ref_id);
3747 a436ad14 2019-08-13 stsp if (tag)
3748 a436ad14 2019-08-13 stsp got_object_tag_close(tag);
3749 a436ad14 2019-08-13 stsp if (cmp != 0)
3750 a436ad14 2019-08-13 stsp continue;
3751 888b7d99 2020-12-26 stsp s = *refs_str;
3752 888b7d99 2020-12-26 stsp if (asprintf(refs_str, "%s%s%s", s ? s : "",
3753 888b7d99 2020-12-26 stsp s ? ", " : "", name) == -1) {
3754 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
3755 199a4027 2019-02-02 stsp free(s);
3756 888b7d99 2020-12-26 stsp *refs_str = NULL;
3757 888b7d99 2020-12-26 stsp break;
3758 199a4027 2019-02-02 stsp }
3759 199a4027 2019-02-02 stsp free(s);
3760 199a4027 2019-02-02 stsp }
3761 888b7d99 2020-12-26 stsp
3762 888b7d99 2020-12-26 stsp return err;
3763 888b7d99 2020-12-26 stsp }
3764 888b7d99 2020-12-26 stsp
3765 888b7d99 2020-12-26 stsp static const struct got_error *
3766 888b7d99 2020-12-26 stsp print_commit(struct got_commit_object *commit, struct got_object_id *id,
3767 888b7d99 2020-12-26 stsp struct got_repository *repo, const char *path,
3768 888b7d99 2020-12-26 stsp struct got_pathlist_head *changed_paths, int show_patch,
3769 e600f124 2021-03-21 stsp int diff_context, struct got_reflist_object_id_map *refs_idmap,
3770 e600f124 2021-03-21 stsp const char *custom_refs_str)
3771 888b7d99 2020-12-26 stsp {
3772 888b7d99 2020-12-26 stsp const struct got_error *err = NULL;
3773 888b7d99 2020-12-26 stsp char *id_str, *datestr, *logmsg0, *logmsg, *line;
3774 888b7d99 2020-12-26 stsp char datebuf[26];
3775 888b7d99 2020-12-26 stsp time_t committer_time;
3776 888b7d99 2020-12-26 stsp const char *author, *committer;
3777 888b7d99 2020-12-26 stsp char *refs_str = NULL;
3778 888b7d99 2020-12-26 stsp
3779 832c249c 2018-06-10 stsp err = got_object_id_str(&id_str, id);
3780 8bf5b3c9 2018-03-17 stsp if (err)
3781 8bf5b3c9 2018-03-17 stsp return err;
3782 788c352e 2018-06-16 stsp
3783 e600f124 2021-03-21 stsp if (custom_refs_str == NULL) {
3784 e600f124 2021-03-21 stsp struct got_reflist_head *refs;
3785 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3786 e600f124 2021-03-21 stsp if (refs) {
3787 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, id, repo);
3788 e600f124 2021-03-21 stsp if (err)
3789 e600f124 2021-03-21 stsp goto done;
3790 e600f124 2021-03-21 stsp }
3791 888b7d99 2020-12-26 stsp }
3792 888b7d99 2020-12-26 stsp
3793 dc424a06 2019-08-07 stsp printf(GOT_COMMIT_SEP_STR);
3794 e600f124 2021-03-21 stsp if (custom_refs_str)
3795 e600f124 2021-03-21 stsp printf("commit %s (%s)\n", id_str, custom_refs_str);
3796 e600f124 2021-03-21 stsp else
3797 e600f124 2021-03-21 stsp printf("commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
3798 e600f124 2021-03-21 stsp refs_str ? refs_str : "", refs_str ? ")" : "");
3799 832c249c 2018-06-10 stsp free(id_str);
3800 d3d493d7 2019-02-21 stsp id_str = NULL;
3801 d3d493d7 2019-02-21 stsp free(refs_str);
3802 d3d493d7 2019-02-21 stsp refs_str = NULL;
3803 45d799e2 2018-12-23 stsp printf("from: %s\n", got_object_commit_get_author(commit));
3804 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
3805 45d799e2 2018-12-23 stsp datestr = get_datestr(&committer_time, datebuf);
3806 09867e48 2019-08-13 stsp if (datestr)
3807 09867e48 2019-08-13 stsp printf("date: %s UTC\n", datestr);
3808 45d799e2 2018-12-23 stsp author = got_object_commit_get_author(commit);
3809 45d799e2 2018-12-23 stsp committer = got_object_commit_get_committer(commit);
3810 45d799e2 2018-12-23 stsp if (strcmp(author, committer) != 0)
3811 45d799e2 2018-12-23 stsp printf("via: %s\n", committer);
3812 45d799e2 2018-12-23 stsp if (got_object_commit_get_nparents(commit) > 1) {
3813 45d799e2 2018-12-23 stsp const struct got_object_id_queue *parent_ids;
3814 79f35eb3 2018-06-11 stsp struct got_object_qid *qid;
3815 3fe1abad 2018-06-10 stsp int n = 1;
3816 45d799e2 2018-12-23 stsp parent_ids = got_object_commit_get_parent_ids(commit);
3817 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, parent_ids, entry) {
3818 79f35eb3 2018-06-11 stsp err = got_object_id_str(&id_str, qid->id);
3819 a0603db2 2018-06-10 stsp if (err)
3820 888b7d99 2020-12-26 stsp goto done;
3821 3fe1abad 2018-06-10 stsp printf("parent %d: %s\n", n++, id_str);
3822 a0603db2 2018-06-10 stsp free(id_str);
3823 888b7d99 2020-12-26 stsp id_str = NULL;
3824 a0603db2 2018-06-10 stsp }
3825 a0603db2 2018-06-10 stsp }
3826 832c249c 2018-06-10 stsp
3827 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
3828 5943eee2 2019-08-13 stsp if (err)
3829 888b7d99 2020-12-26 stsp goto done;
3830 8bf5b3c9 2018-03-17 stsp
3831 621015ac 2018-07-23 stsp logmsg = logmsg0;
3832 832c249c 2018-06-10 stsp do {
3833 832c249c 2018-06-10 stsp line = strsep(&logmsg, "\n");
3834 832c249c 2018-06-10 stsp if (line)
3835 832c249c 2018-06-10 stsp printf(" %s\n", line);
3836 832c249c 2018-06-10 stsp } while (line);
3837 621015ac 2018-07-23 stsp free(logmsg0);
3838 832c249c 2018-06-10 stsp
3839 0208f208 2020-05-05 stsp if (changed_paths) {
3840 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3841 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3842 0208f208 2020-05-05 stsp struct got_diff_changed_path *cp = pe->data;
3843 0208f208 2020-05-05 stsp printf(" %c %s\n", cp->status, pe->path);
3844 0208f208 2020-05-05 stsp }
3845 0208f208 2020-05-05 stsp printf("\n");
3846 0208f208 2020-05-05 stsp }
3847 971751ac 2018-03-27 stsp if (show_patch) {
3848 44392932 2019-08-25 stsp err = print_patch(commit, id, path, diff_context, repo);
3849 971751ac 2018-03-27 stsp if (err == 0)
3850 971751ac 2018-03-27 stsp printf("\n");
3851 971751ac 2018-03-27 stsp }
3852 07862c20 2018-09-15 stsp
3853 cbe7f848 2019-02-11 stsp if (fflush(stdout) != 0 && err == NULL)
3854 638f9024 2019-05-13 stsp err = got_error_from_errno("fflush");
3855 888b7d99 2020-12-26 stsp done:
3856 888b7d99 2020-12-26 stsp free(id_str);
3857 888b7d99 2020-12-26 stsp free(refs_str);
3858 07862c20 2018-09-15 stsp return err;
3859 f42b1b34 2018-03-12 stsp }
3860 5c860e29 2018-03-12 stsp
3861 f42b1b34 2018-03-12 stsp static const struct got_error *
3862 d1fe46f9 2020-04-18 stsp print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
3863 0208f208 2020-05-05 stsp struct got_repository *repo, const char *path, int show_changed_paths,
3864 0208f208 2020-05-05 stsp int show_patch, const char *search_pattern, int diff_context, int limit,
3865 888b7d99 2020-12-26 stsp int log_branches, int reverse_display_order,
3866 888b7d99 2020-12-26 stsp struct got_reflist_object_id_map *refs_idmap)
3867 f42b1b34 2018-03-12 stsp {
3868 f42b1b34 2018-03-12 stsp const struct got_error *err;
3869 372ccdbb 2018-06-10 stsp struct got_commit_graph *graph;
3870 6841bf13 2019-11-29 kn regex_t regex;
3871 6841bf13 2019-11-29 kn int have_match;
3872 dbec59df 2020-04-18 stsp struct got_object_id_queue reversed_commits;
3873 dbec59df 2020-04-18 stsp struct got_object_qid *qid;
3874 dbec59df 2020-04-18 stsp struct got_commit_object *commit;
3875 0208f208 2020-05-05 stsp struct got_pathlist_head changed_paths;
3876 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3877 dbec59df 2020-04-18 stsp
3878 dbdddfee 2021-06-23 naddy STAILQ_INIT(&reversed_commits);
3879 0208f208 2020-05-05 stsp TAILQ_INIT(&changed_paths);
3880 372ccdbb 2018-06-10 stsp
3881 ccecc9fd 2020-04-18 stsp if (search_pattern && regcomp(&regex, search_pattern,
3882 ccecc9fd 2020-04-18 stsp REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
3883 6841bf13 2019-11-29 kn return got_error_msg(GOT_ERR_REGEX, search_pattern);
3884 6841bf13 2019-11-29 kn
3885 48c8c60d 2020-01-27 stsp err = got_commit_graph_open(&graph, path, !log_branches);
3886 f42b1b34 2018-03-12 stsp if (err)
3887 f42b1b34 2018-03-12 stsp return err;
3888 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, root_id, repo,
3889 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
3890 372ccdbb 2018-06-10 stsp if (err)
3891 fcc85cad 2018-07-22 stsp goto done;
3892 656b1f76 2019-05-11 jcs for (;;) {
3893 372ccdbb 2018-06-10 stsp struct got_object_id *id;
3894 8bf5b3c9 2018-03-17 stsp
3895 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
3896 84453469 2018-11-11 stsp break;
3897 84453469 2018-11-11 stsp
3898 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&id, graph, repo,
3899 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
3900 372ccdbb 2018-06-10 stsp if (err) {
3901 ee780d5c 2020-01-04 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
3902 9ba79e04 2018-06-11 stsp err = NULL;
3903 ee780d5c 2020-01-04 stsp break;
3904 7e665116 2018-04-02 stsp }
3905 b43fbaa0 2018-06-11 stsp if (id == NULL)
3906 7e665116 2018-04-02 stsp break;
3907 b43fbaa0 2018-06-11 stsp
3908 f8e900f3 2018-06-11 stsp err = got_object_open_as_commit(&commit, repo, id);
3909 b43fbaa0 2018-06-11 stsp if (err)
3910 fcc85cad 2018-07-22 stsp break;
3911 6841bf13 2019-11-29 kn
3912 502b9684 2020-07-31 stsp if (show_changed_paths && !reverse_display_order) {
3913 0208f208 2020-05-05 stsp err = get_changed_paths(&changed_paths, commit, repo);
3914 0208f208 2020-05-05 stsp if (err)
3915 0208f208 2020-05-05 stsp break;
3916 0208f208 2020-05-05 stsp }
3917 0208f208 2020-05-05 stsp
3918 6841bf13 2019-11-29 kn if (search_pattern) {
3919 6841bf13 2019-11-29 kn err = match_logmsg(&have_match, id, commit, &regex);
3920 6841bf13 2019-11-29 kn if (err) {
3921 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3922 6841bf13 2019-11-29 kn break;
3923 6841bf13 2019-11-29 kn }
3924 0208f208 2020-05-05 stsp if (have_match == 0 && show_changed_paths)
3925 0208f208 2020-05-05 stsp match_changed_paths(&have_match,
3926 0208f208 2020-05-05 stsp &changed_paths, &regex);
3927 6841bf13 2019-11-29 kn if (have_match == 0) {
3928 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3929 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3930 0208f208 2020-05-05 stsp free((char *)pe->path);
3931 0208f208 2020-05-05 stsp free(pe->data);
3932 0208f208 2020-05-05 stsp }
3933 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3934 6841bf13 2019-11-29 kn continue;
3935 6841bf13 2019-11-29 kn }
3936 6841bf13 2019-11-29 kn }
3937 6841bf13 2019-11-29 kn
3938 dbec59df 2020-04-18 stsp if (reverse_display_order) {
3939 dbec59df 2020-04-18 stsp err = got_object_qid_alloc(&qid, id);
3940 dbec59df 2020-04-18 stsp if (err)
3941 dbec59df 2020-04-18 stsp break;
3942 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(&reversed_commits, qid, entry);
3943 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3944 dbec59df 2020-04-18 stsp } else {
3945 0208f208 2020-05-05 stsp err = print_commit(commit, id, repo, path,
3946 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
3947 e600f124 2021-03-21 stsp show_patch, diff_context, refs_idmap, NULL);
3948 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3949 dbec59df 2020-04-18 stsp if (err)
3950 dbec59df 2020-04-18 stsp break;
3951 dbec59df 2020-04-18 stsp }
3952 dbec59df 2020-04-18 stsp if ((limit && --limit == 0) ||
3953 dbec59df 2020-04-18 stsp (end_id && got_object_id_cmp(id, end_id) == 0))
3954 7e665116 2018-04-02 stsp break;
3955 0208f208 2020-05-05 stsp
3956 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3957 0208f208 2020-05-05 stsp free((char *)pe->path);
3958 0208f208 2020-05-05 stsp free(pe->data);
3959 0208f208 2020-05-05 stsp }
3960 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3961 31cedeaf 2018-09-15 stsp }
3962 dbec59df 2020-04-18 stsp if (reverse_display_order) {
3963 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, &reversed_commits, entry) {
3964 dbec59df 2020-04-18 stsp err = got_object_open_as_commit(&commit, repo, qid->id);
3965 dbec59df 2020-04-18 stsp if (err)
3966 dbec59df 2020-04-18 stsp break;
3967 502b9684 2020-07-31 stsp if (show_changed_paths) {
3968 502b9684 2020-07-31 stsp err = get_changed_paths(&changed_paths,
3969 502b9684 2020-07-31 stsp commit, repo);
3970 502b9684 2020-07-31 stsp if (err)
3971 502b9684 2020-07-31 stsp break;
3972 502b9684 2020-07-31 stsp }
3973 dbec59df 2020-04-18 stsp err = print_commit(commit, qid->id, repo, path,
3974 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
3975 e600f124 2021-03-21 stsp show_patch, diff_context, refs_idmap, NULL);
3976 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3977 dbec59df 2020-04-18 stsp if (err)
3978 dbec59df 2020-04-18 stsp break;
3979 502b9684 2020-07-31 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3980 502b9684 2020-07-31 stsp free((char *)pe->path);
3981 502b9684 2020-07-31 stsp free(pe->data);
3982 502b9684 2020-07-31 stsp }
3983 502b9684 2020-07-31 stsp got_pathlist_free(&changed_paths);
3984 dbec59df 2020-04-18 stsp }
3985 dbec59df 2020-04-18 stsp }
3986 fcc85cad 2018-07-22 stsp done:
3987 dbdddfee 2021-06-23 naddy while (!STAILQ_EMPTY(&reversed_commits)) {
3988 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(&reversed_commits);
3989 dbdddfee 2021-06-23 naddy STAILQ_REMOVE_HEAD(&reversed_commits, entry);
3990 dbec59df 2020-04-18 stsp got_object_qid_free(qid);
3991 dbec59df 2020-04-18 stsp }
3992 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3993 0208f208 2020-05-05 stsp free((char *)pe->path);
3994 0208f208 2020-05-05 stsp free(pe->data);
3995 0208f208 2020-05-05 stsp }
3996 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3997 6841bf13 2019-11-29 kn if (search_pattern)
3998 6841bf13 2019-11-29 kn regfree(&regex);
3999 372ccdbb 2018-06-10 stsp got_commit_graph_close(graph);
4000 f42b1b34 2018-03-12 stsp return err;
4001 f42b1b34 2018-03-12 stsp }
4002 5c860e29 2018-03-12 stsp
4003 4ed7e80c 2018-05-20 stsp __dead static void
4004 6f3d1eb0 2018-03-12 stsp usage_log(void)
4005 6f3d1eb0 2018-03-12 stsp {
4006 d1fe46f9 2020-04-18 stsp fprintf(stderr, "usage: %s log [-b] [-c commit] [-C number] [ -l N ] "
4007 0208f208 2020-05-05 stsp "[-p] [-P] [-x commit] [-s search-pattern] [-r repository-path] "
4008 0208f208 2020-05-05 stsp "[-R] [path]\n", getprogname());
4009 6f3d1eb0 2018-03-12 stsp exit(1);
4010 b1ebc001 2019-08-13 stsp }
4011 b1ebc001 2019-08-13 stsp
4012 b1ebc001 2019-08-13 stsp static int
4013 b1ebc001 2019-08-13 stsp get_default_log_limit(void)
4014 b1ebc001 2019-08-13 stsp {
4015 b1ebc001 2019-08-13 stsp const char *got_default_log_limit;
4016 b1ebc001 2019-08-13 stsp long long n;
4017 b1ebc001 2019-08-13 stsp const char *errstr;
4018 b1ebc001 2019-08-13 stsp
4019 b1ebc001 2019-08-13 stsp got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
4020 b1ebc001 2019-08-13 stsp if (got_default_log_limit == NULL)
4021 b1ebc001 2019-08-13 stsp return 0;
4022 b1ebc001 2019-08-13 stsp n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr);
4023 b1ebc001 2019-08-13 stsp if (errstr != NULL)
4024 b1ebc001 2019-08-13 stsp return 0;
4025 b1ebc001 2019-08-13 stsp return n;
4026 6f3d1eb0 2018-03-12 stsp }
4027 6f3d1eb0 2018-03-12 stsp
4028 4ed7e80c 2018-05-20 stsp static const struct got_error *
4029 f42b1b34 2018-03-12 stsp cmd_log(int argc, char *argv[])
4030 f42b1b34 2018-03-12 stsp {
4031 f42b1b34 2018-03-12 stsp const struct got_error *error;
4032 04ca23f4 2018-07-16 stsp struct got_repository *repo = NULL;
4033 cffc0aa4 2019-02-05 stsp struct got_worktree *worktree = NULL;
4034 d1fe46f9 2020-04-18 stsp struct got_object_id *start_id = NULL, *end_id = NULL;
4035 04ca23f4 2018-07-16 stsp char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
4036 d1fe46f9 2020-04-18 stsp const char *start_commit = NULL, *end_commit = NULL;
4037 d1fe46f9 2020-04-18 stsp const char *search_pattern = NULL;
4038 dc1edbfa 2019-11-29 kn int diff_context = -1, ch;
4039 0208f208 2020-05-05 stsp int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
4040 dbec59df 2020-04-18 stsp int reverse_display_order = 0;
4041 64a96a6d 2018-04-01 stsp const char *errstr;
4042 199a4027 2019-02-02 stsp struct got_reflist_head refs;
4043 888b7d99 2020-12-26 stsp struct got_reflist_object_id_map *refs_idmap = NULL;
4044 1b3893a2 2019-03-18 stsp
4045 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
4046 5c860e29 2018-03-12 stsp
4047 6715a751 2018-03-16 stsp #ifndef PROFILE
4048 6098196c 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4049 6098196c 2019-01-04 stsp NULL)
4050 ad242220 2018-09-08 stsp == -1)
4051 f42b1b34 2018-03-12 stsp err(1, "pledge");
4052 6715a751 2018-03-16 stsp #endif
4053 79109fed 2018-03-27 stsp
4054 b1ebc001 2019-08-13 stsp limit = get_default_log_limit();
4055 b1ebc001 2019-08-13 stsp
4056 0208f208 2020-05-05 stsp while ((ch = getopt(argc, argv, "bpPc:C:l:r:Rs:x:")) != -1) {
4057 79109fed 2018-03-27 stsp switch (ch) {
4058 79109fed 2018-03-27 stsp case 'p':
4059 79109fed 2018-03-27 stsp show_patch = 1;
4060 d142fc45 2018-04-01 stsp break;
4061 0208f208 2020-05-05 stsp case 'P':
4062 0208f208 2020-05-05 stsp show_changed_paths = 1;
4063 0208f208 2020-05-05 stsp break;
4064 d142fc45 2018-04-01 stsp case 'c':
4065 d142fc45 2018-04-01 stsp start_commit = optarg;
4066 64a96a6d 2018-04-01 stsp break;
4067 c0cc5c62 2018-10-18 stsp case 'C':
4068 4a8520aa 2018-10-18 stsp diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4069 4a8520aa 2018-10-18 stsp &errstr);
4070 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
4071 c0cc5c62 2018-10-18 stsp err(1, "-C option %s", errstr);
4072 c0cc5c62 2018-10-18 stsp break;
4073 64a96a6d 2018-04-01 stsp case 'l':
4074 b1ebc001 2019-08-13 stsp limit = strtonum(optarg, 0, INT_MAX, &errstr);
4075 64a96a6d 2018-04-01 stsp if (errstr != NULL)
4076 64a96a6d 2018-04-01 stsp err(1, "-l option %s", errstr);
4077 cc54c501 2019-07-15 stsp break;
4078 48c8c60d 2020-01-27 stsp case 'b':
4079 48c8c60d 2020-01-27 stsp log_branches = 1;
4080 a0603db2 2018-06-10 stsp break;
4081 04ca23f4 2018-07-16 stsp case 'r':
4082 04ca23f4 2018-07-16 stsp repo_path = realpath(optarg, NULL);
4083 04ca23f4 2018-07-16 stsp if (repo_path == NULL)
4084 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4085 9ba1d308 2019-10-21 stsp optarg);
4086 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4087 04ca23f4 2018-07-16 stsp break;
4088 dbec59df 2020-04-18 stsp case 'R':
4089 dbec59df 2020-04-18 stsp reverse_display_order = 1;
4090 dbec59df 2020-04-18 stsp break;
4091 6841bf13 2019-11-29 kn case 's':
4092 6841bf13 2019-11-29 kn search_pattern = optarg;
4093 6841bf13 2019-11-29 kn break;
4094 d1fe46f9 2020-04-18 stsp case 'x':
4095 d1fe46f9 2020-04-18 stsp end_commit = optarg;
4096 d1fe46f9 2020-04-18 stsp break;
4097 79109fed 2018-03-27 stsp default:
4098 2deda0b9 2019-03-07 stsp usage_log();
4099 79109fed 2018-03-27 stsp /* NOTREACHED */
4100 79109fed 2018-03-27 stsp }
4101 79109fed 2018-03-27 stsp }
4102 79109fed 2018-03-27 stsp
4103 79109fed 2018-03-27 stsp argc -= optind;
4104 79109fed 2018-03-27 stsp argv += optind;
4105 f42b1b34 2018-03-12 stsp
4106 dc1edbfa 2019-11-29 kn if (diff_context == -1)
4107 dc1edbfa 2019-11-29 kn diff_context = 3;
4108 dc1edbfa 2019-11-29 kn else if (!show_patch)
4109 0429cd76 2020-09-15 naddy errx(1, "-C requires -p");
4110 dc1edbfa 2019-11-29 kn
4111 04ca23f4 2018-07-16 stsp cwd = getcwd(NULL, 0);
4112 04ca23f4 2018-07-16 stsp if (cwd == NULL) {
4113 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4114 04ca23f4 2018-07-16 stsp goto done;
4115 04ca23f4 2018-07-16 stsp }
4116 cffc0aa4 2019-02-05 stsp
4117 50f2fada 2020-04-24 stsp if (repo_path == NULL) {
4118 50f2fada 2020-04-24 stsp error = got_worktree_open(&worktree, cwd);
4119 50f2fada 2020-04-24 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4120 50f2fada 2020-04-24 stsp goto done;
4121 50f2fada 2020-04-24 stsp error = NULL;
4122 50f2fada 2020-04-24 stsp }
4123 cffc0aa4 2019-02-05 stsp
4124 603cdeb0 2020-10-22 stsp if (argc == 1) {
4125 e7301579 2019-03-18 stsp if (worktree) {
4126 e7301579 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
4127 e7301579 2019-03-18 stsp argv[0]);
4128 e7301579 2019-03-18 stsp if (error)
4129 e7301579 2019-03-18 stsp goto done;
4130 e7301579 2019-03-18 stsp } else {
4131 e7301579 2019-03-18 stsp path = strdup(argv[0]);
4132 e7301579 2019-03-18 stsp if (path == NULL) {
4133 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4134 e7301579 2019-03-18 stsp goto done;
4135 e7301579 2019-03-18 stsp }
4136 e7301579 2019-03-18 stsp }
4137 603cdeb0 2020-10-22 stsp } else if (argc != 0)
4138 cbd1af7a 2019-03-18 stsp usage_log();
4139 cbd1af7a 2019-03-18 stsp
4140 5486daa2 2019-05-11 stsp if (repo_path == NULL) {
4141 5486daa2 2019-05-11 stsp repo_path = worktree ?
4142 5486daa2 2019-05-11 stsp strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
4143 5486daa2 2019-05-11 stsp }
4144 04ca23f4 2018-07-16 stsp if (repo_path == NULL) {
4145 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4146 cffc0aa4 2019-02-05 stsp goto done;
4147 04ca23f4 2018-07-16 stsp }
4148 6098196c 2019-01-04 stsp
4149 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4150 d7d4f210 2018-03-12 stsp if (error != NULL)
4151 04ca23f4 2018-07-16 stsp goto done;
4152 f42b1b34 2018-03-12 stsp
4153 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
4154 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
4155 c02c541e 2019-03-29 stsp if (error)
4156 c02c541e 2019-03-29 stsp goto done;
4157 c02c541e 2019-03-29 stsp
4158 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
4159 84de9106 2020-12-26 stsp if (error)
4160 84de9106 2020-12-26 stsp goto done;
4161 84de9106 2020-12-26 stsp
4162 888b7d99 2020-12-26 stsp error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
4163 888b7d99 2020-12-26 stsp if (error)
4164 888b7d99 2020-12-26 stsp goto done;
4165 888b7d99 2020-12-26 stsp
4166 d142fc45 2018-04-01 stsp if (start_commit == NULL) {
4167 3235492e 2018-04-01 stsp struct got_reference *head_ref;
4168 d1fe46f9 2020-04-18 stsp struct got_commit_object *commit = NULL;
4169 1cc14b9f 2019-05-14 stsp error = got_ref_open(&head_ref, repo,
4170 1cc14b9f 2019-05-14 stsp worktree ? got_worktree_get_head_ref_name(worktree)
4171 1cc14b9f 2019-05-14 stsp : GOT_REF_HEAD, 0);
4172 3235492e 2018-04-01 stsp if (error != NULL)
4173 d1fe46f9 2020-04-18 stsp goto done;
4174 d1fe46f9 2020-04-18 stsp error = got_ref_resolve(&start_id, repo, head_ref);
4175 3235492e 2018-04-01 stsp got_ref_close(head_ref);
4176 3235492e 2018-04-01 stsp if (error != NULL)
4177 d1fe46f9 2020-04-18 stsp goto done;
4178 d1fe46f9 2020-04-18 stsp error = got_object_open_as_commit(&commit, repo,
4179 d1fe46f9 2020-04-18 stsp start_id);
4180 d1fe46f9 2020-04-18 stsp if (error != NULL)
4181 d1fe46f9 2020-04-18 stsp goto done;
4182 d1fe46f9 2020-04-18 stsp got_object_commit_close(commit);
4183 3235492e 2018-04-01 stsp } else {
4184 7f9bfb31 2020-11-01 stsp error = got_repo_match_object_id(&start_id, NULL,
4185 84de9106 2020-12-26 stsp start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4186 d1fe46f9 2020-04-18 stsp if (error != NULL)
4187 d1fe46f9 2020-04-18 stsp goto done;
4188 3235492e 2018-04-01 stsp }
4189 d1fe46f9 2020-04-18 stsp if (end_commit != NULL) {
4190 7f9bfb31 2020-11-01 stsp error = got_repo_match_object_id(&end_id, NULL,
4191 84de9106 2020-12-26 stsp end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4192 d1fe46f9 2020-04-18 stsp if (error != NULL)
4193 d1fe46f9 2020-04-18 stsp goto done;
4194 d1fe46f9 2020-04-18 stsp }
4195 04ca23f4 2018-07-16 stsp
4196 deeabeae 2019-08-27 stsp if (worktree) {
4197 603cdeb0 2020-10-22 stsp /*
4198 603cdeb0 2020-10-22 stsp * If a path was specified on the command line it was resolved
4199 603cdeb0 2020-10-22 stsp * to a path in the work tree above. Prepend the work tree's
4200 603cdeb0 2020-10-22 stsp * path prefix to obtain the corresponding in-repository path.
4201 603cdeb0 2020-10-22 stsp */
4202 603cdeb0 2020-10-22 stsp if (path) {
4203 603cdeb0 2020-10-22 stsp const char *prefix;
4204 603cdeb0 2020-10-22 stsp prefix = got_worktree_get_path_prefix(worktree);
4205 603cdeb0 2020-10-22 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
4206 603cdeb0 2020-10-22 stsp (path[0] != '\0') ? "/" : "", path) == -1) {
4207 603cdeb0 2020-10-22 stsp error = got_error_from_errno("asprintf");
4208 603cdeb0 2020-10-22 stsp goto done;
4209 603cdeb0 2020-10-22 stsp }
4210 603cdeb0 2020-10-22 stsp }
4211 deeabeae 2019-08-27 stsp } else
4212 603cdeb0 2020-10-22 stsp error = got_repo_map_path(&in_repo_path, repo,
4213 8fa913ec 2020-11-14 stsp path ? path : "");
4214 04ca23f4 2018-07-16 stsp if (error != NULL)
4215 04ca23f4 2018-07-16 stsp goto done;
4216 04ca23f4 2018-07-16 stsp if (in_repo_path) {
4217 04ca23f4 2018-07-16 stsp free(path);
4218 04ca23f4 2018-07-16 stsp path = in_repo_path;
4219 04ca23f4 2018-07-16 stsp }
4220 199a4027 2019-02-02 stsp
4221 603cdeb0 2020-10-22 stsp error = print_commits(start_id, end_id, repo, path ? path : "",
4222 603cdeb0 2020-10-22 stsp show_changed_paths, show_patch, search_pattern, diff_context,
4223 888b7d99 2020-12-26 stsp limit, log_branches, reverse_display_order, refs_idmap);
4224 04ca23f4 2018-07-16 stsp done:
4225 04ca23f4 2018-07-16 stsp free(path);
4226 04ca23f4 2018-07-16 stsp free(repo_path);
4227 04ca23f4 2018-07-16 stsp free(cwd);
4228 cffc0aa4 2019-02-05 stsp if (worktree)
4229 cffc0aa4 2019-02-05 stsp got_worktree_close(worktree);
4230 ad242220 2018-09-08 stsp if (repo) {
4231 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
4232 ad242220 2018-09-08 stsp if (error == NULL)
4233 1d0f4054 2021-06-17 stsp error = close_err;
4234 ad242220 2018-09-08 stsp }
4235 888b7d99 2020-12-26 stsp if (refs_idmap)
4236 888b7d99 2020-12-26 stsp got_reflist_object_id_map_free(refs_idmap);
4237 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
4238 8bf5b3c9 2018-03-17 stsp return error;
4239 5c860e29 2018-03-12 stsp }
4240 5c860e29 2018-03-12 stsp
4241 4ed7e80c 2018-05-20 stsp __dead static void
4242 3f8b7d6a 2018-04-01 stsp usage_diff(void)
4243 3f8b7d6a 2018-04-01 stsp {
4244 64453f7e 2020-11-21 stsp fprintf(stderr, "usage: %s diff [-a] [-C number] [-r repository-path] "
4245 64453f7e 2020-11-21 stsp "[-s] [-w] [object1 object2 | path]\n", getprogname());
4246 3f8b7d6a 2018-04-01 stsp exit(1);
4247 b00d56cd 2018-04-01 stsp }
4248 b00d56cd 2018-04-01 stsp
4249 b72f483a 2019-02-05 stsp struct print_diff_arg {
4250 b72f483a 2019-02-05 stsp struct got_repository *repo;
4251 b72f483a 2019-02-05 stsp struct got_worktree *worktree;
4252 b72f483a 2019-02-05 stsp int diff_context;
4253 3fc0c068 2019-02-10 stsp const char *id_str;
4254 3fc0c068 2019-02-10 stsp int header_shown;
4255 98eaaa12 2019-08-03 stsp int diff_staged;
4256 63035f9f 2019-10-06 stsp int ignore_whitespace;
4257 64453f7e 2020-11-21 stsp int force_text_diff;
4258 b72f483a 2019-02-05 stsp };
4259 39449a05 2020-07-23 stsp
4260 39449a05 2020-07-23 stsp /*
4261 39449a05 2020-07-23 stsp * Create a file which contains the target path of a symlink so we can feed
4262 39449a05 2020-07-23 stsp * it as content to the diff engine.
4263 39449a05 2020-07-23 stsp */
4264 39449a05 2020-07-23 stsp static const struct got_error *
4265 39449a05 2020-07-23 stsp get_symlink_target_file(int *fd, int dirfd, const char *de_name,
4266 39449a05 2020-07-23 stsp const char *abspath)
4267 39449a05 2020-07-23 stsp {
4268 39449a05 2020-07-23 stsp const struct got_error *err = NULL;
4269 39449a05 2020-07-23 stsp char target_path[PATH_MAX];
4270 39449a05 2020-07-23 stsp ssize_t target_len, outlen;
4271 39449a05 2020-07-23 stsp
4272 39449a05 2020-07-23 stsp *fd = -1;
4273 39449a05 2020-07-23 stsp
4274 39449a05 2020-07-23 stsp if (dirfd != -1) {
4275 39449a05 2020-07-23 stsp target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
4276 39449a05 2020-07-23 stsp if (target_len == -1)
4277 39449a05 2020-07-23 stsp return got_error_from_errno2("readlinkat", abspath);
4278 39449a05 2020-07-23 stsp } else {
4279 39449a05 2020-07-23 stsp target_len = readlink(abspath, target_path, PATH_MAX);
4280 39449a05 2020-07-23 stsp if (target_len == -1)
4281 39449a05 2020-07-23 stsp return got_error_from_errno2("readlink", abspath);
4282 39449a05 2020-07-23 stsp }
4283 39449a05 2020-07-23 stsp
4284 39449a05 2020-07-23 stsp *fd = got_opentempfd();
4285 39449a05 2020-07-23 stsp if (*fd == -1)
4286 39449a05 2020-07-23 stsp return got_error_from_errno("got_opentempfd");
4287 39449a05 2020-07-23 stsp
4288 39449a05 2020-07-23 stsp outlen = write(*fd, target_path, target_len);
4289 39449a05 2020-07-23 stsp if (outlen == -1) {
4290 39449a05 2020-07-23 stsp err = got_error_from_errno("got_opentempfd");
4291 39449a05 2020-07-23 stsp goto done;
4292 39449a05 2020-07-23 stsp }
4293 39449a05 2020-07-23 stsp
4294 39449a05 2020-07-23 stsp if (lseek(*fd, 0, SEEK_SET) == -1) {
4295 39449a05 2020-07-23 stsp err = got_error_from_errno2("lseek", abspath);
4296 39449a05 2020-07-23 stsp goto done;
4297 39449a05 2020-07-23 stsp }
4298 39449a05 2020-07-23 stsp done:
4299 39449a05 2020-07-23 stsp if (err) {
4300 39449a05 2020-07-23 stsp close(*fd);
4301 39449a05 2020-07-23 stsp *fd = -1;
4302 39449a05 2020-07-23 stsp }
4303 39449a05 2020-07-23 stsp return err;
4304 39449a05 2020-07-23 stsp }
4305 b72f483a 2019-02-05 stsp
4306 4ed7e80c 2018-05-20 stsp static const struct got_error *
4307 88d0e355 2019-08-03 stsp print_diff(void *arg, unsigned char status, unsigned char staged_status,
4308 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
4309 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4310 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
4311 b72f483a 2019-02-05 stsp {
4312 b72f483a 2019-02-05 stsp struct print_diff_arg *a = arg;
4313 b72f483a 2019-02-05 stsp const struct got_error *err = NULL;
4314 b72f483a 2019-02-05 stsp struct got_blob_object *blob1 = NULL;
4315 12463d8b 2019-12-13 stsp int fd = -1;
4316 b72f483a 2019-02-05 stsp FILE *f2 = NULL;
4317 4ce46740 2019-08-08 stsp char *abspath = NULL, *label1 = NULL;
4318 b72f483a 2019-02-05 stsp struct stat sb;
4319 b72f483a 2019-02-05 stsp
4320 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
4321 98eaaa12 2019-08-03 stsp if (staged_status != GOT_STATUS_MODIFY &&
4322 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_ADD &&
4323 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
4324 98eaaa12 2019-08-03 stsp return NULL;
4325 98eaaa12 2019-08-03 stsp } else {
4326 98eaaa12 2019-08-03 stsp if (staged_status == GOT_STATUS_DELETE)
4327 98eaaa12 2019-08-03 stsp return NULL;
4328 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
4329 2a06fe5f 2019-08-24 stsp return got_error_set_errno(ENOENT, path);
4330 98eaaa12 2019-08-03 stsp if (status != GOT_STATUS_MODIFY &&
4331 98eaaa12 2019-08-03 stsp status != GOT_STATUS_ADD &&
4332 98eaaa12 2019-08-03 stsp status != GOT_STATUS_DELETE &&
4333 98eaaa12 2019-08-03 stsp status != GOT_STATUS_CONFLICT)
4334 98eaaa12 2019-08-03 stsp return NULL;
4335 98eaaa12 2019-08-03 stsp }
4336 3fc0c068 2019-02-10 stsp
4337 3fc0c068 2019-02-10 stsp if (!a->header_shown) {
4338 98eaaa12 2019-08-03 stsp printf("diff %s %s%s\n", a->id_str,
4339 98eaaa12 2019-08-03 stsp got_worktree_get_root_path(a->worktree),
4340 98eaaa12 2019-08-03 stsp a->diff_staged ? " (staged changes)" : "");
4341 3fc0c068 2019-02-10 stsp a->header_shown = 1;
4342 3fc0c068 2019-02-10 stsp }
4343 b72f483a 2019-02-05 stsp
4344 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
4345 98eaaa12 2019-08-03 stsp const char *label1 = NULL, *label2 = NULL;
4346 98eaaa12 2019-08-03 stsp switch (staged_status) {
4347 98eaaa12 2019-08-03 stsp case GOT_STATUS_MODIFY:
4348 98eaaa12 2019-08-03 stsp label1 = path;
4349 98eaaa12 2019-08-03 stsp label2 = path;
4350 98eaaa12 2019-08-03 stsp break;
4351 98eaaa12 2019-08-03 stsp case GOT_STATUS_ADD:
4352 98eaaa12 2019-08-03 stsp label2 = path;
4353 98eaaa12 2019-08-03 stsp break;
4354 98eaaa12 2019-08-03 stsp case GOT_STATUS_DELETE:
4355 98eaaa12 2019-08-03 stsp label1 = path;
4356 98eaaa12 2019-08-03 stsp break;
4357 98eaaa12 2019-08-03 stsp default:
4358 98eaaa12 2019-08-03 stsp return got_error(GOT_ERR_FILE_STATUS);
4359 98eaaa12 2019-08-03 stsp }
4360 fe621944 2020-11-10 stsp return got_diff_objects_as_blobs(NULL, NULL, blob_id,
4361 fe621944 2020-11-10 stsp staged_blob_id, label1, label2, a->diff_context,
4362 64453f7e 2020-11-21 stsp a->ignore_whitespace, a->force_text_diff, a->repo, stdout);
4363 98eaaa12 2019-08-03 stsp }
4364 98eaaa12 2019-08-03 stsp
4365 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
4366 4ce46740 2019-08-08 stsp staged_status == GOT_STATUS_MODIFY) {
4367 4ce46740 2019-08-08 stsp char *id_str;
4368 408b4ebc 2019-08-03 stsp err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
4369 408b4ebc 2019-08-03 stsp 8192);
4370 4ce46740 2019-08-08 stsp if (err)
4371 4ce46740 2019-08-08 stsp goto done;
4372 4ce46740 2019-08-08 stsp err = got_object_id_str(&id_str, staged_blob_id);
4373 4ce46740 2019-08-08 stsp if (err)
4374 4ce46740 2019-08-08 stsp goto done;
4375 4ce46740 2019-08-08 stsp if (asprintf(&label1, "%s (staged)", id_str) == -1) {
4376 4ce46740 2019-08-08 stsp err = got_error_from_errno("asprintf");
4377 4ce46740 2019-08-08 stsp free(id_str);
4378 4ce46740 2019-08-08 stsp goto done;
4379 4ce46740 2019-08-08 stsp }
4380 4ce46740 2019-08-08 stsp free(id_str);
4381 4ce46740 2019-08-08 stsp } else if (status != GOT_STATUS_ADD) {
4382 016a88dd 2019-05-13 stsp err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192);
4383 4ce46740 2019-08-08 stsp if (err)
4384 4ce46740 2019-08-08 stsp goto done;
4385 4ce46740 2019-08-08 stsp }
4386 d00136be 2019-03-26 stsp
4387 7154f6ce 2019-03-27 stsp if (status != GOT_STATUS_DELETE) {
4388 2ec1f75b 2019-03-26 stsp if (asprintf(&abspath, "%s/%s",
4389 2ec1f75b 2019-03-26 stsp got_worktree_get_root_path(a->worktree), path) == -1) {
4390 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
4391 2ec1f75b 2019-03-26 stsp goto done;
4392 2ec1f75b 2019-03-26 stsp }
4393 b72f483a 2019-02-05 stsp
4394 12463d8b 2019-12-13 stsp if (dirfd != -1) {
4395 12463d8b 2019-12-13 stsp fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
4396 12463d8b 2019-12-13 stsp if (fd == -1) {
4397 39449a05 2020-07-23 stsp if (errno != ELOOP) {
4398 39449a05 2020-07-23 stsp err = got_error_from_errno2("openat",
4399 39449a05 2020-07-23 stsp abspath);
4400 39449a05 2020-07-23 stsp goto done;
4401 39449a05 2020-07-23 stsp }
4402 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
4403 39449a05 2020-07-23 stsp de_name, abspath);
4404 39449a05 2020-07-23 stsp if (err)
4405 39449a05 2020-07-23 stsp goto done;
4406 12463d8b 2019-12-13 stsp }
4407 12463d8b 2019-12-13 stsp } else {
4408 12463d8b 2019-12-13 stsp fd = open(abspath, O_RDONLY | O_NOFOLLOW);
4409 12463d8b 2019-12-13 stsp if (fd == -1) {
4410 39449a05 2020-07-23 stsp if (errno != ELOOP) {
4411 39449a05 2020-07-23 stsp err = got_error_from_errno2("open",
4412 39449a05 2020-07-23 stsp abspath);
4413 39449a05 2020-07-23 stsp goto done;
4414 39449a05 2020-07-23 stsp }
4415 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
4416 39449a05 2020-07-23 stsp de_name, abspath);
4417 39449a05 2020-07-23 stsp if (err)
4418 39449a05 2020-07-23 stsp goto done;
4419 12463d8b 2019-12-13 stsp }
4420 12463d8b 2019-12-13 stsp }
4421 12463d8b 2019-12-13 stsp if (fstat(fd, &sb) == -1) {
4422 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fstat", abspath);
4423 2ec1f75b 2019-03-26 stsp goto done;
4424 2ec1f75b 2019-03-26 stsp }
4425 12463d8b 2019-12-13 stsp f2 = fdopen(fd, "r");
4426 12463d8b 2019-12-13 stsp if (f2 == NULL) {
4427 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fdopen", abspath);
4428 2ec1f75b 2019-03-26 stsp goto done;
4429 2ec1f75b 2019-03-26 stsp }
4430 12463d8b 2019-12-13 stsp fd = -1;
4431 2ec1f75b 2019-03-26 stsp } else
4432 2ec1f75b 2019-03-26 stsp sb.st_size = 0;
4433 b72f483a 2019-02-05 stsp
4434 4ce46740 2019-08-08 stsp err = got_diff_blob_file(blob1, label1, f2, sb.st_size, path,
4435 64453f7e 2020-11-21 stsp a->diff_context, a->ignore_whitespace, a->force_text_diff, stdout);
4436 b72f483a 2019-02-05 stsp done:
4437 b72f483a 2019-02-05 stsp if (blob1)
4438 b72f483a 2019-02-05 stsp got_object_blob_close(blob1);
4439 12463d8b 2019-12-13 stsp if (f2 && fclose(f2) == EOF && err == NULL)
4440 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
4441 12463d8b 2019-12-13 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
4442 12463d8b 2019-12-13 stsp err = got_error_from_errno("close");
4443 b72f483a 2019-02-05 stsp free(abspath);
4444 927df6b7 2019-02-10 stsp return err;
4445 927df6b7 2019-02-10 stsp }
4446 927df6b7 2019-02-10 stsp
4447 927df6b7 2019-02-10 stsp static const struct got_error *
4448 b00d56cd 2018-04-01 stsp cmd_diff(int argc, char *argv[])
4449 b00d56cd 2018-04-01 stsp {
4450 b00d56cd 2018-04-01 stsp const struct got_error *error;
4451 b00d56cd 2018-04-01 stsp struct got_repository *repo = NULL;
4452 b72f483a 2019-02-05 stsp struct got_worktree *worktree = NULL;
4453 b72f483a 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL;
4454 15a94983 2018-12-23 stsp struct got_object_id *id1 = NULL, *id2 = NULL;
4455 cd628e99 2019-05-28 stsp const char *id_str1 = NULL, *id_str2 = NULL;
4456 5e70831e 2019-05-28 stsp char *label1 = NULL, *label2 = NULL;
4457 15a94983 2018-12-23 stsp int type1, type2;
4458 63035f9f 2019-10-06 stsp int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch;
4459 64453f7e 2020-11-21 stsp int force_text_diff = 0;
4460 c0cc5c62 2018-10-18 stsp const char *errstr;
4461 927df6b7 2019-02-10 stsp char *path = NULL;
4462 84de9106 2020-12-26 stsp struct got_reflist_head refs;
4463 b00d56cd 2018-04-01 stsp
4464 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
4465 84de9106 2020-12-26 stsp
4466 b00d56cd 2018-04-01 stsp #ifndef PROFILE
4467 25eccc22 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4468 25eccc22 2019-01-04 stsp NULL) == -1)
4469 b00d56cd 2018-04-01 stsp err(1, "pledge");
4470 b00d56cd 2018-04-01 stsp #endif
4471 b00d56cd 2018-04-01 stsp
4472 64453f7e 2020-11-21 stsp while ((ch = getopt(argc, argv, "aC:r:sw")) != -1) {
4473 b00d56cd 2018-04-01 stsp switch (ch) {
4474 64453f7e 2020-11-21 stsp case 'a':
4475 64453f7e 2020-11-21 stsp force_text_diff = 1;
4476 64453f7e 2020-11-21 stsp break;
4477 c0cc5c62 2018-10-18 stsp case 'C':
4478 dfcab68b 2019-11-29 kn diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4479 dfcab68b 2019-11-29 kn &errstr);
4480 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
4481 c0cc5c62 2018-10-18 stsp err(1, "-C option %s", errstr);
4482 c0cc5c62 2018-10-18 stsp break;
4483 b72f483a 2019-02-05 stsp case 'r':
4484 b72f483a 2019-02-05 stsp repo_path = realpath(optarg, NULL);
4485 b72f483a 2019-02-05 stsp if (repo_path == NULL)
4486 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4487 9ba1d308 2019-10-21 stsp optarg);
4488 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4489 b72f483a 2019-02-05 stsp break;
4490 98eaaa12 2019-08-03 stsp case 's':
4491 98eaaa12 2019-08-03 stsp diff_staged = 1;
4492 63035f9f 2019-10-06 stsp break;
4493 63035f9f 2019-10-06 stsp case 'w':
4494 63035f9f 2019-10-06 stsp ignore_whitespace = 1;
4495 98eaaa12 2019-08-03 stsp break;
4496 b00d56cd 2018-04-01 stsp default:
4497 2deda0b9 2019-03-07 stsp usage_diff();
4498 b00d56cd 2018-04-01 stsp /* NOTREACHED */
4499 b00d56cd 2018-04-01 stsp }
4500 b00d56cd 2018-04-01 stsp }
4501 b00d56cd 2018-04-01 stsp
4502 b00d56cd 2018-04-01 stsp argc -= optind;
4503 b00d56cd 2018-04-01 stsp argv += optind;
4504 b00d56cd 2018-04-01 stsp
4505 b72f483a 2019-02-05 stsp cwd = getcwd(NULL, 0);
4506 b72f483a 2019-02-05 stsp if (cwd == NULL) {
4507 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4508 b72f483a 2019-02-05 stsp goto done;
4509 b72f483a 2019-02-05 stsp }
4510 927df6b7 2019-02-10 stsp if (argc <= 1) {
4511 b72f483a 2019-02-05 stsp if (repo_path)
4512 b72f483a 2019-02-05 stsp errx(1,
4513 b72f483a 2019-02-05 stsp "-r option can't be used when diffing a work tree");
4514 1f03b8da 2020-03-20 stsp error = got_worktree_open(&worktree, cwd);
4515 fa51e947 2020-03-27 stsp if (error) {
4516 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
4517 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "diff",
4518 fa51e947 2020-03-27 stsp cwd);
4519 1f03b8da 2020-03-20 stsp goto done;
4520 fa51e947 2020-03-27 stsp }
4521 b72f483a 2019-02-05 stsp repo_path = strdup(got_worktree_get_repo_path(worktree));
4522 927df6b7 2019-02-10 stsp if (repo_path == NULL) {
4523 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4524 927df6b7 2019-02-10 stsp goto done;
4525 927df6b7 2019-02-10 stsp }
4526 927df6b7 2019-02-10 stsp if (argc == 1) {
4527 6c7ab921 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
4528 cbd1af7a 2019-03-18 stsp argv[0]);
4529 927df6b7 2019-02-10 stsp if (error)
4530 927df6b7 2019-02-10 stsp goto done;
4531 927df6b7 2019-02-10 stsp } else {
4532 927df6b7 2019-02-10 stsp path = strdup("");
4533 927df6b7 2019-02-10 stsp if (path == NULL) {
4534 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4535 927df6b7 2019-02-10 stsp goto done;
4536 927df6b7 2019-02-10 stsp }
4537 927df6b7 2019-02-10 stsp }
4538 b72f483a 2019-02-05 stsp } else if (argc == 2) {
4539 98eaaa12 2019-08-03 stsp if (diff_staged)
4540 98eaaa12 2019-08-03 stsp errx(1, "-s option can't be used when diffing "
4541 98eaaa12 2019-08-03 stsp "objects in repository");
4542 15a94983 2018-12-23 stsp id_str1 = argv[0];
4543 15a94983 2018-12-23 stsp id_str2 = argv[1];
4544 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
4545 1f03b8da 2020-03-20 stsp error = got_worktree_open(&worktree, cwd);
4546 1f03b8da 2020-03-20 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4547 30db809c 2019-06-05 stsp goto done;
4548 1a1242a9 2021-04-01 kn repo_path = strdup(worktree ?
4549 1a1242a9 2021-04-01 kn got_worktree_get_repo_path(worktree) : cwd);
4550 1a1242a9 2021-04-01 kn if (repo_path == NULL) {
4551 1a1242a9 2021-04-01 kn error = got_error_from_errno("strdup");
4552 1a1242a9 2021-04-01 kn goto done;
4553 30db809c 2019-06-05 stsp }
4554 30db809c 2019-06-05 stsp }
4555 b00d56cd 2018-04-01 stsp } else
4556 b00d56cd 2018-04-01 stsp usage_diff();
4557 b00d56cd 2018-04-01 stsp
4558 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4559 76089277 2018-04-01 stsp free(repo_path);
4560 b00d56cd 2018-04-01 stsp if (error != NULL)
4561 b00d56cd 2018-04-01 stsp goto done;
4562 b00d56cd 2018-04-01 stsp
4563 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
4564 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
4565 c02c541e 2019-03-29 stsp if (error)
4566 c02c541e 2019-03-29 stsp goto done;
4567 c02c541e 2019-03-29 stsp
4568 30db809c 2019-06-05 stsp if (argc <= 1) {
4569 b72f483a 2019-02-05 stsp struct print_diff_arg arg;
4570 72ea6654 2019-07-27 stsp struct got_pathlist_head paths;
4571 b72f483a 2019-02-05 stsp char *id_str;
4572 72ea6654 2019-07-27 stsp
4573 72ea6654 2019-07-27 stsp TAILQ_INIT(&paths);
4574 72ea6654 2019-07-27 stsp
4575 b72f483a 2019-02-05 stsp error = got_object_id_str(&id_str,
4576 b72f483a 2019-02-05 stsp got_worktree_get_base_commit_id(worktree));
4577 b72f483a 2019-02-05 stsp if (error)
4578 b72f483a 2019-02-05 stsp goto done;
4579 b72f483a 2019-02-05 stsp arg.repo = repo;
4580 b72f483a 2019-02-05 stsp arg.worktree = worktree;
4581 b72f483a 2019-02-05 stsp arg.diff_context = diff_context;
4582 3fc0c068 2019-02-10 stsp arg.id_str = id_str;
4583 3fc0c068 2019-02-10 stsp arg.header_shown = 0;
4584 98eaaa12 2019-08-03 stsp arg.diff_staged = diff_staged;
4585 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
4586 64453f7e 2020-11-21 stsp arg.force_text_diff = force_text_diff;
4587 b72f483a 2019-02-05 stsp
4588 adc19d55 2019-07-28 stsp error = got_pathlist_append(&paths, path, NULL);
4589 72ea6654 2019-07-27 stsp if (error)
4590 72ea6654 2019-07-27 stsp goto done;
4591 72ea6654 2019-07-27 stsp
4592 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, 0,
4593 f6343036 2021-06-22 stsp print_diff, &arg, check_cancelled, NULL);
4594 b72f483a 2019-02-05 stsp free(id_str);
4595 72ea6654 2019-07-27 stsp got_pathlist_free(&paths);
4596 b72f483a 2019-02-05 stsp goto done;
4597 b72f483a 2019-02-05 stsp }
4598 84de9106 2020-12-26 stsp
4599 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
4600 84de9106 2020-12-26 stsp if (error)
4601 84de9106 2020-12-26 stsp return error;
4602 b72f483a 2019-02-05 stsp
4603 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id1, &label1, id_str1,
4604 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_ANY, &refs, repo);
4605 0adb7196 2019-08-11 stsp if (error)
4606 0adb7196 2019-08-11 stsp goto done;
4607 b00d56cd 2018-04-01 stsp
4608 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id2, &label2, id_str2,
4609 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_ANY, &refs, repo);
4610 0adb7196 2019-08-11 stsp if (error)
4611 0adb7196 2019-08-11 stsp goto done;
4612 b00d56cd 2018-04-01 stsp
4613 15a94983 2018-12-23 stsp error = got_object_get_type(&type1, repo, id1);
4614 15a94983 2018-12-23 stsp if (error)
4615 15a94983 2018-12-23 stsp goto done;
4616 15a94983 2018-12-23 stsp
4617 15a94983 2018-12-23 stsp error = got_object_get_type(&type2, repo, id2);
4618 15a94983 2018-12-23 stsp if (error)
4619 15a94983 2018-12-23 stsp goto done;
4620 15a94983 2018-12-23 stsp
4621 15a94983 2018-12-23 stsp if (type1 != type2) {
4622 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4623 b00d56cd 2018-04-01 stsp goto done;
4624 b00d56cd 2018-04-01 stsp }
4625 b00d56cd 2018-04-01 stsp
4626 15a94983 2018-12-23 stsp switch (type1) {
4627 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_BLOB:
4628 fe621944 2020-11-10 stsp error = got_diff_objects_as_blobs(NULL, NULL, id1, id2,
4629 64453f7e 2020-11-21 stsp NULL, NULL, diff_context, ignore_whitespace,
4630 64453f7e 2020-11-21 stsp force_text_diff, repo, stdout);
4631 b00d56cd 2018-04-01 stsp break;
4632 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_TREE:
4633 fe621944 2020-11-10 stsp error = got_diff_objects_as_trees(NULL, NULL, id1, id2,
4634 64453f7e 2020-11-21 stsp "", "", diff_context, ignore_whitespace, force_text_diff,
4635 64453f7e 2020-11-21 stsp repo, stdout);
4636 b00d56cd 2018-04-01 stsp break;
4637 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_COMMIT:
4638 5e70831e 2019-05-28 stsp printf("diff %s %s\n", label1, label2);
4639 fe621944 2020-11-10 stsp error = got_diff_objects_as_commits(NULL, NULL, id1, id2,
4640 64453f7e 2020-11-21 stsp diff_context, ignore_whitespace, force_text_diff, repo,
4641 64453f7e 2020-11-21 stsp stdout);
4642 b00d56cd 2018-04-01 stsp break;
4643 b00d56cd 2018-04-01 stsp default:
4644 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4645 b00d56cd 2018-04-01 stsp }
4646 b00d56cd 2018-04-01 stsp done:
4647 5e70831e 2019-05-28 stsp free(label1);
4648 5e70831e 2019-05-28 stsp free(label2);
4649 15a94983 2018-12-23 stsp free(id1);
4650 15a94983 2018-12-23 stsp free(id2);
4651 927df6b7 2019-02-10 stsp free(path);
4652 b72f483a 2019-02-05 stsp if (worktree)
4653 b72f483a 2019-02-05 stsp got_worktree_close(worktree);
4654 ad242220 2018-09-08 stsp if (repo) {
4655 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
4656 ad242220 2018-09-08 stsp if (error == NULL)
4657 1d0f4054 2021-06-17 stsp error = close_err;
4658 ad242220 2018-09-08 stsp }
4659 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
4660 b00d56cd 2018-04-01 stsp return error;
4661 404c43c4 2018-06-21 stsp }
4662 404c43c4 2018-06-21 stsp
4663 404c43c4 2018-06-21 stsp __dead static void
4664 404c43c4 2018-06-21 stsp usage_blame(void)
4665 404c43c4 2018-06-21 stsp {
4666 9270e621 2019-02-05 stsp fprintf(stderr,
4667 9270e621 2019-02-05 stsp "usage: %s blame [-c commit] [-r repository-path] path\n",
4668 404c43c4 2018-06-21 stsp getprogname());
4669 404c43c4 2018-06-21 stsp exit(1);
4670 b00d56cd 2018-04-01 stsp }
4671 b00d56cd 2018-04-01 stsp
4672 28315671 2019-08-14 stsp struct blame_line {
4673 28315671 2019-08-14 stsp int annotated;
4674 28315671 2019-08-14 stsp char *id_str;
4675 82f6abb8 2019-08-14 stsp char *committer;
4676 11db6024 2019-10-21 stsp char datebuf[11]; /* YYYY-MM-DD + NUL */
4677 28315671 2019-08-14 stsp };
4678 28315671 2019-08-14 stsp
4679 28315671 2019-08-14 stsp struct blame_cb_args {
4680 28315671 2019-08-14 stsp struct blame_line *lines;
4681 28315671 2019-08-14 stsp int nlines;
4682 7ef28ff8 2019-08-14 stsp int nlines_prec;
4683 28315671 2019-08-14 stsp int lineno_cur;
4684 28315671 2019-08-14 stsp off_t *line_offsets;
4685 28315671 2019-08-14 stsp FILE *f;
4686 82f6abb8 2019-08-14 stsp struct got_repository *repo;
4687 28315671 2019-08-14 stsp };
4688 28315671 2019-08-14 stsp
4689 404c43c4 2018-06-21 stsp static const struct got_error *
4690 28315671 2019-08-14 stsp blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
4691 28315671 2019-08-14 stsp {
4692 28315671 2019-08-14 stsp const struct got_error *err = NULL;
4693 28315671 2019-08-14 stsp struct blame_cb_args *a = arg;
4694 28315671 2019-08-14 stsp struct blame_line *bline;
4695 82f6abb8 2019-08-14 stsp char *line = NULL;
4696 28315671 2019-08-14 stsp size_t linesize = 0;
4697 82f6abb8 2019-08-14 stsp struct got_commit_object *commit = NULL;
4698 28315671 2019-08-14 stsp off_t offset;
4699 bcb49d15 2019-08-14 stsp struct tm tm;
4700 bcb49d15 2019-08-14 stsp time_t committer_time;
4701 28315671 2019-08-14 stsp
4702 28315671 2019-08-14 stsp if (nlines != a->nlines ||
4703 28315671 2019-08-14 stsp (lineno != -1 && lineno < 1) || lineno > a->nlines)
4704 28315671 2019-08-14 stsp return got_error(GOT_ERR_RANGE);
4705 28315671 2019-08-14 stsp
4706 28315671 2019-08-14 stsp if (sigint_received)
4707 28315671 2019-08-14 stsp return got_error(GOT_ERR_ITER_COMPLETED);
4708 28315671 2019-08-14 stsp
4709 2839f8b9 2019-08-18 stsp if (lineno == -1)
4710 2839f8b9 2019-08-18 stsp return NULL; /* no change in this commit */
4711 2839f8b9 2019-08-18 stsp
4712 28315671 2019-08-14 stsp /* Annotate this line. */
4713 28315671 2019-08-14 stsp bline = &a->lines[lineno - 1];
4714 28315671 2019-08-14 stsp if (bline->annotated)
4715 28315671 2019-08-14 stsp return NULL;
4716 28315671 2019-08-14 stsp err = got_object_id_str(&bline->id_str, id);
4717 28315671 2019-08-14 stsp if (err)
4718 28315671 2019-08-14 stsp return err;
4719 82f6abb8 2019-08-14 stsp
4720 82f6abb8 2019-08-14 stsp err = got_object_open_as_commit(&commit, a->repo, id);
4721 82f6abb8 2019-08-14 stsp if (err)
4722 82f6abb8 2019-08-14 stsp goto done;
4723 82f6abb8 2019-08-14 stsp
4724 82f6abb8 2019-08-14 stsp bline->committer = strdup(got_object_commit_get_committer(commit));
4725 82f6abb8 2019-08-14 stsp if (bline->committer == NULL) {
4726 82f6abb8 2019-08-14 stsp err = got_error_from_errno("strdup");
4727 bcb49d15 2019-08-14 stsp goto done;
4728 bcb49d15 2019-08-14 stsp }
4729 bcb49d15 2019-08-14 stsp
4730 bcb49d15 2019-08-14 stsp committer_time = got_object_commit_get_committer_time(commit);
4731 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
4732 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
4733 6db9f7f6 2019-12-10 stsp if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
4734 ec6d1a36 2021-03-21 jrick &tm) == 0) {
4735 bcb49d15 2019-08-14 stsp err = got_error(GOT_ERR_NO_SPACE);
4736 82f6abb8 2019-08-14 stsp goto done;
4737 82f6abb8 2019-08-14 stsp }
4738 28315671 2019-08-14 stsp bline->annotated = 1;
4739 28315671 2019-08-14 stsp
4740 28315671 2019-08-14 stsp /* Print lines annotated so far. */
4741 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4742 28315671 2019-08-14 stsp if (!bline->annotated)
4743 82f6abb8 2019-08-14 stsp goto done;
4744 28315671 2019-08-14 stsp
4745 28315671 2019-08-14 stsp offset = a->line_offsets[a->lineno_cur - 1];
4746 82f6abb8 2019-08-14 stsp if (fseeko(a->f, offset, SEEK_SET) == -1) {
4747 82f6abb8 2019-08-14 stsp err = got_error_from_errno("fseeko");
4748 82f6abb8 2019-08-14 stsp goto done;
4749 82f6abb8 2019-08-14 stsp }
4750 28315671 2019-08-14 stsp
4751 28315671 2019-08-14 stsp while (bline->annotated) {
4752 82f6abb8 2019-08-14 stsp char *smallerthan, *at, *nl, *committer;
4753 82f6abb8 2019-08-14 stsp size_t len;
4754 82f6abb8 2019-08-14 stsp
4755 500467ff 2019-09-25 hiltjo if (getline(&line, &linesize, a->f) == -1) {
4756 28315671 2019-08-14 stsp if (ferror(a->f))
4757 28315671 2019-08-14 stsp err = got_error_from_errno("getline");
4758 28315671 2019-08-14 stsp break;
4759 28315671 2019-08-14 stsp }
4760 82f6abb8 2019-08-14 stsp
4761 82f6abb8 2019-08-14 stsp committer = bline->committer;
4762 82f6abb8 2019-08-14 stsp smallerthan = strchr(committer, '<');
4763 82f6abb8 2019-08-14 stsp if (smallerthan && smallerthan[1] != '\0')
4764 82f6abb8 2019-08-14 stsp committer = smallerthan + 1;
4765 82f6abb8 2019-08-14 stsp at = strchr(committer, '@');
4766 82f6abb8 2019-08-14 stsp if (at)
4767 82f6abb8 2019-08-14 stsp *at = '\0';
4768 82f6abb8 2019-08-14 stsp len = strlen(committer);
4769 82f6abb8 2019-08-14 stsp if (len >= 9)
4770 82f6abb8 2019-08-14 stsp committer[8] = '\0';
4771 28315671 2019-08-14 stsp
4772 28315671 2019-08-14 stsp nl = strchr(line, '\n');
4773 28315671 2019-08-14 stsp if (nl)
4774 28315671 2019-08-14 stsp *nl = '\0';
4775 bcb49d15 2019-08-14 stsp printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
4776 bcb49d15 2019-08-14 stsp bline->id_str, bline->datebuf, committer, line);
4777 28315671 2019-08-14 stsp
4778 28315671 2019-08-14 stsp a->lineno_cur++;
4779 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4780 28315671 2019-08-14 stsp }
4781 82f6abb8 2019-08-14 stsp done:
4782 82f6abb8 2019-08-14 stsp if (commit)
4783 82f6abb8 2019-08-14 stsp got_object_commit_close(commit);
4784 28315671 2019-08-14 stsp free(line);
4785 28315671 2019-08-14 stsp return err;
4786 28315671 2019-08-14 stsp }
4787 28315671 2019-08-14 stsp
4788 28315671 2019-08-14 stsp static const struct got_error *
4789 404c43c4 2018-06-21 stsp cmd_blame(int argc, char *argv[])
4790 404c43c4 2018-06-21 stsp {
4791 404c43c4 2018-06-21 stsp const struct got_error *error;
4792 404c43c4 2018-06-21 stsp struct got_repository *repo = NULL;
4793 0c06baac 2019-02-05 stsp struct got_worktree *worktree = NULL;
4794 66bea077 2018-08-02 stsp char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
4795 0587e10c 2020-07-23 stsp char *link_target = NULL;
4796 28315671 2019-08-14 stsp struct got_object_id *obj_id = NULL;
4797 404c43c4 2018-06-21 stsp struct got_object_id *commit_id = NULL;
4798 28315671 2019-08-14 stsp struct got_blob_object *blob = NULL;
4799 404c43c4 2018-06-21 stsp char *commit_id_str = NULL;
4800 28315671 2019-08-14 stsp struct blame_cb_args bca;
4801 28315671 2019-08-14 stsp int ch, obj_type, i;
4802 be659d10 2020-11-18 stsp off_t filesize;
4803 90f3c347 2019-08-19 stsp
4804 90f3c347 2019-08-19 stsp memset(&bca, 0, sizeof(bca));
4805 404c43c4 2018-06-21 stsp
4806 404c43c4 2018-06-21 stsp #ifndef PROFILE
4807 36e2fb66 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4808 36e2fb66 2019-01-04 stsp NULL) == -1)
4809 404c43c4 2018-06-21 stsp err(1, "pledge");
4810 404c43c4 2018-06-21 stsp #endif
4811 404c43c4 2018-06-21 stsp
4812 66bea077 2018-08-02 stsp while ((ch = getopt(argc, argv, "c:r:")) != -1) {
4813 404c43c4 2018-06-21 stsp switch (ch) {
4814 404c43c4 2018-06-21 stsp case 'c':
4815 404c43c4 2018-06-21 stsp commit_id_str = optarg;
4816 404c43c4 2018-06-21 stsp break;
4817 66bea077 2018-08-02 stsp case 'r':
4818 66bea077 2018-08-02 stsp repo_path = realpath(optarg, NULL);
4819 66bea077 2018-08-02 stsp if (repo_path == NULL)
4820 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4821 9ba1d308 2019-10-21 stsp optarg);
4822 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4823 66bea077 2018-08-02 stsp break;
4824 404c43c4 2018-06-21 stsp default:
4825 2deda0b9 2019-03-07 stsp usage_blame();
4826 404c43c4 2018-06-21 stsp /* NOTREACHED */
4827 404c43c4 2018-06-21 stsp }
4828 404c43c4 2018-06-21 stsp }
4829 404c43c4 2018-06-21 stsp
4830 404c43c4 2018-06-21 stsp argc -= optind;
4831 404c43c4 2018-06-21 stsp argv += optind;
4832 404c43c4 2018-06-21 stsp
4833 a39318fd 2018-08-02 stsp if (argc == 1)
4834 404c43c4 2018-06-21 stsp path = argv[0];
4835 a39318fd 2018-08-02 stsp else
4836 404c43c4 2018-06-21 stsp usage_blame();
4837 404c43c4 2018-06-21 stsp
4838 66bea077 2018-08-02 stsp cwd = getcwd(NULL, 0);
4839 66bea077 2018-08-02 stsp if (cwd == NULL) {
4840 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4841 66bea077 2018-08-02 stsp goto done;
4842 66bea077 2018-08-02 stsp }
4843 66bea077 2018-08-02 stsp if (repo_path == NULL) {
4844 0c06baac 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
4845 0c06baac 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4846 66bea077 2018-08-02 stsp goto done;
4847 0c06baac 2019-02-05 stsp else
4848 0c06baac 2019-02-05 stsp error = NULL;
4849 0c06baac 2019-02-05 stsp if (worktree) {
4850 0c06baac 2019-02-05 stsp repo_path =
4851 0c06baac 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
4852 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
4853 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4854 1f03b8da 2020-03-20 stsp if (error)
4855 1f03b8da 2020-03-20 stsp goto done;
4856 1f03b8da 2020-03-20 stsp }
4857 0c06baac 2019-02-05 stsp } else {
4858 0c06baac 2019-02-05 stsp repo_path = strdup(cwd);
4859 0c06baac 2019-02-05 stsp if (repo_path == NULL) {
4860 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4861 0c06baac 2019-02-05 stsp goto done;
4862 0c06baac 2019-02-05 stsp }
4863 66bea077 2018-08-02 stsp }
4864 66bea077 2018-08-02 stsp }
4865 36e2fb66 2019-01-04 stsp
4866 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4867 c02c541e 2019-03-29 stsp if (error != NULL)
4868 404c43c4 2018-06-21 stsp goto done;
4869 404c43c4 2018-06-21 stsp
4870 0c06baac 2019-02-05 stsp if (worktree) {
4871 6efaaa2d 2019-02-05 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
4872 01740607 2020-11-04 stsp char *p;
4873 01740607 2020-11-04 stsp
4874 01740607 2020-11-04 stsp error = got_worktree_resolve_path(&p, worktree, path);
4875 01740607 2020-11-04 stsp if (error)
4876 01740607 2020-11-04 stsp goto done;
4877 01740607 2020-11-04 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
4878 01740607 2020-11-04 stsp (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
4879 01740607 2020-11-04 stsp p) == -1) {
4880 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
4881 01740607 2020-11-04 stsp free(p);
4882 0c06baac 2019-02-05 stsp goto done;
4883 0c06baac 2019-02-05 stsp }
4884 0c06baac 2019-02-05 stsp free(p);
4885 01740607 2020-11-04 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
4886 0c06baac 2019-02-05 stsp } else {
4887 01740607 2020-11-04 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
4888 01740607 2020-11-04 stsp if (error)
4889 01740607 2020-11-04 stsp goto done;
4890 8fa913ec 2020-11-14 stsp error = got_repo_map_path(&in_repo_path, repo, path);
4891 0c06baac 2019-02-05 stsp }
4892 0c06baac 2019-02-05 stsp if (error)
4893 66bea077 2018-08-02 stsp goto done;
4894 66bea077 2018-08-02 stsp
4895 404c43c4 2018-06-21 stsp if (commit_id_str == NULL) {
4896 404c43c4 2018-06-21 stsp struct got_reference *head_ref;
4897 a0975128 2020-02-07 stsp error = got_ref_open(&head_ref, repo, worktree ?
4898 a0975128 2020-02-07 stsp got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0);
4899 404c43c4 2018-06-21 stsp if (error != NULL)
4900 66bea077 2018-08-02 stsp goto done;
4901 404c43c4 2018-06-21 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
4902 404c43c4 2018-06-21 stsp got_ref_close(head_ref);
4903 404c43c4 2018-06-21 stsp if (error != NULL)
4904 66bea077 2018-08-02 stsp goto done;
4905 404c43c4 2018-06-21 stsp } else {
4906 84de9106 2020-12-26 stsp struct got_reflist_head refs;
4907 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
4908 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
4909 84de9106 2020-12-26 stsp NULL);
4910 84de9106 2020-12-26 stsp if (error)
4911 84de9106 2020-12-26 stsp goto done;
4912 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
4913 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4914 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
4915 30837e32 2019-07-25 stsp if (error)
4916 66bea077 2018-08-02 stsp goto done;
4917 404c43c4 2018-06-21 stsp }
4918 404c43c4 2018-06-21 stsp
4919 0587e10c 2020-07-23 stsp error = got_object_resolve_symlinks(&link_target, in_repo_path,
4920 0587e10c 2020-07-23 stsp commit_id, repo);
4921 0587e10c 2020-07-23 stsp if (error)
4922 0587e10c 2020-07-23 stsp goto done;
4923 0587e10c 2020-07-23 stsp
4924 0587e10c 2020-07-23 stsp error = got_object_id_by_path(&obj_id, repo, commit_id,
4925 0587e10c 2020-07-23 stsp link_target ? link_target : in_repo_path);
4926 28315671 2019-08-14 stsp if (error)
4927 28315671 2019-08-14 stsp goto done;
4928 28315671 2019-08-14 stsp
4929 28315671 2019-08-14 stsp error = got_object_get_type(&obj_type, repo, obj_id);
4930 28315671 2019-08-14 stsp if (error)
4931 28315671 2019-08-14 stsp goto done;
4932 28315671 2019-08-14 stsp
4933 28315671 2019-08-14 stsp if (obj_type != GOT_OBJ_TYPE_BLOB) {
4934 eb59b6d4 2020-07-23 stsp error = got_error_path(link_target ? link_target : in_repo_path,
4935 eb59b6d4 2020-07-23 stsp GOT_ERR_OBJ_TYPE);
4936 28315671 2019-08-14 stsp goto done;
4937 28315671 2019-08-14 stsp }
4938 28315671 2019-08-14 stsp
4939 28315671 2019-08-14 stsp error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
4940 28315671 2019-08-14 stsp if (error)
4941 28315671 2019-08-14 stsp goto done;
4942 28315671 2019-08-14 stsp bca.f = got_opentemp();
4943 28315671 2019-08-14 stsp if (bca.f == NULL) {
4944 28315671 2019-08-14 stsp error = got_error_from_errno("got_opentemp");
4945 28315671 2019-08-14 stsp goto done;
4946 28315671 2019-08-14 stsp }
4947 b02560ec 2019-08-19 stsp error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
4948 28315671 2019-08-14 stsp &bca.line_offsets, bca.f, blob);
4949 7ef28ff8 2019-08-14 stsp if (error || bca.nlines == 0)
4950 28315671 2019-08-14 stsp goto done;
4951 28315671 2019-08-14 stsp
4952 b02560ec 2019-08-19 stsp /* Don't include \n at EOF in the blame line count. */
4953 b02560ec 2019-08-19 stsp if (bca.line_offsets[bca.nlines - 1] == filesize)
4954 b02560ec 2019-08-19 stsp bca.nlines--;
4955 b02560ec 2019-08-19 stsp
4956 28315671 2019-08-14 stsp bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
4957 28315671 2019-08-14 stsp if (bca.lines == NULL) {
4958 28315671 2019-08-14 stsp error = got_error_from_errno("calloc");
4959 28315671 2019-08-14 stsp goto done;
4960 28315671 2019-08-14 stsp }
4961 28315671 2019-08-14 stsp bca.lineno_cur = 1;
4962 7ef28ff8 2019-08-14 stsp bca.nlines_prec = 0;
4963 7ef28ff8 2019-08-14 stsp i = bca.nlines;
4964 7ef28ff8 2019-08-14 stsp while (i > 0) {
4965 7ef28ff8 2019-08-14 stsp i /= 10;
4966 7ef28ff8 2019-08-14 stsp bca.nlines_prec++;
4967 7ef28ff8 2019-08-14 stsp }
4968 82f6abb8 2019-08-14 stsp bca.repo = repo;
4969 7ef28ff8 2019-08-14 stsp
4970 0587e10c 2020-07-23 stsp error = got_blame(link_target ? link_target : in_repo_path, commit_id,
4971 0587e10c 2020-07-23 stsp repo, blame_cb, &bca, check_cancelled, NULL);
4972 404c43c4 2018-06-21 stsp done:
4973 66bea077 2018-08-02 stsp free(in_repo_path);
4974 0587e10c 2020-07-23 stsp free(link_target);
4975 66bea077 2018-08-02 stsp free(repo_path);
4976 66bea077 2018-08-02 stsp free(cwd);
4977 404c43c4 2018-06-21 stsp free(commit_id);
4978 28315671 2019-08-14 stsp free(obj_id);
4979 28315671 2019-08-14 stsp if (blob)
4980 28315671 2019-08-14 stsp got_object_blob_close(blob);
4981 0c06baac 2019-02-05 stsp if (worktree)
4982 0c06baac 2019-02-05 stsp got_worktree_close(worktree);
4983 ad242220 2018-09-08 stsp if (repo) {
4984 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
4985 ad242220 2018-09-08 stsp if (error == NULL)
4986 1d0f4054 2021-06-17 stsp error = close_err;
4987 ad242220 2018-09-08 stsp }
4988 3affba96 2019-09-22 stsp if (bca.lines) {
4989 3affba96 2019-09-22 stsp for (i = 0; i < bca.nlines; i++) {
4990 3affba96 2019-09-22 stsp struct blame_line *bline = &bca.lines[i];
4991 3affba96 2019-09-22 stsp free(bline->id_str);
4992 3affba96 2019-09-22 stsp free(bline->committer);
4993 3affba96 2019-09-22 stsp }
4994 3affba96 2019-09-22 stsp free(bca.lines);
4995 28315671 2019-08-14 stsp }
4996 28315671 2019-08-14 stsp free(bca.line_offsets);
4997 28315671 2019-08-14 stsp if (bca.f && fclose(bca.f) == EOF && error == NULL)
4998 28315671 2019-08-14 stsp error = got_error_from_errno("fclose");
4999 404c43c4 2018-06-21 stsp return error;
5000 5de5890b 2018-10-18 stsp }
5001 5de5890b 2018-10-18 stsp
5002 5de5890b 2018-10-18 stsp __dead static void
5003 5de5890b 2018-10-18 stsp usage_tree(void)
5004 5de5890b 2018-10-18 stsp {
5005 c1669e2e 2019-01-09 stsp fprintf(stderr,
5006 5d58be12 2020-05-17 stsp "usage: %s tree [-c commit] [-r repository-path] [-iR] [path]\n",
5007 5de5890b 2018-10-18 stsp getprogname());
5008 5de5890b 2018-10-18 stsp exit(1);
5009 5de5890b 2018-10-18 stsp }
5010 5de5890b 2018-10-18 stsp
5011 0d6c6ee3 2020-05-20 stsp static const struct got_error *
5012 c1669e2e 2019-01-09 stsp print_entry(struct got_tree_entry *te, const char *id, const char *path,
5013 0d6c6ee3 2020-05-20 stsp const char *root_path, struct got_repository *repo)
5014 c1669e2e 2019-01-09 stsp {
5015 0d6c6ee3 2020-05-20 stsp const struct got_error *err = NULL;
5016 c1669e2e 2019-01-09 stsp int is_root_path = (strcmp(path, root_path) == 0);
5017 848d6979 2019-08-12 stsp const char *modestr = "";
5018 56e0773d 2019-11-28 stsp mode_t mode = got_tree_entry_get_mode(te);
5019 0d6c6ee3 2020-05-20 stsp char *link_target = NULL;
5020 5de5890b 2018-10-18 stsp
5021 c1669e2e 2019-01-09 stsp path += strlen(root_path);
5022 c1669e2e 2019-01-09 stsp while (path[0] == '/')
5023 c1669e2e 2019-01-09 stsp path++;
5024 c1669e2e 2019-01-09 stsp
5025 63c5ca5d 2019-08-24 stsp if (got_object_tree_entry_is_submodule(te))
5026 63c5ca5d 2019-08-24 stsp modestr = "$";
5027 0d6c6ee3 2020-05-20 stsp else if (S_ISLNK(mode)) {
5028 0d6c6ee3 2020-05-20 stsp int i;
5029 0d6c6ee3 2020-05-20 stsp
5030 0d6c6ee3 2020-05-20 stsp err = got_tree_entry_get_symlink_target(&link_target, te, repo);
5031 0d6c6ee3 2020-05-20 stsp if (err)
5032 0d6c6ee3 2020-05-20 stsp return err;
5033 0d6c6ee3 2020-05-20 stsp for (i = 0; i < strlen(link_target); i++) {
5034 0d6c6ee3 2020-05-20 stsp if (!isprint((unsigned char)link_target[i]))
5035 0d6c6ee3 2020-05-20 stsp link_target[i] = '?';
5036 0d6c6ee3 2020-05-20 stsp }
5037 0d6c6ee3 2020-05-20 stsp
5038 848d6979 2019-08-12 stsp modestr = "@";
5039 0d6c6ee3 2020-05-20 stsp }
5040 56e0773d 2019-11-28 stsp else if (S_ISDIR(mode))
5041 848d6979 2019-08-12 stsp modestr = "/";
5042 56e0773d 2019-11-28 stsp else if (mode & S_IXUSR)
5043 848d6979 2019-08-12 stsp modestr = "*";
5044 848d6979 2019-08-12 stsp
5045 0d6c6ee3 2020-05-20 stsp printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
5046 0d6c6ee3 2020-05-20 stsp is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
5047 0d6c6ee3 2020-05-20 stsp link_target ? " -> ": "", link_target ? link_target : "");
5048 0d6c6ee3 2020-05-20 stsp
5049 0d6c6ee3 2020-05-20 stsp free(link_target);
5050 0d6c6ee3 2020-05-20 stsp return NULL;
5051 c1669e2e 2019-01-09 stsp }
5052 c1669e2e 2019-01-09 stsp
5053 5de5890b 2018-10-18 stsp static const struct got_error *
5054 5de5890b 2018-10-18 stsp print_tree(const char *path, struct got_object_id *commit_id,
5055 c1669e2e 2019-01-09 stsp int show_ids, int recurse, const char *root_path,
5056 c1669e2e 2019-01-09 stsp struct got_repository *repo)
5057 5de5890b 2018-10-18 stsp {
5058 5de5890b 2018-10-18 stsp const struct got_error *err = NULL;
5059 5de5890b 2018-10-18 stsp struct got_object_id *tree_id = NULL;
5060 5de5890b 2018-10-18 stsp struct got_tree_object *tree = NULL;
5061 56e0773d 2019-11-28 stsp int nentries, i;
5062 5de5890b 2018-10-18 stsp
5063 5de5890b 2018-10-18 stsp err = got_object_id_by_path(&tree_id, repo, commit_id, path);
5064 5de5890b 2018-10-18 stsp if (err)
5065 5de5890b 2018-10-18 stsp goto done;
5066 5de5890b 2018-10-18 stsp
5067 5de5890b 2018-10-18 stsp err = got_object_open_as_tree(&tree, repo, tree_id);
5068 5de5890b 2018-10-18 stsp if (err)
5069 5de5890b 2018-10-18 stsp goto done;
5070 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
5071 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
5072 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
5073 5de5890b 2018-10-18 stsp char *id = NULL;
5074 84453469 2018-11-11 stsp
5075 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
5076 84453469 2018-11-11 stsp break;
5077 84453469 2018-11-11 stsp
5078 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
5079 5de5890b 2018-10-18 stsp if (show_ids) {
5080 5de5890b 2018-10-18 stsp char *id_str;
5081 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str,
5082 56e0773d 2019-11-28 stsp got_tree_entry_get_id(te));
5083 5de5890b 2018-10-18 stsp if (err)
5084 5de5890b 2018-10-18 stsp goto done;
5085 5de5890b 2018-10-18 stsp if (asprintf(&id, "%s ", id_str) == -1) {
5086 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
5087 5de5890b 2018-10-18 stsp free(id_str);
5088 5de5890b 2018-10-18 stsp goto done;
5089 5de5890b 2018-10-18 stsp }
5090 5de5890b 2018-10-18 stsp free(id_str);
5091 5de5890b 2018-10-18 stsp }
5092 0d6c6ee3 2020-05-20 stsp err = print_entry(te, id, path, root_path, repo);
5093 5de5890b 2018-10-18 stsp free(id);
5094 0d6c6ee3 2020-05-20 stsp if (err)
5095 0d6c6ee3 2020-05-20 stsp goto done;
5096 c1669e2e 2019-01-09 stsp
5097 56e0773d 2019-11-28 stsp if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
5098 c1669e2e 2019-01-09 stsp char *child_path;
5099 c1669e2e 2019-01-09 stsp if (asprintf(&child_path, "%s%s%s", path,
5100 c1669e2e 2019-01-09 stsp path[0] == '/' && path[1] == '\0' ? "" : "/",
5101 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te)) == -1) {
5102 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
5103 c1669e2e 2019-01-09 stsp goto done;
5104 c1669e2e 2019-01-09 stsp }
5105 c1669e2e 2019-01-09 stsp err = print_tree(child_path, commit_id, show_ids, 1,
5106 c1669e2e 2019-01-09 stsp root_path, repo);
5107 c1669e2e 2019-01-09 stsp free(child_path);
5108 c1669e2e 2019-01-09 stsp if (err)
5109 c1669e2e 2019-01-09 stsp goto done;
5110 c1669e2e 2019-01-09 stsp }
5111 5de5890b 2018-10-18 stsp }
5112 5de5890b 2018-10-18 stsp done:
5113 5de5890b 2018-10-18 stsp if (tree)
5114 5de5890b 2018-10-18 stsp got_object_tree_close(tree);
5115 5de5890b 2018-10-18 stsp free(tree_id);
5116 5de5890b 2018-10-18 stsp return err;
5117 404c43c4 2018-06-21 stsp }
5118 404c43c4 2018-06-21 stsp
5119 5de5890b 2018-10-18 stsp static const struct got_error *
5120 5de5890b 2018-10-18 stsp cmd_tree(int argc, char *argv[])
5121 5de5890b 2018-10-18 stsp {
5122 5de5890b 2018-10-18 stsp const struct got_error *error;
5123 5de5890b 2018-10-18 stsp struct got_repository *repo = NULL;
5124 7a2c19d6 2019-02-05 stsp struct got_worktree *worktree = NULL;
5125 4e0a20a4 2020-03-23 tracey const char *path, *refname = NULL;
5126 7a2c19d6 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5127 5de5890b 2018-10-18 stsp struct got_object_id *commit_id = NULL;
5128 5de5890b 2018-10-18 stsp char *commit_id_str = NULL;
5129 c1669e2e 2019-01-09 stsp int show_ids = 0, recurse = 0;
5130 5de5890b 2018-10-18 stsp int ch;
5131 5de5890b 2018-10-18 stsp
5132 5de5890b 2018-10-18 stsp #ifndef PROFILE
5133 0f8d269b 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5134 0f8d269b 2019-01-04 stsp NULL) == -1)
5135 5de5890b 2018-10-18 stsp err(1, "pledge");
5136 5de5890b 2018-10-18 stsp #endif
5137 5de5890b 2018-10-18 stsp
5138 c1669e2e 2019-01-09 stsp while ((ch = getopt(argc, argv, "c:r:iR")) != -1) {
5139 5de5890b 2018-10-18 stsp switch (ch) {
5140 5de5890b 2018-10-18 stsp case 'c':
5141 5de5890b 2018-10-18 stsp commit_id_str = optarg;
5142 5de5890b 2018-10-18 stsp break;
5143 5de5890b 2018-10-18 stsp case 'r':
5144 5de5890b 2018-10-18 stsp repo_path = realpath(optarg, NULL);
5145 5de5890b 2018-10-18 stsp if (repo_path == NULL)
5146 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5147 9ba1d308 2019-10-21 stsp optarg);
5148 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
5149 5de5890b 2018-10-18 stsp break;
5150 5de5890b 2018-10-18 stsp case 'i':
5151 5de5890b 2018-10-18 stsp show_ids = 1;
5152 5de5890b 2018-10-18 stsp break;
5153 c1669e2e 2019-01-09 stsp case 'R':
5154 c1669e2e 2019-01-09 stsp recurse = 1;
5155 c1669e2e 2019-01-09 stsp break;
5156 5de5890b 2018-10-18 stsp default:
5157 2deda0b9 2019-03-07 stsp usage_tree();
5158 5de5890b 2018-10-18 stsp /* NOTREACHED */
5159 5de5890b 2018-10-18 stsp }
5160 5de5890b 2018-10-18 stsp }
5161 5de5890b 2018-10-18 stsp
5162 5de5890b 2018-10-18 stsp argc -= optind;
5163 5de5890b 2018-10-18 stsp argv += optind;
5164 5de5890b 2018-10-18 stsp
5165 5de5890b 2018-10-18 stsp if (argc == 1)
5166 5de5890b 2018-10-18 stsp path = argv[0];
5167 5de5890b 2018-10-18 stsp else if (argc > 1)
5168 5de5890b 2018-10-18 stsp usage_tree();
5169 5de5890b 2018-10-18 stsp else
5170 7a2c19d6 2019-02-05 stsp path = NULL;
5171 7a2c19d6 2019-02-05 stsp
5172 9bf7a39b 2019-02-05 stsp cwd = getcwd(NULL, 0);
5173 9bf7a39b 2019-02-05 stsp if (cwd == NULL) {
5174 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5175 9bf7a39b 2019-02-05 stsp goto done;
5176 9bf7a39b 2019-02-05 stsp }
5177 5de5890b 2018-10-18 stsp if (repo_path == NULL) {
5178 7a2c19d6 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
5179 8994de28 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5180 7a2c19d6 2019-02-05 stsp goto done;
5181 7a2c19d6 2019-02-05 stsp else
5182 7a2c19d6 2019-02-05 stsp error = NULL;
5183 7a2c19d6 2019-02-05 stsp if (worktree) {
5184 7a2c19d6 2019-02-05 stsp repo_path =
5185 7a2c19d6 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
5186 7a2c19d6 2019-02-05 stsp if (repo_path == NULL)
5187 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5188 7a2c19d6 2019-02-05 stsp if (error)
5189 7a2c19d6 2019-02-05 stsp goto done;
5190 7a2c19d6 2019-02-05 stsp } else {
5191 7a2c19d6 2019-02-05 stsp repo_path = strdup(cwd);
5192 7a2c19d6 2019-02-05 stsp if (repo_path == NULL) {
5193 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5194 7a2c19d6 2019-02-05 stsp goto done;
5195 7a2c19d6 2019-02-05 stsp }
5196 5de5890b 2018-10-18 stsp }
5197 5de5890b 2018-10-18 stsp }
5198 5de5890b 2018-10-18 stsp
5199 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5200 5de5890b 2018-10-18 stsp if (error != NULL)
5201 c02c541e 2019-03-29 stsp goto done;
5202 c02c541e 2019-03-29 stsp
5203 4fedbf4c 2020-11-07 stsp if (worktree) {
5204 4fedbf4c 2020-11-07 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
5205 4fedbf4c 2020-11-07 stsp char *p;
5206 5de5890b 2018-10-18 stsp
5207 4fedbf4c 2020-11-07 stsp if (path == NULL)
5208 4fedbf4c 2020-11-07 stsp path = "";
5209 4fedbf4c 2020-11-07 stsp error = got_worktree_resolve_path(&p, worktree, path);
5210 4fedbf4c 2020-11-07 stsp if (error)
5211 4fedbf4c 2020-11-07 stsp goto done;
5212 4fedbf4c 2020-11-07 stsp if (asprintf(&in_repo_path, "%s%s%s", prefix,
5213 4fedbf4c 2020-11-07 stsp (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5214 4fedbf4c 2020-11-07 stsp p) == -1) {
5215 4fedbf4c 2020-11-07 stsp error = got_error_from_errno("asprintf");
5216 9bf7a39b 2019-02-05 stsp free(p);
5217 4fedbf4c 2020-11-07 stsp goto done;
5218 4fedbf4c 2020-11-07 stsp }
5219 4fedbf4c 2020-11-07 stsp free(p);
5220 4fedbf4c 2020-11-07 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5221 4fedbf4c 2020-11-07 stsp if (error)
5222 4fedbf4c 2020-11-07 stsp goto done;
5223 4fedbf4c 2020-11-07 stsp } else {
5224 4fedbf4c 2020-11-07 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5225 4fedbf4c 2020-11-07 stsp if (error)
5226 4fedbf4c 2020-11-07 stsp goto done;
5227 4fedbf4c 2020-11-07 stsp if (path == NULL)
5228 9bf7a39b 2019-02-05 stsp path = "/";
5229 8fa913ec 2020-11-14 stsp error = got_repo_map_path(&in_repo_path, repo, path);
5230 9bf7a39b 2019-02-05 stsp if (error != NULL)
5231 9bf7a39b 2019-02-05 stsp goto done;
5232 9bf7a39b 2019-02-05 stsp }
5233 5de5890b 2018-10-18 stsp
5234 5de5890b 2018-10-18 stsp if (commit_id_str == NULL) {
5235 5de5890b 2018-10-18 stsp struct got_reference *head_ref;
5236 4e0a20a4 2020-03-23 tracey if (worktree)
5237 4e0a20a4 2020-03-23 tracey refname = got_worktree_get_head_ref_name(worktree);
5238 4e0a20a4 2020-03-23 tracey else
5239 4e0a20a4 2020-03-23 tracey refname = GOT_REF_HEAD;
5240 4e0a20a4 2020-03-23 tracey error = got_ref_open(&head_ref, repo, refname, 0);
5241 5de5890b 2018-10-18 stsp if (error != NULL)
5242 5de5890b 2018-10-18 stsp goto done;
5243 5de5890b 2018-10-18 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
5244 5de5890b 2018-10-18 stsp got_ref_close(head_ref);
5245 5de5890b 2018-10-18 stsp if (error != NULL)
5246 5de5890b 2018-10-18 stsp goto done;
5247 5de5890b 2018-10-18 stsp } else {
5248 84de9106 2020-12-26 stsp struct got_reflist_head refs;
5249 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5250 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5251 84de9106 2020-12-26 stsp NULL);
5252 84de9106 2020-12-26 stsp if (error)
5253 84de9106 2020-12-26 stsp goto done;
5254 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
5255 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5256 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
5257 30837e32 2019-07-25 stsp if (error)
5258 5de5890b 2018-10-18 stsp goto done;
5259 5de5890b 2018-10-18 stsp }
5260 5de5890b 2018-10-18 stsp
5261 c1669e2e 2019-01-09 stsp error = print_tree(in_repo_path, commit_id, show_ids, recurse,
5262 c1669e2e 2019-01-09 stsp in_repo_path, repo);
5263 5de5890b 2018-10-18 stsp done:
5264 5de5890b 2018-10-18 stsp free(in_repo_path);
5265 5de5890b 2018-10-18 stsp free(repo_path);
5266 5de5890b 2018-10-18 stsp free(cwd);
5267 5de5890b 2018-10-18 stsp free(commit_id);
5268 7a2c19d6 2019-02-05 stsp if (worktree)
5269 7a2c19d6 2019-02-05 stsp got_worktree_close(worktree);
5270 5de5890b 2018-10-18 stsp if (repo) {
5271 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
5272 5de5890b 2018-10-18 stsp if (error == NULL)
5273 1d0f4054 2021-06-17 stsp error = close_err;
5274 5de5890b 2018-10-18 stsp }
5275 5de5890b 2018-10-18 stsp return error;
5276 5de5890b 2018-10-18 stsp }
5277 5de5890b 2018-10-18 stsp
5278 6bad629b 2019-02-04 stsp __dead static void
5279 6bad629b 2019-02-04 stsp usage_status(void)
5280 6bad629b 2019-02-04 stsp {
5281 00357e4d 2021-09-14 tracey fprintf(stderr, "usage: %s status [-I] [-s status-codes ] "
5282 00357e4d 2021-09-14 tracey "[-S status-codes] [path ...]\n", getprogname());
5283 6bad629b 2019-02-04 stsp exit(1);
5284 6bad629b 2019-02-04 stsp }
5285 00357e4d 2021-09-14 tracey
5286 00357e4d 2021-09-14 tracey struct got_status_arg {
5287 00357e4d 2021-09-14 tracey char *status_codes;
5288 00357e4d 2021-09-14 tracey int suppress;
5289 00357e4d 2021-09-14 tracey };
5290 5c860e29 2018-03-12 stsp
5291 b72f483a 2019-02-05 stsp static const struct got_error *
5292 88d0e355 2019-08-03 stsp print_status(void *arg, unsigned char status, unsigned char staged_status,
5293 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
5294 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5295 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
5296 6bad629b 2019-02-04 stsp {
5297 00357e4d 2021-09-14 tracey struct got_status_arg *st = arg;
5298 00357e4d 2021-09-14 tracey
5299 244725f2 2019-08-03 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
5300 c363b2c1 2019-08-03 stsp status = GOT_STATUS_NO_CHANGE;
5301 00357e4d 2021-09-14 tracey if (st != NULL && st->status_codes) {
5302 00357e4d 2021-09-14 tracey size_t ncodes = strlen(st->status_codes);
5303 00357e4d 2021-09-14 tracey int i, j = 0;
5304 00357e4d 2021-09-14 tracey
5305 081470ac 2020-08-13 stsp for (i = 0; i < ncodes ; i++) {
5306 00357e4d 2021-09-14 tracey if (st->suppress) {
5307 00357e4d 2021-09-14 tracey if (status == st->status_codes[i] ||
5308 00357e4d 2021-09-14 tracey staged_status == st->status_codes[i]) {
5309 00357e4d 2021-09-14 tracey j++;
5310 00357e4d 2021-09-14 tracey continue;
5311 00357e4d 2021-09-14 tracey }
5312 00357e4d 2021-09-14 tracey } else {
5313 00357e4d 2021-09-14 tracey if (status == st->status_codes[i] ||
5314 00357e4d 2021-09-14 tracey staged_status == st->status_codes[i])
5315 00357e4d 2021-09-14 tracey break;
5316 00357e4d 2021-09-14 tracey }
5317 081470ac 2020-08-13 stsp }
5318 00357e4d 2021-09-14 tracey
5319 00357e4d 2021-09-14 tracey if (st->suppress && j == 0)
5320 00357e4d 2021-09-14 tracey goto print;
5321 00357e4d 2021-09-14 tracey
5322 081470ac 2020-08-13 stsp if (i == ncodes)
5323 081470ac 2020-08-13 stsp return NULL;
5324 081470ac 2020-08-13 stsp }
5325 00357e4d 2021-09-14 tracey print:
5326 88d0e355 2019-08-03 stsp printf("%c%c %s\n", status, staged_status, path);
5327 b72f483a 2019-02-05 stsp return NULL;
5328 6bad629b 2019-02-04 stsp }
5329 5c860e29 2018-03-12 stsp
5330 6bad629b 2019-02-04 stsp static const struct got_error *
5331 6bad629b 2019-02-04 stsp cmd_status(int argc, char *argv[])
5332 6bad629b 2019-02-04 stsp {
5333 6bad629b 2019-02-04 stsp const struct got_error *error = NULL;
5334 6bad629b 2019-02-04 stsp struct got_repository *repo = NULL;
5335 6bad629b 2019-02-04 stsp struct got_worktree *worktree = NULL;
5336 00357e4d 2021-09-14 tracey struct got_status_arg st;
5337 00357e4d 2021-09-14 tracey char *cwd = NULL;
5338 72ea6654 2019-07-27 stsp struct got_pathlist_head paths;
5339 a5edda0a 2019-07-27 stsp struct got_pathlist_entry *pe;
5340 f6343036 2021-06-22 stsp int ch, i, no_ignores = 0;
5341 5c860e29 2018-03-12 stsp
5342 72ea6654 2019-07-27 stsp TAILQ_INIT(&paths);
5343 72ea6654 2019-07-27 stsp
5344 00357e4d 2021-09-14 tracey memset(&st, 0, sizeof(st));
5345 00357e4d 2021-09-14 tracey st.status_codes = NULL;
5346 00357e4d 2021-09-14 tracey st.suppress = 0;
5347 00357e4d 2021-09-14 tracey
5348 00357e4d 2021-09-14 tracey while ((ch = getopt(argc, argv, "Is:S:")) != -1) {
5349 6bad629b 2019-02-04 stsp switch (ch) {
5350 f6343036 2021-06-22 stsp case 'I':
5351 f6343036 2021-06-22 stsp no_ignores = 1;
5352 f6343036 2021-06-22 stsp break;
5353 788d4a19 2021-09-14 stsp case 'S':
5354 788d4a19 2021-09-14 stsp if (st.status_codes != NULL && st.suppress == 0)
5355 788d4a19 2021-09-14 stsp option_conflict('S', 's');
5356 788d4a19 2021-09-14 stsp st.suppress = 1;
5357 788d4a19 2021-09-14 stsp /* fallthrough */
5358 081470ac 2020-08-13 stsp case 's':
5359 081470ac 2020-08-13 stsp for (i = 0; i < strlen(optarg); i++) {
5360 081470ac 2020-08-13 stsp switch (optarg[i]) {
5361 081470ac 2020-08-13 stsp case GOT_STATUS_MODIFY:
5362 081470ac 2020-08-13 stsp case GOT_STATUS_ADD:
5363 081470ac 2020-08-13 stsp case GOT_STATUS_DELETE:
5364 081470ac 2020-08-13 stsp case GOT_STATUS_CONFLICT:
5365 081470ac 2020-08-13 stsp case GOT_STATUS_MISSING:
5366 081470ac 2020-08-13 stsp case GOT_STATUS_OBSTRUCTED:
5367 081470ac 2020-08-13 stsp case GOT_STATUS_UNVERSIONED:
5368 081470ac 2020-08-13 stsp case GOT_STATUS_MODE_CHANGE:
5369 081470ac 2020-08-13 stsp case GOT_STATUS_NONEXISTENT:
5370 081470ac 2020-08-13 stsp break;
5371 081470ac 2020-08-13 stsp default:
5372 081470ac 2020-08-13 stsp errx(1, "invalid status code '%c'",
5373 081470ac 2020-08-13 stsp optarg[i]);
5374 081470ac 2020-08-13 stsp }
5375 081470ac 2020-08-13 stsp }
5376 788d4a19 2021-09-14 stsp if (ch == 's' && st.suppress)
5377 b043307b 2021-09-14 stsp option_conflict('s', 'S');
5378 00357e4d 2021-09-14 tracey st.status_codes = optarg;
5379 081470ac 2020-08-13 stsp break;
5380 5c860e29 2018-03-12 stsp default:
5381 2deda0b9 2019-03-07 stsp usage_status();
5382 6bad629b 2019-02-04 stsp /* NOTREACHED */
5383 5c860e29 2018-03-12 stsp }
5384 5c860e29 2018-03-12 stsp }
5385 5c860e29 2018-03-12 stsp
5386 6bad629b 2019-02-04 stsp argc -= optind;
5387 6bad629b 2019-02-04 stsp argv += optind;
5388 5c860e29 2018-03-12 stsp
5389 6bad629b 2019-02-04 stsp #ifndef PROFILE
5390 6bad629b 2019-02-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5391 6bad629b 2019-02-04 stsp NULL) == -1)
5392 6bad629b 2019-02-04 stsp err(1, "pledge");
5393 f42b1b34 2018-03-12 stsp #endif
5394 927df6b7 2019-02-10 stsp cwd = getcwd(NULL, 0);
5395 927df6b7 2019-02-10 stsp if (cwd == NULL) {
5396 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5397 927df6b7 2019-02-10 stsp goto done;
5398 927df6b7 2019-02-10 stsp }
5399 927df6b7 2019-02-10 stsp
5400 927df6b7 2019-02-10 stsp error = got_worktree_open(&worktree, cwd);
5401 fa51e947 2020-03-27 stsp if (error) {
5402 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
5403 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "status", cwd);
5404 a5edda0a 2019-07-27 stsp goto done;
5405 fa51e947 2020-03-27 stsp }
5406 6bad629b 2019-02-04 stsp
5407 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
5408 c9956ddf 2019-09-08 stsp NULL);
5409 6bad629b 2019-02-04 stsp if (error != NULL)
5410 6bad629b 2019-02-04 stsp goto done;
5411 6bad629b 2019-02-04 stsp
5412 d0eebce4 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 1,
5413 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
5414 087fb88c 2019-08-04 stsp if (error)
5415 087fb88c 2019-08-04 stsp goto done;
5416 087fb88c 2019-08-04 stsp
5417 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
5418 6bad629b 2019-02-04 stsp if (error)
5419 6bad629b 2019-02-04 stsp goto done;
5420 6bad629b 2019-02-04 stsp
5421 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, no_ignores,
5422 00357e4d 2021-09-14 tracey print_status, &st, check_cancelled, NULL);
5423 6bad629b 2019-02-04 stsp done:
5424 a5edda0a 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
5425 a5edda0a 2019-07-27 stsp free((char *)pe->path);
5426 72ea6654 2019-07-27 stsp got_pathlist_free(&paths);
5427 927df6b7 2019-02-10 stsp free(cwd);
5428 d0eebce4 2019-03-11 stsp return error;
5429 d0eebce4 2019-03-11 stsp }
5430 d0eebce4 2019-03-11 stsp
5431 d0eebce4 2019-03-11 stsp __dead static void
5432 d0eebce4 2019-03-11 stsp usage_ref(void)
5433 d0eebce4 2019-03-11 stsp {
5434 d0eebce4 2019-03-11 stsp fprintf(stderr,
5435 e31abbf2 2020-03-22 stsp "usage: %s ref [-r repository] [-l] [-c object] [-s reference] "
5436 e31abbf2 2020-03-22 stsp "[-d] [name]\n",
5437 d0eebce4 2019-03-11 stsp getprogname());
5438 d0eebce4 2019-03-11 stsp exit(1);
5439 d0eebce4 2019-03-11 stsp }
5440 d0eebce4 2019-03-11 stsp
5441 d0eebce4 2019-03-11 stsp static const struct got_error *
5442 b2070a3f 2020-03-22 stsp list_refs(struct got_repository *repo, const char *refname)
5443 d0eebce4 2019-03-11 stsp {
5444 d0eebce4 2019-03-11 stsp static const struct got_error *err = NULL;
5445 d0eebce4 2019-03-11 stsp struct got_reflist_head refs;
5446 d0eebce4 2019-03-11 stsp struct got_reflist_entry *re;
5447 d0eebce4 2019-03-11 stsp
5448 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5449 b2070a3f 2020-03-22 stsp err = got_ref_list(&refs, repo, refname, got_ref_cmp_by_name, NULL);
5450 d0eebce4 2019-03-11 stsp if (err)
5451 d0eebce4 2019-03-11 stsp return err;
5452 d0eebce4 2019-03-11 stsp
5453 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry) {
5454 d0eebce4 2019-03-11 stsp char *refstr;
5455 d0eebce4 2019-03-11 stsp refstr = got_ref_to_str(re->ref);
5456 d0eebce4 2019-03-11 stsp if (refstr == NULL)
5457 638f9024 2019-05-13 stsp return got_error_from_errno("got_ref_to_str");
5458 d0eebce4 2019-03-11 stsp printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
5459 d0eebce4 2019-03-11 stsp free(refstr);
5460 d0eebce4 2019-03-11 stsp }
5461 d0eebce4 2019-03-11 stsp
5462 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
5463 d0eebce4 2019-03-11 stsp return NULL;
5464 d0eebce4 2019-03-11 stsp }
5465 d0eebce4 2019-03-11 stsp
5466 d0eebce4 2019-03-11 stsp static const struct got_error *
5467 161728eb 2021-07-24 stsp delete_ref_by_name(struct got_repository *repo, const char *refname)
5468 d0eebce4 2019-03-11 stsp {
5469 161728eb 2021-07-24 stsp const struct got_error *err;
5470 d0eebce4 2019-03-11 stsp struct got_reference *ref;
5471 d0eebce4 2019-03-11 stsp
5472 2f17228e 2019-05-12 stsp err = got_ref_open(&ref, repo, refname, 0);
5473 d0eebce4 2019-03-11 stsp if (err)
5474 d0eebce4 2019-03-11 stsp return err;
5475 993f033b 2021-07-16 stsp
5476 161728eb 2021-07-24 stsp err = delete_ref(repo, ref);
5477 d0eebce4 2019-03-11 stsp got_ref_close(ref);
5478 d0eebce4 2019-03-11 stsp return err;
5479 d0eebce4 2019-03-11 stsp }
5480 d0eebce4 2019-03-11 stsp
5481 d0eebce4 2019-03-11 stsp static const struct got_error *
5482 d83d9d5c 2019-05-13 stsp add_ref(struct got_repository *repo, const char *refname, const char *target)
5483 d0eebce4 2019-03-11 stsp {
5484 d0eebce4 2019-03-11 stsp const struct got_error *err = NULL;
5485 d0eebce4 2019-03-11 stsp struct got_object_id *id;
5486 d0eebce4 2019-03-11 stsp struct got_reference *ref = NULL;
5487 d1644381 2019-07-14 stsp
5488 d1644381 2019-07-14 stsp /*
5489 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
5490 d1644381 2019-07-14 stsp * While technically a valid reference name, this case is usually
5491 d1644381 2019-07-14 stsp * an unintended typo.
5492 d1644381 2019-07-14 stsp */
5493 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
5494 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
5495 d0eebce4 2019-03-11 stsp
5496 dd88155e 2019-06-29 stsp err = got_repo_match_object_id_prefix(&id, target, GOT_OBJ_TYPE_ANY,
5497 dd88155e 2019-06-29 stsp repo);
5498 d83d9d5c 2019-05-13 stsp if (err) {
5499 d83d9d5c 2019-05-13 stsp struct got_reference *target_ref;
5500 d0eebce4 2019-03-11 stsp
5501 d83d9d5c 2019-05-13 stsp if (err->code != GOT_ERR_BAD_OBJ_ID_STR)
5502 d83d9d5c 2019-05-13 stsp return err;
5503 d83d9d5c 2019-05-13 stsp err = got_ref_open(&target_ref, repo, target, 0);
5504 d83d9d5c 2019-05-13 stsp if (err)
5505 d83d9d5c 2019-05-13 stsp return err;
5506 d83d9d5c 2019-05-13 stsp err = got_ref_resolve(&id, repo, target_ref);
5507 d83d9d5c 2019-05-13 stsp got_ref_close(target_ref);
5508 d83d9d5c 2019-05-13 stsp if (err)
5509 d83d9d5c 2019-05-13 stsp return err;
5510 d83d9d5c 2019-05-13 stsp }
5511 d83d9d5c 2019-05-13 stsp
5512 d0eebce4 2019-03-11 stsp err = got_ref_alloc(&ref, refname, id);
5513 d0eebce4 2019-03-11 stsp if (err)
5514 d0eebce4 2019-03-11 stsp goto done;
5515 d0eebce4 2019-03-11 stsp
5516 d0eebce4 2019-03-11 stsp err = got_ref_write(ref, repo);
5517 d0eebce4 2019-03-11 stsp done:
5518 d0eebce4 2019-03-11 stsp if (ref)
5519 d0eebce4 2019-03-11 stsp got_ref_close(ref);
5520 d0eebce4 2019-03-11 stsp free(id);
5521 d1c1ae5f 2019-08-12 stsp return err;
5522 d1c1ae5f 2019-08-12 stsp }
5523 d1c1ae5f 2019-08-12 stsp
5524 d1c1ae5f 2019-08-12 stsp static const struct got_error *
5525 d1c1ae5f 2019-08-12 stsp add_symref(struct got_repository *repo, const char *refname, const char *target)
5526 d1c1ae5f 2019-08-12 stsp {
5527 d1c1ae5f 2019-08-12 stsp const struct got_error *err = NULL;
5528 d1c1ae5f 2019-08-12 stsp struct got_reference *ref = NULL;
5529 d1c1ae5f 2019-08-12 stsp struct got_reference *target_ref = NULL;
5530 d1c1ae5f 2019-08-12 stsp
5531 d1c1ae5f 2019-08-12 stsp /*
5532 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
5533 d1c1ae5f 2019-08-12 stsp * While technically a valid reference name, this case is usually
5534 d1c1ae5f 2019-08-12 stsp * an unintended typo.
5535 d1c1ae5f 2019-08-12 stsp */
5536 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
5537 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
5538 d1c1ae5f 2019-08-12 stsp
5539 d1c1ae5f 2019-08-12 stsp err = got_ref_open(&target_ref, repo, target, 0);
5540 d1c1ae5f 2019-08-12 stsp if (err)
5541 d1c1ae5f 2019-08-12 stsp return err;
5542 d1c1ae5f 2019-08-12 stsp
5543 d1c1ae5f 2019-08-12 stsp err = got_ref_alloc_symref(&ref, refname, target_ref);
5544 d1c1ae5f 2019-08-12 stsp if (err)
5545 d1c1ae5f 2019-08-12 stsp goto done;
5546 d1c1ae5f 2019-08-12 stsp
5547 d1c1ae5f 2019-08-12 stsp err = got_ref_write(ref, repo);
5548 d1c1ae5f 2019-08-12 stsp done:
5549 d1c1ae5f 2019-08-12 stsp if (target_ref)
5550 d1c1ae5f 2019-08-12 stsp got_ref_close(target_ref);
5551 d1c1ae5f 2019-08-12 stsp if (ref)
5552 d1c1ae5f 2019-08-12 stsp got_ref_close(ref);
5553 d0eebce4 2019-03-11 stsp return err;
5554 d0eebce4 2019-03-11 stsp }
5555 d0eebce4 2019-03-11 stsp
5556 d0eebce4 2019-03-11 stsp static const struct got_error *
5557 d0eebce4 2019-03-11 stsp cmd_ref(int argc, char *argv[])
5558 d0eebce4 2019-03-11 stsp {
5559 d0eebce4 2019-03-11 stsp const struct got_error *error = NULL;
5560 d0eebce4 2019-03-11 stsp struct got_repository *repo = NULL;
5561 d0eebce4 2019-03-11 stsp struct got_worktree *worktree = NULL;
5562 d0eebce4 2019-03-11 stsp char *cwd = NULL, *repo_path = NULL;
5563 e31abbf2 2020-03-22 stsp int ch, do_list = 0, do_delete = 0;
5564 b2070a3f 2020-03-22 stsp const char *obj_arg = NULL, *symref_target= NULL;
5565 b2070a3f 2020-03-22 stsp char *refname = NULL;
5566 d0eebce4 2019-03-11 stsp
5567 e31abbf2 2020-03-22 stsp while ((ch = getopt(argc, argv, "c:dr:ls:")) != -1) {
5568 d0eebce4 2019-03-11 stsp switch (ch) {
5569 e31abbf2 2020-03-22 stsp case 'c':
5570 e31abbf2 2020-03-22 stsp obj_arg = optarg;
5571 e31abbf2 2020-03-22 stsp break;
5572 d0eebce4 2019-03-11 stsp case 'd':
5573 e31abbf2 2020-03-22 stsp do_delete = 1;
5574 d0eebce4 2019-03-11 stsp break;
5575 d0eebce4 2019-03-11 stsp case 'r':
5576 d0eebce4 2019-03-11 stsp repo_path = realpath(optarg, NULL);
5577 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
5578 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5579 9ba1d308 2019-10-21 stsp optarg);
5580 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
5581 d0eebce4 2019-03-11 stsp break;
5582 d0eebce4 2019-03-11 stsp case 'l':
5583 d0eebce4 2019-03-11 stsp do_list = 1;
5584 d1c1ae5f 2019-08-12 stsp break;
5585 d1c1ae5f 2019-08-12 stsp case 's':
5586 e31abbf2 2020-03-22 stsp symref_target = optarg;
5587 d0eebce4 2019-03-11 stsp break;
5588 d0eebce4 2019-03-11 stsp default:
5589 d0eebce4 2019-03-11 stsp usage_ref();
5590 d0eebce4 2019-03-11 stsp /* NOTREACHED */
5591 d0eebce4 2019-03-11 stsp }
5592 d0eebce4 2019-03-11 stsp }
5593 d0eebce4 2019-03-11 stsp
5594 e31abbf2 2020-03-22 stsp if (obj_arg && do_list)
5595 ff69268e 2020-12-13 stsp option_conflict('c', 'l');
5596 ff69268e 2020-12-13 stsp if (obj_arg && do_delete)
5597 ff69268e 2020-12-13 stsp option_conflict('c', 'd');
5598 907f15e2 2020-03-22 stsp if (obj_arg && symref_target)
5599 ff69268e 2020-12-13 stsp option_conflict('c', 's');
5600 e31abbf2 2020-03-22 stsp if (symref_target && do_delete)
5601 ff69268e 2020-12-13 stsp option_conflict('s', 'd');
5602 e31abbf2 2020-03-22 stsp if (symref_target && do_list)
5603 ff69268e 2020-12-13 stsp option_conflict('s', 'l');
5604 e31abbf2 2020-03-22 stsp if (do_delete && do_list)
5605 ff69268e 2020-12-13 stsp option_conflict('d', 'l');
5606 d0eebce4 2019-03-11 stsp
5607 d0eebce4 2019-03-11 stsp argc -= optind;
5608 d0eebce4 2019-03-11 stsp argv += optind;
5609 d0eebce4 2019-03-11 stsp
5610 e31abbf2 2020-03-22 stsp if (do_list) {
5611 b2070a3f 2020-03-22 stsp if (argc != 0 && argc != 1)
5612 d0eebce4 2019-03-11 stsp usage_ref();
5613 b2070a3f 2020-03-22 stsp if (argc == 1) {
5614 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
5615 b2070a3f 2020-03-22 stsp if (refname == NULL) {
5616 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
5617 b2070a3f 2020-03-22 stsp goto done;
5618 b2070a3f 2020-03-22 stsp }
5619 b2070a3f 2020-03-22 stsp }
5620 e31abbf2 2020-03-22 stsp } else {
5621 e31abbf2 2020-03-22 stsp if (argc != 1)
5622 e31abbf2 2020-03-22 stsp usage_ref();
5623 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
5624 b2070a3f 2020-03-22 stsp if (refname == NULL) {
5625 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
5626 b2070a3f 2020-03-22 stsp goto done;
5627 b2070a3f 2020-03-22 stsp }
5628 e31abbf2 2020-03-22 stsp }
5629 b2070a3f 2020-03-22 stsp
5630 b2070a3f 2020-03-22 stsp if (refname)
5631 b2070a3f 2020-03-22 stsp got_path_strip_trailing_slashes(refname);
5632 d0eebce4 2019-03-11 stsp
5633 d0eebce4 2019-03-11 stsp #ifndef PROFILE
5634 e0b57350 2019-03-12 stsp if (do_list) {
5635 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5636 e0b57350 2019-03-12 stsp NULL) == -1)
5637 e0b57350 2019-03-12 stsp err(1, "pledge");
5638 e0b57350 2019-03-12 stsp } else {
5639 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5640 e0b57350 2019-03-12 stsp "sendfd unveil", NULL) == -1)
5641 e0b57350 2019-03-12 stsp err(1, "pledge");
5642 e0b57350 2019-03-12 stsp }
5643 d0eebce4 2019-03-11 stsp #endif
5644 d0eebce4 2019-03-11 stsp cwd = getcwd(NULL, 0);
5645 d0eebce4 2019-03-11 stsp if (cwd == NULL) {
5646 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5647 d0eebce4 2019-03-11 stsp goto done;
5648 d0eebce4 2019-03-11 stsp }
5649 d0eebce4 2019-03-11 stsp
5650 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
5651 d0eebce4 2019-03-11 stsp error = got_worktree_open(&worktree, cwd);
5652 d0eebce4 2019-03-11 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5653 d0eebce4 2019-03-11 stsp goto done;
5654 d0eebce4 2019-03-11 stsp else
5655 d0eebce4 2019-03-11 stsp error = NULL;
5656 d0eebce4 2019-03-11 stsp if (worktree) {
5657 d0eebce4 2019-03-11 stsp repo_path =
5658 d0eebce4 2019-03-11 stsp strdup(got_worktree_get_repo_path(worktree));
5659 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
5660 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5661 d0eebce4 2019-03-11 stsp if (error)
5662 d0eebce4 2019-03-11 stsp goto done;
5663 d0eebce4 2019-03-11 stsp } else {
5664 d0eebce4 2019-03-11 stsp repo_path = strdup(cwd);
5665 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
5666 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
5667 d0eebce4 2019-03-11 stsp goto done;
5668 d0eebce4 2019-03-11 stsp }
5669 d0eebce4 2019-03-11 stsp }
5670 d0eebce4 2019-03-11 stsp }
5671 d0eebce4 2019-03-11 stsp
5672 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5673 d0eebce4 2019-03-11 stsp if (error != NULL)
5674 d0eebce4 2019-03-11 stsp goto done;
5675 d0eebce4 2019-03-11 stsp
5676 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
5677 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
5678 c02c541e 2019-03-29 stsp if (error)
5679 c02c541e 2019-03-29 stsp goto done;
5680 c02c541e 2019-03-29 stsp
5681 d0eebce4 2019-03-11 stsp if (do_list)
5682 b2070a3f 2020-03-22 stsp error = list_refs(repo, refname);
5683 e31abbf2 2020-03-22 stsp else if (do_delete)
5684 161728eb 2021-07-24 stsp error = delete_ref_by_name(repo, refname);
5685 e31abbf2 2020-03-22 stsp else if (symref_target)
5686 e31abbf2 2020-03-22 stsp error = add_symref(repo, refname, symref_target);
5687 e31abbf2 2020-03-22 stsp else {
5688 e31abbf2 2020-03-22 stsp if (obj_arg == NULL)
5689 e31abbf2 2020-03-22 stsp usage_ref();
5690 e31abbf2 2020-03-22 stsp error = add_ref(repo, refname, obj_arg);
5691 e31abbf2 2020-03-22 stsp }
5692 4e759de4 2019-06-26 stsp done:
5693 b2070a3f 2020-03-22 stsp free(refname);
5694 1d0f4054 2021-06-17 stsp if (repo) {
5695 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
5696 1d0f4054 2021-06-17 stsp if (error == NULL)
5697 1d0f4054 2021-06-17 stsp error = close_err;
5698 1d0f4054 2021-06-17 stsp }
5699 4e759de4 2019-06-26 stsp if (worktree)
5700 4e759de4 2019-06-26 stsp got_worktree_close(worktree);
5701 4e759de4 2019-06-26 stsp free(cwd);
5702 4e759de4 2019-06-26 stsp free(repo_path);
5703 4e759de4 2019-06-26 stsp return error;
5704 4e759de4 2019-06-26 stsp }
5705 4e759de4 2019-06-26 stsp
5706 4e759de4 2019-06-26 stsp __dead static void
5707 4e759de4 2019-06-26 stsp usage_branch(void)
5708 4e759de4 2019-06-26 stsp {
5709 4e759de4 2019-06-26 stsp fprintf(stderr,
5710 da76fce2 2020-02-24 stsp "usage: %s branch [-c commit] [-d] [-r repository] [-l] [-n] "
5711 da76fce2 2020-02-24 stsp "[name]\n", getprogname());
5712 4e759de4 2019-06-26 stsp exit(1);
5713 4e759de4 2019-06-26 stsp }
5714 4e759de4 2019-06-26 stsp
5715 4e759de4 2019-06-26 stsp static const struct got_error *
5716 4e99b47e 2019-10-04 stsp list_branch(struct got_repository *repo, struct got_worktree *worktree,
5717 4e99b47e 2019-10-04 stsp struct got_reference *ref)
5718 4e99b47e 2019-10-04 stsp {
5719 4e99b47e 2019-10-04 stsp const struct got_error *err = NULL;
5720 4e99b47e 2019-10-04 stsp const char *refname, *marker = " ";
5721 4e99b47e 2019-10-04 stsp char *refstr;
5722 4e99b47e 2019-10-04 stsp
5723 4e99b47e 2019-10-04 stsp refname = got_ref_get_name(ref);
5724 4e99b47e 2019-10-04 stsp if (worktree && strcmp(refname,
5725 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree)) == 0) {
5726 4e99b47e 2019-10-04 stsp struct got_object_id *id = NULL;
5727 4e99b47e 2019-10-04 stsp
5728 4e99b47e 2019-10-04 stsp err = got_ref_resolve(&id, repo, ref);
5729 4e99b47e 2019-10-04 stsp if (err)
5730 4e99b47e 2019-10-04 stsp return err;
5731 4e99b47e 2019-10-04 stsp if (got_object_id_cmp(id,
5732 4e99b47e 2019-10-04 stsp got_worktree_get_base_commit_id(worktree)) == 0)
5733 4e99b47e 2019-10-04 stsp marker = "* ";
5734 4e99b47e 2019-10-04 stsp else
5735 4e99b47e 2019-10-04 stsp marker = "~ ";
5736 4e99b47e 2019-10-04 stsp free(id);
5737 4e99b47e 2019-10-04 stsp }
5738 4e99b47e 2019-10-04 stsp
5739 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5740 4e99b47e 2019-10-04 stsp refname += 11;
5741 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5742 4e99b47e 2019-10-04 stsp refname += 18;
5743 34d4e04c 2021-02-08 stsp if (strncmp(refname, "refs/remotes/", 13) == 0)
5744 34d4e04c 2021-02-08 stsp refname += 13;
5745 4e99b47e 2019-10-04 stsp
5746 4e99b47e 2019-10-04 stsp refstr = got_ref_to_str(ref);
5747 4e99b47e 2019-10-04 stsp if (refstr == NULL)
5748 4e99b47e 2019-10-04 stsp return got_error_from_errno("got_ref_to_str");
5749 4e99b47e 2019-10-04 stsp
5750 4e99b47e 2019-10-04 stsp printf("%s%s: %s\n", marker, refname, refstr);
5751 4e99b47e 2019-10-04 stsp free(refstr);
5752 4e99b47e 2019-10-04 stsp return NULL;
5753 4e99b47e 2019-10-04 stsp }
5754 4e99b47e 2019-10-04 stsp
5755 4e99b47e 2019-10-04 stsp static const struct got_error *
5756 ad89fa31 2019-10-04 stsp show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
5757 ad89fa31 2019-10-04 stsp {
5758 ad89fa31 2019-10-04 stsp const char *refname;
5759 ad89fa31 2019-10-04 stsp
5760 ad89fa31 2019-10-04 stsp if (worktree == NULL)
5761 ad89fa31 2019-10-04 stsp return got_error(GOT_ERR_NOT_WORKTREE);
5762 ad89fa31 2019-10-04 stsp
5763 ad89fa31 2019-10-04 stsp refname = got_worktree_get_head_ref_name(worktree);
5764 ad89fa31 2019-10-04 stsp
5765 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5766 ad89fa31 2019-10-04 stsp refname += 11;
5767 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5768 ad89fa31 2019-10-04 stsp refname += 18;
5769 ad89fa31 2019-10-04 stsp
5770 ad89fa31 2019-10-04 stsp printf("%s\n", refname);
5771 ad89fa31 2019-10-04 stsp
5772 ad89fa31 2019-10-04 stsp return NULL;
5773 ad89fa31 2019-10-04 stsp }
5774 ad89fa31 2019-10-04 stsp
5775 ad89fa31 2019-10-04 stsp static const struct got_error *
5776 ba882ee3 2019-07-11 stsp list_branches(struct got_repository *repo, struct got_worktree *worktree)
5777 4e759de4 2019-06-26 stsp {
5778 4e759de4 2019-06-26 stsp static const struct got_error *err = NULL;
5779 4e759de4 2019-06-26 stsp struct got_reflist_head refs;
5780 4e759de4 2019-06-26 stsp struct got_reflist_entry *re;
5781 4e99b47e 2019-10-04 stsp struct got_reference *temp_ref = NULL;
5782 4e99b47e 2019-10-04 stsp int rebase_in_progress, histedit_in_progress;
5783 4e759de4 2019-06-26 stsp
5784 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
5785 ba882ee3 2019-07-11 stsp
5786 4e99b47e 2019-10-04 stsp if (worktree) {
5787 4e99b47e 2019-10-04 stsp err = got_worktree_rebase_in_progress(&rebase_in_progress,
5788 4e99b47e 2019-10-04 stsp worktree);
5789 4e99b47e 2019-10-04 stsp if (err)
5790 4e99b47e 2019-10-04 stsp return err;
5791 4e99b47e 2019-10-04 stsp
5792 4e99b47e 2019-10-04 stsp err = got_worktree_histedit_in_progress(&histedit_in_progress,
5793 4e99b47e 2019-10-04 stsp worktree);
5794 4e99b47e 2019-10-04 stsp if (err)
5795 4e99b47e 2019-10-04 stsp return err;
5796 4e99b47e 2019-10-04 stsp
5797 4e99b47e 2019-10-04 stsp if (rebase_in_progress || histedit_in_progress) {
5798 4e99b47e 2019-10-04 stsp err = got_ref_open(&temp_ref, repo,
5799 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree), 0);
5800 4e99b47e 2019-10-04 stsp if (err)
5801 4e99b47e 2019-10-04 stsp return err;
5802 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, temp_ref);
5803 4e99b47e 2019-10-04 stsp got_ref_close(temp_ref);
5804 4e99b47e 2019-10-04 stsp }
5805 4e99b47e 2019-10-04 stsp }
5806 4e99b47e 2019-10-04 stsp
5807 b8bad2ba 2019-08-23 stsp err = got_ref_list(&refs, repo, "refs/heads",
5808 b8bad2ba 2019-08-23 stsp got_ref_cmp_by_name, NULL);
5809 4e759de4 2019-06-26 stsp if (err)
5810 4e759de4 2019-06-26 stsp return err;
5811 4e759de4 2019-06-26 stsp
5812 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry)
5813 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, re->ref);
5814 4e759de4 2019-06-26 stsp
5815 4e759de4 2019-06-26 stsp got_ref_list_free(&refs);
5816 34d4e04c 2021-02-08 stsp
5817 34d4e04c 2021-02-08 stsp err = got_ref_list(&refs, repo, "refs/remotes",
5818 34d4e04c 2021-02-08 stsp got_ref_cmp_by_name, NULL);
5819 34d4e04c 2021-02-08 stsp if (err)
5820 34d4e04c 2021-02-08 stsp return err;
5821 34d4e04c 2021-02-08 stsp
5822 34d4e04c 2021-02-08 stsp TAILQ_FOREACH(re, &refs, entry)
5823 34d4e04c 2021-02-08 stsp list_branch(repo, worktree, re->ref);
5824 34d4e04c 2021-02-08 stsp
5825 34d4e04c 2021-02-08 stsp got_ref_list_free(&refs);
5826 34d4e04c 2021-02-08 stsp
5827 4e759de4 2019-06-26 stsp return NULL;
5828 4e759de4 2019-06-26 stsp }
5829 4e759de4 2019-06-26 stsp
5830 4e759de4 2019-06-26 stsp static const struct got_error *
5831 45cd4e47 2019-08-25 stsp delete_branch(struct got_repository *repo, struct got_worktree *worktree,
5832 45cd4e47 2019-08-25 stsp const char *branch_name)
5833 4e759de4 2019-06-26 stsp {
5834 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
5835 45cd4e47 2019-08-25 stsp struct got_reference *ref = NULL;
5836 2f1457c6 2021-08-27 stsp char *refname, *remote_refname = NULL;
5837 4e759de4 2019-06-26 stsp
5838 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "refs/", 5) == 0)
5839 2f1457c6 2021-08-27 stsp branch_name += 5;
5840 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "heads/", 6) == 0)
5841 2f1457c6 2021-08-27 stsp branch_name += 6;
5842 2f1457c6 2021-08-27 stsp else if (strncmp(branch_name, "remotes/", 8) == 0)
5843 2f1457c6 2021-08-27 stsp branch_name += 8;
5844 2f1457c6 2021-08-27 stsp
5845 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
5846 4e759de4 2019-06-26 stsp return got_error_from_errno("asprintf");
5847 4e759de4 2019-06-26 stsp
5848 2f1457c6 2021-08-27 stsp if (asprintf(&remote_refname, "refs/remotes/%s",
5849 2f1457c6 2021-08-27 stsp branch_name) == -1) {
5850 2f1457c6 2021-08-27 stsp err = got_error_from_errno("asprintf");
5851 4e759de4 2019-06-26 stsp goto done;
5852 2f1457c6 2021-08-27 stsp }
5853 4e759de4 2019-06-26 stsp
5854 2f1457c6 2021-08-27 stsp err = got_ref_open(&ref, repo, refname, 0);
5855 2f1457c6 2021-08-27 stsp if (err) {
5856 2f1457c6 2021-08-27 stsp const struct got_error *err2;
5857 2f1457c6 2021-08-27 stsp if (err->code != GOT_ERR_NOT_REF)
5858 2f1457c6 2021-08-27 stsp goto done;
5859 2f1457c6 2021-08-27 stsp /*
5860 2f1457c6 2021-08-27 stsp * Keep 'err' intact such that if neither branch exists
5861 2f1457c6 2021-08-27 stsp * we report "refs/heads" rather than "refs/remotes" in
5862 2f1457c6 2021-08-27 stsp * our error message.
5863 2f1457c6 2021-08-27 stsp */
5864 2f1457c6 2021-08-27 stsp err2 = got_ref_open(&ref, repo, remote_refname, 0);
5865 2f1457c6 2021-08-27 stsp if (err2)
5866 2f1457c6 2021-08-27 stsp goto done;
5867 2f1457c6 2021-08-27 stsp err = NULL;
5868 2f1457c6 2021-08-27 stsp }
5869 2f1457c6 2021-08-27 stsp
5870 45cd4e47 2019-08-25 stsp if (worktree &&
5871 45cd4e47 2019-08-25 stsp strcmp(got_worktree_get_head_ref_name(worktree),
5872 45cd4e47 2019-08-25 stsp got_ref_get_name(ref)) == 0) {
5873 45cd4e47 2019-08-25 stsp err = got_error_msg(GOT_ERR_SAME_BRANCH,
5874 45cd4e47 2019-08-25 stsp "will not delete this work tree's current branch");
5875 45cd4e47 2019-08-25 stsp goto done;
5876 45cd4e47 2019-08-25 stsp }
5877 45cd4e47 2019-08-25 stsp
5878 978a28a1 2021-09-04 naddy err = delete_ref(repo, ref);
5879 4e759de4 2019-06-26 stsp done:
5880 45cd4e47 2019-08-25 stsp if (ref)
5881 45cd4e47 2019-08-25 stsp got_ref_close(ref);
5882 4e759de4 2019-06-26 stsp free(refname);
5883 2f1457c6 2021-08-27 stsp free(remote_refname);
5884 4e759de4 2019-06-26 stsp return err;
5885 4e759de4 2019-06-26 stsp }
5886 4e759de4 2019-06-26 stsp
5887 4e759de4 2019-06-26 stsp static const struct got_error *
5888 4e759de4 2019-06-26 stsp add_branch(struct got_repository *repo, const char *branch_name,
5889 a74f7e83 2019-11-10 stsp struct got_object_id *base_commit_id)
5890 4e759de4 2019-06-26 stsp {
5891 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
5892 4e759de4 2019-06-26 stsp struct got_reference *ref = NULL;
5893 4e759de4 2019-06-26 stsp char *base_refname = NULL, *refname = NULL;
5894 d3f84d51 2019-07-11 stsp
5895 d3f84d51 2019-07-11 stsp /*
5896 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
5897 d3f84d51 2019-07-11 stsp * While technically a valid reference name, this case is usually
5898 d3f84d51 2019-07-11 stsp * an unintended typo.
5899 d3f84d51 2019-07-11 stsp */
5900 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
5901 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
5902 2f1457c6 2021-08-27 stsp
5903 2f1457c6 2021-08-27 stsp if (strncmp(branch_name, "refs/heads/", 11) == 0)
5904 2f1457c6 2021-08-27 stsp branch_name += 11;
5905 4e759de4 2019-06-26 stsp
5906 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
5907 62d463ca 2020-10-20 naddy err = got_error_from_errno("asprintf");
5908 62d463ca 2020-10-20 naddy goto done;
5909 4e759de4 2019-06-26 stsp }
5910 4e759de4 2019-06-26 stsp
5911 4e759de4 2019-06-26 stsp err = got_ref_open(&ref, repo, refname, 0);
5912 4e759de4 2019-06-26 stsp if (err == NULL) {
5913 4e759de4 2019-06-26 stsp err = got_error(GOT_ERR_BRANCH_EXISTS);
5914 4e759de4 2019-06-26 stsp goto done;
5915 4e759de4 2019-06-26 stsp } else if (err->code != GOT_ERR_NOT_REF)
5916 4e759de4 2019-06-26 stsp goto done;
5917 4e759de4 2019-06-26 stsp
5918 a74f7e83 2019-11-10 stsp err = got_ref_alloc(&ref, refname, base_commit_id);
5919 4e759de4 2019-06-26 stsp if (err)
5920 4e759de4 2019-06-26 stsp goto done;
5921 4e759de4 2019-06-26 stsp
5922 4e759de4 2019-06-26 stsp err = got_ref_write(ref, repo);
5923 d0eebce4 2019-03-11 stsp done:
5924 4e759de4 2019-06-26 stsp if (ref)
5925 4e759de4 2019-06-26 stsp got_ref_close(ref);
5926 4e759de4 2019-06-26 stsp free(base_refname);
5927 4e759de4 2019-06-26 stsp free(refname);
5928 4e759de4 2019-06-26 stsp return err;
5929 4e759de4 2019-06-26 stsp }
5930 4e759de4 2019-06-26 stsp
5931 4e759de4 2019-06-26 stsp static const struct got_error *
5932 4e759de4 2019-06-26 stsp cmd_branch(int argc, char *argv[])
5933 4e759de4 2019-06-26 stsp {
5934 4e759de4 2019-06-26 stsp const struct got_error *error = NULL;
5935 4e759de4 2019-06-26 stsp struct got_repository *repo = NULL;
5936 4e759de4 2019-06-26 stsp struct got_worktree *worktree = NULL;
5937 4e759de4 2019-06-26 stsp char *cwd = NULL, *repo_path = NULL;
5938 da76fce2 2020-02-24 stsp int ch, do_list = 0, do_show = 0, do_update = 1;
5939 a74f7e83 2019-11-10 stsp const char *delref = NULL, *commit_id_arg = NULL;
5940 da76fce2 2020-02-24 stsp struct got_reference *ref = NULL;
5941 da76fce2 2020-02-24 stsp struct got_pathlist_head paths;
5942 da76fce2 2020-02-24 stsp struct got_pathlist_entry *pe;
5943 da76fce2 2020-02-24 stsp struct got_object_id *commit_id = NULL;
5944 da76fce2 2020-02-24 stsp char *commit_id_str = NULL;
5945 4e759de4 2019-06-26 stsp
5946 da76fce2 2020-02-24 stsp TAILQ_INIT(&paths);
5947 da76fce2 2020-02-24 stsp
5948 da76fce2 2020-02-24 stsp while ((ch = getopt(argc, argv, "c:d:r:ln")) != -1) {
5949 4e759de4 2019-06-26 stsp switch (ch) {
5950 a74f7e83 2019-11-10 stsp case 'c':
5951 a74f7e83 2019-11-10 stsp commit_id_arg = optarg;
5952 a74f7e83 2019-11-10 stsp break;
5953 4e759de4 2019-06-26 stsp case 'd':
5954 4e759de4 2019-06-26 stsp delref = optarg;
5955 4e759de4 2019-06-26 stsp break;
5956 4e759de4 2019-06-26 stsp case 'r':
5957 4e759de4 2019-06-26 stsp repo_path = realpath(optarg, NULL);
5958 4e759de4 2019-06-26 stsp if (repo_path == NULL)
5959 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5960 9ba1d308 2019-10-21 stsp optarg);
5961 4e759de4 2019-06-26 stsp got_path_strip_trailing_slashes(repo_path);
5962 4e759de4 2019-06-26 stsp break;
5963 4e759de4 2019-06-26 stsp case 'l':
5964 4e759de4 2019-06-26 stsp do_list = 1;
5965 da76fce2 2020-02-24 stsp break;
5966 da76fce2 2020-02-24 stsp case 'n':
5967 da76fce2 2020-02-24 stsp do_update = 0;
5968 4e759de4 2019-06-26 stsp break;
5969 4e759de4 2019-06-26 stsp default:
5970 4e759de4 2019-06-26 stsp usage_branch();
5971 4e759de4 2019-06-26 stsp /* NOTREACHED */
5972 4e759de4 2019-06-26 stsp }
5973 4e759de4 2019-06-26 stsp }
5974 4e759de4 2019-06-26 stsp
5975 4e759de4 2019-06-26 stsp if (do_list && delref)
5976 ff69268e 2020-12-13 stsp option_conflict('l', 'd');
5977 4e759de4 2019-06-26 stsp
5978 4e759de4 2019-06-26 stsp argc -= optind;
5979 4e759de4 2019-06-26 stsp argv += optind;
5980 ad89fa31 2019-10-04 stsp
5981 ad89fa31 2019-10-04 stsp if (!do_list && !delref && argc == 0)
5982 ad89fa31 2019-10-04 stsp do_show = 1;
5983 4e759de4 2019-06-26 stsp
5984 a74f7e83 2019-11-10 stsp if ((do_list || delref || do_show) && commit_id_arg != NULL)
5985 a74f7e83 2019-11-10 stsp errx(1, "-c option can only be used when creating a branch");
5986 a74f7e83 2019-11-10 stsp
5987 4e759de4 2019-06-26 stsp if (do_list || delref) {
5988 4e759de4 2019-06-26 stsp if (argc > 0)
5989 4e759de4 2019-06-26 stsp usage_branch();
5990 a74f7e83 2019-11-10 stsp } else if (!do_show && argc != 1)
5991 4e759de4 2019-06-26 stsp usage_branch();
5992 4e759de4 2019-06-26 stsp
5993 4e759de4 2019-06-26 stsp #ifndef PROFILE
5994 ad89fa31 2019-10-04 stsp if (do_list || do_show) {
5995 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5996 4e759de4 2019-06-26 stsp NULL) == -1)
5997 4e759de4 2019-06-26 stsp err(1, "pledge");
5998 4e759de4 2019-06-26 stsp } else {
5999 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6000 4e759de4 2019-06-26 stsp "sendfd unveil", NULL) == -1)
6001 4e759de4 2019-06-26 stsp err(1, "pledge");
6002 4e759de4 2019-06-26 stsp }
6003 4e759de4 2019-06-26 stsp #endif
6004 4e759de4 2019-06-26 stsp cwd = getcwd(NULL, 0);
6005 4e759de4 2019-06-26 stsp if (cwd == NULL) {
6006 4e759de4 2019-06-26 stsp error = got_error_from_errno("getcwd");
6007 4e759de4 2019-06-26 stsp goto done;
6008 4e759de4 2019-06-26 stsp }
6009 4e759de4 2019-06-26 stsp
6010 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
6011 4e759de4 2019-06-26 stsp error = got_worktree_open(&worktree, cwd);
6012 4e759de4 2019-06-26 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
6013 4e759de4 2019-06-26 stsp goto done;
6014 4e759de4 2019-06-26 stsp else
6015 4e759de4 2019-06-26 stsp error = NULL;
6016 4e759de4 2019-06-26 stsp if (worktree) {
6017 4e759de4 2019-06-26 stsp repo_path =
6018 4e759de4 2019-06-26 stsp strdup(got_worktree_get_repo_path(worktree));
6019 4e759de4 2019-06-26 stsp if (repo_path == NULL)
6020 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
6021 4e759de4 2019-06-26 stsp if (error)
6022 4e759de4 2019-06-26 stsp goto done;
6023 4e759de4 2019-06-26 stsp } else {
6024 4e759de4 2019-06-26 stsp repo_path = strdup(cwd);
6025 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
6026 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
6027 4e759de4 2019-06-26 stsp goto done;
6028 4e759de4 2019-06-26 stsp }
6029 4e759de4 2019-06-26 stsp }
6030 4e759de4 2019-06-26 stsp }
6031 4e759de4 2019-06-26 stsp
6032 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
6033 4e759de4 2019-06-26 stsp if (error != NULL)
6034 4e759de4 2019-06-26 stsp goto done;
6035 4e759de4 2019-06-26 stsp
6036 4e759de4 2019-06-26 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
6037 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
6038 4e759de4 2019-06-26 stsp if (error)
6039 4e759de4 2019-06-26 stsp goto done;
6040 4e759de4 2019-06-26 stsp
6041 ad89fa31 2019-10-04 stsp if (do_show)
6042 ad89fa31 2019-10-04 stsp error = show_current_branch(repo, worktree);
6043 ad89fa31 2019-10-04 stsp else if (do_list)
6044 ba882ee3 2019-07-11 stsp error = list_branches(repo, worktree);
6045 4e759de4 2019-06-26 stsp else if (delref)
6046 45cd4e47 2019-08-25 stsp error = delete_branch(repo, worktree, delref);
6047 4e759de4 2019-06-26 stsp else {
6048 84de9106 2020-12-26 stsp struct got_reflist_head refs;
6049 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6050 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
6051 84de9106 2020-12-26 stsp NULL);
6052 84de9106 2020-12-26 stsp if (error)
6053 84de9106 2020-12-26 stsp goto done;
6054 a74f7e83 2019-11-10 stsp if (commit_id_arg == NULL)
6055 a74f7e83 2019-11-10 stsp commit_id_arg = worktree ?
6056 4e759de4 2019-06-26 stsp got_worktree_get_head_ref_name(worktree) :
6057 4e759de4 2019-06-26 stsp GOT_REF_HEAD;
6058 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
6059 84de9106 2020-12-26 stsp commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo);
6060 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
6061 a74f7e83 2019-11-10 stsp if (error)
6062 a74f7e83 2019-11-10 stsp goto done;
6063 a74f7e83 2019-11-10 stsp error = add_branch(repo, argv[0], commit_id);
6064 da76fce2 2020-02-24 stsp if (error)
6065 da76fce2 2020-02-24 stsp goto done;
6066 da76fce2 2020-02-24 stsp if (worktree && do_update) {
6067 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
6068 da76fce2 2020-02-24 stsp char *branch_refname = NULL;
6069 da76fce2 2020-02-24 stsp
6070 da76fce2 2020-02-24 stsp error = got_object_id_str(&commit_id_str, commit_id);
6071 da76fce2 2020-02-24 stsp if (error)
6072 da76fce2 2020-02-24 stsp goto done;
6073 da76fce2 2020-02-24 stsp error = get_worktree_paths_from_argv(&paths, 0, NULL,
6074 da76fce2 2020-02-24 stsp worktree);
6075 da76fce2 2020-02-24 stsp if (error)
6076 da76fce2 2020-02-24 stsp goto done;
6077 da76fce2 2020-02-24 stsp if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
6078 da76fce2 2020-02-24 stsp == -1) {
6079 da76fce2 2020-02-24 stsp error = got_error_from_errno("asprintf");
6080 da76fce2 2020-02-24 stsp goto done;
6081 da76fce2 2020-02-24 stsp }
6082 da76fce2 2020-02-24 stsp error = got_ref_open(&ref, repo, branch_refname, 0);
6083 da76fce2 2020-02-24 stsp free(branch_refname);
6084 da76fce2 2020-02-24 stsp if (error)
6085 da76fce2 2020-02-24 stsp goto done;
6086 da76fce2 2020-02-24 stsp error = switch_head_ref(ref, commit_id, worktree,
6087 da76fce2 2020-02-24 stsp repo);
6088 da76fce2 2020-02-24 stsp if (error)
6089 da76fce2 2020-02-24 stsp goto done;
6090 da76fce2 2020-02-24 stsp error = got_worktree_set_base_commit_id(worktree, repo,
6091 da76fce2 2020-02-24 stsp commit_id);
6092 da76fce2 2020-02-24 stsp if (error)
6093 da76fce2 2020-02-24 stsp goto done;
6094 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
6095 da76fce2 2020-02-24 stsp error = got_worktree_checkout_files(worktree, &paths,
6096 9627c110 2020-04-18 stsp repo, update_progress, &upa, check_cancelled,
6097 9627c110 2020-04-18 stsp NULL);
6098 da76fce2 2020-02-24 stsp if (error)
6099 da76fce2 2020-02-24 stsp goto done;
6100 4f3c844b 2021-09-14 stsp if (upa.did_something) {
6101 4f3c844b 2021-09-14 stsp printf("Updated to %s: %s\n",
6102 4f3c844b 2021-09-14 stsp got_worktree_get_head_ref_name(worktree),
6103 4f3c844b 2021-09-14 stsp commit_id_str);
6104 4f3c844b 2021-09-14 stsp }
6105 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
6106 da76fce2 2020-02-24 stsp }
6107 4e759de4 2019-06-26 stsp }
6108 4e759de4 2019-06-26 stsp done:
6109 da76fce2 2020-02-24 stsp if (ref)
6110 da76fce2 2020-02-24 stsp got_ref_close(ref);
6111 1d0f4054 2021-06-17 stsp if (repo) {
6112 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6113 1d0f4054 2021-06-17 stsp if (error == NULL)
6114 1d0f4054 2021-06-17 stsp error = close_err;
6115 1d0f4054 2021-06-17 stsp }
6116 d0eebce4 2019-03-11 stsp if (worktree)
6117 d0eebce4 2019-03-11 stsp got_worktree_close(worktree);
6118 d0eebce4 2019-03-11 stsp free(cwd);
6119 d0eebce4 2019-03-11 stsp free(repo_path);
6120 da76fce2 2020-02-24 stsp free(commit_id);
6121 da76fce2 2020-02-24 stsp free(commit_id_str);
6122 da76fce2 2020-02-24 stsp TAILQ_FOREACH(pe, &paths, entry)
6123 da76fce2 2020-02-24 stsp free((char *)pe->path);
6124 da76fce2 2020-02-24 stsp got_pathlist_free(&paths);
6125 d00136be 2019-03-26 stsp return error;
6126 d00136be 2019-03-26 stsp }
6127 d00136be 2019-03-26 stsp
6128 8e7bd50a 2019-08-22 stsp
6129 d00136be 2019-03-26 stsp __dead static void
6130 8e7bd50a 2019-08-22 stsp usage_tag(void)
6131 8e7bd50a 2019-08-22 stsp {
6132 8e7bd50a 2019-08-22 stsp fprintf(stderr,
6133 80106605 2020-02-24 stsp "usage: %s tag [-c commit] [-r repository] [-l] "
6134 80106605 2020-02-24 stsp "[-m message] name\n", getprogname());
6135 8e7bd50a 2019-08-22 stsp exit(1);
6136 b8bad2ba 2019-08-23 stsp }
6137 b8bad2ba 2019-08-23 stsp
6138 b8bad2ba 2019-08-23 stsp #if 0
6139 b8bad2ba 2019-08-23 stsp static const struct got_error *
6140 b8bad2ba 2019-08-23 stsp sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
6141 b8bad2ba 2019-08-23 stsp {
6142 b8bad2ba 2019-08-23 stsp const struct got_error *err = NULL;
6143 b8bad2ba 2019-08-23 stsp struct got_reflist_entry *re, *se, *new;
6144 b8bad2ba 2019-08-23 stsp struct got_object_id *re_id, *se_id;
6145 b8bad2ba 2019-08-23 stsp struct got_tag_object *re_tag, *se_tag;
6146 b8bad2ba 2019-08-23 stsp time_t re_time, se_time;
6147 b8bad2ba 2019-08-23 stsp
6148 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(re, tags, entry) {
6149 dbdddfee 2021-06-23 naddy se = STAILQ_FIRST(sorted);
6150 b8bad2ba 2019-08-23 stsp if (se == NULL) {
6151 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
6152 b8bad2ba 2019-08-23 stsp if (err)
6153 b8bad2ba 2019-08-23 stsp return err;
6154 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(sorted, new, entry);
6155 b8bad2ba 2019-08-23 stsp continue;
6156 b8bad2ba 2019-08-23 stsp } else {
6157 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&re_id, repo, re->ref);
6158 b8bad2ba 2019-08-23 stsp if (err)
6159 b8bad2ba 2019-08-23 stsp break;
6160 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&re_tag, repo, re_id);
6161 b8bad2ba 2019-08-23 stsp free(re_id);
6162 b8bad2ba 2019-08-23 stsp if (err)
6163 b8bad2ba 2019-08-23 stsp break;
6164 b8bad2ba 2019-08-23 stsp re_time = got_object_tag_get_tagger_time(re_tag);
6165 b8bad2ba 2019-08-23 stsp got_object_tag_close(re_tag);
6166 b8bad2ba 2019-08-23 stsp }
6167 b8bad2ba 2019-08-23 stsp
6168 b8bad2ba 2019-08-23 stsp while (se) {
6169 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&se_id, repo, re->ref);
6170 b8bad2ba 2019-08-23 stsp if (err)
6171 b8bad2ba 2019-08-23 stsp break;
6172 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&se_tag, repo, se_id);
6173 b8bad2ba 2019-08-23 stsp free(se_id);
6174 b8bad2ba 2019-08-23 stsp if (err)
6175 b8bad2ba 2019-08-23 stsp break;
6176 b8bad2ba 2019-08-23 stsp se_time = got_object_tag_get_tagger_time(se_tag);
6177 b8bad2ba 2019-08-23 stsp got_object_tag_close(se_tag);
6178 b8bad2ba 2019-08-23 stsp
6179 b8bad2ba 2019-08-23 stsp if (se_time > re_time) {
6180 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
6181 b8bad2ba 2019-08-23 stsp if (err)
6182 b8bad2ba 2019-08-23 stsp return err;
6183 dbdddfee 2021-06-23 naddy STAILQ_INSERT_AFTER(sorted, se, new, entry);
6184 b8bad2ba 2019-08-23 stsp break;
6185 b8bad2ba 2019-08-23 stsp }
6186 dbdddfee 2021-06-23 naddy se = STAILQ_NEXT(se, entry);
6187 b8bad2ba 2019-08-23 stsp continue;
6188 b8bad2ba 2019-08-23 stsp }
6189 b8bad2ba 2019-08-23 stsp }
6190 b8bad2ba 2019-08-23 stsp done:
6191 b8bad2ba 2019-08-23 stsp return err;
6192 8e7bd50a 2019-08-22 stsp }
6193 b8bad2ba 2019-08-23 stsp #endif
6194 b8bad2ba 2019-08-23 stsp
6195 b8bad2ba 2019-08-23 stsp static const struct got_error *
6196 8e7bd50a 2019-08-22 stsp list_tags(struct got_repository *repo, struct got_worktree *worktree)
6197 8e7bd50a 2019-08-22 stsp {
6198 8e7bd50a 2019-08-22 stsp static const struct got_error *err = NULL;
6199 8e7bd50a 2019-08-22 stsp struct got_reflist_head refs;
6200 8e7bd50a 2019-08-22 stsp struct got_reflist_entry *re;
6201 8e7bd50a 2019-08-22 stsp
6202 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6203 8e7bd50a 2019-08-22 stsp
6204 d1f16636 2020-01-15 stsp err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
6205 8e7bd50a 2019-08-22 stsp if (err)
6206 8e7bd50a 2019-08-22 stsp return err;
6207 8e7bd50a 2019-08-22 stsp
6208 d9dff0e5 2020-12-26 stsp TAILQ_FOREACH(re, &refs, entry) {
6209 8e7bd50a 2019-08-22 stsp const char *refname;
6210 8e7bd50a 2019-08-22 stsp char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
6211 8e7bd50a 2019-08-22 stsp char datebuf[26];
6212 d4efa91b 2020-01-14 stsp const char *tagger;
6213 8e7bd50a 2019-08-22 stsp time_t tagger_time;
6214 8e7bd50a 2019-08-22 stsp struct got_object_id *id;
6215 8e7bd50a 2019-08-22 stsp struct got_tag_object *tag;
6216 d4efa91b 2020-01-14 stsp struct got_commit_object *commit = NULL;
6217 8e7bd50a 2019-08-22 stsp
6218 8e7bd50a 2019-08-22 stsp refname = got_ref_get_name(re->ref);
6219 8e7bd50a 2019-08-22 stsp if (strncmp(refname, "refs/tags/", 10) != 0)
6220 8e7bd50a 2019-08-22 stsp continue;
6221 8e7bd50a 2019-08-22 stsp refname += 10;
6222 8e7bd50a 2019-08-22 stsp refstr = got_ref_to_str(re->ref);
6223 8e7bd50a 2019-08-22 stsp if (refstr == NULL) {
6224 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("got_ref_to_str");
6225 8e7bd50a 2019-08-22 stsp break;
6226 8e7bd50a 2019-08-22 stsp }
6227 8e7bd50a 2019-08-22 stsp printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr);
6228 8e7bd50a 2019-08-22 stsp free(refstr);
6229 8e7bd50a 2019-08-22 stsp
6230 8e7bd50a 2019-08-22 stsp err = got_ref_resolve(&id, repo, re->ref);
6231 8e7bd50a 2019-08-22 stsp if (err)
6232 8e7bd50a 2019-08-22 stsp break;
6233 8e7bd50a 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
6234 d4efa91b 2020-01-14 stsp if (err) {
6235 d4efa91b 2020-01-14 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
6236 d4efa91b 2020-01-14 stsp free(id);
6237 d4efa91b 2020-01-14 stsp break;
6238 d4efa91b 2020-01-14 stsp }
6239 d4efa91b 2020-01-14 stsp /* "lightweight" tag */
6240 d4efa91b 2020-01-14 stsp err = got_object_open_as_commit(&commit, repo, id);
6241 d4efa91b 2020-01-14 stsp if (err) {
6242 d4efa91b 2020-01-14 stsp free(id);
6243 d4efa91b 2020-01-14 stsp break;
6244 d4efa91b 2020-01-14 stsp }
6245 d4efa91b 2020-01-14 stsp tagger = got_object_commit_get_committer(commit);
6246 d4efa91b 2020-01-14 stsp tagger_time =
6247 d4efa91b 2020-01-14 stsp got_object_commit_get_committer_time(commit);
6248 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str, id);
6249 d4efa91b 2020-01-14 stsp free(id);
6250 d4efa91b 2020-01-14 stsp if (err)
6251 d4efa91b 2020-01-14 stsp break;
6252 d4efa91b 2020-01-14 stsp } else {
6253 d4efa91b 2020-01-14 stsp free(id);
6254 d4efa91b 2020-01-14 stsp tagger = got_object_tag_get_tagger(tag);
6255 d4efa91b 2020-01-14 stsp tagger_time = got_object_tag_get_tagger_time(tag);
6256 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str,
6257 d4efa91b 2020-01-14 stsp got_object_tag_get_object_id(tag));
6258 d4efa91b 2020-01-14 stsp if (err)
6259 d4efa91b 2020-01-14 stsp break;
6260 d4efa91b 2020-01-14 stsp }
6261 d4efa91b 2020-01-14 stsp printf("from: %s\n", tagger);
6262 2417344c 2019-08-23 stsp datestr = get_datestr(&tagger_time, datebuf);
6263 2417344c 2019-08-23 stsp if (datestr)
6264 2417344c 2019-08-23 stsp printf("date: %s UTC\n", datestr);
6265 d4efa91b 2020-01-14 stsp if (commit)
6266 2417344c 2019-08-23 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str);
6267 d4efa91b 2020-01-14 stsp else {
6268 d4efa91b 2020-01-14 stsp switch (got_object_tag_get_object_type(tag)) {
6269 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_BLOB:
6270 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB,
6271 d4efa91b 2020-01-14 stsp id_str);
6272 d4efa91b 2020-01-14 stsp break;
6273 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TREE:
6274 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TREE,
6275 d4efa91b 2020-01-14 stsp id_str);
6276 d4efa91b 2020-01-14 stsp break;
6277 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_COMMIT:
6278 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT,
6279 d4efa91b 2020-01-14 stsp id_str);
6280 d4efa91b 2020-01-14 stsp break;
6281 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TAG:
6282 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TAG,
6283 d4efa91b 2020-01-14 stsp id_str);
6284 d4efa91b 2020-01-14 stsp break;
6285 d4efa91b 2020-01-14 stsp default:
6286 d4efa91b 2020-01-14 stsp break;
6287 d4efa91b 2020-01-14 stsp }
6288 8e7bd50a 2019-08-22 stsp }
6289 8e7bd50a 2019-08-22 stsp free(id_str);
6290 d4efa91b 2020-01-14 stsp if (commit) {
6291 d4efa91b 2020-01-14 stsp err = got_object_commit_get_logmsg(&tagmsg0, commit);
6292 d4efa91b 2020-01-14 stsp if (err)
6293 d4efa91b 2020-01-14 stsp break;
6294 d4efa91b 2020-01-14 stsp got_object_commit_close(commit);
6295 d4efa91b 2020-01-14 stsp } else {
6296 d4efa91b 2020-01-14 stsp tagmsg0 = strdup(got_object_tag_get_message(tag));
6297 d4efa91b 2020-01-14 stsp got_object_tag_close(tag);
6298 d4efa91b 2020-01-14 stsp if (tagmsg0 == NULL) {
6299 d4efa91b 2020-01-14 stsp err = got_error_from_errno("strdup");
6300 d4efa91b 2020-01-14 stsp break;
6301 d4efa91b 2020-01-14 stsp }
6302 8e7bd50a 2019-08-22 stsp }
6303 8e7bd50a 2019-08-22 stsp
6304 8e7bd50a 2019-08-22 stsp tagmsg = tagmsg0;
6305 8e7bd50a 2019-08-22 stsp do {
6306 8e7bd50a 2019-08-22 stsp line = strsep(&tagmsg, "\n");
6307 8e7bd50a 2019-08-22 stsp if (line)
6308 8e7bd50a 2019-08-22 stsp printf(" %s\n", line);
6309 8e7bd50a 2019-08-22 stsp } while (line);
6310 8e7bd50a 2019-08-22 stsp free(tagmsg0);
6311 8e7bd50a 2019-08-22 stsp }
6312 8e7bd50a 2019-08-22 stsp
6313 8e7bd50a 2019-08-22 stsp got_ref_list_free(&refs);
6314 8e7bd50a 2019-08-22 stsp return NULL;
6315 8e7bd50a 2019-08-22 stsp }
6316 8e7bd50a 2019-08-22 stsp
6317 8e7bd50a 2019-08-22 stsp static const struct got_error *
6318 f372d5cd 2019-10-21 stsp get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
6319 62870f63 2019-08-22 stsp const char *tag_name, const char *repo_path)
6320 8e7bd50a 2019-08-22 stsp {
6321 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
6322 8e7bd50a 2019-08-22 stsp char *template = NULL, *initial_content = NULL;
6323 f372d5cd 2019-10-21 stsp char *editor = NULL;
6324 1601cb9f 2020-09-11 naddy int initial_content_len;
6325 8e7bd50a 2019-08-22 stsp int fd = -1;
6326 8e7bd50a 2019-08-22 stsp
6327 bb63914a 2020-02-17 stsp if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) {
6328 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
6329 8e7bd50a 2019-08-22 stsp goto done;
6330 8e7bd50a 2019-08-22 stsp }
6331 8e7bd50a 2019-08-22 stsp
6332 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
6333 1601cb9f 2020-09-11 naddy "\n# tagging commit %s as %s\n",
6334 1601cb9f 2020-09-11 naddy commit_id_str, tag_name);
6335 1601cb9f 2020-09-11 naddy if (initial_content_len == -1) {
6336 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
6337 8e7bd50a 2019-08-22 stsp goto done;
6338 8e7bd50a 2019-08-22 stsp }
6339 8e7bd50a 2019-08-22 stsp
6340 f372d5cd 2019-10-21 stsp err = got_opentemp_named_fd(tagmsg_path, &fd, template);
6341 8e7bd50a 2019-08-22 stsp if (err)
6342 8e7bd50a 2019-08-22 stsp goto done;
6343 8e7bd50a 2019-08-22 stsp
6344 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
6345 97972933 2020-09-11 stsp err = got_error_from_errno2("write", *tagmsg_path);
6346 97972933 2020-09-11 stsp goto done;
6347 97972933 2020-09-11 stsp }
6348 8e7bd50a 2019-08-22 stsp
6349 8e7bd50a 2019-08-22 stsp err = get_editor(&editor);
6350 8e7bd50a 2019-08-22 stsp if (err)
6351 8e7bd50a 2019-08-22 stsp goto done;
6352 bfa12d5e 2020-09-26 stsp err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content,
6353 0d5bb276 2020-12-15 stsp initial_content_len, 1);
6354 8e7bd50a 2019-08-22 stsp done:
6355 8e7bd50a 2019-08-22 stsp free(initial_content);
6356 8e7bd50a 2019-08-22 stsp free(template);
6357 8e7bd50a 2019-08-22 stsp free(editor);
6358 8e7bd50a 2019-08-22 stsp
6359 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
6360 97972933 2020-09-11 stsp err = got_error_from_errno2("close", *tagmsg_path);
6361 97972933 2020-09-11 stsp
6362 8e7bd50a 2019-08-22 stsp /* Editor is done; we can now apply unveil(2) */
6363 59f86c76 2020-09-11 stsp if (err == NULL)
6364 8e7bd50a 2019-08-22 stsp err = apply_unveil(repo_path, 0, NULL);
6365 59f86c76 2020-09-11 stsp if (err) {
6366 59f86c76 2020-09-11 stsp free(*tagmsg);
6367 59f86c76 2020-09-11 stsp *tagmsg = NULL;
6368 8e7bd50a 2019-08-22 stsp }
6369 8e7bd50a 2019-08-22 stsp return err;
6370 8e7bd50a 2019-08-22 stsp }
6371 8e7bd50a 2019-08-22 stsp
6372 8e7bd50a 2019-08-22 stsp static const struct got_error *
6373 50b0790e 2020-09-11 stsp add_tag(struct got_repository *repo, struct got_worktree *worktree,
6374 50b0790e 2020-09-11 stsp const char *tag_name, const char *commit_arg, const char *tagmsg_arg)
6375 8e7bd50a 2019-08-22 stsp {
6376 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
6377 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id = NULL, *tag_id = NULL;
6378 8e7bd50a 2019-08-22 stsp char *label = NULL, *commit_id_str = NULL;
6379 8e7bd50a 2019-08-22 stsp struct got_reference *ref = NULL;
6380 aba9c984 2019-09-08 stsp char *refname = NULL, *tagmsg = NULL, *tagger = NULL;
6381 f372d5cd 2019-10-21 stsp char *tagmsg_path = NULL, *tag_id_str = NULL;
6382 f372d5cd 2019-10-21 stsp int preserve_tagmsg = 0;
6383 84de9106 2020-12-26 stsp struct got_reflist_head refs;
6384 8e7bd50a 2019-08-22 stsp
6385 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
6386 84de9106 2020-12-26 stsp
6387 8e7bd50a 2019-08-22 stsp /*
6388 bd5895f3 2019-11-28 stsp * Don't let the user create a tag name with a leading '-'.
6389 8e7bd50a 2019-08-22 stsp * While technically a valid reference name, this case is usually
6390 8e7bd50a 2019-08-22 stsp * an unintended typo.
6391 8e7bd50a 2019-08-22 stsp */
6392 bd5895f3 2019-11-28 stsp if (tag_name[0] == '-')
6393 bd5895f3 2019-11-28 stsp return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS);
6394 8e7bd50a 2019-08-22 stsp
6395 50b0790e 2020-09-11 stsp err = get_author(&tagger, repo, worktree);
6396 8e7bd50a 2019-08-22 stsp if (err)
6397 8e7bd50a 2019-08-22 stsp return err;
6398 8e7bd50a 2019-08-22 stsp
6399 84de9106 2020-12-26 stsp err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
6400 84de9106 2020-12-26 stsp if (err)
6401 84de9106 2020-12-26 stsp goto done;
6402 84de9106 2020-12-26 stsp
6403 71a27632 2020-01-15 stsp err = got_repo_match_object_id(&commit_id, &label, commit_arg,
6404 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_COMMIT, &refs, repo);
6405 8e7bd50a 2019-08-22 stsp if (err)
6406 8e7bd50a 2019-08-22 stsp goto done;
6407 8e7bd50a 2019-08-22 stsp
6408 8e7bd50a 2019-08-22 stsp err = got_object_id_str(&commit_id_str, commit_id);
6409 8e7bd50a 2019-08-22 stsp if (err)
6410 8e7bd50a 2019-08-22 stsp goto done;
6411 8e7bd50a 2019-08-22 stsp
6412 8e7bd50a 2019-08-22 stsp if (strncmp("refs/tags/", tag_name, 10) == 0) {
6413 8e7bd50a 2019-08-22 stsp refname = strdup(tag_name);
6414 8e7bd50a 2019-08-22 stsp if (refname == NULL) {
6415 62d463ca 2020-10-20 naddy err = got_error_from_errno("strdup");
6416 62d463ca 2020-10-20 naddy goto done;
6417 8e7bd50a 2019-08-22 stsp }
6418 8e7bd50a 2019-08-22 stsp tag_name += 10;
6419 8e7bd50a 2019-08-22 stsp } else if (asprintf(&refname, "refs/tags/%s", tag_name) == -1) {
6420 62d463ca 2020-10-20 naddy err = got_error_from_errno("asprintf");
6421 62d463ca 2020-10-20 naddy goto done;
6422 8e7bd50a 2019-08-22 stsp }
6423 8e7bd50a 2019-08-22 stsp
6424 8e7bd50a 2019-08-22 stsp err = got_ref_open(&ref, repo, refname, 0);
6425 8e7bd50a 2019-08-22 stsp if (err == NULL) {
6426 8e7bd50a 2019-08-22 stsp err = got_error(GOT_ERR_TAG_EXISTS);
6427 8e7bd50a 2019-08-22 stsp goto done;
6428 8e7bd50a 2019-08-22 stsp } else if (err->code != GOT_ERR_NOT_REF)
6429 8e7bd50a 2019-08-22 stsp goto done;
6430 8e7bd50a 2019-08-22 stsp
6431 8e7bd50a 2019-08-22 stsp if (tagmsg_arg == NULL) {
6432 f372d5cd 2019-10-21 stsp err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
6433 62870f63 2019-08-22 stsp tag_name, got_repo_get_path(repo));
6434 f372d5cd 2019-10-21 stsp if (err) {
6435 f372d5cd 2019-10-21 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY &&
6436 f372d5cd 2019-10-21 stsp tagmsg_path != NULL)
6437 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6438 8e7bd50a 2019-08-22 stsp goto done;
6439 f372d5cd 2019-10-21 stsp }
6440 8e7bd50a 2019-08-22 stsp }
6441 8e7bd50a 2019-08-22 stsp
6442 8e7bd50a 2019-08-22 stsp err = got_object_tag_create(&tag_id, tag_name, commit_id,
6443 8e7bd50a 2019-08-22 stsp tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, repo);
6444 f372d5cd 2019-10-21 stsp if (err) {
6445 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6446 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6447 8e7bd50a 2019-08-22 stsp goto done;
6448 f372d5cd 2019-10-21 stsp }
6449 8e7bd50a 2019-08-22 stsp
6450 8e7bd50a 2019-08-22 stsp err = got_ref_alloc(&ref, refname, tag_id);
6451 f372d5cd 2019-10-21 stsp if (err) {
6452 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6453 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6454 8e7bd50a 2019-08-22 stsp goto done;
6455 f372d5cd 2019-10-21 stsp }
6456 8e7bd50a 2019-08-22 stsp
6457 8e7bd50a 2019-08-22 stsp err = got_ref_write(ref, repo);
6458 f372d5cd 2019-10-21 stsp if (err) {
6459 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6460 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6461 f372d5cd 2019-10-21 stsp goto done;
6462 f372d5cd 2019-10-21 stsp }
6463 8e7bd50a 2019-08-22 stsp
6464 f372d5cd 2019-10-21 stsp err = got_object_id_str(&tag_id_str, tag_id);
6465 f372d5cd 2019-10-21 stsp if (err) {
6466 f372d5cd 2019-10-21 stsp if (tagmsg_path)
6467 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
6468 f372d5cd 2019-10-21 stsp goto done;
6469 8e7bd50a 2019-08-22 stsp }
6470 f372d5cd 2019-10-21 stsp printf("Created tag %s\n", tag_id_str);
6471 8e7bd50a 2019-08-22 stsp done:
6472 f372d5cd 2019-10-21 stsp if (preserve_tagmsg) {
6473 f372d5cd 2019-10-21 stsp fprintf(stderr, "%s: tag message preserved in %s\n",
6474 f372d5cd 2019-10-21 stsp getprogname(), tagmsg_path);
6475 f372d5cd 2019-10-21 stsp } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL)
6476 f372d5cd 2019-10-21 stsp err = got_error_from_errno2("unlink", tagmsg_path);
6477 f372d5cd 2019-10-21 stsp free(tag_id_str);
6478 8e7bd50a 2019-08-22 stsp if (ref)
6479 8e7bd50a 2019-08-22 stsp got_ref_close(ref);
6480 8e7bd50a 2019-08-22 stsp free(commit_id);
6481 8e7bd50a 2019-08-22 stsp free(commit_id_str);
6482 8e7bd50a 2019-08-22 stsp free(refname);
6483 8e7bd50a 2019-08-22 stsp free(tagmsg);
6484 f372d5cd 2019-10-21 stsp free(tagmsg_path);
6485 aba9c984 2019-09-08 stsp free(tagger);
6486 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
6487 8e7bd50a 2019-08-22 stsp return err;
6488 8e7bd50a 2019-08-22 stsp }
6489 8e7bd50a 2019-08-22 stsp
6490 8e7bd50a 2019-08-22 stsp static const struct got_error *
6491 8e7bd50a 2019-08-22 stsp cmd_tag(int argc, char *argv[])
6492 8e7bd50a 2019-08-22 stsp {
6493 8e7bd50a 2019-08-22 stsp const struct got_error *error = NULL;
6494 8e7bd50a 2019-08-22 stsp struct got_repository *repo = NULL;
6495 8e7bd50a 2019-08-22 stsp struct got_worktree *worktree = NULL;
6496 8e7bd50a 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
6497 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL;
6498 8e7bd50a 2019-08-22 stsp const char *tag_name, *commit_id_arg = NULL, *tagmsg = NULL;
6499 8e7bd50a 2019-08-22 stsp int ch, do_list = 0;
6500 8e7bd50a 2019-08-22 stsp
6501 80106605 2020-02-24 stsp while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) {
6502 8e7bd50a 2019-08-22 stsp switch (ch) {
6503 80106605 2020-02-24 stsp case 'c':
6504 80106605 2020-02-24 stsp commit_id_arg = optarg;
6505 80106605 2020-02-24 stsp break;
6506 8e7bd50a 2019-08-22 stsp case 'm':
6507 8e7bd50a 2019-08-22 stsp tagmsg = optarg;
6508 8e7bd50a 2019-08-22 stsp break;
6509 8e7bd50a 2019-08-22 stsp case 'r':
6510 8e7bd50a 2019-08-22 stsp repo_path = realpath(optarg, NULL);
6511 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
6512 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
6513 9ba1d308 2019-10-21 stsp optarg);
6514 8e7bd50a 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
6515 8e7bd50a 2019-08-22 stsp break;
6516 8e7bd50a 2019-08-22 stsp case 'l':
6517 8e7bd50a 2019-08-22 stsp do_list = 1;
6518 8e7bd50a 2019-08-22 stsp break;
6519 8e7bd50a 2019-08-22 stsp default:
6520 8e7bd50a 2019-08-22 stsp usage_tag();
6521 8e7bd50a 2019-08-22 stsp /* NOTREACHED */
6522 8e7bd50a 2019-08-22 stsp }
6523 8e7bd50a 2019-08-22 stsp }
6524 8e7bd50a 2019-08-22 stsp
6525 8e7bd50a 2019-08-22 stsp argc -= optind;
6526 8e7bd50a 2019-08-22 stsp argv += optind;
6527 8e7bd50a 2019-08-22 stsp
6528 8e7bd50a 2019-08-22 stsp if (do_list) {
6529 80106605 2020-02-24 stsp if (commit_id_arg != NULL)
6530 775ce909 2020-03-22 stsp errx(1,
6531 775ce909 2020-03-22 stsp "-c option can only be used when creating a tag");
6532 8e7bd50a 2019-08-22 stsp if (tagmsg)
6533 ff69268e 2020-12-13 stsp option_conflict('l', 'm');
6534 8e7bd50a 2019-08-22 stsp if (argc > 0)
6535 8e7bd50a 2019-08-22 stsp usage_tag();
6536 80106605 2020-02-24 stsp } else if (argc != 1)
6537 8e7bd50a 2019-08-22 stsp usage_tag();
6538 80106605 2020-02-24 stsp
6539 a2887370 2019-08-23 stsp tag_name = argv[0];
6540 8e7bd50a 2019-08-22 stsp
6541 8e7bd50a 2019-08-22 stsp #ifndef PROFILE
6542 8e7bd50a 2019-08-22 stsp if (do_list) {
6543 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6544 8e7bd50a 2019-08-22 stsp NULL) == -1)
6545 8e7bd50a 2019-08-22 stsp err(1, "pledge");
6546 8e7bd50a 2019-08-22 stsp } else {
6547 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6548 8e7bd50a 2019-08-22 stsp "sendfd unveil", NULL) == -1)
6549 8e7bd50a 2019-08-22 stsp err(1, "pledge");
6550 8e7bd50a 2019-08-22 stsp }
6551 8e7bd50a 2019-08-22 stsp #endif
6552 8e7bd50a 2019-08-22 stsp cwd = getcwd(NULL, 0);
6553 8e7bd50a 2019-08-22 stsp if (cwd == NULL) {
6554 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("getcwd");
6555 8e7bd50a 2019-08-22 stsp goto done;
6556 8e7bd50a 2019-08-22 stsp }
6557 8e7bd50a 2019-08-22 stsp
6558 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
6559 8e7bd50a 2019-08-22 stsp error = got_worktree_open(&worktree, cwd);
6560 8e7bd50a 2019-08-22 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
6561 8e7bd50a 2019-08-22 stsp goto done;
6562 8e7bd50a 2019-08-22 stsp else
6563 8e7bd50a 2019-08-22 stsp error = NULL;
6564 8e7bd50a 2019-08-22 stsp if (worktree) {
6565 8e7bd50a 2019-08-22 stsp repo_path =
6566 8e7bd50a 2019-08-22 stsp strdup(got_worktree_get_repo_path(worktree));
6567 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
6568 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
6569 8e7bd50a 2019-08-22 stsp if (error)
6570 8e7bd50a 2019-08-22 stsp goto done;
6571 8e7bd50a 2019-08-22 stsp } else {
6572 8e7bd50a 2019-08-22 stsp repo_path = strdup(cwd);
6573 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
6574 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
6575 8e7bd50a 2019-08-22 stsp goto done;
6576 8e7bd50a 2019-08-22 stsp }
6577 8e7bd50a 2019-08-22 stsp }
6578 8e7bd50a 2019-08-22 stsp }
6579 8e7bd50a 2019-08-22 stsp
6580 8e7bd50a 2019-08-22 stsp if (do_list) {
6581 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
6582 c9956ddf 2019-09-08 stsp if (error != NULL)
6583 c9956ddf 2019-09-08 stsp goto done;
6584 8e7bd50a 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
6585 8e7bd50a 2019-08-22 stsp if (error)
6586 8e7bd50a 2019-08-22 stsp goto done;
6587 8e7bd50a 2019-08-22 stsp error = list_tags(repo, worktree);
6588 8e7bd50a 2019-08-22 stsp } else {
6589 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
6590 c9956ddf 2019-09-08 stsp if (error)
6591 c9956ddf 2019-09-08 stsp goto done;
6592 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
6593 c9956ddf 2019-09-08 stsp if (error != NULL)
6594 c9956ddf 2019-09-08 stsp goto done;
6595 c9956ddf 2019-09-08 stsp
6596 8e7bd50a 2019-08-22 stsp if (tagmsg) {
6597 42a285e2 2020-10-01 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
6598 8e7bd50a 2019-08-22 stsp if (error)
6599 8e7bd50a 2019-08-22 stsp goto done;
6600 8e7bd50a 2019-08-22 stsp }
6601 8e7bd50a 2019-08-22 stsp
6602 8e7bd50a 2019-08-22 stsp if (commit_id_arg == NULL) {
6603 8e7bd50a 2019-08-22 stsp struct got_reference *head_ref;
6604 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id;
6605 8e7bd50a 2019-08-22 stsp error = got_ref_open(&head_ref, repo,
6606 8e7bd50a 2019-08-22 stsp worktree ? got_worktree_get_head_ref_name(worktree)
6607 8e7bd50a 2019-08-22 stsp : GOT_REF_HEAD, 0);
6608 8e7bd50a 2019-08-22 stsp if (error)
6609 8e7bd50a 2019-08-22 stsp goto done;
6610 8e7bd50a 2019-08-22 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
6611 8e7bd50a 2019-08-22 stsp got_ref_close(head_ref);
6612 8e7bd50a 2019-08-22 stsp if (error)
6613 8e7bd50a 2019-08-22 stsp goto done;
6614 8e7bd50a 2019-08-22 stsp error = got_object_id_str(&commit_id_str, commit_id);
6615 8e7bd50a 2019-08-22 stsp free(commit_id);
6616 8e7bd50a 2019-08-22 stsp if (error)
6617 8e7bd50a 2019-08-22 stsp goto done;
6618 8e7bd50a 2019-08-22 stsp }
6619 8e7bd50a 2019-08-22 stsp
6620 50b0790e 2020-09-11 stsp error = add_tag(repo, worktree, tag_name,
6621 8e7bd50a 2019-08-22 stsp commit_id_str ? commit_id_str : commit_id_arg, tagmsg);
6622 8e7bd50a 2019-08-22 stsp }
6623 8e7bd50a 2019-08-22 stsp done:
6624 1d0f4054 2021-06-17 stsp if (repo) {
6625 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6626 1d0f4054 2021-06-17 stsp if (error == NULL)
6627 1d0f4054 2021-06-17 stsp error = close_err;
6628 1d0f4054 2021-06-17 stsp }
6629 8e7bd50a 2019-08-22 stsp if (worktree)
6630 8e7bd50a 2019-08-22 stsp got_worktree_close(worktree);
6631 8e7bd50a 2019-08-22 stsp free(cwd);
6632 8e7bd50a 2019-08-22 stsp free(repo_path);
6633 c9956ddf 2019-09-08 stsp free(gitconfig_path);
6634 8e7bd50a 2019-08-22 stsp free(commit_id_str);
6635 8e7bd50a 2019-08-22 stsp return error;
6636 8e7bd50a 2019-08-22 stsp }
6637 8e7bd50a 2019-08-22 stsp
6638 8e7bd50a 2019-08-22 stsp __dead static void
6639 d00136be 2019-03-26 stsp usage_add(void)
6640 d00136be 2019-03-26 stsp {
6641 c29c428a 2019-12-16 stsp fprintf(stderr, "usage: %s add [-R] [-I] path ...\n",
6642 022fae89 2019-12-06 tracey getprogname());
6643 d00136be 2019-03-26 stsp exit(1);
6644 d00136be 2019-03-26 stsp }
6645 d00136be 2019-03-26 stsp
6646 d00136be 2019-03-26 stsp static const struct got_error *
6647 4e68cba3 2019-11-23 stsp add_progress(void *arg, unsigned char status, const char *path)
6648 4e68cba3 2019-11-23 stsp {
6649 4e68cba3 2019-11-23 stsp while (path[0] == '/')
6650 4e68cba3 2019-11-23 stsp path++;
6651 4e68cba3 2019-11-23 stsp printf("%c %s\n", status, path);
6652 4e68cba3 2019-11-23 stsp return NULL;
6653 4e68cba3 2019-11-23 stsp }
6654 4e68cba3 2019-11-23 stsp
6655 4e68cba3 2019-11-23 stsp static const struct got_error *
6656 d00136be 2019-03-26 stsp cmd_add(int argc, char *argv[])
6657 d00136be 2019-03-26 stsp {
6658 d00136be 2019-03-26 stsp const struct got_error *error = NULL;
6659 031a5338 2019-03-26 stsp struct got_repository *repo = NULL;
6660 d00136be 2019-03-26 stsp struct got_worktree *worktree = NULL;
6661 1dd54920 2019-05-11 stsp char *cwd = NULL;
6662 1dd54920 2019-05-11 stsp struct got_pathlist_head paths;
6663 1dd54920 2019-05-11 stsp struct got_pathlist_entry *pe;
6664 022fae89 2019-12-06 tracey int ch, can_recurse = 0, no_ignores = 0;
6665 1dd54920 2019-05-11 stsp
6666 1dd54920 2019-05-11 stsp TAILQ_INIT(&paths);
6667 d00136be 2019-03-26 stsp
6668 022fae89 2019-12-06 tracey while ((ch = getopt(argc, argv, "IR")) != -1) {
6669 d00136be 2019-03-26 stsp switch (ch) {
6670 022fae89 2019-12-06 tracey case 'I':
6671 022fae89 2019-12-06 tracey no_ignores = 1;
6672 022fae89 2019-12-06 tracey break;
6673 4e68cba3 2019-11-23 stsp case 'R':
6674 4e68cba3 2019-11-23 stsp can_recurse = 1;
6675 4e68cba3 2019-11-23 stsp break;
6676 d00136be 2019-03-26 stsp default:
6677 d00136be 2019-03-26 stsp usage_add();
6678 d00136be 2019-03-26 stsp /* NOTREACHED */
6679 d00136be 2019-03-26 stsp }
6680 d00136be 2019-03-26 stsp }
6681 d00136be 2019-03-26 stsp
6682 d00136be 2019-03-26 stsp argc -= optind;
6683 d00136be 2019-03-26 stsp argv += optind;
6684 d00136be 2019-03-26 stsp
6685 43012d58 2019-07-14 stsp #ifndef PROFILE
6686 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6687 43012d58 2019-07-14 stsp NULL) == -1)
6688 43012d58 2019-07-14 stsp err(1, "pledge");
6689 43012d58 2019-07-14 stsp #endif
6690 723c305c 2019-05-11 jcs if (argc < 1)
6691 d00136be 2019-03-26 stsp usage_add();
6692 d00136be 2019-03-26 stsp
6693 d00136be 2019-03-26 stsp cwd = getcwd(NULL, 0);
6694 d00136be 2019-03-26 stsp if (cwd == NULL) {
6695 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6696 d00136be 2019-03-26 stsp goto done;
6697 d00136be 2019-03-26 stsp }
6698 723c305c 2019-05-11 jcs
6699 d00136be 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
6700 fa51e947 2020-03-27 stsp if (error) {
6701 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6702 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "add", cwd);
6703 d00136be 2019-03-26 stsp goto done;
6704 fa51e947 2020-03-27 stsp }
6705 d00136be 2019-03-26 stsp
6706 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6707 c9956ddf 2019-09-08 stsp NULL);
6708 031a5338 2019-03-26 stsp if (error != NULL)
6709 031a5338 2019-03-26 stsp goto done;
6710 031a5338 2019-03-26 stsp
6711 031a5338 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
6712 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6713 d00136be 2019-03-26 stsp if (error)
6714 d00136be 2019-03-26 stsp goto done;
6715 d00136be 2019-03-26 stsp
6716 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6717 6d022e97 2019-08-04 stsp if (error)
6718 022fae89 2019-12-06 tracey goto done;
6719 022fae89 2019-12-06 tracey
6720 4e68cba3 2019-11-23 stsp if (!can_recurse) {
6721 4e68cba3 2019-11-23 stsp char *ondisk_path;
6722 4e68cba3 2019-11-23 stsp struct stat sb;
6723 4e68cba3 2019-11-23 stsp TAILQ_FOREACH(pe, &paths, entry) {
6724 4e68cba3 2019-11-23 stsp if (asprintf(&ondisk_path, "%s/%s",
6725 4e68cba3 2019-11-23 stsp got_worktree_get_root_path(worktree),
6726 62d463ca 2020-10-20 naddy pe->path) == -1) {
6727 4e68cba3 2019-11-23 stsp error = got_error_from_errno("asprintf");
6728 4e68cba3 2019-11-23 stsp goto done;
6729 4e68cba3 2019-11-23 stsp }
6730 4e68cba3 2019-11-23 stsp if (lstat(ondisk_path, &sb) == -1) {
6731 4e68cba3 2019-11-23 stsp if (errno == ENOENT) {
6732 4e68cba3 2019-11-23 stsp free(ondisk_path);
6733 4e68cba3 2019-11-23 stsp continue;
6734 4e68cba3 2019-11-23 stsp }
6735 4e68cba3 2019-11-23 stsp error = got_error_from_errno2("lstat",
6736 4e68cba3 2019-11-23 stsp ondisk_path);
6737 4e68cba3 2019-11-23 stsp free(ondisk_path);
6738 4e68cba3 2019-11-23 stsp goto done;
6739 4e68cba3 2019-11-23 stsp }
6740 4e68cba3 2019-11-23 stsp free(ondisk_path);
6741 4e68cba3 2019-11-23 stsp if (S_ISDIR(sb.st_mode)) {
6742 4e68cba3 2019-11-23 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
6743 4e68cba3 2019-11-23 stsp "adding directories requires -R option");
6744 4e68cba3 2019-11-23 stsp goto done;
6745 4e68cba3 2019-11-23 stsp }
6746 4e68cba3 2019-11-23 stsp }
6747 4e68cba3 2019-11-23 stsp }
6748 022fae89 2019-12-06 tracey
6749 4e68cba3 2019-11-23 stsp error = got_worktree_schedule_add(worktree, &paths, add_progress,
6750 022fae89 2019-12-06 tracey NULL, repo, no_ignores);
6751 d00136be 2019-03-26 stsp done:
6752 1d0f4054 2021-06-17 stsp if (repo) {
6753 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6754 1d0f4054 2021-06-17 stsp if (error == NULL)
6755 1d0f4054 2021-06-17 stsp error = close_err;
6756 1d0f4054 2021-06-17 stsp }
6757 d00136be 2019-03-26 stsp if (worktree)
6758 d00136be 2019-03-26 stsp got_worktree_close(worktree);
6759 1dd54920 2019-05-11 stsp TAILQ_FOREACH(pe, &paths, entry)
6760 1dd54920 2019-05-11 stsp free((char *)pe->path);
6761 1dd54920 2019-05-11 stsp got_pathlist_free(&paths);
6762 2ec1f75b 2019-03-26 stsp free(cwd);
6763 2ec1f75b 2019-03-26 stsp return error;
6764 2ec1f75b 2019-03-26 stsp }
6765 2ec1f75b 2019-03-26 stsp
6766 2ec1f75b 2019-03-26 stsp __dead static void
6767 648e4ef7 2019-07-09 stsp usage_remove(void)
6768 2ec1f75b 2019-03-26 stsp {
6769 766841c2 2020-08-13 stsp fprintf(stderr, "usage: %s remove [-f] [-k] [-R] [-s status-codes] "
6770 766841c2 2020-08-13 stsp "path ...\n", getprogname());
6771 2ec1f75b 2019-03-26 stsp exit(1);
6772 2a06fe5f 2019-08-24 stsp }
6773 2a06fe5f 2019-08-24 stsp
6774 2a06fe5f 2019-08-24 stsp static const struct got_error *
6775 2a06fe5f 2019-08-24 stsp print_remove_status(void *arg, unsigned char status,
6776 f2a9dc41 2019-12-13 tracey unsigned char staged_status, const char *path)
6777 2a06fe5f 2019-08-24 stsp {
6778 f2a9dc41 2019-12-13 tracey while (path[0] == '/')
6779 f2a9dc41 2019-12-13 tracey path++;
6780 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
6781 2a06fe5f 2019-08-24 stsp return NULL;
6782 2a06fe5f 2019-08-24 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
6783 2a06fe5f 2019-08-24 stsp status = GOT_STATUS_NO_CHANGE;
6784 2a06fe5f 2019-08-24 stsp printf("%c%c %s\n", status, staged_status, path);
6785 2a06fe5f 2019-08-24 stsp return NULL;
6786 2ec1f75b 2019-03-26 stsp }
6787 2ec1f75b 2019-03-26 stsp
6788 2ec1f75b 2019-03-26 stsp static const struct got_error *
6789 648e4ef7 2019-07-09 stsp cmd_remove(int argc, char *argv[])
6790 2ec1f75b 2019-03-26 stsp {
6791 2ec1f75b 2019-03-26 stsp const struct got_error *error = NULL;
6792 2ec1f75b 2019-03-26 stsp struct got_worktree *worktree = NULL;
6793 2ec1f75b 2019-03-26 stsp struct got_repository *repo = NULL;
6794 766841c2 2020-08-13 stsp const char *status_codes = NULL;
6795 17ed4618 2019-06-02 stsp char *cwd = NULL;
6796 17ed4618 2019-06-02 stsp struct got_pathlist_head paths;
6797 17ed4618 2019-06-02 stsp struct got_pathlist_entry *pe;
6798 766841c2 2020-08-13 stsp int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i;
6799 2ec1f75b 2019-03-26 stsp
6800 17ed4618 2019-06-02 stsp TAILQ_INIT(&paths);
6801 17ed4618 2019-06-02 stsp
6802 766841c2 2020-08-13 stsp while ((ch = getopt(argc, argv, "fkRs:")) != -1) {
6803 2ec1f75b 2019-03-26 stsp switch (ch) {
6804 2ec1f75b 2019-03-26 stsp case 'f':
6805 2ec1f75b 2019-03-26 stsp delete_local_mods = 1;
6806 2ec1f75b 2019-03-26 stsp break;
6807 70e3e7f5 2019-12-13 tracey case 'k':
6808 70e3e7f5 2019-12-13 tracey keep_on_disk = 1;
6809 70e3e7f5 2019-12-13 tracey break;
6810 f2a9dc41 2019-12-13 tracey case 'R':
6811 f2a9dc41 2019-12-13 tracey can_recurse = 1;
6812 f2a9dc41 2019-12-13 tracey break;
6813 766841c2 2020-08-13 stsp case 's':
6814 766841c2 2020-08-13 stsp for (i = 0; i < strlen(optarg); i++) {
6815 766841c2 2020-08-13 stsp switch (optarg[i]) {
6816 766841c2 2020-08-13 stsp case GOT_STATUS_MODIFY:
6817 766841c2 2020-08-13 stsp delete_local_mods = 1;
6818 766841c2 2020-08-13 stsp break;
6819 766841c2 2020-08-13 stsp case GOT_STATUS_MISSING:
6820 766841c2 2020-08-13 stsp break;
6821 766841c2 2020-08-13 stsp default:
6822 766841c2 2020-08-13 stsp errx(1, "invalid status code '%c'",
6823 766841c2 2020-08-13 stsp optarg[i]);
6824 766841c2 2020-08-13 stsp }
6825 766841c2 2020-08-13 stsp }
6826 766841c2 2020-08-13 stsp status_codes = optarg;
6827 766841c2 2020-08-13 stsp break;
6828 2ec1f75b 2019-03-26 stsp default:
6829 f2a9dc41 2019-12-13 tracey usage_remove();
6830 2ec1f75b 2019-03-26 stsp /* NOTREACHED */
6831 2ec1f75b 2019-03-26 stsp }
6832 2ec1f75b 2019-03-26 stsp }
6833 2ec1f75b 2019-03-26 stsp
6834 2ec1f75b 2019-03-26 stsp argc -= optind;
6835 2ec1f75b 2019-03-26 stsp argv += optind;
6836 2ec1f75b 2019-03-26 stsp
6837 43012d58 2019-07-14 stsp #ifndef PROFILE
6838 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6839 43012d58 2019-07-14 stsp NULL) == -1)
6840 43012d58 2019-07-14 stsp err(1, "pledge");
6841 43012d58 2019-07-14 stsp #endif
6842 17ed4618 2019-06-02 stsp if (argc < 1)
6843 648e4ef7 2019-07-09 stsp usage_remove();
6844 2ec1f75b 2019-03-26 stsp
6845 2ec1f75b 2019-03-26 stsp cwd = getcwd(NULL, 0);
6846 2ec1f75b 2019-03-26 stsp if (cwd == NULL) {
6847 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6848 2ec1f75b 2019-03-26 stsp goto done;
6849 2ec1f75b 2019-03-26 stsp }
6850 2ec1f75b 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
6851 fa51e947 2020-03-27 stsp if (error) {
6852 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6853 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "remove", cwd);
6854 2ec1f75b 2019-03-26 stsp goto done;
6855 fa51e947 2020-03-27 stsp }
6856 2ec1f75b 2019-03-26 stsp
6857 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6858 c9956ddf 2019-09-08 stsp NULL);
6859 2af4a041 2019-05-11 jcs if (error)
6860 2ec1f75b 2019-03-26 stsp goto done;
6861 2ec1f75b 2019-03-26 stsp
6862 c2253644 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
6863 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6864 2ec1f75b 2019-03-26 stsp if (error)
6865 2ec1f75b 2019-03-26 stsp goto done;
6866 2ec1f75b 2019-03-26 stsp
6867 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6868 6d022e97 2019-08-04 stsp if (error)
6869 6d022e97 2019-08-04 stsp goto done;
6870 17ed4618 2019-06-02 stsp
6871 f2a9dc41 2019-12-13 tracey if (!can_recurse) {
6872 f2a9dc41 2019-12-13 tracey char *ondisk_path;
6873 f2a9dc41 2019-12-13 tracey struct stat sb;
6874 f2a9dc41 2019-12-13 tracey TAILQ_FOREACH(pe, &paths, entry) {
6875 f2a9dc41 2019-12-13 tracey if (asprintf(&ondisk_path, "%s/%s",
6876 f2a9dc41 2019-12-13 tracey got_worktree_get_root_path(worktree),
6877 62d463ca 2020-10-20 naddy pe->path) == -1) {
6878 f2a9dc41 2019-12-13 tracey error = got_error_from_errno("asprintf");
6879 f2a9dc41 2019-12-13 tracey goto done;
6880 f2a9dc41 2019-12-13 tracey }
6881 f2a9dc41 2019-12-13 tracey if (lstat(ondisk_path, &sb) == -1) {
6882 f2a9dc41 2019-12-13 tracey if (errno == ENOENT) {
6883 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6884 f2a9dc41 2019-12-13 tracey continue;
6885 f2a9dc41 2019-12-13 tracey }
6886 f2a9dc41 2019-12-13 tracey error = got_error_from_errno2("lstat",
6887 f2a9dc41 2019-12-13 tracey ondisk_path);
6888 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6889 f2a9dc41 2019-12-13 tracey goto done;
6890 f2a9dc41 2019-12-13 tracey }
6891 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6892 f2a9dc41 2019-12-13 tracey if (S_ISDIR(sb.st_mode)) {
6893 f2a9dc41 2019-12-13 tracey error = got_error_msg(GOT_ERR_BAD_PATH,
6894 f2a9dc41 2019-12-13 tracey "removing directories requires -R option");
6895 f2a9dc41 2019-12-13 tracey goto done;
6896 f2a9dc41 2019-12-13 tracey }
6897 f2a9dc41 2019-12-13 tracey }
6898 f2a9dc41 2019-12-13 tracey }
6899 f2a9dc41 2019-12-13 tracey
6900 17ed4618 2019-06-02 stsp error = got_worktree_schedule_delete(worktree, &paths,
6901 766841c2 2020-08-13 stsp delete_local_mods, status_codes, print_remove_status, NULL,
6902 766841c2 2020-08-13 stsp repo, keep_on_disk);
6903 a129376b 2019-03-28 stsp done:
6904 1d0f4054 2021-06-17 stsp if (repo) {
6905 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
6906 1d0f4054 2021-06-17 stsp if (error == NULL)
6907 1d0f4054 2021-06-17 stsp error = close_err;
6908 1d0f4054 2021-06-17 stsp }
6909 a129376b 2019-03-28 stsp if (worktree)
6910 a129376b 2019-03-28 stsp got_worktree_close(worktree);
6911 17ed4618 2019-06-02 stsp TAILQ_FOREACH(pe, &paths, entry)
6912 17ed4618 2019-06-02 stsp free((char *)pe->path);
6913 17ed4618 2019-06-02 stsp got_pathlist_free(&paths);
6914 a129376b 2019-03-28 stsp free(cwd);
6915 a129376b 2019-03-28 stsp return error;
6916 a129376b 2019-03-28 stsp }
6917 a129376b 2019-03-28 stsp
6918 a129376b 2019-03-28 stsp __dead static void
6919 a129376b 2019-03-28 stsp usage_revert(void)
6920 a129376b 2019-03-28 stsp {
6921 33aa809d 2019-08-08 stsp fprintf(stderr, "usage: %s revert [-p] [-F response-script] [-R] "
6922 33aa809d 2019-08-08 stsp "path ...\n", getprogname());
6923 a129376b 2019-03-28 stsp exit(1);
6924 a129376b 2019-03-28 stsp }
6925 a129376b 2019-03-28 stsp
6926 1ee397ad 2019-07-12 stsp static const struct got_error *
6927 a129376b 2019-03-28 stsp revert_progress(void *arg, unsigned char status, const char *path)
6928 a129376b 2019-03-28 stsp {
6929 fb9704af 2020-01-27 stsp if (status == GOT_STATUS_UNVERSIONED)
6930 fb9704af 2020-01-27 stsp return NULL;
6931 fb9704af 2020-01-27 stsp
6932 a129376b 2019-03-28 stsp while (path[0] == '/')
6933 a129376b 2019-03-28 stsp path++;
6934 a129376b 2019-03-28 stsp printf("%c %s\n", status, path);
6935 33aa809d 2019-08-08 stsp return NULL;
6936 33aa809d 2019-08-08 stsp }
6937 33aa809d 2019-08-08 stsp
6938 33aa809d 2019-08-08 stsp struct choose_patch_arg {
6939 33aa809d 2019-08-08 stsp FILE *patch_script_file;
6940 33aa809d 2019-08-08 stsp const char *action;
6941 33aa809d 2019-08-08 stsp };
6942 33aa809d 2019-08-08 stsp
6943 33aa809d 2019-08-08 stsp static const struct got_error *
6944 33aa809d 2019-08-08 stsp show_change(unsigned char status, const char *path, FILE *patch_file, int n,
6945 33aa809d 2019-08-08 stsp int nchanges, const char *action)
6946 33aa809d 2019-08-08 stsp {
6947 33aa809d 2019-08-08 stsp char *line = NULL;
6948 33aa809d 2019-08-08 stsp size_t linesize = 0;
6949 33aa809d 2019-08-08 stsp ssize_t linelen;
6950 33aa809d 2019-08-08 stsp
6951 33aa809d 2019-08-08 stsp switch (status) {
6952 33aa809d 2019-08-08 stsp case GOT_STATUS_ADD:
6953 33aa809d 2019-08-08 stsp printf("A %s\n%s this addition? [y/n] ", path, action);
6954 33aa809d 2019-08-08 stsp break;
6955 33aa809d 2019-08-08 stsp case GOT_STATUS_DELETE:
6956 33aa809d 2019-08-08 stsp printf("D %s\n%s this deletion? [y/n] ", path, action);
6957 33aa809d 2019-08-08 stsp break;
6958 33aa809d 2019-08-08 stsp case GOT_STATUS_MODIFY:
6959 33aa809d 2019-08-08 stsp if (fseek(patch_file, 0L, SEEK_SET) == -1)
6960 33aa809d 2019-08-08 stsp return got_error_from_errno("fseek");
6961 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
6962 9516e7cb 2019-08-11 stsp while ((linelen = getline(&line, &linesize, patch_file)) != -1)
6963 33aa809d 2019-08-08 stsp printf("%s", line);
6964 33aa809d 2019-08-08 stsp if (ferror(patch_file))
6965 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
6966 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
6967 33aa809d 2019-08-08 stsp printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
6968 33aa809d 2019-08-08 stsp path, n, nchanges, action);
6969 33aa809d 2019-08-08 stsp break;
6970 33aa809d 2019-08-08 stsp default:
6971 33aa809d 2019-08-08 stsp return got_error_path(path, GOT_ERR_FILE_STATUS);
6972 33aa809d 2019-08-08 stsp }
6973 33aa809d 2019-08-08 stsp
6974 33aa809d 2019-08-08 stsp return NULL;
6975 33aa809d 2019-08-08 stsp }
6976 33aa809d 2019-08-08 stsp
6977 33aa809d 2019-08-08 stsp static const struct got_error *
6978 33aa809d 2019-08-08 stsp choose_patch(int *choice, void *arg, unsigned char status, const char *path,
6979 33aa809d 2019-08-08 stsp FILE *patch_file, int n, int nchanges)
6980 33aa809d 2019-08-08 stsp {
6981 33aa809d 2019-08-08 stsp const struct got_error *err = NULL;
6982 33aa809d 2019-08-08 stsp char *line = NULL;
6983 33aa809d 2019-08-08 stsp size_t linesize = 0;
6984 33aa809d 2019-08-08 stsp ssize_t linelen;
6985 33aa809d 2019-08-08 stsp int resp = ' ';
6986 33aa809d 2019-08-08 stsp struct choose_patch_arg *a = arg;
6987 33aa809d 2019-08-08 stsp
6988 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NONE;
6989 33aa809d 2019-08-08 stsp
6990 33aa809d 2019-08-08 stsp if (a->patch_script_file) {
6991 33aa809d 2019-08-08 stsp char *nl;
6992 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
6993 33aa809d 2019-08-08 stsp a->action);
6994 33aa809d 2019-08-08 stsp if (err)
6995 33aa809d 2019-08-08 stsp return err;
6996 33aa809d 2019-08-08 stsp linelen = getline(&line, &linesize, a->patch_script_file);
6997 33aa809d 2019-08-08 stsp if (linelen == -1) {
6998 33aa809d 2019-08-08 stsp if (ferror(a->patch_script_file))
6999 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
7000 33aa809d 2019-08-08 stsp return NULL;
7001 33aa809d 2019-08-08 stsp }
7002 33aa809d 2019-08-08 stsp nl = strchr(line, '\n');
7003 33aa809d 2019-08-08 stsp if (nl)
7004 33aa809d 2019-08-08 stsp *nl = '\0';
7005 33aa809d 2019-08-08 stsp if (strcmp(line, "y") == 0) {
7006 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
7007 33aa809d 2019-08-08 stsp printf("y\n");
7008 33aa809d 2019-08-08 stsp } else if (strcmp(line, "n") == 0) {
7009 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
7010 33aa809d 2019-08-08 stsp printf("n\n");
7011 33aa809d 2019-08-08 stsp } else if (strcmp(line, "q") == 0 &&
7012 33aa809d 2019-08-08 stsp status == GOT_STATUS_MODIFY) {
7013 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
7014 33aa809d 2019-08-08 stsp printf("q\n");
7015 33aa809d 2019-08-08 stsp } else
7016 33aa809d 2019-08-08 stsp printf("invalid response '%s'\n", line);
7017 33aa809d 2019-08-08 stsp free(line);
7018 33aa809d 2019-08-08 stsp return NULL;
7019 33aa809d 2019-08-08 stsp }
7020 33aa809d 2019-08-08 stsp
7021 33aa809d 2019-08-08 stsp while (resp != 'y' && resp != 'n' && resp != 'q') {
7022 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
7023 33aa809d 2019-08-08 stsp a->action);
7024 33aa809d 2019-08-08 stsp if (err)
7025 33aa809d 2019-08-08 stsp return err;
7026 33aa809d 2019-08-08 stsp resp = getchar();
7027 33aa809d 2019-08-08 stsp if (resp == '\n')
7028 33aa809d 2019-08-08 stsp resp = getchar();
7029 33aa809d 2019-08-08 stsp if (status == GOT_STATUS_MODIFY) {
7030 33aa809d 2019-08-08 stsp if (resp != 'y' && resp != 'n' && resp != 'q') {
7031 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
7032 33aa809d 2019-08-08 stsp resp = ' ';
7033 33aa809d 2019-08-08 stsp }
7034 33aa809d 2019-08-08 stsp } else if (resp != 'y' && resp != 'n') {
7035 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
7036 33aa809d 2019-08-08 stsp resp = ' ';
7037 33aa809d 2019-08-08 stsp }
7038 33aa809d 2019-08-08 stsp }
7039 33aa809d 2019-08-08 stsp
7040 33aa809d 2019-08-08 stsp if (resp == 'y')
7041 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
7042 33aa809d 2019-08-08 stsp else if (resp == 'n')
7043 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
7044 33aa809d 2019-08-08 stsp else if (resp == 'q' && status == GOT_STATUS_MODIFY)
7045 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
7046 33aa809d 2019-08-08 stsp
7047 1ee397ad 2019-07-12 stsp return NULL;
7048 a129376b 2019-03-28 stsp }
7049 a129376b 2019-03-28 stsp
7050 33aa809d 2019-08-08 stsp
7051 a129376b 2019-03-28 stsp static const struct got_error *
7052 a129376b 2019-03-28 stsp cmd_revert(int argc, char *argv[])
7053 a129376b 2019-03-28 stsp {
7054 a129376b 2019-03-28 stsp const struct got_error *error = NULL;
7055 a129376b 2019-03-28 stsp struct got_worktree *worktree = NULL;
7056 a129376b 2019-03-28 stsp struct got_repository *repo = NULL;
7057 a129376b 2019-03-28 stsp char *cwd = NULL, *path = NULL;
7058 e20a8b6f 2019-06-04 stsp struct got_pathlist_head paths;
7059 0f6d7415 2019-08-08 stsp struct got_pathlist_entry *pe;
7060 33aa809d 2019-08-08 stsp int ch, can_recurse = 0, pflag = 0;
7061 33aa809d 2019-08-08 stsp FILE *patch_script_file = NULL;
7062 33aa809d 2019-08-08 stsp const char *patch_script_path = NULL;
7063 33aa809d 2019-08-08 stsp struct choose_patch_arg cpa;
7064 a129376b 2019-03-28 stsp
7065 e20a8b6f 2019-06-04 stsp TAILQ_INIT(&paths);
7066 e20a8b6f 2019-06-04 stsp
7067 33aa809d 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:R")) != -1) {
7068 a129376b 2019-03-28 stsp switch (ch) {
7069 33aa809d 2019-08-08 stsp case 'p':
7070 33aa809d 2019-08-08 stsp pflag = 1;
7071 33aa809d 2019-08-08 stsp break;
7072 33aa809d 2019-08-08 stsp case 'F':
7073 33aa809d 2019-08-08 stsp patch_script_path = optarg;
7074 33aa809d 2019-08-08 stsp break;
7075 0f6d7415 2019-08-08 stsp case 'R':
7076 0f6d7415 2019-08-08 stsp can_recurse = 1;
7077 0f6d7415 2019-08-08 stsp break;
7078 a129376b 2019-03-28 stsp default:
7079 a129376b 2019-03-28 stsp usage_revert();
7080 a129376b 2019-03-28 stsp /* NOTREACHED */
7081 a129376b 2019-03-28 stsp }
7082 a129376b 2019-03-28 stsp }
7083 a129376b 2019-03-28 stsp
7084 a129376b 2019-03-28 stsp argc -= optind;
7085 a129376b 2019-03-28 stsp argv += optind;
7086 a129376b 2019-03-28 stsp
7087 43012d58 2019-07-14 stsp #ifndef PROFILE
7088 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7089 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
7090 43012d58 2019-07-14 stsp err(1, "pledge");
7091 43012d58 2019-07-14 stsp #endif
7092 e20a8b6f 2019-06-04 stsp if (argc < 1)
7093 a129376b 2019-03-28 stsp usage_revert();
7094 33aa809d 2019-08-08 stsp if (patch_script_path && !pflag)
7095 33aa809d 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
7096 a129376b 2019-03-28 stsp
7097 a129376b 2019-03-28 stsp cwd = getcwd(NULL, 0);
7098 a129376b 2019-03-28 stsp if (cwd == NULL) {
7099 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
7100 a129376b 2019-03-28 stsp goto done;
7101 a129376b 2019-03-28 stsp }
7102 a129376b 2019-03-28 stsp error = got_worktree_open(&worktree, cwd);
7103 fa51e947 2020-03-27 stsp if (error) {
7104 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7105 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "revert", cwd);
7106 2ec1f75b 2019-03-26 stsp goto done;
7107 fa51e947 2020-03-27 stsp }
7108 a129376b 2019-03-28 stsp
7109 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7110 c9956ddf 2019-09-08 stsp NULL);
7111 a129376b 2019-03-28 stsp if (error != NULL)
7112 a129376b 2019-03-28 stsp goto done;
7113 a129376b 2019-03-28 stsp
7114 33aa809d 2019-08-08 stsp if (patch_script_path) {
7115 33aa809d 2019-08-08 stsp patch_script_file = fopen(patch_script_path, "r");
7116 33aa809d 2019-08-08 stsp if (patch_script_file == NULL) {
7117 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fopen",
7118 33aa809d 2019-08-08 stsp patch_script_path);
7119 33aa809d 2019-08-08 stsp goto done;
7120 33aa809d 2019-08-08 stsp }
7121 33aa809d 2019-08-08 stsp }
7122 a129376b 2019-03-28 stsp error = apply_unveil(got_repo_get_path(repo), 1,
7123 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7124 a129376b 2019-03-28 stsp if (error)
7125 a129376b 2019-03-28 stsp goto done;
7126 a129376b 2019-03-28 stsp
7127 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7128 6d022e97 2019-08-04 stsp if (error)
7129 6d022e97 2019-08-04 stsp goto done;
7130 00db391e 2019-08-03 stsp
7131 0f6d7415 2019-08-08 stsp if (!can_recurse) {
7132 0f6d7415 2019-08-08 stsp char *ondisk_path;
7133 0f6d7415 2019-08-08 stsp struct stat sb;
7134 0f6d7415 2019-08-08 stsp TAILQ_FOREACH(pe, &paths, entry) {
7135 0f6d7415 2019-08-08 stsp if (asprintf(&ondisk_path, "%s/%s",
7136 0f6d7415 2019-08-08 stsp got_worktree_get_root_path(worktree),
7137 62d463ca 2020-10-20 naddy pe->path) == -1) {
7138 0f6d7415 2019-08-08 stsp error = got_error_from_errno("asprintf");
7139 0f6d7415 2019-08-08 stsp goto done;
7140 0f6d7415 2019-08-08 stsp }
7141 0f6d7415 2019-08-08 stsp if (lstat(ondisk_path, &sb) == -1) {
7142 0f6d7415 2019-08-08 stsp if (errno == ENOENT) {
7143 0f6d7415 2019-08-08 stsp free(ondisk_path);
7144 0f6d7415 2019-08-08 stsp continue;
7145 0f6d7415 2019-08-08 stsp }
7146 0f6d7415 2019-08-08 stsp error = got_error_from_errno2("lstat",
7147 0f6d7415 2019-08-08 stsp ondisk_path);
7148 0f6d7415 2019-08-08 stsp free(ondisk_path);
7149 0f6d7415 2019-08-08 stsp goto done;
7150 0f6d7415 2019-08-08 stsp }
7151 0f6d7415 2019-08-08 stsp free(ondisk_path);
7152 0f6d7415 2019-08-08 stsp if (S_ISDIR(sb.st_mode)) {
7153 0f6d7415 2019-08-08 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
7154 0f6d7415 2019-08-08 stsp "reverting directories requires -R option");
7155 0f6d7415 2019-08-08 stsp goto done;
7156 0f6d7415 2019-08-08 stsp }
7157 0f6d7415 2019-08-08 stsp }
7158 0f6d7415 2019-08-08 stsp }
7159 0f6d7415 2019-08-08 stsp
7160 33aa809d 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
7161 33aa809d 2019-08-08 stsp cpa.action = "revert";
7162 33aa809d 2019-08-08 stsp error = got_worktree_revert(worktree, &paths, revert_progress, NULL,
7163 33aa809d 2019-08-08 stsp pflag ? choose_patch : NULL, &cpa, repo);
7164 2ec1f75b 2019-03-26 stsp done:
7165 33aa809d 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
7166 33aa809d 2019-08-08 stsp error == NULL)
7167 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
7168 1d0f4054 2021-06-17 stsp if (repo) {
7169 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
7170 1d0f4054 2021-06-17 stsp if (error == NULL)
7171 1d0f4054 2021-06-17 stsp error = close_err;
7172 1d0f4054 2021-06-17 stsp }
7173 2ec1f75b 2019-03-26 stsp if (worktree)
7174 2ec1f75b 2019-03-26 stsp got_worktree_close(worktree);
7175 2ec1f75b 2019-03-26 stsp free(path);
7176 d00136be 2019-03-26 stsp free(cwd);
7177 6bad629b 2019-02-04 stsp return error;
7178 c4296144 2019-05-09 stsp }
7179 c4296144 2019-05-09 stsp
7180 c4296144 2019-05-09 stsp __dead static void
7181 c4296144 2019-05-09 stsp usage_commit(void)
7182 c4296144 2019-05-09 stsp {
7183 28cf319f 2021-01-28 stsp fprintf(stderr, "usage: %s commit [-F path] [-m msg] [-N] [-S] "
7184 28cf319f 2021-01-28 stsp "[path ...]\n", getprogname());
7185 c4296144 2019-05-09 stsp exit(1);
7186 33ad4cbe 2019-05-12 jcs }
7187 33ad4cbe 2019-05-12 jcs
7188 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg {
7189 e2ba3d07 2019-05-13 stsp const char *cmdline_log;
7190 28cf319f 2021-01-28 stsp const char *prepared_log;
7191 28cf319f 2021-01-28 stsp int non_interactive;
7192 e2ba3d07 2019-05-13 stsp const char *editor;
7193 e0870e44 2019-05-13 stsp const char *worktree_path;
7194 76d98825 2019-06-03 stsp const char *branch_name;
7195 314a6357 2019-05-13 stsp const char *repo_path;
7196 e0870e44 2019-05-13 stsp char *logmsg_path;
7197 e2ba3d07 2019-05-13 stsp
7198 e2ba3d07 2019-05-13 stsp };
7199 28cf319f 2021-01-28 stsp
7200 28cf319f 2021-01-28 stsp static const struct got_error *
7201 28cf319f 2021-01-28 stsp read_prepared_logmsg(char **logmsg, const char *path)
7202 28cf319f 2021-01-28 stsp {
7203 28cf319f 2021-01-28 stsp const struct got_error *err = NULL;
7204 28cf319f 2021-01-28 stsp FILE *f = NULL;
7205 28cf319f 2021-01-28 stsp struct stat sb;
7206 28cf319f 2021-01-28 stsp size_t r;
7207 28cf319f 2021-01-28 stsp
7208 28cf319f 2021-01-28 stsp *logmsg = NULL;
7209 28cf319f 2021-01-28 stsp memset(&sb, 0, sizeof(sb));
7210 28cf319f 2021-01-28 stsp
7211 28cf319f 2021-01-28 stsp f = fopen(path, "r");
7212 28cf319f 2021-01-28 stsp if (f == NULL)
7213 28cf319f 2021-01-28 stsp return got_error_from_errno2("fopen", path);
7214 28cf319f 2021-01-28 stsp
7215 28cf319f 2021-01-28 stsp if (fstat(fileno(f), &sb) == -1) {
7216 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fstat", path);
7217 28cf319f 2021-01-28 stsp goto done;
7218 28cf319f 2021-01-28 stsp }
7219 28cf319f 2021-01-28 stsp if (sb.st_size == 0) {
7220 28cf319f 2021-01-28 stsp err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
7221 28cf319f 2021-01-28 stsp goto done;
7222 28cf319f 2021-01-28 stsp }
7223 28cf319f 2021-01-28 stsp
7224 28cf319f 2021-01-28 stsp *logmsg = malloc(sb.st_size + 1);
7225 28cf319f 2021-01-28 stsp if (*logmsg == NULL) {
7226 28cf319f 2021-01-28 stsp err = got_error_from_errno("malloc");
7227 28cf319f 2021-01-28 stsp goto done;
7228 28cf319f 2021-01-28 stsp }
7229 28cf319f 2021-01-28 stsp
7230 28cf319f 2021-01-28 stsp r = fread(*logmsg, 1, sb.st_size, f);
7231 28cf319f 2021-01-28 stsp if (r != sb.st_size) {
7232 28cf319f 2021-01-28 stsp if (ferror(f))
7233 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fread", path);
7234 28cf319f 2021-01-28 stsp else
7235 28cf319f 2021-01-28 stsp err = got_error(GOT_ERR_IO);
7236 28cf319f 2021-01-28 stsp goto done;
7237 28cf319f 2021-01-28 stsp }
7238 28cf319f 2021-01-28 stsp (*logmsg)[sb.st_size] = '\0';
7239 28cf319f 2021-01-28 stsp done:
7240 28cf319f 2021-01-28 stsp if (fclose(f) == EOF && err == NULL)
7241 28cf319f 2021-01-28 stsp err = got_error_from_errno2("fclose", path);
7242 28cf319f 2021-01-28 stsp if (err) {
7243 28cf319f 2021-01-28 stsp free(*logmsg);
7244 28cf319f 2021-01-28 stsp *logmsg = NULL;
7245 28cf319f 2021-01-28 stsp }
7246 28cf319f 2021-01-28 stsp return err;
7247 28cf319f 2021-01-28 stsp
7248 28cf319f 2021-01-28 stsp }
7249 e0870e44 2019-05-13 stsp
7250 33ad4cbe 2019-05-12 jcs static const struct got_error *
7251 33ad4cbe 2019-05-12 jcs collect_commit_logmsg(struct got_pathlist_head *commitable_paths, char **logmsg,
7252 33ad4cbe 2019-05-12 jcs void *arg)
7253 33ad4cbe 2019-05-12 jcs {
7254 76d98825 2019-06-03 stsp char *initial_content = NULL;
7255 33ad4cbe 2019-05-12 jcs struct got_pathlist_entry *pe;
7256 33ad4cbe 2019-05-12 jcs const struct got_error *err = NULL;
7257 e0870e44 2019-05-13 stsp char *template = NULL;
7258 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg *a = arg;
7259 1601cb9f 2020-09-11 naddy int initial_content_len;
7260 97972933 2020-09-11 stsp int fd = -1;
7261 33ad4cbe 2019-05-12 jcs size_t len;
7262 33ad4cbe 2019-05-12 jcs
7263 33ad4cbe 2019-05-12 jcs /* if a message was specified on the command line, just use it */
7264 e2ba3d07 2019-05-13 stsp if (a->cmdline_log != NULL && strlen(a->cmdline_log) != 0) {
7265 e2ba3d07 2019-05-13 stsp len = strlen(a->cmdline_log) + 1;
7266 33ad4cbe 2019-05-12 jcs *logmsg = malloc(len + 1);
7267 9f42ff69 2019-05-13 stsp if (*logmsg == NULL)
7268 638f9024 2019-05-13 stsp return got_error_from_errno("malloc");
7269 e2ba3d07 2019-05-13 stsp strlcpy(*logmsg, a->cmdline_log, len);
7270 33ad4cbe 2019-05-12 jcs return NULL;
7271 28cf319f 2021-01-28 stsp } else if (a->prepared_log != NULL && a->non_interactive)
7272 28cf319f 2021-01-28 stsp return read_prepared_logmsg(logmsg, a->prepared_log);
7273 33ad4cbe 2019-05-12 jcs
7274 e0870e44 2019-05-13 stsp if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
7275 76d98825 2019-06-03 stsp return got_error_from_errno("asprintf");
7276 76d98825 2019-06-03 stsp
7277 28cf319f 2021-01-28 stsp err = got_opentemp_named_fd(&a->logmsg_path, &fd, template);
7278 28cf319f 2021-01-28 stsp if (err)
7279 28cf319f 2021-01-28 stsp goto done;
7280 28cf319f 2021-01-28 stsp
7281 28cf319f 2021-01-28 stsp if (a->prepared_log) {
7282 28cf319f 2021-01-28 stsp char *msg;
7283 28cf319f 2021-01-28 stsp err = read_prepared_logmsg(&msg, a->prepared_log);
7284 28cf319f 2021-01-28 stsp if (err)
7285 28cf319f 2021-01-28 stsp goto done;
7286 28cf319f 2021-01-28 stsp if (write(fd, msg, strlen(msg)) == -1) {
7287 28cf319f 2021-01-28 stsp err = got_error_from_errno2("write", a->logmsg_path);
7288 28cf319f 2021-01-28 stsp free(msg);
7289 28cf319f 2021-01-28 stsp goto done;
7290 28cf319f 2021-01-28 stsp }
7291 28cf319f 2021-01-28 stsp free(msg);
7292 28cf319f 2021-01-28 stsp }
7293 28cf319f 2021-01-28 stsp
7294 1601cb9f 2020-09-11 naddy initial_content_len = asprintf(&initial_content,
7295 76d98825 2019-06-03 stsp "\n# changes to be committed on branch %s:\n",
7296 1601cb9f 2020-09-11 naddy a->branch_name);
7297 28cf319f 2021-01-28 stsp if (initial_content_len == -1) {
7298 28cf319f 2021-01-28 stsp err = got_error_from_errno("asprintf");
7299 e0870e44 2019-05-13 stsp goto done;
7300 28cf319f 2021-01-28 stsp }
7301 33ad4cbe 2019-05-12 jcs
7302 97972933 2020-09-11 stsp if (write(fd, initial_content, initial_content_len) == -1) {
7303 97972933 2020-09-11 stsp err = got_error_from_errno2("write", a->logmsg_path);
7304 97972933 2020-09-11 stsp goto done;
7305 97972933 2020-09-11 stsp }
7306 33ad4cbe 2019-05-12 jcs
7307 33ad4cbe 2019-05-12 jcs TAILQ_FOREACH(pe, commitable_paths, entry) {
7308 33ad4cbe 2019-05-12 jcs struct got_commitable *ct = pe->data;
7309 8656d6c4 2019-05-20 stsp dprintf(fd, "# %c %s\n",
7310 8656d6c4 2019-05-20 stsp got_commitable_get_status(ct),
7311 8656d6c4 2019-05-20 stsp got_commitable_get_path(ct));
7312 33ad4cbe 2019-05-12 jcs }
7313 33ad4cbe 2019-05-12 jcs
7314 bfa12d5e 2020-09-26 stsp err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content,
7315 28cf319f 2021-01-28 stsp initial_content_len, a->prepared_log ? 0 : 1);
7316 33ad4cbe 2019-05-12 jcs done:
7317 76d98825 2019-06-03 stsp free(initial_content);
7318 e0870e44 2019-05-13 stsp free(template);
7319 314a6357 2019-05-13 stsp
7320 97972933 2020-09-11 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
7321 97972933 2020-09-11 stsp err = got_error_from_errno2("close", a->logmsg_path);
7322 97972933 2020-09-11 stsp
7323 314a6357 2019-05-13 stsp /* Editor is done; we can now apply unveil(2) */
7324 59f86c76 2020-09-11 stsp if (err == NULL)
7325 c530dc23 2019-07-23 stsp err = apply_unveil(a->repo_path, 0, a->worktree_path);
7326 59f86c76 2020-09-11 stsp if (err) {
7327 59f86c76 2020-09-11 stsp free(*logmsg);
7328 59f86c76 2020-09-11 stsp *logmsg = NULL;
7329 3ce1b845 2019-07-15 stsp }
7330 33ad4cbe 2019-05-12 jcs return err;
7331 6bad629b 2019-02-04 stsp }
7332 c4296144 2019-05-09 stsp
7333 c4296144 2019-05-09 stsp static const struct got_error *
7334 c4296144 2019-05-09 stsp cmd_commit(int argc, char *argv[])
7335 c4296144 2019-05-09 stsp {
7336 c4296144 2019-05-09 stsp const struct got_error *error = NULL;
7337 c4296144 2019-05-09 stsp struct got_worktree *worktree = NULL;
7338 c4296144 2019-05-09 stsp struct got_repository *repo = NULL;
7339 5c1e53bc 2019-07-28 stsp char *cwd = NULL, *id_str = NULL;
7340 c4296144 2019-05-09 stsp struct got_object_id *id = NULL;
7341 33ad4cbe 2019-05-12 jcs const char *logmsg = NULL;
7342 28cf319f 2021-01-28 stsp char *prepared_logmsg = NULL;
7343 aba9c984 2019-09-08 stsp struct collect_commit_logmsg_arg cl_arg;
7344 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
7345 7266f21f 2019-10-21 stsp int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
7346 10604dce 2021-09-24 thomas int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0;
7347 5c1e53bc 2019-07-28 stsp struct got_pathlist_head paths;
7348 5c1e53bc 2019-07-28 stsp
7349 5c1e53bc 2019-07-28 stsp TAILQ_INIT(&paths);
7350 6ac5a73c 2019-08-08 stsp cl_arg.logmsg_path = NULL;
7351 c4296144 2019-05-09 stsp
7352 28cf319f 2021-01-28 stsp while ((ch = getopt(argc, argv, "F:m:NS")) != -1) {
7353 c4296144 2019-05-09 stsp switch (ch) {
7354 28cf319f 2021-01-28 stsp case 'F':
7355 28cf319f 2021-01-28 stsp if (logmsg != NULL)
7356 28cf319f 2021-01-28 stsp option_conflict('F', 'm');
7357 28cf319f 2021-01-28 stsp prepared_logmsg = realpath(optarg, NULL);
7358 28cf319f 2021-01-28 stsp if (prepared_logmsg == NULL)
7359 28cf319f 2021-01-28 stsp return got_error_from_errno2("realpath",
7360 28cf319f 2021-01-28 stsp optarg);
7361 28cf319f 2021-01-28 stsp break;
7362 c4296144 2019-05-09 stsp case 'm':
7363 28cf319f 2021-01-28 stsp if (prepared_logmsg)
7364 28cf319f 2021-01-28 stsp option_conflict('m', 'F');
7365 c4296144 2019-05-09 stsp logmsg = optarg;
7366 28cf319f 2021-01-28 stsp break;
7367 28cf319f 2021-01-28 stsp case 'N':
7368 28cf319f 2021-01-28 stsp non_interactive = 1;
7369 c4296144 2019-05-09 stsp break;
7370 35213c7c 2020-07-23 stsp case 'S':
7371 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
7372 35213c7c 2020-07-23 stsp break;
7373 c4296144 2019-05-09 stsp default:
7374 c4296144 2019-05-09 stsp usage_commit();
7375 c4296144 2019-05-09 stsp /* NOTREACHED */
7376 c4296144 2019-05-09 stsp }
7377 c4296144 2019-05-09 stsp }
7378 c4296144 2019-05-09 stsp
7379 c4296144 2019-05-09 stsp argc -= optind;
7380 c4296144 2019-05-09 stsp argv += optind;
7381 c4296144 2019-05-09 stsp
7382 43012d58 2019-07-14 stsp #ifndef PROFILE
7383 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7384 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
7385 43012d58 2019-07-14 stsp err(1, "pledge");
7386 43012d58 2019-07-14 stsp #endif
7387 c4296144 2019-05-09 stsp cwd = getcwd(NULL, 0);
7388 c4296144 2019-05-09 stsp if (cwd == NULL) {
7389 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
7390 c4296144 2019-05-09 stsp goto done;
7391 c4296144 2019-05-09 stsp }
7392 c4296144 2019-05-09 stsp error = got_worktree_open(&worktree, cwd);
7393 fa51e947 2020-03-27 stsp if (error) {
7394 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7395 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "commit", cwd);
7396 7d5807f4 2019-07-11 stsp goto done;
7397 fa51e947 2020-03-27 stsp }
7398 7d5807f4 2019-07-11 stsp
7399 a698f62e 2019-07-25 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
7400 c4296144 2019-05-09 stsp if (error)
7401 a698f62e 2019-07-25 stsp goto done;
7402 a698f62e 2019-07-25 stsp if (rebase_in_progress) {
7403 a698f62e 2019-07-25 stsp error = got_error(GOT_ERR_REBASING);
7404 c4296144 2019-05-09 stsp goto done;
7405 a698f62e 2019-07-25 stsp }
7406 5c1e53bc 2019-07-28 stsp
7407 916f288c 2019-07-30 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
7408 916f288c 2019-07-30 stsp worktree);
7409 5c1e53bc 2019-07-28 stsp if (error)
7410 5c1e53bc 2019-07-28 stsp goto done;
7411 c4296144 2019-05-09 stsp
7412 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
7413 c9956ddf 2019-09-08 stsp if (error)
7414 c9956ddf 2019-09-08 stsp goto done;
7415 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7416 c9956ddf 2019-09-08 stsp gitconfig_path);
7417 c4296144 2019-05-09 stsp if (error != NULL)
7418 c4296144 2019-05-09 stsp goto done;
7419 c4296144 2019-05-09 stsp
7420 10604dce 2021-09-24 thomas error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo);
7421 10604dce 2021-09-24 thomas if (error)
7422 10604dce 2021-09-24 thomas goto done;
7423 10604dce 2021-09-24 thomas if (merge_in_progress) {
7424 10604dce 2021-09-24 thomas error = got_error(GOT_ERR_MERGE_BUSY);
7425 10604dce 2021-09-24 thomas goto done;
7426 10604dce 2021-09-24 thomas }
7427 10604dce 2021-09-24 thomas
7428 50b0790e 2020-09-11 stsp error = get_author(&author, repo, worktree);
7429 aba9c984 2019-09-08 stsp if (error)
7430 aba9c984 2019-09-08 stsp return error;
7431 aba9c984 2019-09-08 stsp
7432 314a6357 2019-05-13 stsp /*
7433 314a6357 2019-05-13 stsp * unveil(2) traverses exec(2); if an editor is used we have
7434 314a6357 2019-05-13 stsp * to apply unveil after the log message has been written.
7435 314a6357 2019-05-13 stsp */
7436 314a6357 2019-05-13 stsp if (logmsg == NULL || strlen(logmsg) == 0)
7437 314a6357 2019-05-13 stsp error = get_editor(&editor);
7438 314a6357 2019-05-13 stsp else
7439 314a6357 2019-05-13 stsp error = apply_unveil(got_repo_get_path(repo), 0,
7440 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7441 c4296144 2019-05-09 stsp if (error)
7442 c4296144 2019-05-09 stsp goto done;
7443 c4296144 2019-05-09 stsp
7444 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7445 087fb88c 2019-08-04 stsp if (error)
7446 087fb88c 2019-08-04 stsp goto done;
7447 087fb88c 2019-08-04 stsp
7448 e2ba3d07 2019-05-13 stsp cl_arg.editor = editor;
7449 e2ba3d07 2019-05-13 stsp cl_arg.cmdline_log = logmsg;
7450 28cf319f 2021-01-28 stsp cl_arg.prepared_log = prepared_logmsg;
7451 28cf319f 2021-01-28 stsp cl_arg.non_interactive = non_interactive;
7452 e0870e44 2019-05-13 stsp cl_arg.worktree_path = got_worktree_get_root_path(worktree);
7453 76d98825 2019-06-03 stsp cl_arg.branch_name = got_worktree_get_head_ref_name(worktree);
7454 916f288c 2019-07-30 stsp if (!histedit_in_progress) {
7455 916f288c 2019-07-30 stsp if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) {
7456 916f288c 2019-07-30 stsp error = got_error(GOT_ERR_COMMIT_BRANCH);
7457 916f288c 2019-07-30 stsp goto done;
7458 916f288c 2019-07-30 stsp }
7459 916f288c 2019-07-30 stsp cl_arg.branch_name += 11;
7460 916f288c 2019-07-30 stsp }
7461 314a6357 2019-05-13 stsp cl_arg.repo_path = got_repo_get_path(repo);
7462 84792843 2019-08-09 stsp error = got_worktree_commit(&id, worktree, &paths, author, NULL,
7463 35213c7c 2020-07-23 stsp allow_bad_symlinks, collect_commit_logmsg, &cl_arg,
7464 35213c7c 2020-07-23 stsp print_status, NULL, repo);
7465 e0870e44 2019-05-13 stsp if (error) {
7466 7266f21f 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
7467 7266f21f 2019-10-21 stsp cl_arg.logmsg_path != NULL)
7468 7266f21f 2019-10-21 stsp preserve_logmsg = 1;
7469 c4296144 2019-05-09 stsp goto done;
7470 e0870e44 2019-05-13 stsp }
7471 c4296144 2019-05-09 stsp
7472 c4296144 2019-05-09 stsp error = got_object_id_str(&id_str, id);
7473 c4296144 2019-05-09 stsp if (error)
7474 c4296144 2019-05-09 stsp goto done;
7475 a7648d7a 2019-06-02 stsp printf("Created commit %s\n", id_str);
7476 c4296144 2019-05-09 stsp done:
7477 7266f21f 2019-10-21 stsp if (preserve_logmsg) {
7478 7266f21f 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
7479 7266f21f 2019-10-21 stsp getprogname(), cl_arg.logmsg_path);
7480 7266f21f 2019-10-21 stsp } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
7481 7266f21f 2019-10-21 stsp error == NULL)
7482 7266f21f 2019-10-21 stsp error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
7483 6ac5a73c 2019-08-08 stsp free(cl_arg.logmsg_path);
7484 1d0f4054 2021-06-17 stsp if (repo) {
7485 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
7486 1d0f4054 2021-06-17 stsp if (error == NULL)
7487 1d0f4054 2021-06-17 stsp error = close_err;
7488 1d0f4054 2021-06-17 stsp }
7489 c4296144 2019-05-09 stsp if (worktree)
7490 c4296144 2019-05-09 stsp got_worktree_close(worktree);
7491 c4296144 2019-05-09 stsp free(cwd);
7492 c4296144 2019-05-09 stsp free(id_str);
7493 c9956ddf 2019-09-08 stsp free(gitconfig_path);
7494 e2ba3d07 2019-05-13 stsp free(editor);
7495 aba9c984 2019-09-08 stsp free(author);
7496 28cf319f 2021-01-28 stsp free(prepared_logmsg);
7497 f8a36e22 2021-08-26 stsp return error;
7498 f8a36e22 2021-08-26 stsp }
7499 f8a36e22 2021-08-26 stsp
7500 f8a36e22 2021-08-26 stsp __dead static void
7501 f8a36e22 2021-08-26 stsp usage_send(void)
7502 f8a36e22 2021-08-26 stsp {
7503 f8a36e22 2021-08-26 stsp fprintf(stderr, "usage: %s send [-a] [-b branch] [-d branch] [-f] "
7504 f8a36e22 2021-08-26 stsp "[-r repository-path] [-t tag] [-T] [-q] [-v] "
7505 f8a36e22 2021-08-26 stsp "[remote-repository]\n", getprogname());
7506 f8a36e22 2021-08-26 stsp exit(1);
7507 f8a36e22 2021-08-26 stsp }
7508 f8a36e22 2021-08-26 stsp
7509 f8a36e22 2021-08-26 stsp struct got_send_progress_arg {
7510 f8a36e22 2021-08-26 stsp char last_scaled_packsize[FMT_SCALED_STRSIZE];
7511 f8a36e22 2021-08-26 stsp int verbosity;
7512 f8a36e22 2021-08-26 stsp int last_ncommits;
7513 f8a36e22 2021-08-26 stsp int last_nobj_total;
7514 f8a36e22 2021-08-26 stsp int last_p_deltify;
7515 f8a36e22 2021-08-26 stsp int last_p_written;
7516 f8a36e22 2021-08-26 stsp int last_p_sent;
7517 f8a36e22 2021-08-26 stsp int printed_something;
7518 f8a36e22 2021-08-26 stsp int sent_something;
7519 f8a36e22 2021-08-26 stsp struct got_pathlist_head *delete_branches;
7520 f8a36e22 2021-08-26 stsp };
7521 f8a36e22 2021-08-26 stsp
7522 f8a36e22 2021-08-26 stsp static const struct got_error *
7523 f8a36e22 2021-08-26 stsp send_progress(void *arg, off_t packfile_size, int ncommits, int nobj_total,
7524 f8a36e22 2021-08-26 stsp int nobj_deltify, int nobj_written, off_t bytes_sent, const char *refname,
7525 f8a36e22 2021-08-26 stsp int success)
7526 f8a36e22 2021-08-26 stsp {
7527 f8a36e22 2021-08-26 stsp struct got_send_progress_arg *a = arg;
7528 f8a36e22 2021-08-26 stsp char scaled_packsize[FMT_SCALED_STRSIZE];
7529 f8a36e22 2021-08-26 stsp char scaled_sent[FMT_SCALED_STRSIZE];
7530 f8a36e22 2021-08-26 stsp int p_deltify = 0, p_written = 0, p_sent = 0;
7531 f8a36e22 2021-08-26 stsp int print_searching = 0, print_total = 0;
7532 f8a36e22 2021-08-26 stsp int print_deltify = 0, print_written = 0, print_sent = 0;
7533 f8a36e22 2021-08-26 stsp
7534 f8a36e22 2021-08-26 stsp if (a->verbosity < 0)
7535 f8a36e22 2021-08-26 stsp return NULL;
7536 f8a36e22 2021-08-26 stsp
7537 f8a36e22 2021-08-26 stsp if (refname) {
7538 f8a36e22 2021-08-26 stsp const char *status = success ? "accepted" : "rejected";
7539 f8a36e22 2021-08-26 stsp
7540 f8a36e22 2021-08-26 stsp if (success) {
7541 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *pe;
7542 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, a->delete_branches, entry) {
7543 f8a36e22 2021-08-26 stsp const char *branchname = pe->path;
7544 f8a36e22 2021-08-26 stsp if (got_path_cmp(branchname, refname,
7545 f8a36e22 2021-08-26 stsp strlen(branchname), strlen(refname)) == 0) {
7546 f8a36e22 2021-08-26 stsp status = "deleted";
7547 27b75514 2021-08-28 stsp a->sent_something = 1;
7548 f8a36e22 2021-08-26 stsp break;
7549 f8a36e22 2021-08-26 stsp }
7550 f8a36e22 2021-08-26 stsp }
7551 f8a36e22 2021-08-26 stsp }
7552 f8a36e22 2021-08-26 stsp
7553 27b75514 2021-08-28 stsp if (a->printed_something)
7554 27b75514 2021-08-28 stsp putchar('\n');
7555 27b75514 2021-08-28 stsp printf("Server has %s %s", status, refname);
7556 f8a36e22 2021-08-26 stsp a->printed_something = 1;
7557 f8a36e22 2021-08-26 stsp return NULL;
7558 f8a36e22 2021-08-26 stsp }
7559 f8a36e22 2021-08-26 stsp
7560 f8a36e22 2021-08-26 stsp if (fmt_scaled(packfile_size, scaled_packsize) == -1)
7561 f8a36e22 2021-08-26 stsp return got_error_from_errno("fmt_scaled");
7562 f8a36e22 2021-08-26 stsp if (fmt_scaled(bytes_sent, scaled_sent) == -1)
7563 f8a36e22 2021-08-26 stsp return got_error_from_errno("fmt_scaled");
7564 f8a36e22 2021-08-26 stsp
7565 f8a36e22 2021-08-26 stsp if (a->last_ncommits != ncommits) {
7566 f8a36e22 2021-08-26 stsp print_searching = 1;
7567 f8a36e22 2021-08-26 stsp a->last_ncommits = ncommits;
7568 f8a36e22 2021-08-26 stsp }
7569 f8a36e22 2021-08-26 stsp
7570 f8a36e22 2021-08-26 stsp if (a->last_nobj_total != nobj_total) {
7571 f8a36e22 2021-08-26 stsp print_searching = 1;
7572 f8a36e22 2021-08-26 stsp print_total = 1;
7573 f8a36e22 2021-08-26 stsp a->last_nobj_total = nobj_total;
7574 f8a36e22 2021-08-26 stsp }
7575 f8a36e22 2021-08-26 stsp
7576 f8a36e22 2021-08-26 stsp if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' ||
7577 f8a36e22 2021-08-26 stsp strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) {
7578 f8a36e22 2021-08-26 stsp if (strlcpy(a->last_scaled_packsize, scaled_packsize,
7579 f8a36e22 2021-08-26 stsp FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
7580 f8a36e22 2021-08-26 stsp return got_error(GOT_ERR_NO_SPACE);
7581 f8a36e22 2021-08-26 stsp }
7582 f8a36e22 2021-08-26 stsp
7583 f8a36e22 2021-08-26 stsp if (nobj_deltify > 0 || nobj_written > 0) {
7584 f8a36e22 2021-08-26 stsp if (nobj_deltify > 0) {
7585 f8a36e22 2021-08-26 stsp p_deltify = (nobj_deltify * 100) / nobj_total;
7586 f8a36e22 2021-08-26 stsp if (p_deltify != a->last_p_deltify) {
7587 f8a36e22 2021-08-26 stsp a->last_p_deltify = p_deltify;
7588 f8a36e22 2021-08-26 stsp print_searching = 1;
7589 f8a36e22 2021-08-26 stsp print_total = 1;
7590 f8a36e22 2021-08-26 stsp print_deltify = 1;
7591 f8a36e22 2021-08-26 stsp }
7592 f8a36e22 2021-08-26 stsp }
7593 f8a36e22 2021-08-26 stsp if (nobj_written > 0) {
7594 f8a36e22 2021-08-26 stsp p_written = (nobj_written * 100) / nobj_total;
7595 f8a36e22 2021-08-26 stsp if (p_written != a->last_p_written) {
7596 f8a36e22 2021-08-26 stsp a->last_p_written = p_written;
7597 f8a36e22 2021-08-26 stsp print_searching = 1;
7598 f8a36e22 2021-08-26 stsp print_total = 1;
7599 f8a36e22 2021-08-26 stsp print_deltify = 1;
7600 f8a36e22 2021-08-26 stsp print_written = 1;
7601 f8a36e22 2021-08-26 stsp }
7602 f8a36e22 2021-08-26 stsp }
7603 f8a36e22 2021-08-26 stsp }
7604 f8a36e22 2021-08-26 stsp
7605 f8a36e22 2021-08-26 stsp if (bytes_sent > 0) {
7606 f8a36e22 2021-08-26 stsp p_sent = (bytes_sent * 100) / packfile_size;
7607 f8a36e22 2021-08-26 stsp if (p_sent != a->last_p_sent) {
7608 f8a36e22 2021-08-26 stsp a->last_p_sent = p_sent;
7609 f8a36e22 2021-08-26 stsp print_searching = 1;
7610 f8a36e22 2021-08-26 stsp print_total = 1;
7611 f8a36e22 2021-08-26 stsp print_deltify = 1;
7612 f8a36e22 2021-08-26 stsp print_written = 1;
7613 f8a36e22 2021-08-26 stsp print_sent = 1;
7614 f8a36e22 2021-08-26 stsp }
7615 f8a36e22 2021-08-26 stsp a->sent_something = 1;
7616 f8a36e22 2021-08-26 stsp }
7617 f8a36e22 2021-08-26 stsp
7618 f8a36e22 2021-08-26 stsp if (print_searching || print_total || print_deltify || print_written ||
7619 f8a36e22 2021-08-26 stsp print_sent)
7620 f8a36e22 2021-08-26 stsp printf("\r");
7621 f8a36e22 2021-08-26 stsp if (print_searching)
7622 f8a36e22 2021-08-26 stsp printf("packing %d reference%s", ncommits,
7623 f8a36e22 2021-08-26 stsp ncommits == 1 ? "" : "s");
7624 f8a36e22 2021-08-26 stsp if (print_total)
7625 f8a36e22 2021-08-26 stsp printf("; %d object%s", nobj_total,
7626 f8a36e22 2021-08-26 stsp nobj_total == 1 ? "" : "s");
7627 f8a36e22 2021-08-26 stsp if (print_deltify)
7628 f8a36e22 2021-08-26 stsp printf("; deltify: %d%%", p_deltify);
7629 f8a36e22 2021-08-26 stsp if (print_sent)
7630 f8a36e22 2021-08-26 stsp printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE,
7631 f8a36e22 2021-08-26 stsp scaled_packsize, p_sent);
7632 f8a36e22 2021-08-26 stsp else if (print_written)
7633 f8a36e22 2021-08-26 stsp printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE,
7634 f8a36e22 2021-08-26 stsp scaled_packsize, p_written);
7635 f8a36e22 2021-08-26 stsp if (print_searching || print_total || print_deltify ||
7636 f8a36e22 2021-08-26 stsp print_written || print_sent) {
7637 f8a36e22 2021-08-26 stsp a->printed_something = 1;
7638 f8a36e22 2021-08-26 stsp fflush(stdout);
7639 f8a36e22 2021-08-26 stsp }
7640 f8a36e22 2021-08-26 stsp return NULL;
7641 f8a36e22 2021-08-26 stsp }
7642 f8a36e22 2021-08-26 stsp
7643 f8a36e22 2021-08-26 stsp static const struct got_error *
7644 f8a36e22 2021-08-26 stsp cmd_send(int argc, char *argv[])
7645 f8a36e22 2021-08-26 stsp {
7646 f8a36e22 2021-08-26 stsp const struct got_error *error = NULL;
7647 f8a36e22 2021-08-26 stsp char *cwd = NULL, *repo_path = NULL;
7648 f8a36e22 2021-08-26 stsp const char *remote_name;
7649 f8a36e22 2021-08-26 stsp char *proto = NULL, *host = NULL, *port = NULL;
7650 f8a36e22 2021-08-26 stsp char *repo_name = NULL, *server_path = NULL;
7651 f8a36e22 2021-08-26 stsp const struct got_remote_repo *remotes, *remote = NULL;
7652 f8a36e22 2021-08-26 stsp int nremotes, nbranches = 0, ntags = 0, ndelete_branches = 0;
7653 f8a36e22 2021-08-26 stsp struct got_repository *repo = NULL;
7654 f8a36e22 2021-08-26 stsp struct got_worktree *worktree = NULL;
7655 f8a36e22 2021-08-26 stsp const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
7656 f8a36e22 2021-08-26 stsp struct got_pathlist_head branches;
7657 f8a36e22 2021-08-26 stsp struct got_pathlist_head tags;
7658 f8a36e22 2021-08-26 stsp struct got_reflist_head all_branches;
7659 f8a36e22 2021-08-26 stsp struct got_reflist_head all_tags;
7660 f8a36e22 2021-08-26 stsp struct got_pathlist_head delete_args;
7661 f8a36e22 2021-08-26 stsp struct got_pathlist_head delete_branches;
7662 f8a36e22 2021-08-26 stsp struct got_reflist_entry *re;
7663 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *pe;
7664 f8a36e22 2021-08-26 stsp int i, ch, sendfd = -1, sendstatus;
7665 f8a36e22 2021-08-26 stsp pid_t sendpid = -1;
7666 f8a36e22 2021-08-26 stsp struct got_send_progress_arg spa;
7667 f8a36e22 2021-08-26 stsp int verbosity = 0, overwrite_refs = 0;
7668 f8a36e22 2021-08-26 stsp int send_all_branches = 0, send_all_tags = 0;
7669 f8a36e22 2021-08-26 stsp struct got_reference *ref = NULL;
7670 f8a36e22 2021-08-26 stsp
7671 f8a36e22 2021-08-26 stsp TAILQ_INIT(&branches);
7672 f8a36e22 2021-08-26 stsp TAILQ_INIT(&tags);
7673 f8a36e22 2021-08-26 stsp TAILQ_INIT(&all_branches);
7674 f8a36e22 2021-08-26 stsp TAILQ_INIT(&all_tags);
7675 f8a36e22 2021-08-26 stsp TAILQ_INIT(&delete_args);
7676 f8a36e22 2021-08-26 stsp TAILQ_INIT(&delete_branches);
7677 f8a36e22 2021-08-26 stsp
7678 f8a36e22 2021-08-26 stsp while ((ch = getopt(argc, argv, "ab:d:fr:t:Tvq")) != -1) {
7679 f8a36e22 2021-08-26 stsp switch (ch) {
7680 f8a36e22 2021-08-26 stsp case 'a':
7681 f8a36e22 2021-08-26 stsp send_all_branches = 1;
7682 f8a36e22 2021-08-26 stsp break;
7683 f8a36e22 2021-08-26 stsp case 'b':
7684 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches, optarg, NULL);
7685 f8a36e22 2021-08-26 stsp if (error)
7686 f8a36e22 2021-08-26 stsp return error;
7687 f8a36e22 2021-08-26 stsp nbranches++;
7688 f8a36e22 2021-08-26 stsp break;
7689 f8a36e22 2021-08-26 stsp case 'd':
7690 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&delete_args, optarg, NULL);
7691 f8a36e22 2021-08-26 stsp if (error)
7692 f8a36e22 2021-08-26 stsp return error;
7693 f8a36e22 2021-08-26 stsp break;
7694 f8a36e22 2021-08-26 stsp case 'f':
7695 f8a36e22 2021-08-26 stsp overwrite_refs = 1;
7696 f8a36e22 2021-08-26 stsp break;
7697 f8a36e22 2021-08-26 stsp case 'r':
7698 f8a36e22 2021-08-26 stsp repo_path = realpath(optarg, NULL);
7699 f8a36e22 2021-08-26 stsp if (repo_path == NULL)
7700 f8a36e22 2021-08-26 stsp return got_error_from_errno2("realpath",
7701 f8a36e22 2021-08-26 stsp optarg);
7702 f8a36e22 2021-08-26 stsp got_path_strip_trailing_slashes(repo_path);
7703 f8a36e22 2021-08-26 stsp break;
7704 f8a36e22 2021-08-26 stsp case 't':
7705 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&tags, optarg, NULL);
7706 f8a36e22 2021-08-26 stsp if (error)
7707 f8a36e22 2021-08-26 stsp return error;
7708 f8a36e22 2021-08-26 stsp ntags++;
7709 f8a36e22 2021-08-26 stsp break;
7710 f8a36e22 2021-08-26 stsp case 'T':
7711 f8a36e22 2021-08-26 stsp send_all_tags = 1;
7712 f8a36e22 2021-08-26 stsp break;
7713 f8a36e22 2021-08-26 stsp case 'v':
7714 f8a36e22 2021-08-26 stsp if (verbosity < 0)
7715 f8a36e22 2021-08-26 stsp verbosity = 0;
7716 f8a36e22 2021-08-26 stsp else if (verbosity < 3)
7717 f8a36e22 2021-08-26 stsp verbosity++;
7718 f8a36e22 2021-08-26 stsp break;
7719 f8a36e22 2021-08-26 stsp case 'q':
7720 f8a36e22 2021-08-26 stsp verbosity = -1;
7721 f8a36e22 2021-08-26 stsp break;
7722 f8a36e22 2021-08-26 stsp default:
7723 f8a36e22 2021-08-26 stsp usage_send();
7724 f8a36e22 2021-08-26 stsp /* NOTREACHED */
7725 f8a36e22 2021-08-26 stsp }
7726 f8a36e22 2021-08-26 stsp }
7727 f8a36e22 2021-08-26 stsp argc -= optind;
7728 f8a36e22 2021-08-26 stsp argv += optind;
7729 f8a36e22 2021-08-26 stsp
7730 f8a36e22 2021-08-26 stsp if (send_all_branches && !TAILQ_EMPTY(&branches))
7731 f8a36e22 2021-08-26 stsp option_conflict('a', 'b');
7732 f8a36e22 2021-08-26 stsp if (send_all_tags && !TAILQ_EMPTY(&tags))
7733 f8a36e22 2021-08-26 stsp option_conflict('T', 't');
7734 f8a36e22 2021-08-26 stsp
7735 f8a36e22 2021-08-26 stsp
7736 f8a36e22 2021-08-26 stsp if (argc == 0)
7737 f8a36e22 2021-08-26 stsp remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
7738 f8a36e22 2021-08-26 stsp else if (argc == 1)
7739 f8a36e22 2021-08-26 stsp remote_name = argv[0];
7740 f8a36e22 2021-08-26 stsp else
7741 f8a36e22 2021-08-26 stsp usage_send();
7742 f8a36e22 2021-08-26 stsp
7743 f8a36e22 2021-08-26 stsp cwd = getcwd(NULL, 0);
7744 f8a36e22 2021-08-26 stsp if (cwd == NULL) {
7745 f8a36e22 2021-08-26 stsp error = got_error_from_errno("getcwd");
7746 f8a36e22 2021-08-26 stsp goto done;
7747 f8a36e22 2021-08-26 stsp }
7748 f8a36e22 2021-08-26 stsp
7749 f8a36e22 2021-08-26 stsp if (repo_path == NULL) {
7750 f8a36e22 2021-08-26 stsp error = got_worktree_open(&worktree, cwd);
7751 f8a36e22 2021-08-26 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
7752 f8a36e22 2021-08-26 stsp goto done;
7753 f8a36e22 2021-08-26 stsp else
7754 f8a36e22 2021-08-26 stsp error = NULL;
7755 f8a36e22 2021-08-26 stsp if (worktree) {
7756 f8a36e22 2021-08-26 stsp repo_path =
7757 f8a36e22 2021-08-26 stsp strdup(got_worktree_get_repo_path(worktree));
7758 f8a36e22 2021-08-26 stsp if (repo_path == NULL)
7759 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
7760 f8a36e22 2021-08-26 stsp if (error)
7761 f8a36e22 2021-08-26 stsp goto done;
7762 f8a36e22 2021-08-26 stsp } else {
7763 f8a36e22 2021-08-26 stsp repo_path = strdup(cwd);
7764 f8a36e22 2021-08-26 stsp if (repo_path == NULL) {
7765 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
7766 f8a36e22 2021-08-26 stsp goto done;
7767 f8a36e22 2021-08-26 stsp }
7768 f8a36e22 2021-08-26 stsp }
7769 f8a36e22 2021-08-26 stsp }
7770 f8a36e22 2021-08-26 stsp
7771 f8a36e22 2021-08-26 stsp error = got_repo_open(&repo, repo_path, NULL);
7772 f8a36e22 2021-08-26 stsp if (error)
7773 f8a36e22 2021-08-26 stsp goto done;
7774 f8a36e22 2021-08-26 stsp
7775 f8a36e22 2021-08-26 stsp if (worktree) {
7776 f8a36e22 2021-08-26 stsp worktree_conf = got_worktree_get_gotconfig(worktree);
7777 f8a36e22 2021-08-26 stsp if (worktree_conf) {
7778 f8a36e22 2021-08-26 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
7779 f8a36e22 2021-08-26 stsp worktree_conf);
7780 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
7781 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
7782 f8a36e22 2021-08-26 stsp remote = &remotes[i];
7783 f8a36e22 2021-08-26 stsp break;
7784 f8a36e22 2021-08-26 stsp }
7785 f8a36e22 2021-08-26 stsp }
7786 f8a36e22 2021-08-26 stsp }
7787 f8a36e22 2021-08-26 stsp }
7788 f8a36e22 2021-08-26 stsp if (remote == NULL) {
7789 f8a36e22 2021-08-26 stsp repo_conf = got_repo_get_gotconfig(repo);
7790 f8a36e22 2021-08-26 stsp if (repo_conf) {
7791 f8a36e22 2021-08-26 stsp got_gotconfig_get_remotes(&nremotes, &remotes,
7792 f8a36e22 2021-08-26 stsp repo_conf);
7793 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
7794 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
7795 f8a36e22 2021-08-26 stsp remote = &remotes[i];
7796 f8a36e22 2021-08-26 stsp break;
7797 f8a36e22 2021-08-26 stsp }
7798 f8a36e22 2021-08-26 stsp }
7799 f8a36e22 2021-08-26 stsp }
7800 f8a36e22 2021-08-26 stsp }
7801 f8a36e22 2021-08-26 stsp if (remote == NULL) {
7802 f8a36e22 2021-08-26 stsp got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
7803 f8a36e22 2021-08-26 stsp for (i = 0; i < nremotes; i++) {
7804 f8a36e22 2021-08-26 stsp if (strcmp(remotes[i].name, remote_name) == 0) {
7805 f8a36e22 2021-08-26 stsp remote = &remotes[i];
7806 f8a36e22 2021-08-26 stsp break;
7807 f8a36e22 2021-08-26 stsp }
7808 f8a36e22 2021-08-26 stsp }
7809 f8a36e22 2021-08-26 stsp }
7810 f8a36e22 2021-08-26 stsp if (remote == NULL) {
7811 f8a36e22 2021-08-26 stsp error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
7812 f8a36e22 2021-08-26 stsp goto done;
7813 f8a36e22 2021-08-26 stsp }
7814 f8a36e22 2021-08-26 stsp
7815 5e5da8c4 2021-09-05 stsp error = got_dial_parse_uri(&proto, &host, &port, &server_path,
7816 6480c871 2021-08-30 stsp &repo_name, remote->send_url);
7817 f8a36e22 2021-08-26 stsp if (error)
7818 f8a36e22 2021-08-26 stsp goto done;
7819 f8a36e22 2021-08-26 stsp
7820 f8a36e22 2021-08-26 stsp if (strcmp(proto, "git") == 0) {
7821 f8a36e22 2021-08-26 stsp #ifndef PROFILE
7822 f8a36e22 2021-08-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7823 f8a36e22 2021-08-26 stsp "sendfd dns inet unveil", NULL) == -1)
7824 f8a36e22 2021-08-26 stsp err(1, "pledge");
7825 f8a36e22 2021-08-26 stsp #endif
7826 f8a36e22 2021-08-26 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
7827 f8a36e22 2021-08-26 stsp strcmp(proto, "ssh") == 0) {
7828 f8a36e22 2021-08-26 stsp #ifndef PROFILE
7829 f8a36e22 2021-08-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7830 f8a36e22 2021-08-26 stsp "sendfd unveil", NULL) == -1)
7831 f8a36e22 2021-08-26 stsp err(1, "pledge");
7832 f8a36e22 2021-08-26 stsp #endif
7833 f8a36e22 2021-08-26 stsp } else if (strcmp(proto, "http") == 0 ||
7834 f8a36e22 2021-08-26 stsp strcmp(proto, "git+http") == 0) {
7835 f8a36e22 2021-08-26 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
7836 f8a36e22 2021-08-26 stsp goto done;
7837 f8a36e22 2021-08-26 stsp } else {
7838 f8a36e22 2021-08-26 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
7839 f8a36e22 2021-08-26 stsp goto done;
7840 f8a36e22 2021-08-26 stsp }
7841 f8a36e22 2021-08-26 stsp
7842 d65a88a2 2021-09-05 stsp error = got_dial_apply_unveil(proto);
7843 d65a88a2 2021-09-05 stsp if (error)
7844 d65a88a2 2021-09-05 stsp goto done;
7845 d65a88a2 2021-09-05 stsp
7846 f8a36e22 2021-08-26 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
7847 f8a36e22 2021-08-26 stsp if (error)
7848 f8a36e22 2021-08-26 stsp goto done;
7849 f8a36e22 2021-08-26 stsp
7850 f8a36e22 2021-08-26 stsp if (send_all_branches) {
7851 f8a36e22 2021-08-26 stsp error = got_ref_list(&all_branches, repo, "refs/heads",
7852 f8a36e22 2021-08-26 stsp got_ref_cmp_by_name, NULL);
7853 f8a36e22 2021-08-26 stsp if (error)
7854 f8a36e22 2021-08-26 stsp goto done;
7855 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(re, &all_branches, entry) {
7856 f8a36e22 2021-08-26 stsp const char *branchname = got_ref_get_name(re->ref);
7857 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches,
7858 f8a36e22 2021-08-26 stsp branchname, NULL);
7859 f8a36e22 2021-08-26 stsp if (error)
7860 f8a36e22 2021-08-26 stsp goto done;
7861 f8a36e22 2021-08-26 stsp nbranches++;
7862 f8a36e22 2021-08-26 stsp }
7863 eac1df47 2021-09-01 stsp } else if (nbranches == 0) {
7864 eac1df47 2021-09-01 stsp for (i = 0; i < remote->nsend_branches; i++) {
7865 eac1df47 2021-09-01 stsp got_pathlist_append(&branches,
7866 eac1df47 2021-09-01 stsp remote->send_branches[i], NULL);
7867 eac1df47 2021-09-01 stsp }
7868 f8a36e22 2021-08-26 stsp }
7869 f8a36e22 2021-08-26 stsp
7870 f8a36e22 2021-08-26 stsp if (send_all_tags) {
7871 f8a36e22 2021-08-26 stsp error = got_ref_list(&all_tags, repo, "refs/tags",
7872 f8a36e22 2021-08-26 stsp got_ref_cmp_by_name, NULL);
7873 f8a36e22 2021-08-26 stsp if (error)
7874 f8a36e22 2021-08-26 stsp goto done;
7875 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(re, &all_tags, entry) {
7876 f8a36e22 2021-08-26 stsp const char *tagname = got_ref_get_name(re->ref);
7877 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&tags,
7878 f8a36e22 2021-08-26 stsp tagname, NULL);
7879 f8a36e22 2021-08-26 stsp if (error)
7880 f8a36e22 2021-08-26 stsp goto done;
7881 f8a36e22 2021-08-26 stsp ntags++;
7882 f8a36e22 2021-08-26 stsp }
7883 f8a36e22 2021-08-26 stsp }
7884 f8a36e22 2021-08-26 stsp
7885 f8a36e22 2021-08-26 stsp /*
7886 f8a36e22 2021-08-26 stsp * To prevent accidents only branches in refs/heads/ can be deleted
7887 f8a36e22 2021-08-26 stsp * with 'got send -d'.
7888 f8a36e22 2021-08-26 stsp * Deleting anything else requires local repository access or Git.
7889 f8a36e22 2021-08-26 stsp */
7890 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, &delete_args, entry) {
7891 f8a36e22 2021-08-26 stsp const char *branchname = pe->path;
7892 f8a36e22 2021-08-26 stsp char *s;
7893 f8a36e22 2021-08-26 stsp struct got_pathlist_entry *new;
7894 f8a36e22 2021-08-26 stsp if (strncmp(branchname, "refs/heads/", 11) == 0) {
7895 f8a36e22 2021-08-26 stsp s = strdup(branchname);
7896 f8a36e22 2021-08-26 stsp if (s == NULL) {
7897 f8a36e22 2021-08-26 stsp error = got_error_from_errno("strdup");
7898 f8a36e22 2021-08-26 stsp goto done;
7899 f8a36e22 2021-08-26 stsp }
7900 f8a36e22 2021-08-26 stsp } else {
7901 f8a36e22 2021-08-26 stsp if (asprintf(&s, "refs/heads/%s", branchname) == -1) {
7902 f8a36e22 2021-08-26 stsp error = got_error_from_errno("asprintf");
7903 f8a36e22 2021-08-26 stsp goto done;
7904 f8a36e22 2021-08-26 stsp }
7905 f8a36e22 2021-08-26 stsp }
7906 f8a36e22 2021-08-26 stsp error = got_pathlist_insert(&new, &delete_branches, s, NULL);
7907 f8a36e22 2021-08-26 stsp if (error || new == NULL /* duplicate */)
7908 f8a36e22 2021-08-26 stsp free(s);
7909 f8a36e22 2021-08-26 stsp if (error)
7910 f8a36e22 2021-08-26 stsp goto done;
7911 f8a36e22 2021-08-26 stsp ndelete_branches++;
7912 f8a36e22 2021-08-26 stsp }
7913 f8a36e22 2021-08-26 stsp
7914 f8a36e22 2021-08-26 stsp if (nbranches == 0 && ndelete_branches == 0) {
7915 f8a36e22 2021-08-26 stsp struct got_reference *head_ref;
7916 f8a36e22 2021-08-26 stsp if (worktree)
7917 f8a36e22 2021-08-26 stsp error = got_ref_open(&head_ref, repo,
7918 f8a36e22 2021-08-26 stsp got_worktree_get_head_ref_name(worktree), 0);
7919 f8a36e22 2021-08-26 stsp else
7920 f8a36e22 2021-08-26 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
7921 f8a36e22 2021-08-26 stsp if (error)
7922 f8a36e22 2021-08-26 stsp goto done;
7923 f8a36e22 2021-08-26 stsp if (got_ref_is_symbolic(head_ref)) {
7924 f8a36e22 2021-08-26 stsp error = got_ref_resolve_symbolic(&ref, repo, head_ref);
7925 f8a36e22 2021-08-26 stsp got_ref_close(head_ref);
7926 f8a36e22 2021-08-26 stsp if (error)
7927 f8a36e22 2021-08-26 stsp goto done;
7928 f8a36e22 2021-08-26 stsp } else
7929 f8a36e22 2021-08-26 stsp ref = head_ref;
7930 f8a36e22 2021-08-26 stsp error = got_pathlist_append(&branches, got_ref_get_name(ref),
7931 abc59930 2021-09-05 naddy NULL);
7932 f8a36e22 2021-08-26 stsp if (error)
7933 f8a36e22 2021-08-26 stsp goto done;
7934 f8a36e22 2021-08-26 stsp nbranches++;
7935 f8a36e22 2021-08-26 stsp }
7936 f8a36e22 2021-08-26 stsp
7937 f8a36e22 2021-08-26 stsp if (verbosity >= 0)
7938 f8a36e22 2021-08-26 stsp printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
7939 f8a36e22 2021-08-26 stsp port ? ":" : "", port ? port : "");
7940 f8a36e22 2021-08-26 stsp
7941 f8a36e22 2021-08-26 stsp error = got_send_connect(&sendpid, &sendfd, proto, host, port,
7942 f8a36e22 2021-08-26 stsp server_path, verbosity);
7943 f8a36e22 2021-08-26 stsp if (error)
7944 f8a36e22 2021-08-26 stsp goto done;
7945 f8a36e22 2021-08-26 stsp
7946 f8a36e22 2021-08-26 stsp memset(&spa, 0, sizeof(spa));
7947 f8a36e22 2021-08-26 stsp spa.last_scaled_packsize[0] = '\0';
7948 f8a36e22 2021-08-26 stsp spa.last_p_deltify = -1;
7949 f8a36e22 2021-08-26 stsp spa.last_p_written = -1;
7950 f8a36e22 2021-08-26 stsp spa.verbosity = verbosity;
7951 f8a36e22 2021-08-26 stsp spa.delete_branches = &delete_branches;
7952 f8a36e22 2021-08-26 stsp error = got_send_pack(remote_name, &branches, &tags, &delete_branches,
7953 f8a36e22 2021-08-26 stsp verbosity, overwrite_refs, sendfd, repo, send_progress, &spa,
7954 f8a36e22 2021-08-26 stsp check_cancelled, NULL);
7955 f8a36e22 2021-08-26 stsp if (spa.printed_something)
7956 f8a36e22 2021-08-26 stsp putchar('\n');
7957 f8a36e22 2021-08-26 stsp if (error)
7958 f8a36e22 2021-08-26 stsp goto done;
7959 f8a36e22 2021-08-26 stsp if (!spa.sent_something && verbosity >= 0)
7960 f8a36e22 2021-08-26 stsp printf("Already up-to-date\n");
7961 f8a36e22 2021-08-26 stsp done:
7962 f8a36e22 2021-08-26 stsp if (sendpid > 0) {
7963 f8a36e22 2021-08-26 stsp if (kill(sendpid, SIGTERM) == -1)
7964 f8a36e22 2021-08-26 stsp error = got_error_from_errno("kill");
7965 f8a36e22 2021-08-26 stsp if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL)
7966 f8a36e22 2021-08-26 stsp error = got_error_from_errno("waitpid");
7967 f8a36e22 2021-08-26 stsp }
7968 f8a36e22 2021-08-26 stsp if (sendfd != -1 && close(sendfd) == -1 && error == NULL)
7969 f8a36e22 2021-08-26 stsp error = got_error_from_errno("close");
7970 f8a36e22 2021-08-26 stsp if (repo) {
7971 f8a36e22 2021-08-26 stsp const struct got_error *close_err = got_repo_close(repo);
7972 f8a36e22 2021-08-26 stsp if (error == NULL)
7973 f8a36e22 2021-08-26 stsp error = close_err;
7974 f8a36e22 2021-08-26 stsp }
7975 f8a36e22 2021-08-26 stsp if (worktree)
7976 f8a36e22 2021-08-26 stsp got_worktree_close(worktree);
7977 f8a36e22 2021-08-26 stsp if (ref)
7978 f8a36e22 2021-08-26 stsp got_ref_close(ref);
7979 f8a36e22 2021-08-26 stsp got_pathlist_free(&branches);
7980 f8a36e22 2021-08-26 stsp got_pathlist_free(&tags);
7981 f8a36e22 2021-08-26 stsp got_ref_list_free(&all_branches);
7982 f8a36e22 2021-08-26 stsp got_ref_list_free(&all_tags);
7983 f8a36e22 2021-08-26 stsp got_pathlist_free(&delete_args);
7984 f8a36e22 2021-08-26 stsp TAILQ_FOREACH(pe, &delete_branches, entry)
7985 f8a36e22 2021-08-26 stsp free((char *)pe->path);
7986 f8a36e22 2021-08-26 stsp got_pathlist_free(&delete_branches);
7987 f8a36e22 2021-08-26 stsp free(cwd);
7988 f8a36e22 2021-08-26 stsp free(repo_path);
7989 f8a36e22 2021-08-26 stsp free(proto);
7990 f8a36e22 2021-08-26 stsp free(host);
7991 f8a36e22 2021-08-26 stsp free(port);
7992 f8a36e22 2021-08-26 stsp free(server_path);
7993 f8a36e22 2021-08-26 stsp free(repo_name);
7994 234035bc 2019-06-01 stsp return error;
7995 234035bc 2019-06-01 stsp }
7996 234035bc 2019-06-01 stsp
7997 234035bc 2019-06-01 stsp __dead static void
7998 234035bc 2019-06-01 stsp usage_cherrypick(void)
7999 234035bc 2019-06-01 stsp {
8000 234035bc 2019-06-01 stsp fprintf(stderr, "usage: %s cherrypick commit-id\n", getprogname());
8001 234035bc 2019-06-01 stsp exit(1);
8002 234035bc 2019-06-01 stsp }
8003 234035bc 2019-06-01 stsp
8004 234035bc 2019-06-01 stsp static const struct got_error *
8005 234035bc 2019-06-01 stsp cmd_cherrypick(int argc, char *argv[])
8006 234035bc 2019-06-01 stsp {
8007 234035bc 2019-06-01 stsp const struct got_error *error = NULL;
8008 234035bc 2019-06-01 stsp struct got_worktree *worktree = NULL;
8009 234035bc 2019-06-01 stsp struct got_repository *repo = NULL;
8010 234035bc 2019-06-01 stsp char *cwd = NULL, *commit_id_str = NULL;
8011 234035bc 2019-06-01 stsp struct got_object_id *commit_id = NULL;
8012 234035bc 2019-06-01 stsp struct got_commit_object *commit = NULL;
8013 234035bc 2019-06-01 stsp struct got_object_qid *pid;
8014 9627c110 2020-04-18 stsp int ch;
8015 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8016 234035bc 2019-06-01 stsp
8017 234035bc 2019-06-01 stsp while ((ch = getopt(argc, argv, "")) != -1) {
8018 234035bc 2019-06-01 stsp switch (ch) {
8019 234035bc 2019-06-01 stsp default:
8020 234035bc 2019-06-01 stsp usage_cherrypick();
8021 234035bc 2019-06-01 stsp /* NOTREACHED */
8022 234035bc 2019-06-01 stsp }
8023 234035bc 2019-06-01 stsp }
8024 234035bc 2019-06-01 stsp
8025 234035bc 2019-06-01 stsp argc -= optind;
8026 234035bc 2019-06-01 stsp argv += optind;
8027 234035bc 2019-06-01 stsp
8028 43012d58 2019-07-14 stsp #ifndef PROFILE
8029 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8030 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
8031 43012d58 2019-07-14 stsp err(1, "pledge");
8032 43012d58 2019-07-14 stsp #endif
8033 234035bc 2019-06-01 stsp if (argc != 1)
8034 234035bc 2019-06-01 stsp usage_cherrypick();
8035 234035bc 2019-06-01 stsp
8036 234035bc 2019-06-01 stsp cwd = getcwd(NULL, 0);
8037 234035bc 2019-06-01 stsp if (cwd == NULL) {
8038 234035bc 2019-06-01 stsp error = got_error_from_errno("getcwd");
8039 234035bc 2019-06-01 stsp goto done;
8040 234035bc 2019-06-01 stsp }
8041 234035bc 2019-06-01 stsp error = got_worktree_open(&worktree, cwd);
8042 fa51e947 2020-03-27 stsp if (error) {
8043 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8044 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "cherrypick",
8045 fa51e947 2020-03-27 stsp cwd);
8046 234035bc 2019-06-01 stsp goto done;
8047 fa51e947 2020-03-27 stsp }
8048 234035bc 2019-06-01 stsp
8049 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8050 c9956ddf 2019-09-08 stsp NULL);
8051 234035bc 2019-06-01 stsp if (error != NULL)
8052 234035bc 2019-06-01 stsp goto done;
8053 234035bc 2019-06-01 stsp
8054 234035bc 2019-06-01 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8055 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
8056 234035bc 2019-06-01 stsp if (error)
8057 234035bc 2019-06-01 stsp goto done;
8058 234035bc 2019-06-01 stsp
8059 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&commit_id, argv[0],
8060 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_COMMIT, repo);
8061 234035bc 2019-06-01 stsp if (error != NULL) {
8062 234035bc 2019-06-01 stsp struct got_reference *ref;
8063 234035bc 2019-06-01 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
8064 234035bc 2019-06-01 stsp goto done;
8065 234035bc 2019-06-01 stsp error = got_ref_open(&ref, repo, argv[0], 0);
8066 234035bc 2019-06-01 stsp if (error != NULL)
8067 234035bc 2019-06-01 stsp goto done;
8068 234035bc 2019-06-01 stsp error = got_ref_resolve(&commit_id, repo, ref);
8069 234035bc 2019-06-01 stsp got_ref_close(ref);
8070 234035bc 2019-06-01 stsp if (error != NULL)
8071 234035bc 2019-06-01 stsp goto done;
8072 234035bc 2019-06-01 stsp }
8073 234035bc 2019-06-01 stsp error = got_object_id_str(&commit_id_str, commit_id);
8074 234035bc 2019-06-01 stsp if (error)
8075 234035bc 2019-06-01 stsp goto done;
8076 234035bc 2019-06-01 stsp
8077 234035bc 2019-06-01 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8078 234035bc 2019-06-01 stsp if (error)
8079 234035bc 2019-06-01 stsp goto done;
8080 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8081 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8082 03415a1a 2019-06-02 stsp error = got_worktree_merge_files(worktree, pid ? pid->id : NULL,
8083 9627c110 2020-04-18 stsp commit_id, repo, update_progress, &upa, check_cancelled,
8084 03415a1a 2019-06-02 stsp NULL);
8085 234035bc 2019-06-01 stsp if (error != NULL)
8086 234035bc 2019-06-01 stsp goto done;
8087 234035bc 2019-06-01 stsp
8088 9627c110 2020-04-18 stsp if (upa.did_something)
8089 a7648d7a 2019-06-02 stsp printf("Merged commit %s\n", commit_id_str);
8090 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8091 234035bc 2019-06-01 stsp done:
8092 234035bc 2019-06-01 stsp if (commit)
8093 234035bc 2019-06-01 stsp got_object_commit_close(commit);
8094 234035bc 2019-06-01 stsp free(commit_id_str);
8095 234035bc 2019-06-01 stsp if (worktree)
8096 234035bc 2019-06-01 stsp got_worktree_close(worktree);
8097 1d0f4054 2021-06-17 stsp if (repo) {
8098 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
8099 1d0f4054 2021-06-17 stsp if (error == NULL)
8100 1d0f4054 2021-06-17 stsp error = close_err;
8101 1d0f4054 2021-06-17 stsp }
8102 c4296144 2019-05-09 stsp return error;
8103 c4296144 2019-05-09 stsp }
8104 5ef14e63 2019-06-02 stsp
8105 5ef14e63 2019-06-02 stsp __dead static void
8106 5ef14e63 2019-06-02 stsp usage_backout(void)
8107 5ef14e63 2019-06-02 stsp {
8108 5ef14e63 2019-06-02 stsp fprintf(stderr, "usage: %s backout commit-id\n", getprogname());
8109 5ef14e63 2019-06-02 stsp exit(1);
8110 5ef14e63 2019-06-02 stsp }
8111 5ef14e63 2019-06-02 stsp
8112 5ef14e63 2019-06-02 stsp static const struct got_error *
8113 5ef14e63 2019-06-02 stsp cmd_backout(int argc, char *argv[])
8114 5ef14e63 2019-06-02 stsp {
8115 5ef14e63 2019-06-02 stsp const struct got_error *error = NULL;
8116 5ef14e63 2019-06-02 stsp struct got_worktree *worktree = NULL;
8117 5ef14e63 2019-06-02 stsp struct got_repository *repo = NULL;
8118 5ef14e63 2019-06-02 stsp char *cwd = NULL, *commit_id_str = NULL;
8119 5ef14e63 2019-06-02 stsp struct got_object_id *commit_id = NULL;
8120 5ef14e63 2019-06-02 stsp struct got_commit_object *commit = NULL;
8121 5ef14e63 2019-06-02 stsp struct got_object_qid *pid;
8122 9627c110 2020-04-18 stsp int ch;
8123 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8124 5ef14e63 2019-06-02 stsp
8125 5ef14e63 2019-06-02 stsp while ((ch = getopt(argc, argv, "")) != -1) {
8126 5ef14e63 2019-06-02 stsp switch (ch) {
8127 5ef14e63 2019-06-02 stsp default:
8128 5ef14e63 2019-06-02 stsp usage_backout();
8129 5ef14e63 2019-06-02 stsp /* NOTREACHED */
8130 5ef14e63 2019-06-02 stsp }
8131 5ef14e63 2019-06-02 stsp }
8132 5ef14e63 2019-06-02 stsp
8133 5ef14e63 2019-06-02 stsp argc -= optind;
8134 5ef14e63 2019-06-02 stsp argv += optind;
8135 5ef14e63 2019-06-02 stsp
8136 43012d58 2019-07-14 stsp #ifndef PROFILE
8137 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8138 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
8139 43012d58 2019-07-14 stsp err(1, "pledge");
8140 43012d58 2019-07-14 stsp #endif
8141 5ef14e63 2019-06-02 stsp if (argc != 1)
8142 5ef14e63 2019-06-02 stsp usage_backout();
8143 5ef14e63 2019-06-02 stsp
8144 5ef14e63 2019-06-02 stsp cwd = getcwd(NULL, 0);
8145 5ef14e63 2019-06-02 stsp if (cwd == NULL) {
8146 5ef14e63 2019-06-02 stsp error = got_error_from_errno("getcwd");
8147 5ef14e63 2019-06-02 stsp goto done;
8148 5ef14e63 2019-06-02 stsp }
8149 5ef14e63 2019-06-02 stsp error = got_worktree_open(&worktree, cwd);
8150 fa51e947 2020-03-27 stsp if (error) {
8151 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8152 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "backout", cwd);
8153 5ef14e63 2019-06-02 stsp goto done;
8154 fa51e947 2020-03-27 stsp }
8155 5ef14e63 2019-06-02 stsp
8156 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8157 c9956ddf 2019-09-08 stsp NULL);
8158 5ef14e63 2019-06-02 stsp if (error != NULL)
8159 5ef14e63 2019-06-02 stsp goto done;
8160 5ef14e63 2019-06-02 stsp
8161 5ef14e63 2019-06-02 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8162 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
8163 5ef14e63 2019-06-02 stsp if (error)
8164 5ef14e63 2019-06-02 stsp goto done;
8165 5ef14e63 2019-06-02 stsp
8166 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&commit_id, argv[0],
8167 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_COMMIT, repo);
8168 5ef14e63 2019-06-02 stsp if (error != NULL) {
8169 5ef14e63 2019-06-02 stsp struct got_reference *ref;
8170 5ef14e63 2019-06-02 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
8171 5ef14e63 2019-06-02 stsp goto done;
8172 5ef14e63 2019-06-02 stsp error = got_ref_open(&ref, repo, argv[0], 0);
8173 5ef14e63 2019-06-02 stsp if (error != NULL)
8174 5ef14e63 2019-06-02 stsp goto done;
8175 5ef14e63 2019-06-02 stsp error = got_ref_resolve(&commit_id, repo, ref);
8176 5ef14e63 2019-06-02 stsp got_ref_close(ref);
8177 5ef14e63 2019-06-02 stsp if (error != NULL)
8178 5ef14e63 2019-06-02 stsp goto done;
8179 5ef14e63 2019-06-02 stsp }
8180 5ef14e63 2019-06-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
8181 5ef14e63 2019-06-02 stsp if (error)
8182 5ef14e63 2019-06-02 stsp goto done;
8183 5ef14e63 2019-06-02 stsp
8184 5ef14e63 2019-06-02 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8185 5ef14e63 2019-06-02 stsp if (error)
8186 5ef14e63 2019-06-02 stsp goto done;
8187 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8188 5ef14e63 2019-06-02 stsp if (pid == NULL) {
8189 5ef14e63 2019-06-02 stsp error = got_error(GOT_ERR_ROOT_COMMIT);
8190 5ef14e63 2019-06-02 stsp goto done;
8191 5ef14e63 2019-06-02 stsp }
8192 5ef14e63 2019-06-02 stsp
8193 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8194 10604dce 2021-09-24 thomas error = got_worktree_merge_files(worktree, commit_id, pid->id,
8195 10604dce 2021-09-24 thomas repo, update_progress, &upa, check_cancelled, NULL);
8196 5ef14e63 2019-06-02 stsp if (error != NULL)
8197 5ef14e63 2019-06-02 stsp goto done;
8198 5ef14e63 2019-06-02 stsp
8199 9627c110 2020-04-18 stsp if (upa.did_something)
8200 a7648d7a 2019-06-02 stsp printf("Backed out commit %s\n", commit_id_str);
8201 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8202 5ef14e63 2019-06-02 stsp done:
8203 5ef14e63 2019-06-02 stsp if (commit)
8204 5ef14e63 2019-06-02 stsp got_object_commit_close(commit);
8205 5ef14e63 2019-06-02 stsp free(commit_id_str);
8206 818c7501 2019-07-11 stsp if (worktree)
8207 818c7501 2019-07-11 stsp got_worktree_close(worktree);
8208 1d0f4054 2021-06-17 stsp if (repo) {
8209 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
8210 1d0f4054 2021-06-17 stsp if (error == NULL)
8211 1d0f4054 2021-06-17 stsp error = close_err;
8212 1d0f4054 2021-06-17 stsp }
8213 818c7501 2019-07-11 stsp return error;
8214 818c7501 2019-07-11 stsp }
8215 818c7501 2019-07-11 stsp
8216 818c7501 2019-07-11 stsp __dead static void
8217 818c7501 2019-07-11 stsp usage_rebase(void)
8218 818c7501 2019-07-11 stsp {
8219 643b85bc 2021-07-16 stsp fprintf(stderr, "usage: %s rebase [-a] [-c] [-l] [-X] [branch]\n",
8220 af54c8f8 2019-07-11 stsp getprogname());
8221 818c7501 2019-07-11 stsp exit(1);
8222 0ebf8283 2019-07-24 stsp }
8223 0ebf8283 2019-07-24 stsp
8224 0ebf8283 2019-07-24 stsp void
8225 0ebf8283 2019-07-24 stsp trim_logmsg(char *logmsg, int limit)
8226 0ebf8283 2019-07-24 stsp {
8227 0ebf8283 2019-07-24 stsp char *nl;
8228 0ebf8283 2019-07-24 stsp size_t len;
8229 0ebf8283 2019-07-24 stsp
8230 0ebf8283 2019-07-24 stsp len = strlen(logmsg);
8231 0ebf8283 2019-07-24 stsp if (len > limit)
8232 0ebf8283 2019-07-24 stsp len = limit;
8233 0ebf8283 2019-07-24 stsp logmsg[len] = '\0';
8234 0ebf8283 2019-07-24 stsp nl = strchr(logmsg, '\n');
8235 0ebf8283 2019-07-24 stsp if (nl)
8236 0ebf8283 2019-07-24 stsp *nl = '\0';
8237 0ebf8283 2019-07-24 stsp }
8238 0ebf8283 2019-07-24 stsp
8239 0ebf8283 2019-07-24 stsp static const struct got_error *
8240 0ebf8283 2019-07-24 stsp get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
8241 0ebf8283 2019-07-24 stsp {
8242 5943eee2 2019-08-13 stsp const struct got_error *err;
8243 5943eee2 2019-08-13 stsp char *logmsg0 = NULL;
8244 5943eee2 2019-08-13 stsp const char *s;
8245 0ebf8283 2019-07-24 stsp
8246 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
8247 5943eee2 2019-08-13 stsp if (err)
8248 5943eee2 2019-08-13 stsp return err;
8249 0ebf8283 2019-07-24 stsp
8250 5943eee2 2019-08-13 stsp s = logmsg0;
8251 5943eee2 2019-08-13 stsp while (isspace((unsigned char)s[0]))
8252 5943eee2 2019-08-13 stsp s++;
8253 5943eee2 2019-08-13 stsp
8254 5943eee2 2019-08-13 stsp *logmsg = strdup(s);
8255 5943eee2 2019-08-13 stsp if (*logmsg == NULL) {
8256 5943eee2 2019-08-13 stsp err = got_error_from_errno("strdup");
8257 5943eee2 2019-08-13 stsp goto done;
8258 5943eee2 2019-08-13 stsp }
8259 0ebf8283 2019-07-24 stsp
8260 0ebf8283 2019-07-24 stsp trim_logmsg(*logmsg, limit);
8261 5943eee2 2019-08-13 stsp done:
8262 5943eee2 2019-08-13 stsp free(logmsg0);
8263 a0ea4fc0 2020-02-28 stsp return err;
8264 a0ea4fc0 2020-02-28 stsp }
8265 a0ea4fc0 2020-02-28 stsp
8266 a0ea4fc0 2020-02-28 stsp static const struct got_error *
8267 a0ea4fc0 2020-02-28 stsp show_rebase_merge_conflict(struct got_object_id *id, struct got_repository *repo)
8268 a0ea4fc0 2020-02-28 stsp {
8269 a0ea4fc0 2020-02-28 stsp const struct got_error *err;
8270 a0ea4fc0 2020-02-28 stsp struct got_commit_object *commit = NULL;
8271 a0ea4fc0 2020-02-28 stsp char *id_str = NULL, *logmsg = NULL;
8272 a0ea4fc0 2020-02-28 stsp
8273 a0ea4fc0 2020-02-28 stsp err = got_object_open_as_commit(&commit, repo, id);
8274 a0ea4fc0 2020-02-28 stsp if (err)
8275 a0ea4fc0 2020-02-28 stsp return err;
8276 a0ea4fc0 2020-02-28 stsp
8277 a0ea4fc0 2020-02-28 stsp err = got_object_id_str(&id_str, id);
8278 a0ea4fc0 2020-02-28 stsp if (err)
8279 a0ea4fc0 2020-02-28 stsp goto done;
8280 a0ea4fc0 2020-02-28 stsp
8281 a0ea4fc0 2020-02-28 stsp id_str[12] = '\0';
8282 a0ea4fc0 2020-02-28 stsp
8283 a0ea4fc0 2020-02-28 stsp err = get_short_logmsg(&logmsg, 42, commit);
8284 a0ea4fc0 2020-02-28 stsp if (err)
8285 a0ea4fc0 2020-02-28 stsp goto done;
8286 a0ea4fc0 2020-02-28 stsp
8287 a0ea4fc0 2020-02-28 stsp printf("%s -> merge conflict: %s\n", id_str, logmsg);
8288 a0ea4fc0 2020-02-28 stsp done:
8289 a0ea4fc0 2020-02-28 stsp free(id_str);
8290 a0ea4fc0 2020-02-28 stsp got_object_commit_close(commit);
8291 a0ea4fc0 2020-02-28 stsp free(logmsg);
8292 5943eee2 2019-08-13 stsp return err;
8293 818c7501 2019-07-11 stsp }
8294 818c7501 2019-07-11 stsp
8295 818c7501 2019-07-11 stsp static const struct got_error *
8296 818c7501 2019-07-11 stsp show_rebase_progress(struct got_commit_object *commit,
8297 818c7501 2019-07-11 stsp struct got_object_id *old_id, struct got_object_id *new_id)
8298 818c7501 2019-07-11 stsp {
8299 818c7501 2019-07-11 stsp const struct got_error *err;
8300 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
8301 818c7501 2019-07-11 stsp
8302 818c7501 2019-07-11 stsp err = got_object_id_str(&old_id_str, old_id);
8303 818c7501 2019-07-11 stsp if (err)
8304 818c7501 2019-07-11 stsp goto done;
8305 818c7501 2019-07-11 stsp
8306 ff0d2220 2019-07-11 stsp if (new_id) {
8307 ff0d2220 2019-07-11 stsp err = got_object_id_str(&new_id_str, new_id);
8308 ff0d2220 2019-07-11 stsp if (err)
8309 ff0d2220 2019-07-11 stsp goto done;
8310 ff0d2220 2019-07-11 stsp }
8311 818c7501 2019-07-11 stsp
8312 818c7501 2019-07-11 stsp old_id_str[12] = '\0';
8313 ff0d2220 2019-07-11 stsp if (new_id_str)
8314 ff0d2220 2019-07-11 stsp new_id_str[12] = '\0';
8315 0ebf8283 2019-07-24 stsp
8316 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
8317 0ebf8283 2019-07-24 stsp if (err)
8318 0ebf8283 2019-07-24 stsp goto done;
8319 0ebf8283 2019-07-24 stsp
8320 ff0d2220 2019-07-11 stsp printf("%s -> %s: %s\n", old_id_str,
8321 ff0d2220 2019-07-11 stsp new_id_str ? new_id_str : "no-op change", logmsg);
8322 818c7501 2019-07-11 stsp done:
8323 818c7501 2019-07-11 stsp free(old_id_str);
8324 818c7501 2019-07-11 stsp free(new_id_str);
8325 272a1371 2020-02-28 stsp free(logmsg);
8326 818c7501 2019-07-11 stsp return err;
8327 818c7501 2019-07-11 stsp }
8328 818c7501 2019-07-11 stsp
8329 1ee397ad 2019-07-12 stsp static const struct got_error *
8330 3e3a69f1 2019-07-25 stsp rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
8331 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_reference *new_base_branch,
8332 e600f124 2021-03-21 stsp struct got_reference *tmp_branch, struct got_repository *repo,
8333 e600f124 2021-03-21 stsp int create_backup)
8334 818c7501 2019-07-11 stsp {
8335 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n", got_ref_get_name(branch));
8336 3e3a69f1 2019-07-25 stsp return got_worktree_rebase_complete(worktree, fileindex,
8337 e600f124 2021-03-21 stsp new_base_branch, tmp_branch, branch, repo, create_backup);
8338 818c7501 2019-07-11 stsp }
8339 818c7501 2019-07-11 stsp
8340 818c7501 2019-07-11 stsp static const struct got_error *
8341 01757395 2019-07-12 stsp rebase_commit(struct got_pathlist_head *merged_paths,
8342 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
8343 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch,
8344 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id, struct got_repository *repo)
8345 ff0d2220 2019-07-11 stsp {
8346 ff0d2220 2019-07-11 stsp const struct got_error *error;
8347 ff0d2220 2019-07-11 stsp struct got_commit_object *commit;
8348 ff0d2220 2019-07-11 stsp struct got_object_id *new_commit_id;
8349 ff0d2220 2019-07-11 stsp
8350 ff0d2220 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8351 ff0d2220 2019-07-11 stsp if (error)
8352 ff0d2220 2019-07-11 stsp return error;
8353 ff0d2220 2019-07-11 stsp
8354 01757395 2019-07-12 stsp error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
8355 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, commit_id, repo);
8356 ff0d2220 2019-07-11 stsp if (error) {
8357 ff0d2220 2019-07-11 stsp if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
8358 ff0d2220 2019-07-11 stsp goto done;
8359 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, NULL);
8360 ff0d2220 2019-07-11 stsp } else {
8361 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, new_commit_id);
8362 ff0d2220 2019-07-11 stsp free(new_commit_id);
8363 ff0d2220 2019-07-11 stsp }
8364 ff0d2220 2019-07-11 stsp done:
8365 ff0d2220 2019-07-11 stsp got_object_commit_close(commit);
8366 ff0d2220 2019-07-11 stsp return error;
8367 64c6d990 2019-07-11 stsp }
8368 64c6d990 2019-07-11 stsp
8369 64c6d990 2019-07-11 stsp struct check_path_prefix_arg {
8370 64c6d990 2019-07-11 stsp const char *path_prefix;
8371 64c6d990 2019-07-11 stsp size_t len;
8372 8ca9bd68 2019-07-25 stsp int errcode;
8373 64c6d990 2019-07-11 stsp };
8374 64c6d990 2019-07-11 stsp
8375 64c6d990 2019-07-11 stsp static const struct got_error *
8376 8ca9bd68 2019-07-25 stsp check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
8377 64c6d990 2019-07-11 stsp struct got_blob_object *blob2, struct got_object_id *id1,
8378 64c6d990 2019-07-11 stsp struct got_object_id *id2, const char *path1, const char *path2,
8379 46f68b20 2019-10-19 stsp mode_t mode1, mode_t mode2, struct got_repository *repo)
8380 64c6d990 2019-07-11 stsp {
8381 64c6d990 2019-07-11 stsp struct check_path_prefix_arg *a = arg;
8382 64c6d990 2019-07-11 stsp
8383 64c6d990 2019-07-11 stsp if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
8384 64c6d990 2019-07-11 stsp (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
8385 8ca9bd68 2019-07-25 stsp return got_error(a->errcode);
8386 64c6d990 2019-07-11 stsp
8387 64c6d990 2019-07-11 stsp return NULL;
8388 64c6d990 2019-07-11 stsp }
8389 64c6d990 2019-07-11 stsp
8390 64c6d990 2019-07-11 stsp static const struct got_error *
8391 8ca9bd68 2019-07-25 stsp check_path_prefix(struct got_object_id *parent_id,
8392 64c6d990 2019-07-11 stsp struct got_object_id *commit_id, const char *path_prefix,
8393 8ca9bd68 2019-07-25 stsp int errcode, struct got_repository *repo)
8394 64c6d990 2019-07-11 stsp {
8395 64c6d990 2019-07-11 stsp const struct got_error *err;
8396 64c6d990 2019-07-11 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
8397 64c6d990 2019-07-11 stsp struct got_commit_object *commit = NULL, *parent_commit = NULL;
8398 64c6d990 2019-07-11 stsp struct check_path_prefix_arg cpp_arg;
8399 64c6d990 2019-07-11 stsp
8400 64c6d990 2019-07-11 stsp if (got_path_is_root_dir(path_prefix))
8401 64c6d990 2019-07-11 stsp return NULL;
8402 64c6d990 2019-07-11 stsp
8403 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
8404 64c6d990 2019-07-11 stsp if (err)
8405 64c6d990 2019-07-11 stsp goto done;
8406 64c6d990 2019-07-11 stsp
8407 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&parent_commit, repo, parent_id);
8408 64c6d990 2019-07-11 stsp if (err)
8409 64c6d990 2019-07-11 stsp goto done;
8410 64c6d990 2019-07-11 stsp
8411 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree1, repo,
8412 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(parent_commit));
8413 64c6d990 2019-07-11 stsp if (err)
8414 64c6d990 2019-07-11 stsp goto done;
8415 64c6d990 2019-07-11 stsp
8416 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree2, repo,
8417 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(commit));
8418 64c6d990 2019-07-11 stsp if (err)
8419 64c6d990 2019-07-11 stsp goto done;
8420 64c6d990 2019-07-11 stsp
8421 64c6d990 2019-07-11 stsp cpp_arg.path_prefix = path_prefix;
8422 d23ace97 2019-07-25 stsp while (cpp_arg.path_prefix[0] == '/')
8423 d23ace97 2019-07-25 stsp cpp_arg.path_prefix++;
8424 d23ace97 2019-07-25 stsp cpp_arg.len = strlen(cpp_arg.path_prefix);
8425 8ca9bd68 2019-07-25 stsp cpp_arg.errcode = errcode;
8426 8ca9bd68 2019-07-25 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
8427 31b4484f 2019-07-27 stsp check_path_prefix_in_diff, &cpp_arg, 0);
8428 64c6d990 2019-07-11 stsp done:
8429 64c6d990 2019-07-11 stsp if (tree1)
8430 64c6d990 2019-07-11 stsp got_object_tree_close(tree1);
8431 64c6d990 2019-07-11 stsp if (tree2)
8432 64c6d990 2019-07-11 stsp got_object_tree_close(tree2);
8433 64c6d990 2019-07-11 stsp if (commit)
8434 64c6d990 2019-07-11 stsp got_object_commit_close(commit);
8435 64c6d990 2019-07-11 stsp if (parent_commit)
8436 64c6d990 2019-07-11 stsp got_object_commit_close(parent_commit);
8437 64c6d990 2019-07-11 stsp return err;
8438 ff0d2220 2019-07-11 stsp }
8439 ff0d2220 2019-07-11 stsp
8440 ff0d2220 2019-07-11 stsp static const struct got_error *
8441 8ca9bd68 2019-07-25 stsp collect_commits(struct got_object_id_queue *commits,
8442 af61c510 2019-07-19 stsp struct got_object_id *initial_commit_id,
8443 af61c510 2019-07-19 stsp struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
8444 8ca9bd68 2019-07-25 stsp const char *path_prefix, int path_prefix_errcode,
8445 8ca9bd68 2019-07-25 stsp struct got_repository *repo)
8446 af61c510 2019-07-19 stsp {
8447 af61c510 2019-07-19 stsp const struct got_error *err = NULL;
8448 af61c510 2019-07-19 stsp struct got_commit_graph *graph = NULL;
8449 af61c510 2019-07-19 stsp struct got_object_id *parent_id = NULL;
8450 af61c510 2019-07-19 stsp struct got_object_qid *qid;
8451 af61c510 2019-07-19 stsp struct got_object_id *commit_id = initial_commit_id;
8452 af61c510 2019-07-19 stsp
8453 3d509237 2020-01-04 stsp err = got_commit_graph_open(&graph, "/", 1);
8454 af61c510 2019-07-19 stsp if (err)
8455 af61c510 2019-07-19 stsp return err;
8456 af61c510 2019-07-19 stsp
8457 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, iter_start_id, repo,
8458 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
8459 af61c510 2019-07-19 stsp if (err)
8460 af61c510 2019-07-19 stsp goto done;
8461 af61c510 2019-07-19 stsp while (got_object_id_cmp(commit_id, iter_stop_id) != 0) {
8462 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&parent_id, graph, repo,
8463 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
8464 af61c510 2019-07-19 stsp if (err) {
8465 af61c510 2019-07-19 stsp if (err->code == GOT_ERR_ITER_COMPLETED) {
8466 af61c510 2019-07-19 stsp err = got_error_msg(GOT_ERR_ANCESTRY,
8467 af61c510 2019-07-19 stsp "ran out of commits to rebase before "
8468 af61c510 2019-07-19 stsp "youngest common ancestor commit has "
8469 af61c510 2019-07-19 stsp "been reached?!?");
8470 ee780d5c 2020-01-04 stsp }
8471 ee780d5c 2020-01-04 stsp goto done;
8472 af61c510 2019-07-19 stsp } else {
8473 8ca9bd68 2019-07-25 stsp err = check_path_prefix(parent_id, commit_id,
8474 8ca9bd68 2019-07-25 stsp path_prefix, path_prefix_errcode, repo);
8475 af61c510 2019-07-19 stsp if (err)
8476 af61c510 2019-07-19 stsp goto done;
8477 af61c510 2019-07-19 stsp
8478 af61c510 2019-07-19 stsp err = got_object_qid_alloc(&qid, commit_id);
8479 af61c510 2019-07-19 stsp if (err)
8480 af61c510 2019-07-19 stsp goto done;
8481 dbdddfee 2021-06-23 naddy STAILQ_INSERT_HEAD(commits, qid, entry);
8482 af61c510 2019-07-19 stsp commit_id = parent_id;
8483 af61c510 2019-07-19 stsp }
8484 af61c510 2019-07-19 stsp }
8485 af61c510 2019-07-19 stsp done:
8486 af61c510 2019-07-19 stsp got_commit_graph_close(graph);
8487 af61c510 2019-07-19 stsp return err;
8488 e600f124 2021-03-21 stsp }
8489 e600f124 2021-03-21 stsp
8490 e600f124 2021-03-21 stsp static const struct got_error *
8491 e600f124 2021-03-21 stsp get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
8492 e600f124 2021-03-21 stsp {
8493 e600f124 2021-03-21 stsp const struct got_error *err = NULL;
8494 e600f124 2021-03-21 stsp time_t committer_time;
8495 e600f124 2021-03-21 stsp struct tm tm;
8496 e600f124 2021-03-21 stsp char datebuf[11]; /* YYYY-MM-DD + NUL */
8497 e600f124 2021-03-21 stsp char *author0 = NULL, *author, *smallerthan;
8498 e600f124 2021-03-21 stsp char *logmsg0 = NULL, *logmsg, *newline;
8499 e600f124 2021-03-21 stsp
8500 e600f124 2021-03-21 stsp committer_time = got_object_commit_get_committer_time(commit);
8501 e385fc42 2021-08-30 stsp if (gmtime_r(&committer_time, &tm) == NULL)
8502 e385fc42 2021-08-30 stsp return got_error_from_errno("gmtime_r");
8503 e3199de8 2021-03-21 stsp if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
8504 e600f124 2021-03-21 stsp return got_error(GOT_ERR_NO_SPACE);
8505 e600f124 2021-03-21 stsp
8506 e600f124 2021-03-21 stsp author0 = strdup(got_object_commit_get_author(commit));
8507 e600f124 2021-03-21 stsp if (author0 == NULL)
8508 e600f124 2021-03-21 stsp return got_error_from_errno("strdup");
8509 e600f124 2021-03-21 stsp author = author0;
8510 e600f124 2021-03-21 stsp smallerthan = strchr(author, '<');
8511 e600f124 2021-03-21 stsp if (smallerthan && smallerthan[1] != '\0')
8512 e600f124 2021-03-21 stsp author = smallerthan + 1;
8513 e600f124 2021-03-21 stsp author[strcspn(author, "@>")] = '\0';
8514 e600f124 2021-03-21 stsp
8515 e600f124 2021-03-21 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
8516 e600f124 2021-03-21 stsp if (err)
8517 e600f124 2021-03-21 stsp goto done;
8518 e600f124 2021-03-21 stsp logmsg = logmsg0;
8519 e600f124 2021-03-21 stsp while (*logmsg == '\n')
8520 e600f124 2021-03-21 stsp logmsg++;
8521 e600f124 2021-03-21 stsp newline = strchr(logmsg, '\n');
8522 e600f124 2021-03-21 stsp if (newline)
8523 e600f124 2021-03-21 stsp *newline = '\0';
8524 e600f124 2021-03-21 stsp
8525 e600f124 2021-03-21 stsp if (asprintf(brief_str, "%s %s %s",
8526 e600f124 2021-03-21 stsp datebuf, author, logmsg) == -1)
8527 e600f124 2021-03-21 stsp err = got_error_from_errno("asprintf");
8528 e600f124 2021-03-21 stsp done:
8529 e600f124 2021-03-21 stsp free(author0);
8530 e600f124 2021-03-21 stsp free(logmsg0);
8531 643b85bc 2021-07-16 stsp return err;
8532 643b85bc 2021-07-16 stsp }
8533 643b85bc 2021-07-16 stsp
8534 643b85bc 2021-07-16 stsp static const struct got_error *
8535 643b85bc 2021-07-16 stsp delete_backup_ref(struct got_reference *ref, struct got_object_id *id,
8536 643b85bc 2021-07-16 stsp struct got_repository *repo)
8537 643b85bc 2021-07-16 stsp {
8538 643b85bc 2021-07-16 stsp const struct got_error *err;
8539 643b85bc 2021-07-16 stsp char *id_str;
8540 643b85bc 2021-07-16 stsp
8541 643b85bc 2021-07-16 stsp err = got_object_id_str(&id_str, id);
8542 643b85bc 2021-07-16 stsp if (err)
8543 643b85bc 2021-07-16 stsp return err;
8544 643b85bc 2021-07-16 stsp
8545 643b85bc 2021-07-16 stsp err = got_ref_delete(ref, repo);
8546 643b85bc 2021-07-16 stsp if (err)
8547 643b85bc 2021-07-16 stsp goto done;
8548 643b85bc 2021-07-16 stsp
8549 643b85bc 2021-07-16 stsp printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str);
8550 643b85bc 2021-07-16 stsp done:
8551 643b85bc 2021-07-16 stsp free(id_str);
8552 e600f124 2021-03-21 stsp return err;
8553 e600f124 2021-03-21 stsp }
8554 e600f124 2021-03-21 stsp
8555 e600f124 2021-03-21 stsp static const struct got_error *
8556 e600f124 2021-03-21 stsp print_backup_ref(const char *branch_name, const char *new_id_str,
8557 e600f124 2021-03-21 stsp struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
8558 e600f124 2021-03-21 stsp struct got_reflist_object_id_map *refs_idmap,
8559 e600f124 2021-03-21 stsp struct got_repository *repo)
8560 e600f124 2021-03-21 stsp {
8561 e600f124 2021-03-21 stsp const struct got_error *err = NULL;
8562 e600f124 2021-03-21 stsp struct got_reflist_head *refs;
8563 e600f124 2021-03-21 stsp char *refs_str = NULL;
8564 e600f124 2021-03-21 stsp struct got_object_id *new_commit_id = NULL;
8565 e600f124 2021-03-21 stsp struct got_commit_object *new_commit = NULL;
8566 e600f124 2021-03-21 stsp char *new_commit_brief_str = NULL;
8567 e600f124 2021-03-21 stsp struct got_object_id *yca_id = NULL;
8568 e600f124 2021-03-21 stsp struct got_commit_object *yca_commit = NULL;
8569 e600f124 2021-03-21 stsp char *yca_id_str = NULL, *yca_brief_str = NULL;
8570 e600f124 2021-03-21 stsp char *custom_refs_str;
8571 e600f124 2021-03-21 stsp
8572 e600f124 2021-03-21 stsp if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
8573 e600f124 2021-03-21 stsp return got_error_from_errno("asprintf");
8574 e600f124 2021-03-21 stsp
8575 e600f124 2021-03-21 stsp err = print_commit(old_commit, old_commit_id, repo, NULL, NULL,
8576 e600f124 2021-03-21 stsp 0, 0, refs_idmap, custom_refs_str);
8577 e600f124 2021-03-21 stsp if (err)
8578 e600f124 2021-03-21 stsp goto done;
8579 e600f124 2021-03-21 stsp
8580 e600f124 2021-03-21 stsp err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
8581 e600f124 2021-03-21 stsp if (err)
8582 e600f124 2021-03-21 stsp goto done;
8583 e600f124 2021-03-21 stsp
8584 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
8585 e600f124 2021-03-21 stsp if (refs) {
8586 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, new_commit_id, repo);
8587 e600f124 2021-03-21 stsp if (err)
8588 e600f124 2021-03-21 stsp goto done;
8589 e600f124 2021-03-21 stsp }
8590 e600f124 2021-03-21 stsp
8591 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
8592 e600f124 2021-03-21 stsp if (err)
8593 e600f124 2021-03-21 stsp goto done;
8594 e600f124 2021-03-21 stsp
8595 e600f124 2021-03-21 stsp err = get_commit_brief_str(&new_commit_brief_str, new_commit);
8596 e600f124 2021-03-21 stsp if (err)
8597 e600f124 2021-03-21 stsp goto done;
8598 e600f124 2021-03-21 stsp
8599 e600f124 2021-03-21 stsp err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
8600 e600f124 2021-03-21 stsp old_commit_id, new_commit_id, repo, check_cancelled, NULL);
8601 e600f124 2021-03-21 stsp if (err)
8602 e600f124 2021-03-21 stsp goto done;
8603 e600f124 2021-03-21 stsp
8604 e600f124 2021-03-21 stsp printf("has become commit %s%s%s%s\n %s\n", new_id_str,
8605 e600f124 2021-03-21 stsp refs_str ? " (" : "", refs_str ? refs_str : "",
8606 e600f124 2021-03-21 stsp refs_str ? ")" : "", new_commit_brief_str);
8607 e600f124 2021-03-21 stsp if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
8608 e600f124 2021-03-21 stsp got_object_id_cmp(yca_id, old_commit_id) != 0) {
8609 e600f124 2021-03-21 stsp free(refs_str);
8610 e600f124 2021-03-21 stsp refs_str = NULL;
8611 e600f124 2021-03-21 stsp
8612 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&yca_commit, repo, yca_id);
8613 e600f124 2021-03-21 stsp if (err)
8614 e600f124 2021-03-21 stsp goto done;
8615 e600f124 2021-03-21 stsp
8616 e600f124 2021-03-21 stsp err = get_commit_brief_str(&yca_brief_str, yca_commit);
8617 e600f124 2021-03-21 stsp if (err)
8618 e600f124 2021-03-21 stsp goto done;
8619 e600f124 2021-03-21 stsp
8620 e600f124 2021-03-21 stsp err = got_object_id_str(&yca_id_str, yca_id);
8621 e600f124 2021-03-21 stsp if (err)
8622 e600f124 2021-03-21 stsp goto done;
8623 e600f124 2021-03-21 stsp
8624 e600f124 2021-03-21 stsp refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
8625 e600f124 2021-03-21 stsp if (refs) {
8626 e600f124 2021-03-21 stsp err = build_refs_str(&refs_str, refs, yca_id, repo);
8627 e600f124 2021-03-21 stsp if (err)
8628 e600f124 2021-03-21 stsp goto done;
8629 e600f124 2021-03-21 stsp }
8630 e600f124 2021-03-21 stsp printf("history forked at %s%s%s%s\n %s\n",
8631 e600f124 2021-03-21 stsp yca_id_str,
8632 e600f124 2021-03-21 stsp refs_str ? " (" : "", refs_str ? refs_str : "",
8633 e600f124 2021-03-21 stsp refs_str ? ")" : "", yca_brief_str);
8634 e600f124 2021-03-21 stsp }
8635 e600f124 2021-03-21 stsp done:
8636 e600f124 2021-03-21 stsp free(custom_refs_str);
8637 e600f124 2021-03-21 stsp free(new_commit_id);
8638 e600f124 2021-03-21 stsp free(refs_str);
8639 e600f124 2021-03-21 stsp free(yca_id);
8640 e600f124 2021-03-21 stsp free(yca_id_str);
8641 e600f124 2021-03-21 stsp free(yca_brief_str);
8642 e600f124 2021-03-21 stsp if (new_commit)
8643 e600f124 2021-03-21 stsp got_object_commit_close(new_commit);
8644 e600f124 2021-03-21 stsp if (yca_commit)
8645 e600f124 2021-03-21 stsp got_object_commit_close(yca_commit);
8646 e600f124 2021-03-21 stsp
8647 e600f124 2021-03-21 stsp return NULL;
8648 af61c510 2019-07-19 stsp }
8649 af61c510 2019-07-19 stsp
8650 af61c510 2019-07-19 stsp static const struct got_error *
8651 643b85bc 2021-07-16 stsp process_backup_refs(const char *backup_ref_prefix, const char *wanted_branch_name,
8652 643b85bc 2021-07-16 stsp int delete, struct got_repository *repo)
8653 e600f124 2021-03-21 stsp {
8654 e600f124 2021-03-21 stsp const struct got_error *err;
8655 e600f124 2021-03-21 stsp struct got_reflist_head refs, backup_refs;
8656 e600f124 2021-03-21 stsp struct got_reflist_entry *re;
8657 e600f124 2021-03-21 stsp const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
8658 e600f124 2021-03-21 stsp struct got_object_id *old_commit_id = NULL;
8659 e600f124 2021-03-21 stsp char *branch_name = NULL;
8660 e600f124 2021-03-21 stsp struct got_commit_object *old_commit = NULL;
8661 e600f124 2021-03-21 stsp struct got_reflist_object_id_map *refs_idmap = NULL;
8662 9e822917 2021-03-23 stsp int wanted_branch_found = 0;
8663 e600f124 2021-03-21 stsp
8664 e600f124 2021-03-21 stsp TAILQ_INIT(&refs);
8665 e600f124 2021-03-21 stsp TAILQ_INIT(&backup_refs);
8666 e600f124 2021-03-21 stsp
8667 e600f124 2021-03-21 stsp err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
8668 e600f124 2021-03-21 stsp if (err)
8669 e600f124 2021-03-21 stsp return err;
8670 e600f124 2021-03-21 stsp
8671 e600f124 2021-03-21 stsp err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
8672 e600f124 2021-03-21 stsp if (err)
8673 e600f124 2021-03-21 stsp goto done;
8674 e600f124 2021-03-21 stsp
8675 e600f124 2021-03-21 stsp if (wanted_branch_name) {
8676 e600f124 2021-03-21 stsp if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
8677 e600f124 2021-03-21 stsp wanted_branch_name += 11;
8678 e600f124 2021-03-21 stsp }
8679 e600f124 2021-03-21 stsp
8680 e600f124 2021-03-21 stsp err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
8681 e600f124 2021-03-21 stsp got_ref_cmp_by_commit_timestamp_descending, repo);
8682 e600f124 2021-03-21 stsp if (err)
8683 e600f124 2021-03-21 stsp goto done;
8684 e600f124 2021-03-21 stsp
8685 e600f124 2021-03-21 stsp TAILQ_FOREACH(re, &backup_refs, entry) {
8686 e600f124 2021-03-21 stsp const char *refname = got_ref_get_name(re->ref);
8687 e600f124 2021-03-21 stsp char *slash;
8688 e600f124 2021-03-21 stsp
8689 643b85bc 2021-07-16 stsp err = check_cancelled(NULL);
8690 643b85bc 2021-07-16 stsp if (err)
8691 643b85bc 2021-07-16 stsp break;
8692 643b85bc 2021-07-16 stsp
8693 e600f124 2021-03-21 stsp err = got_ref_resolve(&old_commit_id, repo, re->ref);
8694 e600f124 2021-03-21 stsp if (err)
8695 e600f124 2021-03-21 stsp break;
8696 e600f124 2021-03-21 stsp
8697 e600f124 2021-03-21 stsp err = got_object_open_as_commit(&old_commit, repo,
8698 e600f124 2021-03-21 stsp old_commit_id);
8699 e600f124 2021-03-21 stsp if (err)
8700 e600f124 2021-03-21 stsp break;
8701 e600f124 2021-03-21 stsp
8702 e600f124 2021-03-21 stsp if (strncmp(backup_ref_prefix, refname,
8703 e600f124 2021-03-21 stsp backup_ref_prefix_len) == 0)
8704 e600f124 2021-03-21 stsp refname += backup_ref_prefix_len;
8705 e600f124 2021-03-21 stsp
8706 e600f124 2021-03-21 stsp while (refname[0] == '/')
8707 e600f124 2021-03-21 stsp refname++;
8708 e600f124 2021-03-21 stsp
8709 e600f124 2021-03-21 stsp branch_name = strdup(refname);
8710 e600f124 2021-03-21 stsp if (branch_name == NULL) {
8711 e600f124 2021-03-21 stsp err = got_error_from_errno("strdup");
8712 e600f124 2021-03-21 stsp break;
8713 e600f124 2021-03-21 stsp }
8714 e600f124 2021-03-21 stsp slash = strrchr(branch_name, '/');
8715 e600f124 2021-03-21 stsp if (slash) {
8716 e600f124 2021-03-21 stsp *slash = '\0';
8717 e600f124 2021-03-21 stsp refname += strlen(branch_name) + 1;
8718 e600f124 2021-03-21 stsp }
8719 e600f124 2021-03-21 stsp
8720 e600f124 2021-03-21 stsp if (wanted_branch_name == NULL ||
8721 e600f124 2021-03-21 stsp strcmp(wanted_branch_name, branch_name) == 0) {
8722 9e822917 2021-03-23 stsp wanted_branch_found = 1;
8723 643b85bc 2021-07-16 stsp if (delete) {
8724 643b85bc 2021-07-16 stsp err = delete_backup_ref(re->ref,
8725 643b85bc 2021-07-16 stsp old_commit_id, repo);
8726 643b85bc 2021-07-16 stsp } else {
8727 643b85bc 2021-07-16 stsp err = print_backup_ref(branch_name, refname,
8728 abc59930 2021-09-05 naddy old_commit_id, old_commit, refs_idmap,
8729 abc59930 2021-09-05 naddy repo);
8730 643b85bc 2021-07-16 stsp }
8731 e600f124 2021-03-21 stsp if (err)
8732 e600f124 2021-03-21 stsp break;
8733 e600f124 2021-03-21 stsp }
8734 e600f124 2021-03-21 stsp
8735 e600f124 2021-03-21 stsp free(old_commit_id);
8736 e600f124 2021-03-21 stsp old_commit_id = NULL;
8737 e600f124 2021-03-21 stsp free(branch_name);
8738 e600f124 2021-03-21 stsp branch_name = NULL;
8739 e600f124 2021-03-21 stsp got_object_commit_close(old_commit);
8740 e600f124 2021-03-21 stsp old_commit = NULL;
8741 e600f124 2021-03-21 stsp }
8742 9e822917 2021-03-23 stsp
8743 9e822917 2021-03-23 stsp if (wanted_branch_name && !wanted_branch_found) {
8744 9e822917 2021-03-23 stsp err = got_error_fmt(GOT_ERR_NOT_REF,
8745 9e822917 2021-03-23 stsp "%s/%s/", backup_ref_prefix, wanted_branch_name);
8746 9e822917 2021-03-23 stsp }
8747 e600f124 2021-03-21 stsp done:
8748 e600f124 2021-03-21 stsp if (refs_idmap)
8749 e600f124 2021-03-21 stsp got_reflist_object_id_map_free(refs_idmap);
8750 e600f124 2021-03-21 stsp got_ref_list_free(&refs);
8751 e600f124 2021-03-21 stsp got_ref_list_free(&backup_refs);
8752 e600f124 2021-03-21 stsp free(old_commit_id);
8753 e600f124 2021-03-21 stsp free(branch_name);
8754 e600f124 2021-03-21 stsp if (old_commit)
8755 e600f124 2021-03-21 stsp got_object_commit_close(old_commit);
8756 e600f124 2021-03-21 stsp return err;
8757 e600f124 2021-03-21 stsp }
8758 e600f124 2021-03-21 stsp
8759 e600f124 2021-03-21 stsp static const struct got_error *
8760 818c7501 2019-07-11 stsp cmd_rebase(int argc, char *argv[])
8761 818c7501 2019-07-11 stsp {
8762 818c7501 2019-07-11 stsp const struct got_error *error = NULL;
8763 818c7501 2019-07-11 stsp struct got_worktree *worktree = NULL;
8764 818c7501 2019-07-11 stsp struct got_repository *repo = NULL;
8765 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
8766 818c7501 2019-07-11 stsp char *cwd = NULL;
8767 818c7501 2019-07-11 stsp struct got_reference *branch = NULL;
8768 818c7501 2019-07-11 stsp struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
8769 818c7501 2019-07-11 stsp struct got_object_id *commit_id = NULL, *parent_id = NULL;
8770 818c7501 2019-07-11 stsp struct got_object_id *resume_commit_id = NULL;
8771 818c7501 2019-07-11 stsp struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
8772 818c7501 2019-07-11 stsp struct got_commit_object *commit = NULL;
8773 818c7501 2019-07-11 stsp int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
8774 10604dce 2021-09-24 thomas int histedit_in_progress = 0, merge_in_progress = 0;
8775 10604dce 2021-09-24 thomas int create_backup = 1, list_backups = 0, delete_backups = 0;
8776 818c7501 2019-07-11 stsp unsigned char rebase_status = GOT_STATUS_NO_CHANGE;
8777 818c7501 2019-07-11 stsp struct got_object_id_queue commits;
8778 01757395 2019-07-12 stsp struct got_pathlist_head merged_paths;
8779 818c7501 2019-07-11 stsp const struct got_object_id_queue *parent_ids;
8780 818c7501 2019-07-11 stsp struct got_object_qid *qid, *pid;
8781 818c7501 2019-07-11 stsp
8782 dbdddfee 2021-06-23 naddy STAILQ_INIT(&commits);
8783 01757395 2019-07-12 stsp TAILQ_INIT(&merged_paths);
8784 818c7501 2019-07-11 stsp
8785 643b85bc 2021-07-16 stsp while ((ch = getopt(argc, argv, "aclX")) != -1) {
8786 818c7501 2019-07-11 stsp switch (ch) {
8787 818c7501 2019-07-11 stsp case 'a':
8788 818c7501 2019-07-11 stsp abort_rebase = 1;
8789 818c7501 2019-07-11 stsp break;
8790 818c7501 2019-07-11 stsp case 'c':
8791 818c7501 2019-07-11 stsp continue_rebase = 1;
8792 818c7501 2019-07-11 stsp break;
8793 e600f124 2021-03-21 stsp case 'l':
8794 e600f124 2021-03-21 stsp list_backups = 1;
8795 e600f124 2021-03-21 stsp break;
8796 643b85bc 2021-07-16 stsp case 'X':
8797 643b85bc 2021-07-16 stsp delete_backups = 1;
8798 643b85bc 2021-07-16 stsp break;
8799 818c7501 2019-07-11 stsp default:
8800 818c7501 2019-07-11 stsp usage_rebase();
8801 818c7501 2019-07-11 stsp /* NOTREACHED */
8802 818c7501 2019-07-11 stsp }
8803 818c7501 2019-07-11 stsp }
8804 818c7501 2019-07-11 stsp
8805 818c7501 2019-07-11 stsp argc -= optind;
8806 818c7501 2019-07-11 stsp argv += optind;
8807 818c7501 2019-07-11 stsp
8808 43012d58 2019-07-14 stsp #ifndef PROFILE
8809 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8810 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
8811 43012d58 2019-07-14 stsp err(1, "pledge");
8812 43012d58 2019-07-14 stsp #endif
8813 e600f124 2021-03-21 stsp if (list_backups) {
8814 e600f124 2021-03-21 stsp if (abort_rebase)
8815 e600f124 2021-03-21 stsp option_conflict('l', 'a');
8816 e600f124 2021-03-21 stsp if (continue_rebase)
8817 e600f124 2021-03-21 stsp option_conflict('l', 'c');
8818 643b85bc 2021-07-16 stsp if (delete_backups)
8819 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
8820 643b85bc 2021-07-16 stsp if (argc != 0 && argc != 1)
8821 643b85bc 2021-07-16 stsp usage_rebase();
8822 643b85bc 2021-07-16 stsp } else if (delete_backups) {
8823 643b85bc 2021-07-16 stsp if (abort_rebase)
8824 643b85bc 2021-07-16 stsp option_conflict('X', 'a');
8825 643b85bc 2021-07-16 stsp if (continue_rebase)
8826 643b85bc 2021-07-16 stsp option_conflict('X', 'c');
8827 643b85bc 2021-07-16 stsp if (list_backups)
8828 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
8829 e600f124 2021-03-21 stsp if (argc != 0 && argc != 1)
8830 818c7501 2019-07-11 stsp usage_rebase();
8831 e600f124 2021-03-21 stsp } else {
8832 e600f124 2021-03-21 stsp if (abort_rebase && continue_rebase)
8833 e600f124 2021-03-21 stsp usage_rebase();
8834 e600f124 2021-03-21 stsp else if (abort_rebase || continue_rebase) {
8835 e600f124 2021-03-21 stsp if (argc != 0)
8836 e600f124 2021-03-21 stsp usage_rebase();
8837 e600f124 2021-03-21 stsp } else if (argc != 1)
8838 e600f124 2021-03-21 stsp usage_rebase();
8839 e600f124 2021-03-21 stsp }
8840 818c7501 2019-07-11 stsp
8841 818c7501 2019-07-11 stsp cwd = getcwd(NULL, 0);
8842 818c7501 2019-07-11 stsp if (cwd == NULL) {
8843 818c7501 2019-07-11 stsp error = got_error_from_errno("getcwd");
8844 818c7501 2019-07-11 stsp goto done;
8845 818c7501 2019-07-11 stsp }
8846 818c7501 2019-07-11 stsp error = got_worktree_open(&worktree, cwd);
8847 fa51e947 2020-03-27 stsp if (error) {
8848 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
8849 e600f124 2021-03-21 stsp if (error->code != GOT_ERR_NOT_WORKTREE)
8850 e600f124 2021-03-21 stsp goto done;
8851 e600f124 2021-03-21 stsp } else {
8852 e600f124 2021-03-21 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8853 e600f124 2021-03-21 stsp error = wrap_not_worktree_error(error,
8854 e600f124 2021-03-21 stsp "rebase", cwd);
8855 e600f124 2021-03-21 stsp goto done;
8856 e600f124 2021-03-21 stsp }
8857 fa51e947 2020-03-27 stsp }
8858 818c7501 2019-07-11 stsp
8859 e600f124 2021-03-21 stsp error = got_repo_open(&repo,
8860 e600f124 2021-03-21 stsp worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL);
8861 818c7501 2019-07-11 stsp if (error != NULL)
8862 818c7501 2019-07-11 stsp goto done;
8863 818c7501 2019-07-11 stsp
8864 818c7501 2019-07-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8865 e600f124 2021-03-21 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
8866 7ef62c4e 2020-02-24 stsp if (error)
8867 7ef62c4e 2020-02-24 stsp goto done;
8868 7ef62c4e 2020-02-24 stsp
8869 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
8870 643b85bc 2021-07-16 stsp error = process_backup_refs(
8871 643b85bc 2021-07-16 stsp GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
8872 643b85bc 2021-07-16 stsp argc == 1 ? argv[0] : NULL, delete_backups, repo);
8873 e600f124 2021-03-21 stsp goto done; /* nothing else to do */
8874 e600f124 2021-03-21 stsp }
8875 e600f124 2021-03-21 stsp
8876 7ef62c4e 2020-02-24 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
8877 7ef62c4e 2020-02-24 stsp worktree);
8878 818c7501 2019-07-11 stsp if (error)
8879 7ef62c4e 2020-02-24 stsp goto done;
8880 7ef62c4e 2020-02-24 stsp if (histedit_in_progress) {
8881 7ef62c4e 2020-02-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
8882 10604dce 2021-09-24 thomas goto done;
8883 10604dce 2021-09-24 thomas }
8884 10604dce 2021-09-24 thomas
8885 10604dce 2021-09-24 thomas error = got_worktree_merge_in_progress(&merge_in_progress,
8886 10604dce 2021-09-24 thomas worktree, repo);
8887 10604dce 2021-09-24 thomas if (error)
8888 10604dce 2021-09-24 thomas goto done;
8889 10604dce 2021-09-24 thomas if (merge_in_progress) {
8890 10604dce 2021-09-24 thomas error = got_error(GOT_ERR_MERGE_BUSY);
8891 818c7501 2019-07-11 stsp goto done;
8892 7ef62c4e 2020-02-24 stsp }
8893 818c7501 2019-07-11 stsp
8894 818c7501 2019-07-11 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
8895 818c7501 2019-07-11 stsp if (error)
8896 818c7501 2019-07-11 stsp goto done;
8897 818c7501 2019-07-11 stsp
8898 f6794adc 2019-07-23 stsp if (abort_rebase) {
8899 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8900 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
8901 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
8902 f6794adc 2019-07-23 stsp goto done;
8903 f6794adc 2019-07-23 stsp }
8904 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
8905 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
8906 3e3a69f1 2019-07-25 stsp worktree, repo);
8907 818c7501 2019-07-11 stsp if (error)
8908 818c7501 2019-07-11 stsp goto done;
8909 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n",
8910 818c7501 2019-07-11 stsp got_ref_get_symref_target(new_base_branch));
8911 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8912 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_abort(worktree, fileindex, repo,
8913 9627c110 2020-04-18 stsp new_base_branch, update_progress, &upa);
8914 818c7501 2019-07-11 stsp if (error)
8915 818c7501 2019-07-11 stsp goto done;
8916 818c7501 2019-07-11 stsp printf("Rebase of %s aborted\n", got_ref_get_name(branch));
8917 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8918 818c7501 2019-07-11 stsp goto done; /* nothing else to do */
8919 818c7501 2019-07-11 stsp }
8920 818c7501 2019-07-11 stsp
8921 818c7501 2019-07-11 stsp if (continue_rebase) {
8922 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
8923 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
8924 f6794adc 2019-07-23 stsp goto done;
8925 f6794adc 2019-07-23 stsp }
8926 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
8927 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
8928 3e3a69f1 2019-07-25 stsp worktree, repo);
8929 818c7501 2019-07-11 stsp if (error)
8930 818c7501 2019-07-11 stsp goto done;
8931 818c7501 2019-07-11 stsp
8932 3e3a69f1 2019-07-25 stsp error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
8933 01757395 2019-07-12 stsp resume_commit_id, repo);
8934 818c7501 2019-07-11 stsp if (error)
8935 818c7501 2019-07-11 stsp goto done;
8936 818c7501 2019-07-11 stsp
8937 ff0d2220 2019-07-11 stsp yca_id = got_object_id_dup(resume_commit_id);
8938 ff0d2220 2019-07-11 stsp if (yca_id == NULL) {
8939 818c7501 2019-07-11 stsp error = got_error_from_errno("got_object_id_dup");
8940 818c7501 2019-07-11 stsp goto done;
8941 818c7501 2019-07-11 stsp }
8942 818c7501 2019-07-11 stsp } else {
8943 818c7501 2019-07-11 stsp error = got_ref_open(&branch, repo, argv[0], 0);
8944 818c7501 2019-07-11 stsp if (error != NULL)
8945 818c7501 2019-07-11 stsp goto done;
8946 ff0d2220 2019-07-11 stsp }
8947 818c7501 2019-07-11 stsp
8948 ff0d2220 2019-07-11 stsp error = got_ref_resolve(&branch_head_commit_id, repo, branch);
8949 ff0d2220 2019-07-11 stsp if (error)
8950 ff0d2220 2019-07-11 stsp goto done;
8951 ff0d2220 2019-07-11 stsp
8952 ff0d2220 2019-07-11 stsp if (!continue_rebase) {
8953 a51a74b3 2019-07-27 stsp struct got_object_id *base_commit_id;
8954 a51a74b3 2019-07-27 stsp
8955 a51a74b3 2019-07-27 stsp base_commit_id = got_worktree_get_base_commit_id(worktree);
8956 818c7501 2019-07-11 stsp error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
8957 6fb7cd11 2019-08-22 stsp base_commit_id, branch_head_commit_id, repo,
8958 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
8959 818c7501 2019-07-11 stsp if (error)
8960 818c7501 2019-07-11 stsp goto done;
8961 818c7501 2019-07-11 stsp if (yca_id == NULL) {
8962 818c7501 2019-07-11 stsp error = got_error_msg(GOT_ERR_ANCESTRY,
8963 818c7501 2019-07-11 stsp "specified branch shares no common ancestry "
8964 818c7501 2019-07-11 stsp "with work tree's branch");
8965 818c7501 2019-07-11 stsp goto done;
8966 818c7501 2019-07-11 stsp }
8967 818c7501 2019-07-11 stsp
8968 a51a74b3 2019-07-27 stsp error = check_same_branch(base_commit_id, branch, yca_id, repo);
8969 a51a74b3 2019-07-27 stsp if (error) {
8970 a51a74b3 2019-07-27 stsp if (error->code != GOT_ERR_ANCESTRY)
8971 a51a74b3 2019-07-27 stsp goto done;
8972 a51a74b3 2019-07-27 stsp error = NULL;
8973 a51a74b3 2019-07-27 stsp } else {
8974 df3ed485 2021-01-31 stsp static char msg[128];
8975 df3ed485 2021-01-31 stsp snprintf(msg, sizeof(msg),
8976 df3ed485 2021-01-31 stsp "%s is already based on %s",
8977 df3ed485 2021-01-31 stsp got_ref_get_name(branch),
8978 df3ed485 2021-01-31 stsp got_worktree_get_head_ref_name(worktree));
8979 df3ed485 2021-01-31 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH, msg);
8980 a51a74b3 2019-07-27 stsp goto done;
8981 a51a74b3 2019-07-27 stsp }
8982 818c7501 2019-07-11 stsp error = got_worktree_rebase_prepare(&new_base_branch,
8983 3e3a69f1 2019-07-25 stsp &tmp_branch, &fileindex, worktree, branch, repo);
8984 818c7501 2019-07-11 stsp if (error)
8985 818c7501 2019-07-11 stsp goto done;
8986 818c7501 2019-07-11 stsp }
8987 818c7501 2019-07-11 stsp
8988 ff0d2220 2019-07-11 stsp commit_id = branch_head_commit_id;
8989 818c7501 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
8990 818c7501 2019-07-11 stsp if (error)
8991 818c7501 2019-07-11 stsp goto done;
8992 818c7501 2019-07-11 stsp
8993 818c7501 2019-07-11 stsp parent_ids = got_object_commit_get_parent_ids(commit);
8994 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
8995 fc66b545 2019-08-12 stsp if (pid == NULL) {
8996 fc66b545 2019-08-12 stsp if (!continue_rebase) {
8997 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8998 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8999 fc66b545 2019-08-12 stsp error = got_worktree_rebase_abort(worktree, fileindex,
9000 9627c110 2020-04-18 stsp repo, new_base_branch, update_progress, &upa);
9001 fc66b545 2019-08-12 stsp if (error)
9002 fc66b545 2019-08-12 stsp goto done;
9003 fc66b545 2019-08-12 stsp printf("Rebase of %s aborted\n",
9004 fc66b545 2019-08-12 stsp got_ref_get_name(branch));
9005 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
9006 9627c110 2020-04-18 stsp
9007 fc66b545 2019-08-12 stsp }
9008 fc66b545 2019-08-12 stsp error = got_error(GOT_ERR_EMPTY_REBASE);
9009 fc66b545 2019-08-12 stsp goto done;
9010 fc66b545 2019-08-12 stsp }
9011 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, commit_id, pid->id,
9012 8ca9bd68 2019-07-25 stsp yca_id, got_worktree_get_path_prefix(worktree),
9013 8ca9bd68 2019-07-25 stsp GOT_ERR_REBASE_PATH, repo);
9014 818c7501 2019-07-11 stsp got_object_commit_close(commit);
9015 818c7501 2019-07-11 stsp commit = NULL;
9016 818c7501 2019-07-11 stsp if (error)
9017 818c7501 2019-07-11 stsp goto done;
9018 64c6d990 2019-07-11 stsp
9019 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(&commits)) {
9020 38b0338b 2019-11-29 stsp if (continue_rebase) {
9021 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex,
9022 e600f124 2021-03-21 stsp branch, new_base_branch, tmp_branch, repo,
9023 e600f124 2021-03-21 stsp create_backup);
9024 38b0338b 2019-11-29 stsp goto done;
9025 38b0338b 2019-11-29 stsp } else {
9026 38b0338b 2019-11-29 stsp /* Fast-forward the reference of the branch. */
9027 38b0338b 2019-11-29 stsp struct got_object_id *new_head_commit_id;
9028 38b0338b 2019-11-29 stsp char *id_str;
9029 38b0338b 2019-11-29 stsp error = got_ref_resolve(&new_head_commit_id, repo,
9030 38b0338b 2019-11-29 stsp new_base_branch);
9031 38b0338b 2019-11-29 stsp if (error)
9032 38b0338b 2019-11-29 stsp goto done;
9033 38b0338b 2019-11-29 stsp error = got_object_id_str(&id_str, new_head_commit_id);
9034 38b0338b 2019-11-29 stsp printf("Forwarding %s to commit %s\n",
9035 38b0338b 2019-11-29 stsp got_ref_get_name(branch), id_str);
9036 38b0338b 2019-11-29 stsp free(id_str);
9037 38b0338b 2019-11-29 stsp error = got_ref_change_ref(branch,
9038 38b0338b 2019-11-29 stsp new_head_commit_id);
9039 38b0338b 2019-11-29 stsp if (error)
9040 38b0338b 2019-11-29 stsp goto done;
9041 e600f124 2021-03-21 stsp /* No backup needed since objects did not change. */
9042 e600f124 2021-03-21 stsp create_backup = 0;
9043 38b0338b 2019-11-29 stsp }
9044 818c7501 2019-07-11 stsp }
9045 818c7501 2019-07-11 stsp
9046 818c7501 2019-07-11 stsp pid = NULL;
9047 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, &commits, entry) {
9048 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
9049 9627c110 2020-04-18 stsp
9050 818c7501 2019-07-11 stsp commit_id = qid->id;
9051 818c7501 2019-07-11 stsp parent_id = pid ? pid->id : yca_id;
9052 818c7501 2019-07-11 stsp pid = qid;
9053 818c7501 2019-07-11 stsp
9054 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
9055 01757395 2019-07-12 stsp error = got_worktree_rebase_merge_files(&merged_paths,
9056 3e3a69f1 2019-07-25 stsp worktree, fileindex, parent_id, commit_id, repo,
9057 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
9058 818c7501 2019-07-11 stsp if (error)
9059 818c7501 2019-07-11 stsp goto done;
9060 9627c110 2020-04-18 stsp
9061 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
9062 9627c110 2020-04-18 stsp if (upa.conflicts > 0)
9063 9627c110 2020-04-18 stsp rebase_status = GOT_STATUS_CONFLICT;
9064 818c7501 2019-07-11 stsp
9065 01757395 2019-07-12 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
9066 a0ea4fc0 2020-02-28 stsp error = show_rebase_merge_conflict(qid->id, repo);
9067 a0ea4fc0 2020-02-28 stsp if (error)
9068 a0ea4fc0 2020-02-28 stsp goto done;
9069 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
9070 818c7501 2019-07-11 stsp break;
9071 01757395 2019-07-12 stsp }
9072 818c7501 2019-07-11 stsp
9073 3e3a69f1 2019-07-25 stsp error = rebase_commit(&merged_paths, worktree, fileindex,
9074 3e3a69f1 2019-07-25 stsp tmp_branch, commit_id, repo);
9075 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
9076 818c7501 2019-07-11 stsp if (error)
9077 818c7501 2019-07-11 stsp goto done;
9078 818c7501 2019-07-11 stsp }
9079 818c7501 2019-07-11 stsp
9080 818c7501 2019-07-11 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
9081 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_postpone(worktree, fileindex);
9082 818c7501 2019-07-11 stsp if (error)
9083 818c7501 2019-07-11 stsp goto done;
9084 818c7501 2019-07-11 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
9085 11495e04 2019-07-12 stsp "conflicts must be resolved before rebasing can continue");
9086 818c7501 2019-07-11 stsp } else
9087 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex, branch,
9088 e600f124 2021-03-21 stsp new_base_branch, tmp_branch, repo, create_backup);
9089 818c7501 2019-07-11 stsp done:
9090 818c7501 2019-07-11 stsp got_object_id_queue_free(&commits);
9091 818c7501 2019-07-11 stsp free(branch_head_commit_id);
9092 818c7501 2019-07-11 stsp free(resume_commit_id);
9093 818c7501 2019-07-11 stsp free(yca_id);
9094 818c7501 2019-07-11 stsp if (commit)
9095 818c7501 2019-07-11 stsp got_object_commit_close(commit);
9096 818c7501 2019-07-11 stsp if (branch)
9097 818c7501 2019-07-11 stsp got_ref_close(branch);
9098 818c7501 2019-07-11 stsp if (new_base_branch)
9099 818c7501 2019-07-11 stsp got_ref_close(new_base_branch);
9100 818c7501 2019-07-11 stsp if (tmp_branch)
9101 818c7501 2019-07-11 stsp got_ref_close(tmp_branch);
9102 5ef14e63 2019-06-02 stsp if (worktree)
9103 5ef14e63 2019-06-02 stsp got_worktree_close(worktree);
9104 1d0f4054 2021-06-17 stsp if (repo) {
9105 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
9106 1d0f4054 2021-06-17 stsp if (error == NULL)
9107 1d0f4054 2021-06-17 stsp error = close_err;
9108 1d0f4054 2021-06-17 stsp }
9109 5ef14e63 2019-06-02 stsp return error;
9110 0ebf8283 2019-07-24 stsp }
9111 0ebf8283 2019-07-24 stsp
9112 0ebf8283 2019-07-24 stsp __dead static void
9113 0ebf8283 2019-07-24 stsp usage_histedit(void)
9114 0ebf8283 2019-07-24 stsp {
9115 e600f124 2021-03-21 stsp fprintf(stderr, "usage: %s histedit [-a] [-c] [-f] "
9116 643b85bc 2021-07-16 stsp "[-F histedit-script] [-m] [-l] [-X] [branch]\n",
9117 643b85bc 2021-07-16 stsp getprogname());
9118 0ebf8283 2019-07-24 stsp exit(1);
9119 0ebf8283 2019-07-24 stsp }
9120 0ebf8283 2019-07-24 stsp
9121 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_PICK 'p'
9122 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_EDIT 'e'
9123 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_FOLD 'f'
9124 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_DROP 'd'
9125 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_MESG 'm'
9126 0ebf8283 2019-07-24 stsp
9127 0ebf8283 2019-07-24 stsp static struct got_histedit_cmd {
9128 0ebf8283 2019-07-24 stsp unsigned char code;
9129 0ebf8283 2019-07-24 stsp const char *name;
9130 0ebf8283 2019-07-24 stsp const char *desc;
9131 0ebf8283 2019-07-24 stsp } got_histedit_cmds[] = {
9132 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_PICK, "pick", "use commit" },
9133 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
9134 82997472 2020-01-29 stsp { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
9135 82997472 2020-01-29 stsp "be used" },
9136 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
9137 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_MESG, "mesg",
9138 0ebf8283 2019-07-24 stsp "single-line log message for commit above (open editor if empty)" },
9139 0ebf8283 2019-07-24 stsp };
9140 0ebf8283 2019-07-24 stsp
9141 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry {
9142 0ebf8283 2019-07-24 stsp TAILQ_ENTRY(got_histedit_list_entry) entry;
9143 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id;
9144 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
9145 0ebf8283 2019-07-24 stsp char *logmsg;
9146 0ebf8283 2019-07-24 stsp };
9147 0ebf8283 2019-07-24 stsp TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
9148 0ebf8283 2019-07-24 stsp
9149 0ebf8283 2019-07-24 stsp static const struct got_error *
9150 0ebf8283 2019-07-24 stsp histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
9151 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
9152 0ebf8283 2019-07-24 stsp {
9153 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9154 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *id_str = NULL;
9155 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9156 8138f3e1 2019-08-11 stsp int n;
9157 0ebf8283 2019-07-24 stsp
9158 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
9159 0ebf8283 2019-07-24 stsp if (err)
9160 0ebf8283 2019-07-24 stsp goto done;
9161 0ebf8283 2019-07-24 stsp
9162 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 34, commit);
9163 0ebf8283 2019-07-24 stsp if (err)
9164 0ebf8283 2019-07-24 stsp goto done;
9165 0ebf8283 2019-07-24 stsp
9166 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, commit_id);
9167 0ebf8283 2019-07-24 stsp if (err)
9168 0ebf8283 2019-07-24 stsp goto done;
9169 0ebf8283 2019-07-24 stsp
9170 0ebf8283 2019-07-24 stsp n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
9171 0ebf8283 2019-07-24 stsp if (n < 0)
9172 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
9173 0ebf8283 2019-07-24 stsp done:
9174 0ebf8283 2019-07-24 stsp if (commit)
9175 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9176 0ebf8283 2019-07-24 stsp free(id_str);
9177 0ebf8283 2019-07-24 stsp free(logmsg);
9178 0ebf8283 2019-07-24 stsp return err;
9179 0ebf8283 2019-07-24 stsp }
9180 0ebf8283 2019-07-24 stsp
9181 0ebf8283 2019-07-24 stsp static const struct got_error *
9182 083957f4 2020-02-24 stsp histedit_write_commit_list(struct got_object_id_queue *commits,
9183 466785b9 2020-12-10 jrick FILE *f, int edit_logmsg_only, int fold_only, struct got_repository *repo)
9184 0ebf8283 2019-07-24 stsp {
9185 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9186 0ebf8283 2019-07-24 stsp struct got_object_qid *qid;
9187 466785b9 2020-12-10 jrick const char *histedit_cmd = NULL;
9188 0ebf8283 2019-07-24 stsp
9189 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(commits))
9190 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
9191 0ebf8283 2019-07-24 stsp
9192 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, commits, entry) {
9193 466785b9 2020-12-10 jrick histedit_cmd = got_histedit_cmds[0].name;
9194 dbdddfee 2021-06-23 naddy if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
9195 466785b9 2020-12-10 jrick histedit_cmd = "fold";
9196 466785b9 2020-12-10 jrick err = histedit_write_commit(qid->id, histedit_cmd, f, repo);
9197 0ebf8283 2019-07-24 stsp if (err)
9198 0ebf8283 2019-07-24 stsp break;
9199 083957f4 2020-02-24 stsp if (edit_logmsg_only) {
9200 083957f4 2020-02-24 stsp int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
9201 083957f4 2020-02-24 stsp if (n < 0) {
9202 083957f4 2020-02-24 stsp err = got_ferror(f, GOT_ERR_IO);
9203 083957f4 2020-02-24 stsp break;
9204 083957f4 2020-02-24 stsp }
9205 083957f4 2020-02-24 stsp }
9206 0ebf8283 2019-07-24 stsp }
9207 0ebf8283 2019-07-24 stsp
9208 0ebf8283 2019-07-24 stsp return err;
9209 0ebf8283 2019-07-24 stsp }
9210 0ebf8283 2019-07-24 stsp
9211 0ebf8283 2019-07-24 stsp static const struct got_error *
9212 514f2ffe 2020-01-29 stsp write_cmd_list(FILE *f, const char *branch_name,
9213 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits)
9214 0ebf8283 2019-07-24 stsp {
9215 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9216 6059809a 2020-12-17 stsp size_t i;
9217 6059809a 2020-12-17 stsp int n;
9218 514f2ffe 2020-01-29 stsp char *id_str;
9219 514f2ffe 2020-01-29 stsp struct got_object_qid *qid;
9220 514f2ffe 2020-01-29 stsp
9221 dbdddfee 2021-06-23 naddy qid = STAILQ_FIRST(commits);
9222 514f2ffe 2020-01-29 stsp err = got_object_id_str(&id_str, qid->id);
9223 514f2ffe 2020-01-29 stsp if (err)
9224 514f2ffe 2020-01-29 stsp return err;
9225 514f2ffe 2020-01-29 stsp
9226 514f2ffe 2020-01-29 stsp n = fprintf(f,
9227 514f2ffe 2020-01-29 stsp "# Editing the history of branch '%s' starting at\n"
9228 514f2ffe 2020-01-29 stsp "# commit %s\n"
9229 514f2ffe 2020-01-29 stsp "# Commits will be processed in order from top to "
9230 514f2ffe 2020-01-29 stsp "bottom of this file.\n", branch_name, id_str);
9231 514f2ffe 2020-01-29 stsp if (n < 0) {
9232 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
9233 514f2ffe 2020-01-29 stsp goto done;
9234 514f2ffe 2020-01-29 stsp }
9235 0ebf8283 2019-07-24 stsp
9236 0ebf8283 2019-07-24 stsp n = fprintf(f, "# Available histedit commands:\n");
9237 514f2ffe 2020-01-29 stsp if (n < 0) {
9238 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
9239 514f2ffe 2020-01-29 stsp goto done;
9240 514f2ffe 2020-01-29 stsp }
9241 0ebf8283 2019-07-24 stsp
9242 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
9243 0ebf8283 2019-07-24 stsp struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
9244 0ebf8283 2019-07-24 stsp n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
9245 0ebf8283 2019-07-24 stsp cmd->desc);
9246 0ebf8283 2019-07-24 stsp if (n < 0) {
9247 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
9248 0ebf8283 2019-07-24 stsp break;
9249 0ebf8283 2019-07-24 stsp }
9250 0ebf8283 2019-07-24 stsp }
9251 514f2ffe 2020-01-29 stsp done:
9252 514f2ffe 2020-01-29 stsp free(id_str);
9253 0ebf8283 2019-07-24 stsp return err;
9254 0ebf8283 2019-07-24 stsp }
9255 0ebf8283 2019-07-24 stsp
9256 0ebf8283 2019-07-24 stsp static const struct got_error *
9257 0ebf8283 2019-07-24 stsp histedit_syntax_error(int lineno)
9258 0ebf8283 2019-07-24 stsp {
9259 0ebf8283 2019-07-24 stsp static char msg[42];
9260 0ebf8283 2019-07-24 stsp int ret;
9261 0ebf8283 2019-07-24 stsp
9262 0ebf8283 2019-07-24 stsp ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
9263 0ebf8283 2019-07-24 stsp lineno);
9264 0ebf8283 2019-07-24 stsp if (ret == -1 || ret >= sizeof(msg))
9265 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_SYNTAX);
9266 0ebf8283 2019-07-24 stsp
9267 0ebf8283 2019-07-24 stsp return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
9268 0ebf8283 2019-07-24 stsp }
9269 0ebf8283 2019-07-24 stsp
9270 0ebf8283 2019-07-24 stsp static const struct got_error *
9271 0ebf8283 2019-07-24 stsp append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
9272 0ebf8283 2019-07-24 stsp char *logmsg, struct got_repository *repo)
9273 0ebf8283 2019-07-24 stsp {
9274 0ebf8283 2019-07-24 stsp const struct got_error *err;
9275 0ebf8283 2019-07-24 stsp struct got_commit_object *folded_commit = NULL;
9276 5943eee2 2019-08-13 stsp char *id_str, *folded_logmsg = NULL;
9277 0ebf8283 2019-07-24 stsp
9278 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9279 0ebf8283 2019-07-24 stsp if (err)
9280 0ebf8283 2019-07-24 stsp return err;
9281 0ebf8283 2019-07-24 stsp
9282 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
9283 0ebf8283 2019-07-24 stsp if (err)
9284 0ebf8283 2019-07-24 stsp goto done;
9285 0ebf8283 2019-07-24 stsp
9286 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
9287 5943eee2 2019-08-13 stsp if (err)
9288 5943eee2 2019-08-13 stsp goto done;
9289 0ebf8283 2019-07-24 stsp if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
9290 0ebf8283 2019-07-24 stsp logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
9291 5943eee2 2019-08-13 stsp folded_logmsg) == -1) {
9292 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
9293 0ebf8283 2019-07-24 stsp }
9294 0ebf8283 2019-07-24 stsp done:
9295 0ebf8283 2019-07-24 stsp if (folded_commit)
9296 0ebf8283 2019-07-24 stsp got_object_commit_close(folded_commit);
9297 0ebf8283 2019-07-24 stsp free(id_str);
9298 5943eee2 2019-08-13 stsp free(folded_logmsg);
9299 0ebf8283 2019-07-24 stsp return err;
9300 0ebf8283 2019-07-24 stsp }
9301 0ebf8283 2019-07-24 stsp
9302 0ebf8283 2019-07-24 stsp static struct got_histedit_list_entry *
9303 0ebf8283 2019-07-24 stsp get_folded_commits(struct got_histedit_list_entry *hle)
9304 0ebf8283 2019-07-24 stsp {
9305 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *prev, *folded = NULL;
9306 0ebf8283 2019-07-24 stsp
9307 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(hle, got_histedit_list, entry);
9308 3f9de99f 2019-07-24 stsp while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
9309 3f9de99f 2019-07-24 stsp prev->cmd->code == GOT_HISTEDIT_DROP)) {
9310 3f9de99f 2019-07-24 stsp if (prev->cmd->code == GOT_HISTEDIT_FOLD)
9311 3f9de99f 2019-07-24 stsp folded = prev;
9312 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(prev, got_histedit_list, entry);
9313 0ebf8283 2019-07-24 stsp }
9314 0ebf8283 2019-07-24 stsp
9315 0ebf8283 2019-07-24 stsp return folded;
9316 0ebf8283 2019-07-24 stsp }
9317 0ebf8283 2019-07-24 stsp
9318 0ebf8283 2019-07-24 stsp static const struct got_error *
9319 0ebf8283 2019-07-24 stsp histedit_edit_logmsg(struct got_histedit_list_entry *hle,
9320 0ebf8283 2019-07-24 stsp struct got_repository *repo)
9321 0ebf8283 2019-07-24 stsp {
9322 5943eee2 2019-08-13 stsp char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
9323 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
9324 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9325 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9326 1601cb9f 2020-09-11 naddy int logmsg_len;
9327 0ebf8283 2019-07-24 stsp int fd;
9328 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *folded = NULL;
9329 0ebf8283 2019-07-24 stsp
9330 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
9331 0ebf8283 2019-07-24 stsp if (err)
9332 0ebf8283 2019-07-24 stsp return err;
9333 0ebf8283 2019-07-24 stsp
9334 0ebf8283 2019-07-24 stsp folded = get_folded_commits(hle);
9335 0ebf8283 2019-07-24 stsp if (folded) {
9336 0ebf8283 2019-07-24 stsp while (folded != hle) {
9337 3f9de99f 2019-07-24 stsp if (folded->cmd->code == GOT_HISTEDIT_DROP) {
9338 3f9de99f 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
9339 3f9de99f 2019-07-24 stsp continue;
9340 3f9de99f 2019-07-24 stsp }
9341 0ebf8283 2019-07-24 stsp err = append_folded_commit_msg(&new_msg, folded,
9342 0ebf8283 2019-07-24 stsp logmsg, repo);
9343 0ebf8283 2019-07-24 stsp if (err)
9344 0ebf8283 2019-07-24 stsp goto done;
9345 0ebf8283 2019-07-24 stsp free(logmsg);
9346 0ebf8283 2019-07-24 stsp logmsg = new_msg;
9347 0ebf8283 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
9348 0ebf8283 2019-07-24 stsp }
9349 0ebf8283 2019-07-24 stsp }
9350 0ebf8283 2019-07-24 stsp
9351 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9352 0ebf8283 2019-07-24 stsp if (err)
9353 0ebf8283 2019-07-24 stsp goto done;
9354 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&orig_logmsg, commit);
9355 5943eee2 2019-08-13 stsp if (err)
9356 5943eee2 2019-08-13 stsp goto done;
9357 1601cb9f 2020-09-11 naddy logmsg_len = asprintf(&new_msg,
9358 0ebf8283 2019-07-24 stsp "%s\n# original log message of commit %s: %s",
9359 1601cb9f 2020-09-11 naddy logmsg ? logmsg : "", id_str, orig_logmsg);
9360 1601cb9f 2020-09-11 naddy if (logmsg_len == -1) {
9361 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
9362 0ebf8283 2019-07-24 stsp goto done;
9363 0ebf8283 2019-07-24 stsp }
9364 0ebf8283 2019-07-24 stsp free(logmsg);
9365 0ebf8283 2019-07-24 stsp logmsg = new_msg;
9366 0ebf8283 2019-07-24 stsp
9367 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
9368 0ebf8283 2019-07-24 stsp if (err)
9369 0ebf8283 2019-07-24 stsp goto done;
9370 0ebf8283 2019-07-24 stsp
9371 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(&logmsg_path, &fd,
9372 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-logmsg");
9373 0ebf8283 2019-07-24 stsp if (err)
9374 0ebf8283 2019-07-24 stsp goto done;
9375 0ebf8283 2019-07-24 stsp
9376 1601cb9f 2020-09-11 naddy write(fd, logmsg, logmsg_len);
9377 0ebf8283 2019-07-24 stsp close(fd);
9378 0ebf8283 2019-07-24 stsp
9379 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
9380 0ebf8283 2019-07-24 stsp if (err)
9381 0ebf8283 2019-07-24 stsp goto done;
9382 0ebf8283 2019-07-24 stsp
9383 bfa12d5e 2020-09-26 stsp err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
9384 0d5bb276 2020-12-15 stsp logmsg_len, 0);
9385 0ebf8283 2019-07-24 stsp if (err) {
9386 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
9387 0ebf8283 2019-07-24 stsp goto done;
9388 71392a05 2020-12-13 stsp err = NULL;
9389 71392a05 2020-12-13 stsp hle->logmsg = strdup(new_msg);
9390 71392a05 2020-12-13 stsp if (hle->logmsg == NULL)
9391 71392a05 2020-12-13 stsp err = got_error_from_errno("strdup");
9392 0ebf8283 2019-07-24 stsp }
9393 0ebf8283 2019-07-24 stsp done:
9394 0ebf8283 2019-07-24 stsp if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
9395 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", logmsg_path);
9396 0ebf8283 2019-07-24 stsp free(logmsg_path);
9397 0ebf8283 2019-07-24 stsp free(logmsg);
9398 5943eee2 2019-08-13 stsp free(orig_logmsg);
9399 0ebf8283 2019-07-24 stsp free(editor);
9400 0ebf8283 2019-07-24 stsp if (commit)
9401 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9402 0ebf8283 2019-07-24 stsp return err;
9403 5ef14e63 2019-06-02 stsp }
9404 0ebf8283 2019-07-24 stsp
9405 0ebf8283 2019-07-24 stsp static const struct got_error *
9406 0ebf8283 2019-07-24 stsp histedit_parse_list(struct got_histedit_list *histedit_cmds,
9407 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
9408 0ebf8283 2019-07-24 stsp {
9409 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9410 0ebf8283 2019-07-24 stsp char *line = NULL, *p, *end;
9411 6059809a 2020-12-17 stsp size_t i, size;
9412 0ebf8283 2019-07-24 stsp ssize_t len;
9413 6059809a 2020-12-17 stsp int lineno = 0;
9414 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
9415 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id = NULL;
9416 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle = NULL;
9417 0ebf8283 2019-07-24 stsp
9418 0ebf8283 2019-07-24 stsp for (;;) {
9419 0ebf8283 2019-07-24 stsp len = getline(&line, &size, f);
9420 0ebf8283 2019-07-24 stsp if (len == -1) {
9421 0ebf8283 2019-07-24 stsp const struct got_error *getline_err;
9422 0ebf8283 2019-07-24 stsp if (feof(f))
9423 0ebf8283 2019-07-24 stsp break;
9424 0ebf8283 2019-07-24 stsp getline_err = got_error_from_errno("getline");
9425 0ebf8283 2019-07-24 stsp err = got_ferror(f, getline_err->code);
9426 0ebf8283 2019-07-24 stsp break;
9427 0ebf8283 2019-07-24 stsp }
9428 0ebf8283 2019-07-24 stsp lineno++;
9429 0ebf8283 2019-07-24 stsp p = line;
9430 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
9431 0ebf8283 2019-07-24 stsp p++;
9432 0ebf8283 2019-07-24 stsp if (p[0] == '#' || p[0] == '\0') {
9433 0ebf8283 2019-07-24 stsp free(line);
9434 0ebf8283 2019-07-24 stsp line = NULL;
9435 0ebf8283 2019-07-24 stsp continue;
9436 0ebf8283 2019-07-24 stsp }
9437 0ebf8283 2019-07-24 stsp cmd = NULL;
9438 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
9439 0ebf8283 2019-07-24 stsp cmd = &got_histedit_cmds[i];
9440 0ebf8283 2019-07-24 stsp if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
9441 0ebf8283 2019-07-24 stsp isspace((unsigned char)p[strlen(cmd->name)])) {
9442 0ebf8283 2019-07-24 stsp p += strlen(cmd->name);
9443 0ebf8283 2019-07-24 stsp break;
9444 0ebf8283 2019-07-24 stsp }
9445 0ebf8283 2019-07-24 stsp if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
9446 0ebf8283 2019-07-24 stsp p++;
9447 0ebf8283 2019-07-24 stsp break;
9448 0ebf8283 2019-07-24 stsp }
9449 0ebf8283 2019-07-24 stsp }
9450 6c1844f6 2019-07-25 stsp if (i == nitems(got_histedit_cmds)) {
9451 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
9452 0ebf8283 2019-07-24 stsp break;
9453 0ebf8283 2019-07-24 stsp }
9454 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
9455 0ebf8283 2019-07-24 stsp p++;
9456 0ebf8283 2019-07-24 stsp if (cmd->code == GOT_HISTEDIT_MESG) {
9457 0ebf8283 2019-07-24 stsp if (hle == NULL || hle->logmsg != NULL) {
9458 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CMD);
9459 0ebf8283 2019-07-24 stsp break;
9460 0ebf8283 2019-07-24 stsp }
9461 0ebf8283 2019-07-24 stsp if (p[0] == '\0') {
9462 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
9463 0ebf8283 2019-07-24 stsp if (err)
9464 0ebf8283 2019-07-24 stsp break;
9465 0ebf8283 2019-07-24 stsp } else {
9466 0ebf8283 2019-07-24 stsp hle->logmsg = strdup(p);
9467 0ebf8283 2019-07-24 stsp if (hle->logmsg == NULL) {
9468 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
9469 0ebf8283 2019-07-24 stsp break;
9470 0ebf8283 2019-07-24 stsp }
9471 0ebf8283 2019-07-24 stsp }
9472 0ebf8283 2019-07-24 stsp free(line);
9473 0ebf8283 2019-07-24 stsp line = NULL;
9474 0ebf8283 2019-07-24 stsp continue;
9475 0ebf8283 2019-07-24 stsp } else {
9476 0ebf8283 2019-07-24 stsp end = p;
9477 0ebf8283 2019-07-24 stsp while (end[0] && !isspace((unsigned char)end[0]))
9478 0ebf8283 2019-07-24 stsp end++;
9479 0ebf8283 2019-07-24 stsp *end = '\0';
9480 0ebf8283 2019-07-24 stsp
9481 0ebf8283 2019-07-24 stsp err = got_object_resolve_id_str(&commit_id, repo, p);
9482 0ebf8283 2019-07-24 stsp if (err) {
9483 0ebf8283 2019-07-24 stsp /* override error code */
9484 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
9485 0ebf8283 2019-07-24 stsp break;
9486 0ebf8283 2019-07-24 stsp }
9487 0ebf8283 2019-07-24 stsp }
9488 0ebf8283 2019-07-24 stsp hle = malloc(sizeof(*hle));
9489 0ebf8283 2019-07-24 stsp if (hle == NULL) {
9490 0ebf8283 2019-07-24 stsp err = got_error_from_errno("malloc");
9491 0ebf8283 2019-07-24 stsp break;
9492 0ebf8283 2019-07-24 stsp }
9493 0ebf8283 2019-07-24 stsp hle->cmd = cmd;
9494 0ebf8283 2019-07-24 stsp hle->commit_id = commit_id;
9495 0ebf8283 2019-07-24 stsp hle->logmsg = NULL;
9496 0ebf8283 2019-07-24 stsp commit_id = NULL;
9497 0ebf8283 2019-07-24 stsp free(line);
9498 0ebf8283 2019-07-24 stsp line = NULL;
9499 0ebf8283 2019-07-24 stsp TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
9500 0ebf8283 2019-07-24 stsp }
9501 0ebf8283 2019-07-24 stsp
9502 0ebf8283 2019-07-24 stsp free(line);
9503 0ebf8283 2019-07-24 stsp free(commit_id);
9504 0ebf8283 2019-07-24 stsp return err;
9505 0ebf8283 2019-07-24 stsp }
9506 0ebf8283 2019-07-24 stsp
9507 0ebf8283 2019-07-24 stsp static const struct got_error *
9508 bfce7f83 2019-07-27 stsp histedit_check_script(struct got_histedit_list *histedit_cmds,
9509 bfce7f83 2019-07-27 stsp struct got_object_id_queue *commits, struct got_repository *repo)
9510 bfce7f83 2019-07-27 stsp {
9511 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL;
9512 bfce7f83 2019-07-27 stsp struct got_object_qid *qid;
9513 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
9514 5b87815e 2020-03-05 stsp static char msg[92];
9515 bfce7f83 2019-07-27 stsp char *id_str;
9516 bfce7f83 2019-07-27 stsp
9517 bfce7f83 2019-07-27 stsp if (TAILQ_EMPTY(histedit_cmds))
9518 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
9519 bfce7f83 2019-07-27 stsp "histedit script contains no commands");
9520 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(commits))
9521 a0de39f3 2019-08-09 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
9522 5b87815e 2020-03-05 stsp
9523 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
9524 5b87815e 2020-03-05 stsp struct got_histedit_list_entry *hle2;
9525 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle2, histedit_cmds, entry) {
9526 5b87815e 2020-03-05 stsp if (hle == hle2)
9527 5b87815e 2020-03-05 stsp continue;
9528 5b87815e 2020-03-05 stsp if (got_object_id_cmp(hle->commit_id,
9529 5b87815e 2020-03-05 stsp hle2->commit_id) != 0)
9530 5b87815e 2020-03-05 stsp continue;
9531 5b87815e 2020-03-05 stsp err = got_object_id_str(&id_str, hle->commit_id);
9532 5b87815e 2020-03-05 stsp if (err)
9533 5b87815e 2020-03-05 stsp return err;
9534 5b87815e 2020-03-05 stsp snprintf(msg, sizeof(msg), "commit %s is listed "
9535 5b87815e 2020-03-05 stsp "more than once in histedit script", id_str);
9536 5b87815e 2020-03-05 stsp free(id_str);
9537 5b87815e 2020-03-05 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
9538 5b87815e 2020-03-05 stsp }
9539 5b87815e 2020-03-05 stsp }
9540 bfce7f83 2019-07-27 stsp
9541 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(qid, commits, entry) {
9542 bfce7f83 2019-07-27 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
9543 bfce7f83 2019-07-27 stsp if (got_object_id_cmp(qid->id, hle->commit_id) == 0)
9544 bfce7f83 2019-07-27 stsp break;
9545 bfce7f83 2019-07-27 stsp }
9546 bfce7f83 2019-07-27 stsp if (hle == NULL) {
9547 bfce7f83 2019-07-27 stsp err = got_object_id_str(&id_str, qid->id);
9548 bfce7f83 2019-07-27 stsp if (err)
9549 bfce7f83 2019-07-27 stsp return err;
9550 bfce7f83 2019-07-27 stsp snprintf(msg, sizeof(msg),
9551 bfce7f83 2019-07-27 stsp "commit %s missing from histedit script", id_str);
9552 bfce7f83 2019-07-27 stsp free(id_str);
9553 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
9554 bfce7f83 2019-07-27 stsp }
9555 bfce7f83 2019-07-27 stsp }
9556 bfce7f83 2019-07-27 stsp
9557 0def28b1 2019-08-17 stsp hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
9558 0def28b1 2019-08-17 stsp if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
9559 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD,
9560 bfce7f83 2019-07-27 stsp "last commit in histedit script cannot be folded");
9561 bfce7f83 2019-07-27 stsp
9562 bfce7f83 2019-07-27 stsp return NULL;
9563 bfce7f83 2019-07-27 stsp }
9564 bfce7f83 2019-07-27 stsp
9565 bfce7f83 2019-07-27 stsp static const struct got_error *
9566 0ebf8283 2019-07-24 stsp histedit_run_editor(struct got_histedit_list *histedit_cmds,
9567 bfce7f83 2019-07-27 stsp const char *path, struct got_object_id_queue *commits,
9568 bfce7f83 2019-07-27 stsp struct got_repository *repo)
9569 0ebf8283 2019-07-24 stsp {
9570 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9571 0ebf8283 2019-07-24 stsp char *editor;
9572 0ebf8283 2019-07-24 stsp FILE *f = NULL;
9573 0ebf8283 2019-07-24 stsp
9574 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
9575 0ebf8283 2019-07-24 stsp if (err)
9576 0ebf8283 2019-07-24 stsp return err;
9577 0ebf8283 2019-07-24 stsp
9578 0ebf8283 2019-07-24 stsp if (spawn_editor(editor, path) == -1) {
9579 0ebf8283 2019-07-24 stsp err = got_error_from_errno("failed spawning editor");
9580 0ebf8283 2019-07-24 stsp goto done;
9581 0ebf8283 2019-07-24 stsp }
9582 0ebf8283 2019-07-24 stsp
9583 0ebf8283 2019-07-24 stsp f = fopen(path, "r");
9584 0ebf8283 2019-07-24 stsp if (f == NULL) {
9585 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fopen");
9586 0ebf8283 2019-07-24 stsp goto done;
9587 0ebf8283 2019-07-24 stsp }
9588 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
9589 bfce7f83 2019-07-27 stsp if (err)
9590 bfce7f83 2019-07-27 stsp goto done;
9591 bfce7f83 2019-07-27 stsp
9592 bfce7f83 2019-07-27 stsp err = histedit_check_script(histedit_cmds, commits, repo);
9593 0ebf8283 2019-07-24 stsp done:
9594 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
9595 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
9596 0ebf8283 2019-07-24 stsp free(editor);
9597 0ebf8283 2019-07-24 stsp return err;
9598 0ebf8283 2019-07-24 stsp }
9599 0ebf8283 2019-07-24 stsp
9600 0ebf8283 2019-07-24 stsp static const struct got_error *
9601 bfce7f83 2019-07-27 stsp histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
9602 514f2ffe 2020-01-29 stsp struct got_object_id_queue *, const char *, const char *,
9603 514f2ffe 2020-01-29 stsp struct got_repository *);
9604 0ebf8283 2019-07-24 stsp
9605 0ebf8283 2019-07-24 stsp static const struct got_error *
9606 0ebf8283 2019-07-24 stsp histedit_edit_script(struct got_histedit_list *histedit_cmds,
9607 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits, const char *branch_name,
9608 466785b9 2020-12-10 jrick int edit_logmsg_only, int fold_only, struct got_repository *repo)
9609 0ebf8283 2019-07-24 stsp {
9610 0ebf8283 2019-07-24 stsp const struct got_error *err;
9611 0ebf8283 2019-07-24 stsp FILE *f = NULL;
9612 0ebf8283 2019-07-24 stsp char *path = NULL;
9613 0ebf8283 2019-07-24 stsp
9614 0ebf8283 2019-07-24 stsp err = got_opentemp_named(&path, &f, "got-histedit");
9615 0ebf8283 2019-07-24 stsp if (err)
9616 0ebf8283 2019-07-24 stsp return err;
9617 0ebf8283 2019-07-24 stsp
9618 514f2ffe 2020-01-29 stsp err = write_cmd_list(f, branch_name, commits);
9619 0ebf8283 2019-07-24 stsp if (err)
9620 0ebf8283 2019-07-24 stsp goto done;
9621 0ebf8283 2019-07-24 stsp
9622 466785b9 2020-12-10 jrick err = histedit_write_commit_list(commits, f, edit_logmsg_only,
9623 466785b9 2020-12-10 jrick fold_only, repo);
9624 0ebf8283 2019-07-24 stsp if (err)
9625 0ebf8283 2019-07-24 stsp goto done;
9626 0ebf8283 2019-07-24 stsp
9627 466785b9 2020-12-10 jrick if (edit_logmsg_only || fold_only) {
9628 083957f4 2020-02-24 stsp rewind(f);
9629 083957f4 2020-02-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
9630 083957f4 2020-02-24 stsp } else {
9631 56b63ca4 2021-01-22 stsp if (fclose(f) == EOF) {
9632 083957f4 2020-02-24 stsp err = got_error_from_errno("fclose");
9633 0ebf8283 2019-07-24 stsp goto done;
9634 083957f4 2020-02-24 stsp }
9635 083957f4 2020-02-24 stsp f = NULL;
9636 083957f4 2020-02-24 stsp err = histedit_run_editor(histedit_cmds, path, commits, repo);
9637 083957f4 2020-02-24 stsp if (err) {
9638 083957f4 2020-02-24 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
9639 083957f4 2020-02-24 stsp err->code != GOT_ERR_HISTEDIT_CMD)
9640 083957f4 2020-02-24 stsp goto done;
9641 083957f4 2020-02-24 stsp err = histedit_edit_list_retry(histedit_cmds, err,
9642 083957f4 2020-02-24 stsp commits, path, branch_name, repo);
9643 083957f4 2020-02-24 stsp }
9644 0ebf8283 2019-07-24 stsp }
9645 0ebf8283 2019-07-24 stsp done:
9646 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
9647 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
9648 0ebf8283 2019-07-24 stsp if (path && unlink(path) != 0 && err == NULL)
9649 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", path);
9650 0ebf8283 2019-07-24 stsp free(path);
9651 0ebf8283 2019-07-24 stsp return err;
9652 0ebf8283 2019-07-24 stsp }
9653 0ebf8283 2019-07-24 stsp
9654 0ebf8283 2019-07-24 stsp static const struct got_error *
9655 0ebf8283 2019-07-24 stsp histedit_save_list(struct got_histedit_list *histedit_cmds,
9656 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
9657 0ebf8283 2019-07-24 stsp {
9658 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9659 0ebf8283 2019-07-24 stsp char *path = NULL;
9660 0ebf8283 2019-07-24 stsp FILE *f = NULL;
9661 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
9662 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9663 0ebf8283 2019-07-24 stsp
9664 c3022ba5 2019-07-27 stsp err = got_worktree_get_histedit_script_path(&path, worktree);
9665 0ebf8283 2019-07-24 stsp if (err)
9666 0ebf8283 2019-07-24 stsp return err;
9667 0ebf8283 2019-07-24 stsp
9668 0ebf8283 2019-07-24 stsp f = fopen(path, "w");
9669 0ebf8283 2019-07-24 stsp if (f == NULL) {
9670 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
9671 0ebf8283 2019-07-24 stsp goto done;
9672 0ebf8283 2019-07-24 stsp }
9673 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
9674 0ebf8283 2019-07-24 stsp err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
9675 0ebf8283 2019-07-24 stsp repo);
9676 0ebf8283 2019-07-24 stsp if (err)
9677 0ebf8283 2019-07-24 stsp break;
9678 0ebf8283 2019-07-24 stsp
9679 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
9680 0ebf8283 2019-07-24 stsp int n = fprintf(f, "%c %s\n",
9681 0ebf8283 2019-07-24 stsp GOT_HISTEDIT_MESG, hle->logmsg);
9682 0ebf8283 2019-07-24 stsp if (n < 0) {
9683 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
9684 0ebf8283 2019-07-24 stsp break;
9685 0ebf8283 2019-07-24 stsp }
9686 0ebf8283 2019-07-24 stsp }
9687 0ebf8283 2019-07-24 stsp }
9688 0ebf8283 2019-07-24 stsp done:
9689 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
9690 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
9691 0ebf8283 2019-07-24 stsp free(path);
9692 0ebf8283 2019-07-24 stsp if (commit)
9693 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9694 0ebf8283 2019-07-24 stsp return err;
9695 0ebf8283 2019-07-24 stsp }
9696 0ebf8283 2019-07-24 stsp
9697 bfce7f83 2019-07-27 stsp void
9698 bfce7f83 2019-07-27 stsp histedit_free_list(struct got_histedit_list *histedit_cmds)
9699 bfce7f83 2019-07-27 stsp {
9700 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
9701 bfce7f83 2019-07-27 stsp
9702 bfce7f83 2019-07-27 stsp while ((hle = TAILQ_FIRST(histedit_cmds))) {
9703 bfce7f83 2019-07-27 stsp TAILQ_REMOVE(histedit_cmds, hle, entry);
9704 bfce7f83 2019-07-27 stsp free(hle);
9705 bfce7f83 2019-07-27 stsp }
9706 bfce7f83 2019-07-27 stsp }
9707 bfce7f83 2019-07-27 stsp
9708 0ebf8283 2019-07-24 stsp static const struct got_error *
9709 0ebf8283 2019-07-24 stsp histedit_load_list(struct got_histedit_list *histedit_cmds,
9710 0ebf8283 2019-07-24 stsp const char *path, struct got_repository *repo)
9711 0ebf8283 2019-07-24 stsp {
9712 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
9713 0ebf8283 2019-07-24 stsp FILE *f = NULL;
9714 0ebf8283 2019-07-24 stsp
9715 0ebf8283 2019-07-24 stsp f = fopen(path, "r");
9716 0ebf8283 2019-07-24 stsp if (f == NULL) {
9717 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
9718 0ebf8283 2019-07-24 stsp goto done;
9719 0ebf8283 2019-07-24 stsp }
9720 0ebf8283 2019-07-24 stsp
9721 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
9722 0ebf8283 2019-07-24 stsp done:
9723 56b63ca4 2021-01-22 stsp if (f && fclose(f) == EOF && err == NULL)
9724 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
9725 0ebf8283 2019-07-24 stsp return err;
9726 0ebf8283 2019-07-24 stsp }
9727 0ebf8283 2019-07-24 stsp
9728 0ebf8283 2019-07-24 stsp static const struct got_error *
9729 0ebf8283 2019-07-24 stsp histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
9730 bfce7f83 2019-07-27 stsp const struct got_error *edit_err, struct got_object_id_queue *commits,
9731 514f2ffe 2020-01-29 stsp const char *path, const char *branch_name, struct got_repository *repo)
9732 0ebf8283 2019-07-24 stsp {
9733 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL, *prev_err = edit_err;
9734 0ebf8283 2019-07-24 stsp int resp = ' ';
9735 0ebf8283 2019-07-24 stsp
9736 b006047e 2019-07-25 stsp while (resp != 'c' && resp != 'r' && resp != 'a') {
9737 0ebf8283 2019-07-24 stsp printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
9738 bfce7f83 2019-07-27 stsp "or (a)bort: ", getprogname(), prev_err->msg);
9739 0ebf8283 2019-07-24 stsp resp = getchar();
9740 a61a4414 2019-08-07 stsp if (resp == '\n')
9741 a61a4414 2019-08-07 stsp resp = getchar();
9742 426ebf2e 2019-07-25 stsp if (resp == 'c') {
9743 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
9744 bfce7f83 2019-07-27 stsp err = histedit_run_editor(histedit_cmds, path, commits,
9745 bfce7f83 2019-07-27 stsp repo);
9746 426ebf2e 2019-07-25 stsp if (err) {
9747 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
9748 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
9749 426ebf2e 2019-07-25 stsp break;
9750 bfce7f83 2019-07-27 stsp prev_err = err;
9751 426ebf2e 2019-07-25 stsp resp = ' ';
9752 426ebf2e 2019-07-25 stsp continue;
9753 426ebf2e 2019-07-25 stsp }
9754 bfce7f83 2019-07-27 stsp break;
9755 426ebf2e 2019-07-25 stsp } else if (resp == 'r') {
9756 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
9757 0ebf8283 2019-07-24 stsp err = histedit_edit_script(histedit_cmds,
9758 466785b9 2020-12-10 jrick commits, branch_name, 0, 0, repo);
9759 426ebf2e 2019-07-25 stsp if (err) {
9760 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
9761 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
9762 426ebf2e 2019-07-25 stsp break;
9763 bfce7f83 2019-07-27 stsp prev_err = err;
9764 426ebf2e 2019-07-25 stsp resp = ' ';
9765 426ebf2e 2019-07-25 stsp continue;
9766 426ebf2e 2019-07-25 stsp }
9767 bfce7f83 2019-07-27 stsp break;
9768 426ebf2e 2019-07-25 stsp } else if (resp == 'a') {
9769 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CANCEL);
9770 0ebf8283 2019-07-24 stsp break;
9771 426ebf2e 2019-07-25 stsp } else
9772 0ebf8283 2019-07-24 stsp printf("invalid response '%c'\n", resp);
9773 0ebf8283 2019-07-24 stsp }
9774 0ebf8283 2019-07-24 stsp
9775 0ebf8283 2019-07-24 stsp return err;
9776 0ebf8283 2019-07-24 stsp }
9777 0ebf8283 2019-07-24 stsp
9778 0ebf8283 2019-07-24 stsp static const struct got_error *
9779 0ebf8283 2019-07-24 stsp histedit_complete(struct got_worktree *worktree,
9780 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex, struct got_reference *tmp_branch,
9781 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_repository *repo)
9782 0ebf8283 2019-07-24 stsp {
9783 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
9784 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
9785 3e3a69f1 2019-07-25 stsp return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
9786 3e3a69f1 2019-07-25 stsp branch, repo);
9787 0ebf8283 2019-07-24 stsp }
9788 0ebf8283 2019-07-24 stsp
9789 0ebf8283 2019-07-24 stsp static const struct got_error *
9790 0ebf8283 2019-07-24 stsp show_histedit_progress(struct got_commit_object *commit,
9791 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle, struct got_object_id *new_id)
9792 0ebf8283 2019-07-24 stsp {
9793 0ebf8283 2019-07-24 stsp const struct got_error *err;
9794 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
9795 0ebf8283 2019-07-24 stsp
9796 0ebf8283 2019-07-24 stsp err = got_object_id_str(&old_id_str, hle->commit_id);
9797 0ebf8283 2019-07-24 stsp if (err)
9798 0ebf8283 2019-07-24 stsp goto done;
9799 0ebf8283 2019-07-24 stsp
9800 0ebf8283 2019-07-24 stsp if (new_id) {
9801 0ebf8283 2019-07-24 stsp err = got_object_id_str(&new_id_str, new_id);
9802 0ebf8283 2019-07-24 stsp if (err)
9803 0ebf8283 2019-07-24 stsp goto done;
9804 0ebf8283 2019-07-24 stsp }
9805 0ebf8283 2019-07-24 stsp
9806 0ebf8283 2019-07-24 stsp old_id_str[12] = '\0';
9807 0ebf8283 2019-07-24 stsp if (new_id_str)
9808 0ebf8283 2019-07-24 stsp new_id_str[12] = '\0';
9809 0ebf8283 2019-07-24 stsp
9810 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
9811 0ebf8283 2019-07-24 stsp logmsg = strdup(hle->logmsg);
9812 0ebf8283 2019-07-24 stsp if (logmsg == NULL) {
9813 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
9814 0ebf8283 2019-07-24 stsp goto done;
9815 0ebf8283 2019-07-24 stsp }
9816 0ebf8283 2019-07-24 stsp trim_logmsg(logmsg, 42);
9817 0ebf8283 2019-07-24 stsp } else {
9818 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
9819 0ebf8283 2019-07-24 stsp if (err)
9820 0ebf8283 2019-07-24 stsp goto done;
9821 0ebf8283 2019-07-24 stsp }
9822 0ebf8283 2019-07-24 stsp
9823 0ebf8283 2019-07-24 stsp switch (hle->cmd->code) {
9824 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_PICK:
9825 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_EDIT:
9826 0ebf8283 2019-07-24 stsp printf("%s -> %s: %s\n", old_id_str,
9827 0ebf8283 2019-07-24 stsp new_id_str ? new_id_str : "no-op change", logmsg);
9828 0ebf8283 2019-07-24 stsp break;
9829 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_DROP:
9830 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_FOLD:
9831 0ebf8283 2019-07-24 stsp printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
9832 0ebf8283 2019-07-24 stsp logmsg);
9833 0ebf8283 2019-07-24 stsp break;
9834 0ebf8283 2019-07-24 stsp default:
9835 0ebf8283 2019-07-24 stsp break;
9836 0ebf8283 2019-07-24 stsp }
9837 0ebf8283 2019-07-24 stsp done:
9838 0ebf8283 2019-07-24 stsp free(old_id_str);
9839 0ebf8283 2019-07-24 stsp free(new_id_str);
9840 0ebf8283 2019-07-24 stsp return err;
9841 0ebf8283 2019-07-24 stsp }
9842 0ebf8283 2019-07-24 stsp
9843 0ebf8283 2019-07-24 stsp static const struct got_error *
9844 0ebf8283 2019-07-24 stsp histedit_commit(struct got_pathlist_head *merged_paths,
9845 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
9846 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
9847 3e3a69f1 2019-07-25 stsp struct got_repository *repo)
9848 0ebf8283 2019-07-24 stsp {
9849 0ebf8283 2019-07-24 stsp const struct got_error *err;
9850 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
9851 0ebf8283 2019-07-24 stsp struct got_object_id *new_commit_id;
9852 0ebf8283 2019-07-24 stsp
9853 0ebf8283 2019-07-24 stsp if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
9854 0ebf8283 2019-07-24 stsp && hle->logmsg == NULL) {
9855 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
9856 0ebf8283 2019-07-24 stsp if (err)
9857 0ebf8283 2019-07-24 stsp return err;
9858 0ebf8283 2019-07-24 stsp }
9859 0ebf8283 2019-07-24 stsp
9860 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
9861 0ebf8283 2019-07-24 stsp if (err)
9862 0ebf8283 2019-07-24 stsp return err;
9863 0ebf8283 2019-07-24 stsp
9864 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
9865 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, hle->commit_id,
9866 3e3a69f1 2019-07-25 stsp hle->logmsg, repo);
9867 0ebf8283 2019-07-24 stsp if (err) {
9868 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
9869 0ebf8283 2019-07-24 stsp goto done;
9870 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, NULL);
9871 0ebf8283 2019-07-24 stsp } else {
9872 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, new_commit_id);
9873 0ebf8283 2019-07-24 stsp free(new_commit_id);
9874 0ebf8283 2019-07-24 stsp }
9875 0ebf8283 2019-07-24 stsp done:
9876 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9877 0ebf8283 2019-07-24 stsp return err;
9878 0ebf8283 2019-07-24 stsp }
9879 0ebf8283 2019-07-24 stsp
9880 0ebf8283 2019-07-24 stsp static const struct got_error *
9881 0ebf8283 2019-07-24 stsp histedit_skip_commit(struct got_histedit_list_entry *hle,
9882 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
9883 0ebf8283 2019-07-24 stsp {
9884 0ebf8283 2019-07-24 stsp const struct got_error *error;
9885 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
9886 0ebf8283 2019-07-24 stsp
9887 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
9888 0ebf8283 2019-07-24 stsp repo);
9889 0ebf8283 2019-07-24 stsp if (error)
9890 0ebf8283 2019-07-24 stsp return error;
9891 0ebf8283 2019-07-24 stsp
9892 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo, hle->commit_id);
9893 0ebf8283 2019-07-24 stsp if (error)
9894 0ebf8283 2019-07-24 stsp return error;
9895 0ebf8283 2019-07-24 stsp
9896 0ebf8283 2019-07-24 stsp error = show_histedit_progress(commit, hle, NULL);
9897 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
9898 0ebf8283 2019-07-24 stsp return error;
9899 ab20a43a 2020-01-29 stsp }
9900 ab20a43a 2020-01-29 stsp
9901 ab20a43a 2020-01-29 stsp static const struct got_error *
9902 ab20a43a 2020-01-29 stsp check_local_changes(void *arg, unsigned char status,
9903 ab20a43a 2020-01-29 stsp unsigned char staged_status, const char *path,
9904 ab20a43a 2020-01-29 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9905 ab20a43a 2020-01-29 stsp struct got_object_id *commit_id, int dirfd, const char *de_name)
9906 ab20a43a 2020-01-29 stsp {
9907 ab20a43a 2020-01-29 stsp int *have_local_changes = arg;
9908 ab20a43a 2020-01-29 stsp
9909 ab20a43a 2020-01-29 stsp switch (status) {
9910 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
9911 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
9912 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
9913 ab20a43a 2020-01-29 stsp case GOT_STATUS_CONFLICT:
9914 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
9915 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
9916 ab20a43a 2020-01-29 stsp default:
9917 ab20a43a 2020-01-29 stsp break;
9918 ab20a43a 2020-01-29 stsp }
9919 ab20a43a 2020-01-29 stsp
9920 ab20a43a 2020-01-29 stsp switch (staged_status) {
9921 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
9922 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
9923 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
9924 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
9925 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
9926 ab20a43a 2020-01-29 stsp default:
9927 ab20a43a 2020-01-29 stsp break;
9928 ab20a43a 2020-01-29 stsp }
9929 ab20a43a 2020-01-29 stsp
9930 ab20a43a 2020-01-29 stsp return NULL;
9931 0ebf8283 2019-07-24 stsp }
9932 0ebf8283 2019-07-24 stsp
9933 0ebf8283 2019-07-24 stsp static const struct got_error *
9934 0ebf8283 2019-07-24 stsp cmd_histedit(int argc, char *argv[])
9935 0ebf8283 2019-07-24 stsp {
9936 0ebf8283 2019-07-24 stsp const struct got_error *error = NULL;
9937 0ebf8283 2019-07-24 stsp struct got_worktree *worktree = NULL;
9938 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
9939 0ebf8283 2019-07-24 stsp struct got_repository *repo = NULL;
9940 0ebf8283 2019-07-24 stsp char *cwd = NULL;
9941 0ebf8283 2019-07-24 stsp struct got_reference *branch = NULL;
9942 0ebf8283 2019-07-24 stsp struct got_reference *tmp_branch = NULL;
9943 0ebf8283 2019-07-24 stsp struct got_object_id *resume_commit_id = NULL;
9944 0ebf8283 2019-07-24 stsp struct got_object_id *base_commit_id = NULL;
9945 0ebf8283 2019-07-24 stsp struct got_object_id *head_commit_id = NULL;
9946 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
9947 10604dce 2021-09-24 thomas int ch, rebase_in_progress = 0, merge_in_progress = 0;
9948 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
9949 0ebf8283 2019-07-24 stsp int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
9950 466785b9 2020-12-10 jrick int edit_logmsg_only = 0, fold_only = 0;
9951 643b85bc 2021-07-16 stsp int list_backups = 0, delete_backups = 0;
9952 0ebf8283 2019-07-24 stsp const char *edit_script_path = NULL;
9953 0ebf8283 2019-07-24 stsp unsigned char rebase_status = GOT_STATUS_NO_CHANGE;
9954 0ebf8283 2019-07-24 stsp struct got_object_id_queue commits;
9955 0ebf8283 2019-07-24 stsp struct got_pathlist_head merged_paths;
9956 0ebf8283 2019-07-24 stsp const struct got_object_id_queue *parent_ids;
9957 0ebf8283 2019-07-24 stsp struct got_object_qid *pid;
9958 0ebf8283 2019-07-24 stsp struct got_histedit_list histedit_cmds;
9959 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
9960 0ebf8283 2019-07-24 stsp
9961 dbdddfee 2021-06-23 naddy STAILQ_INIT(&commits);
9962 0ebf8283 2019-07-24 stsp TAILQ_INIT(&histedit_cmds);
9963 0ebf8283 2019-07-24 stsp TAILQ_INIT(&merged_paths);
9964 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
9965 0ebf8283 2019-07-24 stsp
9966 643b85bc 2021-07-16 stsp while ((ch = getopt(argc, argv, "acfF:mlX")) != -1) {
9967 0ebf8283 2019-07-24 stsp switch (ch) {
9968 0ebf8283 2019-07-24 stsp case 'a':
9969 0ebf8283 2019-07-24 stsp abort_edit = 1;
9970 0ebf8283 2019-07-24 stsp break;
9971 0ebf8283 2019-07-24 stsp case 'c':
9972 0ebf8283 2019-07-24 stsp continue_edit = 1;
9973 0ebf8283 2019-07-24 stsp break;
9974 466785b9 2020-12-10 jrick case 'f':
9975 466785b9 2020-12-10 jrick fold_only = 1;
9976 466785b9 2020-12-10 jrick break;
9977 0ebf8283 2019-07-24 stsp case 'F':
9978 0ebf8283 2019-07-24 stsp edit_script_path = optarg;
9979 0ebf8283 2019-07-24 stsp break;
9980 083957f4 2020-02-24 stsp case 'm':
9981 083957f4 2020-02-24 stsp edit_logmsg_only = 1;
9982 083957f4 2020-02-24 stsp break;
9983 e600f124 2021-03-21 stsp case 'l':
9984 e600f124 2021-03-21 stsp list_backups = 1;
9985 e600f124 2021-03-21 stsp break;
9986 643b85bc 2021-07-16 stsp case 'X':
9987 643b85bc 2021-07-16 stsp delete_backups = 1;
9988 643b85bc 2021-07-16 stsp break;
9989 0ebf8283 2019-07-24 stsp default:
9990 0ebf8283 2019-07-24 stsp usage_histedit();
9991 0ebf8283 2019-07-24 stsp /* NOTREACHED */
9992 0ebf8283 2019-07-24 stsp }
9993 0ebf8283 2019-07-24 stsp }
9994 0ebf8283 2019-07-24 stsp
9995 0ebf8283 2019-07-24 stsp argc -= optind;
9996 0ebf8283 2019-07-24 stsp argv += optind;
9997 0ebf8283 2019-07-24 stsp
9998 0ebf8283 2019-07-24 stsp #ifndef PROFILE
9999 0ebf8283 2019-07-24 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10000 0ebf8283 2019-07-24 stsp "unveil", NULL) == -1)
10001 0ebf8283 2019-07-24 stsp err(1, "pledge");
10002 0ebf8283 2019-07-24 stsp #endif
10003 0ebf8283 2019-07-24 stsp if (abort_edit && continue_edit)
10004 ff69268e 2020-12-13 stsp option_conflict('a', 'c');
10005 083957f4 2020-02-24 stsp if (edit_script_path && edit_logmsg_only)
10006 ff69268e 2020-12-13 stsp option_conflict('F', 'm');
10007 083957f4 2020-02-24 stsp if (abort_edit && edit_logmsg_only)
10008 ff69268e 2020-12-13 stsp option_conflict('a', 'm');
10009 083957f4 2020-02-24 stsp if (continue_edit && edit_logmsg_only)
10010 ff69268e 2020-12-13 stsp option_conflict('c', 'm');
10011 466785b9 2020-12-10 jrick if (abort_edit && fold_only)
10012 ff69268e 2020-12-13 stsp option_conflict('a', 'f');
10013 ff69268e 2020-12-13 stsp if (continue_edit && fold_only)
10014 ff69268e 2020-12-13 stsp option_conflict('c', 'f');
10015 466785b9 2020-12-10 jrick if (fold_only && edit_logmsg_only)
10016 ff69268e 2020-12-13 stsp option_conflict('f', 'm');
10017 b3805337 2020-12-13 stsp if (edit_script_path && fold_only)
10018 b3805337 2020-12-13 stsp option_conflict('F', 'f');
10019 e600f124 2021-03-21 stsp if (list_backups) {
10020 e600f124 2021-03-21 stsp if (abort_edit)
10021 e600f124 2021-03-21 stsp option_conflict('l', 'a');
10022 e600f124 2021-03-21 stsp if (continue_edit)
10023 e600f124 2021-03-21 stsp option_conflict('l', 'c');
10024 e600f124 2021-03-21 stsp if (edit_script_path)
10025 e600f124 2021-03-21 stsp option_conflict('l', 'F');
10026 e600f124 2021-03-21 stsp if (edit_logmsg_only)
10027 e600f124 2021-03-21 stsp option_conflict('l', 'm');
10028 e600f124 2021-03-21 stsp if (fold_only)
10029 e600f124 2021-03-21 stsp option_conflict('l', 'f');
10030 643b85bc 2021-07-16 stsp if (delete_backups)
10031 643b85bc 2021-07-16 stsp option_conflict('l', 'X');
10032 e600f124 2021-03-21 stsp if (argc != 0 && argc != 1)
10033 e600f124 2021-03-21 stsp usage_histedit();
10034 643b85bc 2021-07-16 stsp } else if (delete_backups) {
10035 643b85bc 2021-07-16 stsp if (abort_edit)
10036 643b85bc 2021-07-16 stsp option_conflict('X', 'a');
10037 643b85bc 2021-07-16 stsp if (continue_edit)
10038 643b85bc 2021-07-16 stsp option_conflict('X', 'c');
10039 643b85bc 2021-07-16 stsp if (edit_script_path)
10040 643b85bc 2021-07-16 stsp option_conflict('X', 'F');
10041 643b85bc 2021-07-16 stsp if (edit_logmsg_only)
10042 643b85bc 2021-07-16 stsp option_conflict('X', 'm');
10043 643b85bc 2021-07-16 stsp if (fold_only)
10044 643b85bc 2021-07-16 stsp option_conflict('X', 'f');
10045 643b85bc 2021-07-16 stsp if (list_backups)
10046 643b85bc 2021-07-16 stsp option_conflict('X', 'l');
10047 643b85bc 2021-07-16 stsp if (argc != 0 && argc != 1)
10048 643b85bc 2021-07-16 stsp usage_histedit();
10049 e600f124 2021-03-21 stsp } else if (argc != 0)
10050 0ebf8283 2019-07-24 stsp usage_histedit();
10051 0ebf8283 2019-07-24 stsp
10052 0ebf8283 2019-07-24 stsp /*
10053 0ebf8283 2019-07-24 stsp * This command cannot apply unveil(2) in all cases because the
10054 0ebf8283 2019-07-24 stsp * user may choose to run an editor to edit the histedit script
10055 0ebf8283 2019-07-24 stsp * and to edit individual commit log messages.
10056 0ebf8283 2019-07-24 stsp * unveil(2) traverses exec(2); if an editor is used we have to
10057 0ebf8283 2019-07-24 stsp * apply unveil after edit script and log messages have been written.
10058 0ebf8283 2019-07-24 stsp * XXX TODO: Make use of unveil(2) where possible.
10059 0ebf8283 2019-07-24 stsp */
10060 0ebf8283 2019-07-24 stsp
10061 0ebf8283 2019-07-24 stsp cwd = getcwd(NULL, 0);
10062 0ebf8283 2019-07-24 stsp if (cwd == NULL) {
10063 0ebf8283 2019-07-24 stsp error = got_error_from_errno("getcwd");
10064 0ebf8283 2019-07-24 stsp goto done;
10065 0ebf8283 2019-07-24 stsp }
10066 0ebf8283 2019-07-24 stsp error = got_worktree_open(&worktree, cwd);
10067 fa51e947 2020-03-27 stsp if (error) {
10068 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
10069 e600f124 2021-03-21 stsp if (error->code != GOT_ERR_NOT_WORKTREE)
10070 e600f124 2021-03-21 stsp goto done;
10071 e600f124 2021-03-21 stsp } else {
10072 e600f124 2021-03-21 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
10073 e600f124 2021-03-21 stsp error = wrap_not_worktree_error(error,
10074 e600f124 2021-03-21 stsp "histedit", cwd);
10075 e600f124 2021-03-21 stsp goto done;
10076 e600f124 2021-03-21 stsp }
10077 e600f124 2021-03-21 stsp }
10078 e600f124 2021-03-21 stsp
10079 643b85bc 2021-07-16 stsp if (list_backups || delete_backups) {
10080 e600f124 2021-03-21 stsp error = got_repo_open(&repo,
10081 e600f124 2021-03-21 stsp worktree ? got_worktree_get_repo_path(worktree) : cwd,
10082 e600f124 2021-03-21 stsp NULL);
10083 e600f124 2021-03-21 stsp if (error != NULL)
10084 e600f124 2021-03-21 stsp goto done;
10085 e600f124 2021-03-21 stsp error = apply_unveil(got_repo_get_path(repo), 0,
10086 e600f124 2021-03-21 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
10087 e600f124 2021-03-21 stsp if (error)
10088 e600f124 2021-03-21 stsp goto done;
10089 643b85bc 2021-07-16 stsp error = process_backup_refs(
10090 e600f124 2021-03-21 stsp GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
10091 643b85bc 2021-07-16 stsp argc == 1 ? argv[0] : NULL, delete_backups, repo);
10092 e600f124 2021-03-21 stsp goto done; /* nothing else to do */
10093 fa51e947 2020-03-27 stsp }
10094 0ebf8283 2019-07-24 stsp
10095 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
10096 c9956ddf 2019-09-08 stsp NULL);
10097 0ebf8283 2019-07-24 stsp if (error != NULL)
10098 0ebf8283 2019-07-24 stsp goto done;
10099 0ebf8283 2019-07-24 stsp
10100 0ebf8283 2019-07-24 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
10101 0ebf8283 2019-07-24 stsp if (error)
10102 0ebf8283 2019-07-24 stsp goto done;
10103 0ebf8283 2019-07-24 stsp if (rebase_in_progress) {
10104 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_REBASING);
10105 10604dce 2021-09-24 thomas goto done;
10106 10604dce 2021-09-24 thomas }
10107 10604dce 2021-09-24 thomas
10108 10604dce 2021-09-24 thomas error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
10109 10604dce 2021-09-24 thomas repo);
10110 10604dce 2021-09-24 thomas if (error)
10111 10604dce 2021-09-24 thomas goto done;
10112 10604dce 2021-09-24 thomas if (merge_in_progress) {
10113 10604dce 2021-09-24 thomas error = got_error(GOT_ERR_MERGE_BUSY);
10114 0ebf8283 2019-07-24 stsp goto done;
10115 0ebf8283 2019-07-24 stsp }
10116 0ebf8283 2019-07-24 stsp
10117 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
10118 0ebf8283 2019-07-24 stsp if (error)
10119 0ebf8283 2019-07-24 stsp goto done;
10120 0ebf8283 2019-07-24 stsp
10121 083957f4 2020-02-24 stsp if (edit_in_progress && edit_logmsg_only) {
10122 083957f4 2020-02-24 stsp error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
10123 083957f4 2020-02-24 stsp "histedit operation is in progress in this "
10124 083957f4 2020-02-24 stsp "work tree and must be continued or aborted "
10125 083957f4 2020-02-24 stsp "before the -m option can be used");
10126 083957f4 2020-02-24 stsp goto done;
10127 083957f4 2020-02-24 stsp }
10128 466785b9 2020-12-10 jrick if (edit_in_progress && fold_only) {
10129 466785b9 2020-12-10 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
10130 466785b9 2020-12-10 jrick "histedit operation is in progress in this "
10131 466785b9 2020-12-10 jrick "work tree and must be continued or aborted "
10132 466785b9 2020-12-10 jrick "before the -f option can be used");
10133 466785b9 2020-12-10 jrick goto done;
10134 466785b9 2020-12-10 jrick }
10135 083957f4 2020-02-24 stsp
10136 0ebf8283 2019-07-24 stsp if (edit_in_progress && abort_edit) {
10137 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
10138 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
10139 3e3a69f1 2019-07-25 stsp worktree, repo);
10140 0ebf8283 2019-07-24 stsp if (error)
10141 0ebf8283 2019-07-24 stsp goto done;
10142 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
10143 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
10144 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_abort(worktree, fileindex, repo,
10145 9627c110 2020-04-18 stsp branch, base_commit_id, update_progress, &upa);
10146 0ebf8283 2019-07-24 stsp if (error)
10147 0ebf8283 2019-07-24 stsp goto done;
10148 0ebf8283 2019-07-24 stsp printf("Histedit of %s aborted\n",
10149 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
10150 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10151 0ebf8283 2019-07-24 stsp goto done; /* nothing else to do */
10152 0ebf8283 2019-07-24 stsp } else if (abort_edit) {
10153 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
10154 0ebf8283 2019-07-24 stsp goto done;
10155 0ebf8283 2019-07-24 stsp }
10156 0ebf8283 2019-07-24 stsp
10157 0ebf8283 2019-07-24 stsp if (continue_edit) {
10158 0ebf8283 2019-07-24 stsp char *path;
10159 0ebf8283 2019-07-24 stsp
10160 0ebf8283 2019-07-24 stsp if (!edit_in_progress) {
10161 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
10162 0ebf8283 2019-07-24 stsp goto done;
10163 0ebf8283 2019-07-24 stsp }
10164 0ebf8283 2019-07-24 stsp
10165 c3022ba5 2019-07-27 stsp error = got_worktree_get_histedit_script_path(&path, worktree);
10166 0ebf8283 2019-07-24 stsp if (error)
10167 0ebf8283 2019-07-24 stsp goto done;
10168 0ebf8283 2019-07-24 stsp
10169 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds, path, repo);
10170 0ebf8283 2019-07-24 stsp free(path);
10171 0ebf8283 2019-07-24 stsp if (error)
10172 0ebf8283 2019-07-24 stsp goto done;
10173 0ebf8283 2019-07-24 stsp
10174 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
10175 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
10176 3e3a69f1 2019-07-25 stsp worktree, repo);
10177 0ebf8283 2019-07-24 stsp if (error)
10178 0ebf8283 2019-07-24 stsp goto done;
10179 0ebf8283 2019-07-24 stsp
10180 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
10181 0ebf8283 2019-07-24 stsp if (error)
10182 0ebf8283 2019-07-24 stsp goto done;
10183 0ebf8283 2019-07-24 stsp
10184 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10185 0ebf8283 2019-07-24 stsp head_commit_id);
10186 0ebf8283 2019-07-24 stsp if (error)
10187 0ebf8283 2019-07-24 stsp goto done;
10188 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10189 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10190 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
10191 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10192 3aac7cf7 2019-07-25 stsp goto done;
10193 3aac7cf7 2019-07-25 stsp }
10194 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, head_commit_id, pid->id,
10195 8ca9bd68 2019-07-25 stsp base_commit_id, got_worktree_get_path_prefix(worktree),
10196 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
10197 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10198 0ebf8283 2019-07-24 stsp commit = NULL;
10199 0ebf8283 2019-07-24 stsp if (error)
10200 0ebf8283 2019-07-24 stsp goto done;
10201 0ebf8283 2019-07-24 stsp } else {
10202 0ebf8283 2019-07-24 stsp if (edit_in_progress) {
10203 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
10204 0ebf8283 2019-07-24 stsp goto done;
10205 0ebf8283 2019-07-24 stsp }
10206 0ebf8283 2019-07-24 stsp
10207 0ebf8283 2019-07-24 stsp error = got_ref_open(&branch, repo,
10208 0ebf8283 2019-07-24 stsp got_worktree_get_head_ref_name(worktree), 0);
10209 0ebf8283 2019-07-24 stsp if (error != NULL)
10210 0ebf8283 2019-07-24 stsp goto done;
10211 0ebf8283 2019-07-24 stsp
10212 c7d20a3f 2019-07-30 stsp if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
10213 c7d20a3f 2019-07-30 stsp error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
10214 c7d20a3f 2019-07-30 stsp "will not edit commit history of a branch outside "
10215 c7d20a3f 2019-07-30 stsp "the \"refs/heads/\" reference namespace");
10216 c7d20a3f 2019-07-30 stsp goto done;
10217 c7d20a3f 2019-07-30 stsp }
10218 c7d20a3f 2019-07-30 stsp
10219 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
10220 bfce7f83 2019-07-27 stsp got_ref_close(branch);
10221 bfce7f83 2019-07-27 stsp branch = NULL;
10222 0ebf8283 2019-07-24 stsp if (error)
10223 0ebf8283 2019-07-24 stsp goto done;
10224 0ebf8283 2019-07-24 stsp
10225 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10226 0ebf8283 2019-07-24 stsp head_commit_id);
10227 0ebf8283 2019-07-24 stsp if (error)
10228 0ebf8283 2019-07-24 stsp goto done;
10229 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10230 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10231 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
10232 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10233 3aac7cf7 2019-07-25 stsp goto done;
10234 3aac7cf7 2019-07-25 stsp }
10235 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, head_commit_id, pid->id,
10236 8ca9bd68 2019-07-25 stsp got_worktree_get_base_commit_id(worktree),
10237 8ca9bd68 2019-07-25 stsp got_worktree_get_path_prefix(worktree),
10238 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
10239 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10240 0ebf8283 2019-07-24 stsp commit = NULL;
10241 0ebf8283 2019-07-24 stsp if (error)
10242 0ebf8283 2019-07-24 stsp goto done;
10243 0ebf8283 2019-07-24 stsp
10244 dbdddfee 2021-06-23 naddy if (STAILQ_EMPTY(&commits)) {
10245 c5996fff 2020-01-29 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
10246 c5996fff 2020-01-29 stsp goto done;
10247 c5996fff 2020-01-29 stsp }
10248 c5996fff 2020-01-29 stsp
10249 bfce7f83 2019-07-27 stsp error = got_worktree_histedit_prepare(&tmp_branch, &branch,
10250 bfce7f83 2019-07-27 stsp &base_commit_id, &fileindex, worktree, repo);
10251 bfce7f83 2019-07-27 stsp if (error)
10252 bfce7f83 2019-07-27 stsp goto done;
10253 bfce7f83 2019-07-27 stsp
10254 0ebf8283 2019-07-24 stsp if (edit_script_path) {
10255 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds,
10256 0ebf8283 2019-07-24 stsp edit_script_path, repo);
10257 6ba2bea2 2019-07-27 stsp if (error) {
10258 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10259 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10260 9627c110 2020-04-18 stsp update_progress, &upa);
10261 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10262 0ebf8283 2019-07-24 stsp goto done;
10263 6ba2bea2 2019-07-27 stsp }
10264 0ebf8283 2019-07-24 stsp } else {
10265 514f2ffe 2020-01-29 stsp const char *branch_name;
10266 514f2ffe 2020-01-29 stsp branch_name = got_ref_get_symref_target(branch);
10267 514f2ffe 2020-01-29 stsp if (strncmp(branch_name, "refs/heads/", 11) == 0)
10268 514f2ffe 2020-01-29 stsp branch_name += 11;
10269 0ebf8283 2019-07-24 stsp error = histedit_edit_script(&histedit_cmds, &commits,
10270 466785b9 2020-12-10 jrick branch_name, edit_logmsg_only, fold_only, repo);
10271 6ba2bea2 2019-07-27 stsp if (error) {
10272 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10273 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10274 9627c110 2020-04-18 stsp update_progress, &upa);
10275 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10276 0ebf8283 2019-07-24 stsp goto done;
10277 6ba2bea2 2019-07-27 stsp }
10278 0ebf8283 2019-07-24 stsp
10279 0ebf8283 2019-07-24 stsp }
10280 0ebf8283 2019-07-24 stsp
10281 0ebf8283 2019-07-24 stsp error = histedit_save_list(&histedit_cmds, worktree,
10282 0ebf8283 2019-07-24 stsp repo);
10283 6ba2bea2 2019-07-27 stsp if (error) {
10284 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
10285 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
10286 9627c110 2020-04-18 stsp update_progress, &upa);
10287 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10288 0ebf8283 2019-07-24 stsp goto done;
10289 6ba2bea2 2019-07-27 stsp }
10290 0ebf8283 2019-07-24 stsp
10291 0ebf8283 2019-07-24 stsp }
10292 0ebf8283 2019-07-24 stsp
10293 4ec14e60 2019-08-28 hiltjo error = histedit_check_script(&histedit_cmds, &commits, repo);
10294 4ec14e60 2019-08-28 hiltjo if (error)
10295 0ebf8283 2019-07-24 stsp goto done;
10296 0ebf8283 2019-07-24 stsp
10297 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, &histedit_cmds, entry) {
10298 0ebf8283 2019-07-24 stsp if (resume_commit_id) {
10299 0ebf8283 2019-07-24 stsp if (got_object_id_cmp(hle->commit_id,
10300 0ebf8283 2019-07-24 stsp resume_commit_id) != 0)
10301 0ebf8283 2019-07-24 stsp continue;
10302 0ebf8283 2019-07-24 stsp
10303 0ebf8283 2019-07-24 stsp resume_commit_id = NULL;
10304 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP ||
10305 0ebf8283 2019-07-24 stsp hle->cmd->code == GOT_HISTEDIT_FOLD) {
10306 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree,
10307 62d463ca 2020-10-20 naddy repo);
10308 ab20a43a 2020-01-29 stsp if (error)
10309 ab20a43a 2020-01-29 stsp goto done;
10310 0ebf8283 2019-07-24 stsp } else {
10311 ab20a43a 2020-01-29 stsp struct got_pathlist_head paths;
10312 ab20a43a 2020-01-29 stsp int have_changes = 0;
10313 ab20a43a 2020-01-29 stsp
10314 ab20a43a 2020-01-29 stsp TAILQ_INIT(&paths);
10315 ab20a43a 2020-01-29 stsp error = got_pathlist_append(&paths, "", NULL);
10316 ab20a43a 2020-01-29 stsp if (error)
10317 ab20a43a 2020-01-29 stsp goto done;
10318 ab20a43a 2020-01-29 stsp error = got_worktree_status(worktree, &paths,
10319 f6343036 2021-06-22 stsp repo, 0, check_local_changes, &have_changes,
10320 ab20a43a 2020-01-29 stsp check_cancelled, NULL);
10321 ab20a43a 2020-01-29 stsp got_pathlist_free(&paths);
10322 ab20a43a 2020-01-29 stsp if (error) {
10323 ab20a43a 2020-01-29 stsp if (error->code != GOT_ERR_CANCELLED)
10324 ab20a43a 2020-01-29 stsp goto done;
10325 ab20a43a 2020-01-29 stsp if (sigint_received || sigpipe_received)
10326 ab20a43a 2020-01-29 stsp goto done;
10327 ab20a43a 2020-01-29 stsp }
10328 ab20a43a 2020-01-29 stsp if (have_changes) {
10329 ab20a43a 2020-01-29 stsp error = histedit_commit(NULL, worktree,
10330 ab20a43a 2020-01-29 stsp fileindex, tmp_branch, hle, repo);
10331 ab20a43a 2020-01-29 stsp if (error)
10332 ab20a43a 2020-01-29 stsp goto done;
10333 ab20a43a 2020-01-29 stsp } else {
10334 ab20a43a 2020-01-29 stsp error = got_object_open_as_commit(
10335 ab20a43a 2020-01-29 stsp &commit, repo, hle->commit_id);
10336 ab20a43a 2020-01-29 stsp if (error)
10337 ab20a43a 2020-01-29 stsp goto done;
10338 ab20a43a 2020-01-29 stsp error = show_histedit_progress(commit,
10339 ab20a43a 2020-01-29 stsp hle, NULL);
10340 ab20a43a 2020-01-29 stsp got_object_commit_close(commit);
10341 ab20a43a 2020-01-29 stsp commit = NULL;
10342 ab20a43a 2020-01-29 stsp if (error)
10343 ab20a43a 2020-01-29 stsp goto done;
10344 ab20a43a 2020-01-29 stsp }
10345 0ebf8283 2019-07-24 stsp }
10346 0ebf8283 2019-07-24 stsp continue;
10347 0ebf8283 2019-07-24 stsp }
10348 0ebf8283 2019-07-24 stsp
10349 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP) {
10350 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
10351 0ebf8283 2019-07-24 stsp if (error)
10352 0ebf8283 2019-07-24 stsp goto done;
10353 0ebf8283 2019-07-24 stsp continue;
10354 0ebf8283 2019-07-24 stsp }
10355 0ebf8283 2019-07-24 stsp
10356 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
10357 0ebf8283 2019-07-24 stsp hle->commit_id);
10358 0ebf8283 2019-07-24 stsp if (error)
10359 0ebf8283 2019-07-24 stsp goto done;
10360 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
10361 dbdddfee 2021-06-23 naddy pid = STAILQ_FIRST(parent_ids);
10362 0ebf8283 2019-07-24 stsp
10363 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_merge_files(&merged_paths,
10364 3e3a69f1 2019-07-25 stsp worktree, fileindex, pid->id, hle->commit_id, repo,
10365 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
10366 0ebf8283 2019-07-24 stsp if (error)
10367 0ebf8283 2019-07-24 stsp goto done;
10368 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10369 0ebf8283 2019-07-24 stsp commit = NULL;
10370 0ebf8283 2019-07-24 stsp
10371 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10372 9627c110 2020-04-18 stsp if (upa.conflicts > 0)
10373 9627c110 2020-04-18 stsp rebase_status = GOT_STATUS_CONFLICT;
10374 9627c110 2020-04-18 stsp
10375 0ebf8283 2019-07-24 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
10376 a0ea4fc0 2020-02-28 stsp error = show_rebase_merge_conflict(hle->commit_id,
10377 a0ea4fc0 2020-02-28 stsp repo);
10378 a0ea4fc0 2020-02-28 stsp if (error)
10379 a0ea4fc0 2020-02-28 stsp goto done;
10380 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10381 0ebf8283 2019-07-24 stsp break;
10382 0ebf8283 2019-07-24 stsp }
10383 0ebf8283 2019-07-24 stsp
10384 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
10385 0ebf8283 2019-07-24 stsp char *id_str;
10386 0ebf8283 2019-07-24 stsp error = got_object_id_str(&id_str, hle->commit_id);
10387 0ebf8283 2019-07-24 stsp if (error)
10388 0ebf8283 2019-07-24 stsp goto done;
10389 0ebf8283 2019-07-24 stsp printf("Stopping histedit for amending commit %s\n",
10390 0ebf8283 2019-07-24 stsp id_str);
10391 0ebf8283 2019-07-24 stsp free(id_str);
10392 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10393 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree,
10394 3e3a69f1 2019-07-25 stsp fileindex);
10395 0ebf8283 2019-07-24 stsp goto done;
10396 0ebf8283 2019-07-24 stsp }
10397 0ebf8283 2019-07-24 stsp
10398 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
10399 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
10400 0ebf8283 2019-07-24 stsp if (error)
10401 0ebf8283 2019-07-24 stsp goto done;
10402 0ebf8283 2019-07-24 stsp continue;
10403 0ebf8283 2019-07-24 stsp }
10404 0ebf8283 2019-07-24 stsp
10405 3e3a69f1 2019-07-25 stsp error = histedit_commit(&merged_paths, worktree, fileindex,
10406 3e3a69f1 2019-07-25 stsp tmp_branch, hle, repo);
10407 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
10408 0ebf8283 2019-07-24 stsp if (error)
10409 0ebf8283 2019-07-24 stsp goto done;
10410 0ebf8283 2019-07-24 stsp }
10411 0ebf8283 2019-07-24 stsp
10412 0ebf8283 2019-07-24 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
10413 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree, fileindex);
10414 0ebf8283 2019-07-24 stsp if (error)
10415 0ebf8283 2019-07-24 stsp goto done;
10416 0ebf8283 2019-07-24 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
10417 4cb8f8f3 2020-03-05 stsp "conflicts must be resolved before histedit can continue");
10418 0ebf8283 2019-07-24 stsp } else
10419 3e3a69f1 2019-07-25 stsp error = histedit_complete(worktree, fileindex, tmp_branch,
10420 3e3a69f1 2019-07-25 stsp branch, repo);
10421 0ebf8283 2019-07-24 stsp done:
10422 0ebf8283 2019-07-24 stsp got_object_id_queue_free(&commits);
10423 bfce7f83 2019-07-27 stsp histedit_free_list(&histedit_cmds);
10424 0ebf8283 2019-07-24 stsp free(head_commit_id);
10425 0ebf8283 2019-07-24 stsp free(base_commit_id);
10426 0ebf8283 2019-07-24 stsp free(resume_commit_id);
10427 0ebf8283 2019-07-24 stsp if (commit)
10428 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
10429 0ebf8283 2019-07-24 stsp if (branch)
10430 0ebf8283 2019-07-24 stsp got_ref_close(branch);
10431 0ebf8283 2019-07-24 stsp if (tmp_branch)
10432 0ebf8283 2019-07-24 stsp got_ref_close(tmp_branch);
10433 0ebf8283 2019-07-24 stsp if (worktree)
10434 0ebf8283 2019-07-24 stsp got_worktree_close(worktree);
10435 1d0f4054 2021-06-17 stsp if (repo) {
10436 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
10437 1d0f4054 2021-06-17 stsp if (error == NULL)
10438 1d0f4054 2021-06-17 stsp error = close_err;
10439 1d0f4054 2021-06-17 stsp }
10440 2822a352 2019-10-15 stsp return error;
10441 2822a352 2019-10-15 stsp }
10442 2822a352 2019-10-15 stsp
10443 2822a352 2019-10-15 stsp __dead static void
10444 2822a352 2019-10-15 stsp usage_integrate(void)
10445 2822a352 2019-10-15 stsp {
10446 2822a352 2019-10-15 stsp fprintf(stderr, "usage: %s integrate branch\n", getprogname());
10447 2822a352 2019-10-15 stsp exit(1);
10448 2822a352 2019-10-15 stsp }
10449 2822a352 2019-10-15 stsp
10450 2822a352 2019-10-15 stsp static const struct got_error *
10451 2822a352 2019-10-15 stsp cmd_integrate(int argc, char *argv[])
10452 2822a352 2019-10-15 stsp {
10453 2822a352 2019-10-15 stsp const struct got_error *error = NULL;
10454 2822a352 2019-10-15 stsp struct got_repository *repo = NULL;
10455 2822a352 2019-10-15 stsp struct got_worktree *worktree = NULL;
10456 2822a352 2019-10-15 stsp char *cwd = NULL, *refname = NULL, *base_refname = NULL;
10457 2822a352 2019-10-15 stsp const char *branch_arg = NULL;
10458 2822a352 2019-10-15 stsp struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
10459 2822a352 2019-10-15 stsp struct got_fileindex *fileindex = NULL;
10460 2822a352 2019-10-15 stsp struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
10461 9627c110 2020-04-18 stsp int ch;
10462 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
10463 2822a352 2019-10-15 stsp
10464 2822a352 2019-10-15 stsp while ((ch = getopt(argc, argv, "")) != -1) {
10465 2822a352 2019-10-15 stsp switch (ch) {
10466 2822a352 2019-10-15 stsp default:
10467 2822a352 2019-10-15 stsp usage_integrate();
10468 2822a352 2019-10-15 stsp /* NOTREACHED */
10469 2822a352 2019-10-15 stsp }
10470 2822a352 2019-10-15 stsp }
10471 2822a352 2019-10-15 stsp
10472 2822a352 2019-10-15 stsp argc -= optind;
10473 2822a352 2019-10-15 stsp argv += optind;
10474 2822a352 2019-10-15 stsp
10475 2822a352 2019-10-15 stsp if (argc != 1)
10476 2822a352 2019-10-15 stsp usage_integrate();
10477 2822a352 2019-10-15 stsp branch_arg = argv[0];
10478 b08a0ccd 2020-09-24 stsp #ifndef PROFILE
10479 2822a352 2019-10-15 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10480 2822a352 2019-10-15 stsp "unveil", NULL) == -1)
10481 2822a352 2019-10-15 stsp err(1, "pledge");
10482 b08a0ccd 2020-09-24 stsp #endif
10483 2822a352 2019-10-15 stsp cwd = getcwd(NULL, 0);
10484 2822a352 2019-10-15 stsp if (cwd == NULL) {
10485 2822a352 2019-10-15 stsp error = got_error_from_errno("getcwd");
10486 2822a352 2019-10-15 stsp goto done;
10487 2822a352 2019-10-15 stsp }
10488 2822a352 2019-10-15 stsp
10489 2822a352 2019-10-15 stsp error = got_worktree_open(&worktree, cwd);
10490 fa51e947 2020-03-27 stsp if (error) {
10491 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
10492 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "integrate",
10493 fa51e947 2020-03-27 stsp cwd);
10494 2822a352 2019-10-15 stsp goto done;
10495 fa51e947 2020-03-27 stsp }
10496 2822a352 2019-10-15 stsp
10497 2822a352 2019-10-15 stsp error = check_rebase_or_histedit_in_progress(worktree);
10498 2822a352 2019-10-15 stsp if (error)
10499 2822a352 2019-10-15 stsp goto done;
10500 2822a352 2019-10-15 stsp
10501 2822a352 2019-10-15 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
10502 2822a352 2019-10-15 stsp NULL);
10503 2822a352 2019-10-15 stsp if (error != NULL)
10504 2822a352 2019-10-15 stsp goto done;
10505 2822a352 2019-10-15 stsp
10506 2822a352 2019-10-15 stsp error = apply_unveil(got_repo_get_path(repo), 0,
10507 2822a352 2019-10-15 stsp got_worktree_get_root_path(worktree));
10508 2822a352 2019-10-15 stsp if (error)
10509 2822a352 2019-10-15 stsp goto done;
10510 2822a352 2019-10-15 stsp
10511 10604dce 2021-09-24 thomas error = check_merge_in_progress(worktree, repo);
10512 10604dce 2021-09-24 thomas if (error)
10513 10604dce 2021-09-24 thomas goto done;
10514 10604dce 2021-09-24 thomas
10515 2822a352 2019-10-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
10516 2822a352 2019-10-15 stsp error = got_error_from_errno("asprintf");
10517 2822a352 2019-10-15 stsp goto done;
10518 2822a352 2019-10-15 stsp }
10519 2822a352 2019-10-15 stsp
10520 2822a352 2019-10-15 stsp error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
10521 2822a352 2019-10-15 stsp &base_branch_ref, worktree, refname, repo);
10522 2822a352 2019-10-15 stsp if (error)
10523 2822a352 2019-10-15 stsp goto done;
10524 2822a352 2019-10-15 stsp
10525 2822a352 2019-10-15 stsp refname = strdup(got_ref_get_name(branch_ref));
10526 2822a352 2019-10-15 stsp if (refname == NULL) {
10527 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
10528 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
10529 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
10530 2822a352 2019-10-15 stsp goto done;
10531 2822a352 2019-10-15 stsp }
10532 2822a352 2019-10-15 stsp base_refname = strdup(got_ref_get_name(base_branch_ref));
10533 2822a352 2019-10-15 stsp if (base_refname == NULL) {
10534 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
10535 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
10536 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
10537 2822a352 2019-10-15 stsp goto done;
10538 2822a352 2019-10-15 stsp }
10539 2822a352 2019-10-15 stsp
10540 2822a352 2019-10-15 stsp error = got_ref_resolve(&commit_id, repo, branch_ref);
10541 2822a352 2019-10-15 stsp if (error)
10542 2822a352 2019-10-15 stsp goto done;
10543 2822a352 2019-10-15 stsp
10544 2822a352 2019-10-15 stsp error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
10545 2822a352 2019-10-15 stsp if (error)
10546 2822a352 2019-10-15 stsp goto done;
10547 2822a352 2019-10-15 stsp
10548 2822a352 2019-10-15 stsp if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
10549 2822a352 2019-10-15 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH,
10550 2822a352 2019-10-15 stsp "specified branch has already been integrated");
10551 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
10552 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
10553 2822a352 2019-10-15 stsp goto done;
10554 2822a352 2019-10-15 stsp }
10555 2822a352 2019-10-15 stsp
10556 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
10557 2822a352 2019-10-15 stsp if (error) {
10558 2822a352 2019-10-15 stsp if (error->code == GOT_ERR_ANCESTRY)
10559 2822a352 2019-10-15 stsp error = got_error(GOT_ERR_REBASE_REQUIRED);
10560 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
10561 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
10562 2822a352 2019-10-15 stsp goto done;
10563 2822a352 2019-10-15 stsp }
10564 2822a352 2019-10-15 stsp
10565 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
10566 2822a352 2019-10-15 stsp error = got_worktree_integrate_continue(worktree, fileindex, repo,
10567 9627c110 2020-04-18 stsp branch_ref, base_branch_ref, update_progress, &upa,
10568 2822a352 2019-10-15 stsp check_cancelled, NULL);
10569 2822a352 2019-10-15 stsp if (error)
10570 2822a352 2019-10-15 stsp goto done;
10571 2822a352 2019-10-15 stsp
10572 2822a352 2019-10-15 stsp printf("Integrated %s into %s\n", refname, base_refname);
10573 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
10574 2822a352 2019-10-15 stsp done:
10575 1d0f4054 2021-06-17 stsp if (repo) {
10576 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
10577 1d0f4054 2021-06-17 stsp if (error == NULL)
10578 1d0f4054 2021-06-17 stsp error = close_err;
10579 1d0f4054 2021-06-17 stsp }
10580 2822a352 2019-10-15 stsp if (worktree)
10581 2822a352 2019-10-15 stsp got_worktree_close(worktree);
10582 2822a352 2019-10-15 stsp free(cwd);
10583 2822a352 2019-10-15 stsp free(base_commit_id);
10584 2822a352 2019-10-15 stsp free(commit_id);
10585 2822a352 2019-10-15 stsp free(refname);
10586 2822a352 2019-10-15 stsp free(base_refname);
10587 10604dce 2021-09-24 thomas return error;
10588 10604dce 2021-09-24 thomas }
10589 10604dce 2021-09-24 thomas
10590 10604dce 2021-09-24 thomas __dead static void
10591 10604dce 2021-09-24 thomas usage_merge(void)
10592 10604dce 2021-09-24 thomas {
10593 10604dce 2021-09-24 thomas fprintf(stderr, "usage: %s merge [-a] [-c] [branch]\n",
10594 10604dce 2021-09-24 thomas getprogname());
10595 10604dce 2021-09-24 thomas exit(1);
10596 10604dce 2021-09-24 thomas }
10597 10604dce 2021-09-24 thomas
10598 10604dce 2021-09-24 thomas static const struct got_error *
10599 10604dce 2021-09-24 thomas cmd_merge(int argc, char *argv[])
10600 10604dce 2021-09-24 thomas {
10601 10604dce 2021-09-24 thomas const struct got_error *error = NULL;
10602 10604dce 2021-09-24 thomas struct got_worktree *worktree = NULL;
10603 10604dce 2021-09-24 thomas struct got_repository *repo = NULL;
10604 10604dce 2021-09-24 thomas struct got_fileindex *fileindex = NULL;
10605 10604dce 2021-09-24 thomas char *cwd = NULL, *id_str = NULL, *author = NULL;
10606 10604dce 2021-09-24 thomas struct got_reference *branch = NULL, *wt_branch = NULL;
10607 10604dce 2021-09-24 thomas struct got_object_id *branch_tip = NULL, *yca_id = NULL;
10608 10604dce 2021-09-24 thomas struct got_object_id *wt_branch_tip = NULL;
10609 10604dce 2021-09-24 thomas int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
10610 10604dce 2021-09-24 thomas struct got_update_progress_arg upa;
10611 10604dce 2021-09-24 thomas struct got_object_id *merge_commit_id = NULL;
10612 10604dce 2021-09-24 thomas char *branch_name = NULL;
10613 10604dce 2021-09-24 thomas
10614 10604dce 2021-09-24 thomas memset(&upa, 0, sizeof(upa));
10615 10604dce 2021-09-24 thomas
10616 10604dce 2021-09-24 thomas while ((ch = getopt(argc, argv, "ac")) != -1) {
10617 10604dce 2021-09-24 thomas switch (ch) {
10618 10604dce 2021-09-24 thomas case 'a':
10619 10604dce 2021-09-24 thomas abort_merge = 1;
10620 10604dce 2021-09-24 thomas break;
10621 10604dce 2021-09-24 thomas case 'c':
10622 10604dce 2021-09-24 thomas continue_merge = 1;
10623 10604dce 2021-09-24 thomas break;
10624 10604dce 2021-09-24 thomas default:
10625 10604dce 2021-09-24 thomas usage_rebase();
10626 10604dce 2021-09-24 thomas /* NOTREACHED */
10627 10604dce 2021-09-24 thomas }
10628 10604dce 2021-09-24 thomas }
10629 10604dce 2021-09-24 thomas
10630 10604dce 2021-09-24 thomas argc -= optind;
10631 10604dce 2021-09-24 thomas argv += optind;
10632 10604dce 2021-09-24 thomas
10633 10604dce 2021-09-24 thomas #ifndef PROFILE
10634 10604dce 2021-09-24 thomas if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10635 10604dce 2021-09-24 thomas "unveil", NULL) == -1)
10636 10604dce 2021-09-24 thomas err(1, "pledge");
10637 10604dce 2021-09-24 thomas #endif
10638 10604dce 2021-09-24 thomas
10639 10604dce 2021-09-24 thomas if (abort_merge && continue_merge)
10640 10604dce 2021-09-24 thomas option_conflict('a', 'c');
10641 10604dce 2021-09-24 thomas if (abort_merge || continue_merge) {
10642 10604dce 2021-09-24 thomas if (argc != 0)
10643 10604dce 2021-09-24 thomas usage_merge();
10644 10604dce 2021-09-24 thomas } else if (argc != 1)
10645 10604dce 2021-09-24 thomas usage_merge();
10646 10604dce 2021-09-24 thomas
10647 10604dce 2021-09-24 thomas cwd = getcwd(NULL, 0);
10648 10604dce 2021-09-24 thomas if (cwd == NULL) {
10649 10604dce 2021-09-24 thomas error = got_error_from_errno("getcwd");
10650 10604dce 2021-09-24 thomas goto done;
10651 10604dce 2021-09-24 thomas }
10652 10604dce 2021-09-24 thomas
10653 10604dce 2021-09-24 thomas error = got_worktree_open(&worktree, cwd);
10654 10604dce 2021-09-24 thomas if (error) {
10655 10604dce 2021-09-24 thomas if (error->code == GOT_ERR_NOT_WORKTREE)
10656 10604dce 2021-09-24 thomas error = wrap_not_worktree_error(error,
10657 10604dce 2021-09-24 thomas "merge", cwd);
10658 10604dce 2021-09-24 thomas goto done;
10659 10604dce 2021-09-24 thomas }
10660 10604dce 2021-09-24 thomas
10661 10604dce 2021-09-24 thomas error = got_repo_open(&repo,
10662 10604dce 2021-09-24 thomas worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL);
10663 10604dce 2021-09-24 thomas if (error != NULL)
10664 10604dce 2021-09-24 thomas goto done;
10665 10604dce 2021-09-24 thomas
10666 10604dce 2021-09-24 thomas error = apply_unveil(got_repo_get_path(repo), 0,
10667 10604dce 2021-09-24 thomas worktree ? got_worktree_get_root_path(worktree) : NULL);
10668 10604dce 2021-09-24 thomas if (error)
10669 10604dce 2021-09-24 thomas goto done;
10670 10604dce 2021-09-24 thomas
10671 10604dce 2021-09-24 thomas error = check_rebase_or_histedit_in_progress(worktree);
10672 10604dce 2021-09-24 thomas if (error)
10673 10604dce 2021-09-24 thomas goto done;
10674 10604dce 2021-09-24 thomas
10675 10604dce 2021-09-24 thomas error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
10676 10604dce 2021-09-24 thomas repo);
10677 10604dce 2021-09-24 thomas if (error)
10678 10604dce 2021-09-24 thomas goto done;
10679 10604dce 2021-09-24 thomas
10680 10604dce 2021-09-24 thomas if (abort_merge) {
10681 10604dce 2021-09-24 thomas if (!merge_in_progress) {
10682 10604dce 2021-09-24 thomas error = got_error(GOT_ERR_NOT_MERGING);
10683 10604dce 2021-09-24 thomas goto done;
10684 10604dce 2021-09-24 thomas }
10685 10604dce 2021-09-24 thomas error = got_worktree_merge_continue(&branch_name,
10686 10604dce 2021-09-24 thomas &branch_tip, &fileindex, worktree, repo);
10687 10604dce 2021-09-24 thomas if (error)
10688 10604dce 2021-09-24 thomas goto done;
10689 10604dce 2021-09-24 thomas error = got_worktree_merge_abort(worktree, fileindex, repo,
10690 10604dce 2021-09-24 thomas update_progress, &upa);
10691 10604dce 2021-09-24 thomas if (error)
10692 10604dce 2021-09-24 thomas goto done;
10693 10604dce 2021-09-24 thomas printf("Merge of %s aborted\n", branch_name);
10694 10604dce 2021-09-24 thomas goto done; /* nothing else to do */
10695 10604dce 2021-09-24 thomas }
10696 10604dce 2021-09-24 thomas
10697 10604dce 2021-09-24 thomas error = get_author(&author, repo, worktree);
10698 10604dce 2021-09-24 thomas if (error)
10699 10604dce 2021-09-24 thomas goto done;
10700 10604dce 2021-09-24 thomas
10701 10604dce 2021-09-24 thomas if (continue_merge) {
10702 10604dce 2021-09-24 thomas if (!merge_in_progress) {
10703 10604dce 2021-09-24 thomas error = got_error(GOT_ERR_NOT_MERGING);
10704 10604dce 2021-09-24 thomas goto done;
10705 10604dce 2021-09-24 thomas }
10706 10604dce 2021-09-24 thomas error = got_worktree_merge_continue(&branch_name,
10707 10604dce 2021-09-24 thomas &branch_tip, &fileindex, worktree, repo);
10708 10604dce 2021-09-24 thomas if (error)
10709 10604dce 2021-09-24 thomas goto done;
10710 10604dce 2021-09-24 thomas } else {
10711 10604dce 2021-09-24 thomas error = got_ref_open(&branch, repo, argv[0], 0);
10712 10604dce 2021-09-24 thomas if (error != NULL)
10713 10604dce 2021-09-24 thomas goto done;
10714 10604dce 2021-09-24 thomas branch_name = strdup(got_ref_get_name(branch));
10715 10604dce 2021-09-24 thomas if (branch_name == NULL) {
10716 10604dce 2021-09-24 thomas error = got_error_from_errno("strdup");
10717 10604dce 2021-09-24 thomas goto done;
10718 10604dce 2021-09-24 thomas }
10719 10604dce 2021-09-24 thomas error = got_ref_resolve(&branch_tip, repo, branch);
10720 10604dce 2021-09-24 thomas if (error)
10721 10604dce 2021-09-24 thomas goto done;
10722 10604dce 2021-09-24 thomas }
10723 10604dce 2021-09-24 thomas
10724 10604dce 2021-09-24 thomas error = got_ref_open(&wt_branch, repo,
10725 10604dce 2021-09-24 thomas got_worktree_get_head_ref_name(worktree), 0);
10726 10604dce 2021-09-24 thomas if (error)
10727 10604dce 2021-09-24 thomas goto done;
10728 10604dce 2021-09-24 thomas error = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
10729 10604dce 2021-09-24 thomas if (error)
10730 10604dce 2021-09-24 thomas goto done;
10731 10604dce 2021-09-24 thomas error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
10732 10604dce 2021-09-24 thomas wt_branch_tip, branch_tip, repo,
10733 10604dce 2021-09-24 thomas check_cancelled, NULL);
10734 10604dce 2021-09-24 thomas if (error)
10735 10604dce 2021-09-24 thomas goto done;
10736 10604dce 2021-09-24 thomas if (yca_id == NULL) {
10737 10604dce 2021-09-24 thomas error = got_error_msg(GOT_ERR_ANCESTRY,
10738 10604dce 2021-09-24 thomas "specified branch shares no common ancestry "
10739 10604dce 2021-09-24 thomas "with work tree's branch");
10740 10604dce 2021-09-24 thomas goto done;
10741 10604dce 2021-09-24 thomas }
10742 10604dce 2021-09-24 thomas
10743 10604dce 2021-09-24 thomas if (!continue_merge) {
10744 10604dce 2021-09-24 thomas error = check_path_prefix(wt_branch_tip, branch_tip,
10745 10604dce 2021-09-24 thomas got_worktree_get_path_prefix(worktree),
10746 10604dce 2021-09-24 thomas GOT_ERR_MERGE_PATH, repo);
10747 10604dce 2021-09-24 thomas if (error)
10748 10604dce 2021-09-24 thomas goto done;
10749 10604dce 2021-09-24 thomas error = check_same_branch(wt_branch_tip, branch,
10750 10604dce 2021-09-24 thomas yca_id, repo);
10751 10604dce 2021-09-24 thomas if (error) {
10752 10604dce 2021-09-24 thomas if (error->code != GOT_ERR_ANCESTRY)
10753 10604dce 2021-09-24 thomas goto done;
10754 10604dce 2021-09-24 thomas error = NULL;
10755 10604dce 2021-09-24 thomas } else {
10756 10604dce 2021-09-24 thomas static char msg[512];
10757 10604dce 2021-09-24 thomas snprintf(msg, sizeof(msg),
10758 10604dce 2021-09-24 thomas "cannot create a merge commit because "
10759 10604dce 2021-09-24 thomas "%s is based on %s; %s can be integrated "
10760 10604dce 2021-09-24 thomas "with 'got integrate' instead", branch_name,
10761 10604dce 2021-09-24 thomas got_worktree_get_head_ref_name(worktree),
10762 10604dce 2021-09-24 thomas branch_name);
10763 10604dce 2021-09-24 thomas error = got_error_msg(GOT_ERR_SAME_BRANCH, msg);
10764 10604dce 2021-09-24 thomas goto done;
10765 10604dce 2021-09-24 thomas }
10766 10604dce 2021-09-24 thomas error = got_worktree_merge_prepare(&fileindex, worktree,
10767 10604dce 2021-09-24 thomas branch, repo);
10768 10604dce 2021-09-24 thomas if (error)
10769 10604dce 2021-09-24 thomas goto done;
10770 10604dce 2021-09-24 thomas
10771 10604dce 2021-09-24 thomas error = got_worktree_merge_branch(worktree, fileindex,
10772 10604dce 2021-09-24 thomas yca_id, branch_tip, repo, update_progress, &upa,
10773 10604dce 2021-09-24 thomas check_cancelled, NULL);
10774 10604dce 2021-09-24 thomas if (error)
10775 10604dce 2021-09-24 thomas goto done;
10776 10604dce 2021-09-24 thomas print_update_progress_stats(&upa);
10777 10604dce 2021-09-24 thomas }
10778 10604dce 2021-09-24 thomas
10779 88d249c2 2021-09-24 thomas if (upa.conflicts > 0 || upa.missing > 0) {
10780 10604dce 2021-09-24 thomas error = got_worktree_merge_postpone(worktree, fileindex);
10781 10604dce 2021-09-24 thomas if (error)
10782 10604dce 2021-09-24 thomas goto done;
10783 88d249c2 2021-09-24 thomas if (upa.conflicts > 0 && upa.missing == 0) {
10784 10604dce 2021-09-24 thomas error = got_error_msg(GOT_ERR_CONFLICTS,
10785 10604dce 2021-09-24 thomas "conflicts must be resolved before merging "
10786 10604dce 2021-09-24 thomas "can continue");
10787 10604dce 2021-09-24 thomas } else if (upa.conflicts > 0) {
10788 10604dce 2021-09-24 thomas error = got_error_msg(GOT_ERR_CONFLICTS,
10789 10604dce 2021-09-24 thomas "conflicts must be resolved before merging "
10790 10604dce 2021-09-24 thomas "can continue; changes destined for missing "
10791 88d249c2 2021-09-24 thomas "files were not yet merged and "
10792 10604dce 2021-09-24 thomas "should be merged manually if required before the "
10793 10604dce 2021-09-24 thomas "merge operation is continued");
10794 10604dce 2021-09-24 thomas } else {
10795 10604dce 2021-09-24 thomas error = got_error_msg(GOT_ERR_CONFLICTS,
10796 88d249c2 2021-09-24 thomas "changes destined for missing "
10797 10604dce 2021-09-24 thomas "files were not yet merged and should be "
10798 10604dce 2021-09-24 thomas "merged manually if required before the "
10799 10604dce 2021-09-24 thomas "merge operation is continued");
10800 10604dce 2021-09-24 thomas }
10801 10604dce 2021-09-24 thomas goto done;
10802 10604dce 2021-09-24 thomas } else {
10803 10604dce 2021-09-24 thomas error = got_worktree_merge_commit(&merge_commit_id, worktree,
10804 10604dce 2021-09-24 thomas fileindex, author, NULL, 1, branch_tip, branch_name, repo);
10805 10604dce 2021-09-24 thomas if (error)
10806 10604dce 2021-09-24 thomas goto done;
10807 10604dce 2021-09-24 thomas error = got_worktree_merge_complete(worktree, fileindex, repo);
10808 10604dce 2021-09-24 thomas if (error)
10809 10604dce 2021-09-24 thomas goto done;
10810 10604dce 2021-09-24 thomas error = got_object_id_str(&id_str, merge_commit_id);
10811 10604dce 2021-09-24 thomas if (error)
10812 10604dce 2021-09-24 thomas goto done;
10813 10604dce 2021-09-24 thomas printf("Merged %s into %s: %s\n", branch_name,
10814 10604dce 2021-09-24 thomas got_worktree_get_head_ref_name(worktree),
10815 10604dce 2021-09-24 thomas id_str);
10816 10604dce 2021-09-24 thomas
10817 10604dce 2021-09-24 thomas }
10818 10604dce 2021-09-24 thomas done:
10819 10604dce 2021-09-24 thomas free(id_str);
10820 10604dce 2021-09-24 thomas free(merge_commit_id);
10821 10604dce 2021-09-24 thomas free(author);
10822 10604dce 2021-09-24 thomas free(branch_tip);
10823 10604dce 2021-09-24 thomas free(branch_name);
10824 10604dce 2021-09-24 thomas free(yca_id);
10825 10604dce 2021-09-24 thomas if (branch)
10826 10604dce 2021-09-24 thomas got_ref_close(branch);
10827 10604dce 2021-09-24 thomas if (wt_branch)
10828 10604dce 2021-09-24 thomas got_ref_close(wt_branch);
10829 10604dce 2021-09-24 thomas if (worktree)
10830 10604dce 2021-09-24 thomas got_worktree_close(worktree);
10831 10604dce 2021-09-24 thomas if (repo) {
10832 10604dce 2021-09-24 thomas const struct got_error *close_err = got_repo_close(repo);
10833 10604dce 2021-09-24 thomas if (error == NULL)
10834 10604dce 2021-09-24 thomas error = close_err;
10835 10604dce 2021-09-24 thomas }
10836 715dc77e 2019-08-03 stsp return error;
10837 715dc77e 2019-08-03 stsp }
10838 715dc77e 2019-08-03 stsp
10839 715dc77e 2019-08-03 stsp __dead static void
10840 715dc77e 2019-08-03 stsp usage_stage(void)
10841 715dc77e 2019-08-03 stsp {
10842 f3055044 2019-08-07 stsp fprintf(stderr, "usage: %s stage [-l] | [-p] [-F response-script] "
10843 35213c7c 2020-07-23 stsp "[-S] [file-path ...]\n",
10844 715dc77e 2019-08-03 stsp getprogname());
10845 715dc77e 2019-08-03 stsp exit(1);
10846 715dc77e 2019-08-03 stsp }
10847 715dc77e 2019-08-03 stsp
10848 715dc77e 2019-08-03 stsp static const struct got_error *
10849 408b4ebc 2019-08-03 stsp print_stage(void *arg, unsigned char status, unsigned char staged_status,
10850 408b4ebc 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
10851 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
10852 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
10853 408b4ebc 2019-08-03 stsp {
10854 408b4ebc 2019-08-03 stsp const struct got_error *err = NULL;
10855 408b4ebc 2019-08-03 stsp char *id_str = NULL;
10856 408b4ebc 2019-08-03 stsp
10857 408b4ebc 2019-08-03 stsp if (staged_status != GOT_STATUS_ADD &&
10858 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_MODIFY &&
10859 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
10860 408b4ebc 2019-08-03 stsp return NULL;
10861 408b4ebc 2019-08-03 stsp
10862 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
10863 408b4ebc 2019-08-03 stsp staged_status == GOT_STATUS_MODIFY)
10864 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, staged_blob_id);
10865 408b4ebc 2019-08-03 stsp else
10866 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, blob_id);
10867 408b4ebc 2019-08-03 stsp if (err)
10868 408b4ebc 2019-08-03 stsp return err;
10869 408b4ebc 2019-08-03 stsp
10870 408b4ebc 2019-08-03 stsp printf("%s %c %s\n", id_str, staged_status, path);
10871 408b4ebc 2019-08-03 stsp free(id_str);
10872 dc424a06 2019-08-07 stsp return NULL;
10873 dc424a06 2019-08-07 stsp }
10874 2e1f37b0 2019-08-08 stsp
10875 dc424a06 2019-08-07 stsp static const struct got_error *
10876 715dc77e 2019-08-03 stsp cmd_stage(int argc, char *argv[])
10877 715dc77e 2019-08-03 stsp {
10878 715dc77e 2019-08-03 stsp const struct got_error *error = NULL;
10879 715dc77e 2019-08-03 stsp struct got_repository *repo = NULL;
10880 715dc77e 2019-08-03 stsp struct got_worktree *worktree = NULL;
10881 715dc77e 2019-08-03 stsp char *cwd = NULL;
10882 715dc77e 2019-08-03 stsp struct got_pathlist_head paths;
10883 715dc77e 2019-08-03 stsp struct got_pathlist_entry *pe;
10884 35213c7c 2020-07-23 stsp int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
10885 dc424a06 2019-08-07 stsp FILE *patch_script_file = NULL;
10886 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
10887 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
10888 715dc77e 2019-08-03 stsp
10889 715dc77e 2019-08-03 stsp TAILQ_INIT(&paths);
10890 715dc77e 2019-08-03 stsp
10891 35213c7c 2020-07-23 stsp while ((ch = getopt(argc, argv, "lpF:S")) != -1) {
10892 715dc77e 2019-08-03 stsp switch (ch) {
10893 408b4ebc 2019-08-03 stsp case 'l':
10894 408b4ebc 2019-08-03 stsp list_stage = 1;
10895 408b4ebc 2019-08-03 stsp break;
10896 dc424a06 2019-08-07 stsp case 'p':
10897 dc424a06 2019-08-07 stsp pflag = 1;
10898 dc424a06 2019-08-07 stsp break;
10899 dc424a06 2019-08-07 stsp case 'F':
10900 dc424a06 2019-08-07 stsp patch_script_path = optarg;
10901 dc424a06 2019-08-07 stsp break;
10902 35213c7c 2020-07-23 stsp case 'S':
10903 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
10904 35213c7c 2020-07-23 stsp break;
10905 715dc77e 2019-08-03 stsp default:
10906 715dc77e 2019-08-03 stsp usage_stage();
10907 715dc77e 2019-08-03 stsp /* NOTREACHED */
10908 715dc77e 2019-08-03 stsp }
10909 715dc77e 2019-08-03 stsp }
10910 715dc77e 2019-08-03 stsp
10911 715dc77e 2019-08-03 stsp argc -= optind;
10912 715dc77e 2019-08-03 stsp argv += optind;
10913 715dc77e 2019-08-03 stsp
10914 715dc77e 2019-08-03 stsp #ifndef PROFILE
10915 715dc77e 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10916 715dc77e 2019-08-03 stsp "unveil", NULL) == -1)
10917 715dc77e 2019-08-03 stsp err(1, "pledge");
10918 715dc77e 2019-08-03 stsp #endif
10919 2db2652d 2019-08-07 stsp if (list_stage && (pflag || patch_script_path))
10920 2db2652d 2019-08-07 stsp errx(1, "-l option cannot be used with other options");
10921 dc424a06 2019-08-07 stsp if (patch_script_path && !pflag)
10922 dc424a06 2019-08-07 stsp errx(1, "-F option can only be used together with -p option");
10923 715dc77e 2019-08-03 stsp
10924 715dc77e 2019-08-03 stsp cwd = getcwd(NULL, 0);
10925 715dc77e 2019-08-03 stsp if (cwd == NULL) {
10926 715dc77e 2019-08-03 stsp error = got_error_from_errno("getcwd");
10927 715dc77e 2019-08-03 stsp goto done;
10928 715dc77e 2019-08-03 stsp }
10929 715dc77e 2019-08-03 stsp
10930 715dc77e 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
10931 fa51e947 2020-03-27 stsp if (error) {
10932 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
10933 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "stage", cwd);
10934 715dc77e 2019-08-03 stsp goto done;
10935 fa51e947 2020-03-27 stsp }
10936 715dc77e 2019-08-03 stsp
10937 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
10938 c9956ddf 2019-09-08 stsp NULL);
10939 715dc77e 2019-08-03 stsp if (error != NULL)
10940 715dc77e 2019-08-03 stsp goto done;
10941 715dc77e 2019-08-03 stsp
10942 dc424a06 2019-08-07 stsp if (patch_script_path) {
10943 dc424a06 2019-08-07 stsp patch_script_file = fopen(patch_script_path, "r");
10944 dc424a06 2019-08-07 stsp if (patch_script_file == NULL) {
10945 dc424a06 2019-08-07 stsp error = got_error_from_errno2("fopen",
10946 dc424a06 2019-08-07 stsp patch_script_path);
10947 dc424a06 2019-08-07 stsp goto done;
10948 dc424a06 2019-08-07 stsp }
10949 dc424a06 2019-08-07 stsp }
10950 9fd7cd22 2019-08-30 stsp error = apply_unveil(got_repo_get_path(repo), 0,
10951 715dc77e 2019-08-03 stsp got_worktree_get_root_path(worktree));
10952 715dc77e 2019-08-03 stsp if (error)
10953 715dc77e 2019-08-03 stsp goto done;
10954 715dc77e 2019-08-03 stsp
10955 10604dce 2021-09-24 thomas error = check_merge_in_progress(worktree, repo);
10956 10604dce 2021-09-24 thomas if (error)
10957 10604dce 2021-09-24 thomas goto done;
10958 10604dce 2021-09-24 thomas
10959 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
10960 6d022e97 2019-08-04 stsp if (error)
10961 6d022e97 2019-08-04 stsp goto done;
10962 715dc77e 2019-08-03 stsp
10963 6d022e97 2019-08-04 stsp if (list_stage)
10964 f6343036 2021-06-22 stsp error = got_worktree_status(worktree, &paths, repo, 0,
10965 408b4ebc 2019-08-03 stsp print_stage, NULL, check_cancelled, NULL);
10966 2e1f37b0 2019-08-08 stsp else {
10967 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
10968 2e1f37b0 2019-08-08 stsp cpa.action = "stage";
10969 dc424a06 2019-08-07 stsp error = got_worktree_stage(worktree, &paths,
10970 dc424a06 2019-08-07 stsp pflag ? NULL : print_status, NULL,
10971 35213c7c 2020-07-23 stsp pflag ? choose_patch : NULL, &cpa,
10972 35213c7c 2020-07-23 stsp allow_bad_symlinks, repo);
10973 2e1f37b0 2019-08-08 stsp }
10974 ad493afc 2019-08-03 stsp done:
10975 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
10976 2e1f37b0 2019-08-08 stsp error == NULL)
10977 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
10978 1d0f4054 2021-06-17 stsp if (repo) {
10979 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
10980 1d0f4054 2021-06-17 stsp if (error == NULL)
10981 1d0f4054 2021-06-17 stsp error = close_err;
10982 1d0f4054 2021-06-17 stsp }
10983 ad493afc 2019-08-03 stsp if (worktree)
10984 ad493afc 2019-08-03 stsp got_worktree_close(worktree);
10985 ad493afc 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
10986 ad493afc 2019-08-03 stsp free((char *)pe->path);
10987 ad493afc 2019-08-03 stsp got_pathlist_free(&paths);
10988 ad493afc 2019-08-03 stsp free(cwd);
10989 ad493afc 2019-08-03 stsp return error;
10990 ad493afc 2019-08-03 stsp }
10991 ad493afc 2019-08-03 stsp
10992 ad493afc 2019-08-03 stsp __dead static void
10993 ad493afc 2019-08-03 stsp usage_unstage(void)
10994 ad493afc 2019-08-03 stsp {
10995 2e1f37b0 2019-08-08 stsp fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
10996 2e1f37b0 2019-08-08 stsp "[file-path ...]\n",
10997 ad493afc 2019-08-03 stsp getprogname());
10998 ad493afc 2019-08-03 stsp exit(1);
10999 ad493afc 2019-08-03 stsp }
11000 ad493afc 2019-08-03 stsp
11001 ad493afc 2019-08-03 stsp
11002 ad493afc 2019-08-03 stsp static const struct got_error *
11003 ad493afc 2019-08-03 stsp cmd_unstage(int argc, char *argv[])
11004 ad493afc 2019-08-03 stsp {
11005 ad493afc 2019-08-03 stsp const struct got_error *error = NULL;
11006 ad493afc 2019-08-03 stsp struct got_repository *repo = NULL;
11007 ad493afc 2019-08-03 stsp struct got_worktree *worktree = NULL;
11008 ad493afc 2019-08-03 stsp char *cwd = NULL;
11009 ad493afc 2019-08-03 stsp struct got_pathlist_head paths;
11010 ad493afc 2019-08-03 stsp struct got_pathlist_entry *pe;
11011 9627c110 2020-04-18 stsp int ch, pflag = 0;
11012 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
11013 2e1f37b0 2019-08-08 stsp FILE *patch_script_file = NULL;
11014 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
11015 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
11016 ad493afc 2019-08-03 stsp
11017 ad493afc 2019-08-03 stsp TAILQ_INIT(&paths);
11018 ad493afc 2019-08-03 stsp
11019 2e1f37b0 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:")) != -1) {
11020 ad493afc 2019-08-03 stsp switch (ch) {
11021 2e1f37b0 2019-08-08 stsp case 'p':
11022 2e1f37b0 2019-08-08 stsp pflag = 1;
11023 2e1f37b0 2019-08-08 stsp break;
11024 2e1f37b0 2019-08-08 stsp case 'F':
11025 2e1f37b0 2019-08-08 stsp patch_script_path = optarg;
11026 2e1f37b0 2019-08-08 stsp break;
11027 ad493afc 2019-08-03 stsp default:
11028 ad493afc 2019-08-03 stsp usage_unstage();
11029 ad493afc 2019-08-03 stsp /* NOTREACHED */
11030 ad493afc 2019-08-03 stsp }
11031 ad493afc 2019-08-03 stsp }
11032 ad493afc 2019-08-03 stsp
11033 ad493afc 2019-08-03 stsp argc -= optind;
11034 ad493afc 2019-08-03 stsp argv += optind;
11035 ad493afc 2019-08-03 stsp
11036 ad493afc 2019-08-03 stsp #ifndef PROFILE
11037 ad493afc 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11038 ad493afc 2019-08-03 stsp "unveil", NULL) == -1)
11039 ad493afc 2019-08-03 stsp err(1, "pledge");
11040 ad493afc 2019-08-03 stsp #endif
11041 2e1f37b0 2019-08-08 stsp if (patch_script_path && !pflag)
11042 2e1f37b0 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
11043 2e1f37b0 2019-08-08 stsp
11044 ad493afc 2019-08-03 stsp cwd = getcwd(NULL, 0);
11045 ad493afc 2019-08-03 stsp if (cwd == NULL) {
11046 ad493afc 2019-08-03 stsp error = got_error_from_errno("getcwd");
11047 ad493afc 2019-08-03 stsp goto done;
11048 ad493afc 2019-08-03 stsp }
11049 ad493afc 2019-08-03 stsp
11050 ad493afc 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
11051 fa51e947 2020-03-27 stsp if (error) {
11052 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11053 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "unstage", cwd);
11054 ad493afc 2019-08-03 stsp goto done;
11055 fa51e947 2020-03-27 stsp }
11056 ad493afc 2019-08-03 stsp
11057 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
11058 c9956ddf 2019-09-08 stsp NULL);
11059 ad493afc 2019-08-03 stsp if (error != NULL)
11060 ad493afc 2019-08-03 stsp goto done;
11061 ad493afc 2019-08-03 stsp
11062 2e1f37b0 2019-08-08 stsp if (patch_script_path) {
11063 2e1f37b0 2019-08-08 stsp patch_script_file = fopen(patch_script_path, "r");
11064 2e1f37b0 2019-08-08 stsp if (patch_script_file == NULL) {
11065 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fopen",
11066 2e1f37b0 2019-08-08 stsp patch_script_path);
11067 2e1f37b0 2019-08-08 stsp goto done;
11068 2e1f37b0 2019-08-08 stsp }
11069 2e1f37b0 2019-08-08 stsp }
11070 2e1f37b0 2019-08-08 stsp
11071 00f36e47 2019-09-06 stsp error = apply_unveil(got_repo_get_path(repo), 0,
11072 ad493afc 2019-08-03 stsp got_worktree_get_root_path(worktree));
11073 ad493afc 2019-08-03 stsp if (error)
11074 ad493afc 2019-08-03 stsp goto done;
11075 ad493afc 2019-08-03 stsp
11076 ad493afc 2019-08-03 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
11077 ad493afc 2019-08-03 stsp if (error)
11078 ad493afc 2019-08-03 stsp goto done;
11079 ad493afc 2019-08-03 stsp
11080 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
11081 2e1f37b0 2019-08-08 stsp cpa.action = "unstage";
11082 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
11083 ad493afc 2019-08-03 stsp error = got_worktree_unstage(worktree, &paths, update_progress,
11084 9627c110 2020-04-18 stsp &upa, pflag ? choose_patch : NULL, &cpa, repo);
11085 9627c110 2020-04-18 stsp if (!error)
11086 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
11087 715dc77e 2019-08-03 stsp done:
11088 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
11089 2e1f37b0 2019-08-08 stsp error == NULL)
11090 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
11091 1d0f4054 2021-06-17 stsp if (repo) {
11092 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
11093 1d0f4054 2021-06-17 stsp if (error == NULL)
11094 1d0f4054 2021-06-17 stsp error = close_err;
11095 1d0f4054 2021-06-17 stsp }
11096 715dc77e 2019-08-03 stsp if (worktree)
11097 715dc77e 2019-08-03 stsp got_worktree_close(worktree);
11098 715dc77e 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
11099 715dc77e 2019-08-03 stsp free((char *)pe->path);
11100 715dc77e 2019-08-03 stsp got_pathlist_free(&paths);
11101 715dc77e 2019-08-03 stsp free(cwd);
11102 01073a5d 2019-08-22 stsp return error;
11103 01073a5d 2019-08-22 stsp }
11104 01073a5d 2019-08-22 stsp
11105 01073a5d 2019-08-22 stsp __dead static void
11106 01073a5d 2019-08-22 stsp usage_cat(void)
11107 01073a5d 2019-08-22 stsp {
11108 896e9b6f 2019-08-26 stsp fprintf(stderr, "usage: %s cat [-r repository ] [ -c commit ] [ -P ] "
11109 896e9b6f 2019-08-26 stsp "arg1 [arg2 ...]\n", getprogname());
11110 01073a5d 2019-08-22 stsp exit(1);
11111 01073a5d 2019-08-22 stsp }
11112 01073a5d 2019-08-22 stsp
11113 01073a5d 2019-08-22 stsp static const struct got_error *
11114 01073a5d 2019-08-22 stsp cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11115 01073a5d 2019-08-22 stsp {
11116 01073a5d 2019-08-22 stsp const struct got_error *err;
11117 01073a5d 2019-08-22 stsp struct got_blob_object *blob;
11118 01073a5d 2019-08-22 stsp
11119 01073a5d 2019-08-22 stsp err = got_object_open_as_blob(&blob, repo, id, 8192);
11120 01073a5d 2019-08-22 stsp if (err)
11121 01073a5d 2019-08-22 stsp return err;
11122 01073a5d 2019-08-22 stsp
11123 01073a5d 2019-08-22 stsp err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob);
11124 01073a5d 2019-08-22 stsp got_object_blob_close(blob);
11125 01073a5d 2019-08-22 stsp return err;
11126 01073a5d 2019-08-22 stsp }
11127 01073a5d 2019-08-22 stsp
11128 01073a5d 2019-08-22 stsp static const struct got_error *
11129 01073a5d 2019-08-22 stsp cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11130 01073a5d 2019-08-22 stsp {
11131 01073a5d 2019-08-22 stsp const struct got_error *err;
11132 01073a5d 2019-08-22 stsp struct got_tree_object *tree;
11133 56e0773d 2019-11-28 stsp int nentries, i;
11134 01073a5d 2019-08-22 stsp
11135 01073a5d 2019-08-22 stsp err = got_object_open_as_tree(&tree, repo, id);
11136 01073a5d 2019-08-22 stsp if (err)
11137 01073a5d 2019-08-22 stsp return err;
11138 01073a5d 2019-08-22 stsp
11139 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
11140 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
11141 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
11142 01073a5d 2019-08-22 stsp char *id_str;
11143 01073a5d 2019-08-22 stsp if (sigint_received || sigpipe_received)
11144 01073a5d 2019-08-22 stsp break;
11145 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
11146 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
11147 01073a5d 2019-08-22 stsp if (err)
11148 01073a5d 2019-08-22 stsp break;
11149 56e0773d 2019-11-28 stsp fprintf(outfile, "%s %.7o %s\n", id_str,
11150 56e0773d 2019-11-28 stsp got_tree_entry_get_mode(te),
11151 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te));
11152 01073a5d 2019-08-22 stsp free(id_str);
11153 01073a5d 2019-08-22 stsp }
11154 01073a5d 2019-08-22 stsp
11155 01073a5d 2019-08-22 stsp got_object_tree_close(tree);
11156 01073a5d 2019-08-22 stsp return err;
11157 01073a5d 2019-08-22 stsp }
11158 01073a5d 2019-08-22 stsp
11159 01073a5d 2019-08-22 stsp static const struct got_error *
11160 01073a5d 2019-08-22 stsp cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11161 01073a5d 2019-08-22 stsp {
11162 01073a5d 2019-08-22 stsp const struct got_error *err;
11163 01073a5d 2019-08-22 stsp struct got_commit_object *commit;
11164 01073a5d 2019-08-22 stsp const struct got_object_id_queue *parent_ids;
11165 01073a5d 2019-08-22 stsp struct got_object_qid *pid;
11166 01073a5d 2019-08-22 stsp char *id_str = NULL;
11167 24ea5512 2019-08-22 stsp const char *logmsg = NULL;
11168 01073a5d 2019-08-22 stsp
11169 01073a5d 2019-08-22 stsp err = got_object_open_as_commit(&commit, repo, id);
11170 01073a5d 2019-08-22 stsp if (err)
11171 01073a5d 2019-08-22 stsp return err;
11172 01073a5d 2019-08-22 stsp
11173 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
11174 01073a5d 2019-08-22 stsp if (err)
11175 01073a5d 2019-08-22 stsp goto done;
11176 01073a5d 2019-08-22 stsp
11177 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str);
11178 01073a5d 2019-08-22 stsp parent_ids = got_object_commit_get_parent_ids(commit);
11179 8aa93786 2019-08-22 stsp fprintf(outfile, "numparents %d\n",
11180 01073a5d 2019-08-22 stsp got_object_commit_get_nparents(commit));
11181 dbdddfee 2021-06-23 naddy STAILQ_FOREACH(pid, parent_ids, entry) {
11182 01073a5d 2019-08-22 stsp char *pid_str;
11183 01073a5d 2019-08-22 stsp err = got_object_id_str(&pid_str, pid->id);
11184 01073a5d 2019-08-22 stsp if (err)
11185 01073a5d 2019-08-22 stsp goto done;
11186 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str);
11187 01073a5d 2019-08-22 stsp free(pid_str);
11188 01073a5d 2019-08-22 stsp }
11189 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_AUTHOR,
11190 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
11191 1367695b 2020-09-26 naddy (long long)got_object_commit_get_author_time(commit));
11192 01073a5d 2019-08-22 stsp
11193 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_COMMITTER,
11194 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
11195 1367695b 2020-09-26 naddy (long long)got_object_commit_get_committer_time(commit));
11196 01073a5d 2019-08-22 stsp
11197 24ea5512 2019-08-22 stsp logmsg = got_object_commit_get_logmsg_raw(commit);
11198 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
11199 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", logmsg);
11200 01073a5d 2019-08-22 stsp done:
11201 01073a5d 2019-08-22 stsp free(id_str);
11202 01073a5d 2019-08-22 stsp got_object_commit_close(commit);
11203 01073a5d 2019-08-22 stsp return err;
11204 01073a5d 2019-08-22 stsp }
11205 01073a5d 2019-08-22 stsp
11206 01073a5d 2019-08-22 stsp static const struct got_error *
11207 01073a5d 2019-08-22 stsp cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
11208 01073a5d 2019-08-22 stsp {
11209 01073a5d 2019-08-22 stsp const struct got_error *err;
11210 01073a5d 2019-08-22 stsp struct got_tag_object *tag;
11211 01073a5d 2019-08-22 stsp char *id_str = NULL;
11212 01073a5d 2019-08-22 stsp const char *tagmsg = NULL;
11213 01073a5d 2019-08-22 stsp
11214 01073a5d 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
11215 01073a5d 2019-08-22 stsp if (err)
11216 01073a5d 2019-08-22 stsp return err;
11217 01073a5d 2019-08-22 stsp
11218 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
11219 01073a5d 2019-08-22 stsp if (err)
11220 01073a5d 2019-08-22 stsp goto done;
11221 01073a5d 2019-08-22 stsp
11222 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str);
11223 e15d5241 2019-08-22 stsp
11224 01073a5d 2019-08-22 stsp switch (got_object_tag_get_object_type(tag)) {
11225 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
11226 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11227 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_BLOB);
11228 01073a5d 2019-08-22 stsp break;
11229 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
11230 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11231 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TREE);
11232 01073a5d 2019-08-22 stsp break;
11233 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
11234 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11235 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_COMMIT);
11236 01073a5d 2019-08-22 stsp break;
11237 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
11238 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
11239 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TAG);
11240 01073a5d 2019-08-22 stsp break;
11241 01073a5d 2019-08-22 stsp default:
11242 01073a5d 2019-08-22 stsp break;
11243 01073a5d 2019-08-22 stsp }
11244 01073a5d 2019-08-22 stsp
11245 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG,
11246 e15d5241 2019-08-22 stsp got_object_tag_get_name(tag));
11247 e15d5241 2019-08-22 stsp
11248 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_TAG_LABEL_TAGGER,
11249 8aa93786 2019-08-22 stsp got_object_tag_get_tagger(tag),
11250 1367695b 2020-09-26 naddy (long long)got_object_tag_get_tagger_time(tag));
11251 01073a5d 2019-08-22 stsp
11252 01073a5d 2019-08-22 stsp tagmsg = got_object_tag_get_message(tag);
11253 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
11254 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", tagmsg);
11255 01073a5d 2019-08-22 stsp done:
11256 01073a5d 2019-08-22 stsp free(id_str);
11257 01073a5d 2019-08-22 stsp got_object_tag_close(tag);
11258 01073a5d 2019-08-22 stsp return err;
11259 01073a5d 2019-08-22 stsp }
11260 01073a5d 2019-08-22 stsp
11261 01073a5d 2019-08-22 stsp static const struct got_error *
11262 01073a5d 2019-08-22 stsp cmd_cat(int argc, char *argv[])
11263 01073a5d 2019-08-22 stsp {
11264 01073a5d 2019-08-22 stsp const struct got_error *error;
11265 01073a5d 2019-08-22 stsp struct got_repository *repo = NULL;
11266 01073a5d 2019-08-22 stsp struct got_worktree *worktree = NULL;
11267 01073a5d 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *label = NULL;
11268 896e9b6f 2019-08-26 stsp const char *commit_id_str = NULL;
11269 896e9b6f 2019-08-26 stsp struct got_object_id *id = NULL, *commit_id = NULL;
11270 896e9b6f 2019-08-26 stsp int ch, obj_type, i, force_path = 0;
11271 84de9106 2020-12-26 stsp struct got_reflist_head refs;
11272 84de9106 2020-12-26 stsp
11273 d9dff0e5 2020-12-26 stsp TAILQ_INIT(&refs);
11274 01073a5d 2019-08-22 stsp
11275 01073a5d 2019-08-22 stsp #ifndef PROFILE
11276 01073a5d 2019-08-22 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
11277 01073a5d 2019-08-22 stsp NULL) == -1)
11278 01073a5d 2019-08-22 stsp err(1, "pledge");
11279 01073a5d 2019-08-22 stsp #endif
11280 01073a5d 2019-08-22 stsp
11281 896e9b6f 2019-08-26 stsp while ((ch = getopt(argc, argv, "c:r:P")) != -1) {
11282 01073a5d 2019-08-22 stsp switch (ch) {
11283 896e9b6f 2019-08-26 stsp case 'c':
11284 896e9b6f 2019-08-26 stsp commit_id_str = optarg;
11285 896e9b6f 2019-08-26 stsp break;
11286 01073a5d 2019-08-22 stsp case 'r':
11287 01073a5d 2019-08-22 stsp repo_path = realpath(optarg, NULL);
11288 01073a5d 2019-08-22 stsp if (repo_path == NULL)
11289 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
11290 9ba1d308 2019-10-21 stsp optarg);
11291 01073a5d 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
11292 01073a5d 2019-08-22 stsp break;
11293 896e9b6f 2019-08-26 stsp case 'P':
11294 896e9b6f 2019-08-26 stsp force_path = 1;
11295 896e9b6f 2019-08-26 stsp break;
11296 01073a5d 2019-08-22 stsp default:
11297 01073a5d 2019-08-22 stsp usage_cat();
11298 01073a5d 2019-08-22 stsp /* NOTREACHED */
11299 01073a5d 2019-08-22 stsp }
11300 01073a5d 2019-08-22 stsp }
11301 01073a5d 2019-08-22 stsp
11302 01073a5d 2019-08-22 stsp argc -= optind;
11303 01073a5d 2019-08-22 stsp argv += optind;
11304 01073a5d 2019-08-22 stsp
11305 01073a5d 2019-08-22 stsp cwd = getcwd(NULL, 0);
11306 01073a5d 2019-08-22 stsp if (cwd == NULL) {
11307 01073a5d 2019-08-22 stsp error = got_error_from_errno("getcwd");
11308 01073a5d 2019-08-22 stsp goto done;
11309 01073a5d 2019-08-22 stsp }
11310 01073a5d 2019-08-22 stsp error = got_worktree_open(&worktree, cwd);
11311 01073a5d 2019-08-22 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
11312 01073a5d 2019-08-22 stsp goto done;
11313 01073a5d 2019-08-22 stsp if (worktree) {
11314 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
11315 01073a5d 2019-08-22 stsp repo_path = strdup(
11316 01073a5d 2019-08-22 stsp got_worktree_get_repo_path(worktree));
11317 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
11318 01073a5d 2019-08-22 stsp error = got_error_from_errno("strdup");
11319 01073a5d 2019-08-22 stsp goto done;
11320 01073a5d 2019-08-22 stsp }
11321 01073a5d 2019-08-22 stsp }
11322 01073a5d 2019-08-22 stsp }
11323 01073a5d 2019-08-22 stsp
11324 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
11325 01073a5d 2019-08-22 stsp repo_path = getcwd(NULL, 0);
11326 01073a5d 2019-08-22 stsp if (repo_path == NULL)
11327 01073a5d 2019-08-22 stsp return got_error_from_errno("getcwd");
11328 01073a5d 2019-08-22 stsp }
11329 01073a5d 2019-08-22 stsp
11330 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
11331 01073a5d 2019-08-22 stsp free(repo_path);
11332 01073a5d 2019-08-22 stsp if (error != NULL)
11333 01073a5d 2019-08-22 stsp goto done;
11334 01073a5d 2019-08-22 stsp
11335 01073a5d 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
11336 896e9b6f 2019-08-26 stsp if (error)
11337 896e9b6f 2019-08-26 stsp goto done;
11338 896e9b6f 2019-08-26 stsp
11339 84de9106 2020-12-26 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
11340 84de9106 2020-12-26 stsp if (error)
11341 84de9106 2020-12-26 stsp goto done;
11342 84de9106 2020-12-26 stsp
11343 896e9b6f 2019-08-26 stsp if (commit_id_str == NULL)
11344 896e9b6f 2019-08-26 stsp commit_id_str = GOT_REF_HEAD;
11345 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
11346 84de9106 2020-12-26 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
11347 01073a5d 2019-08-22 stsp if (error)
11348 01073a5d 2019-08-22 stsp goto done;
11349 01073a5d 2019-08-22 stsp
11350 01073a5d 2019-08-22 stsp for (i = 0; i < argc; i++) {
11351 896e9b6f 2019-08-26 stsp if (force_path) {
11352 896e9b6f 2019-08-26 stsp error = got_object_id_by_path(&id, repo, commit_id,
11353 896e9b6f 2019-08-26 stsp argv[i]);
11354 896e9b6f 2019-08-26 stsp if (error)
11355 896e9b6f 2019-08-26 stsp break;
11356 896e9b6f 2019-08-26 stsp } else {
11357 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id, &label, argv[i],
11358 84de9106 2020-12-26 stsp GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */,
11359 84de9106 2020-12-26 stsp repo);
11360 896e9b6f 2019-08-26 stsp if (error) {
11361 896e9b6f 2019-08-26 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR &&
11362 896e9b6f 2019-08-26 stsp error->code != GOT_ERR_NOT_REF)
11363 896e9b6f 2019-08-26 stsp break;
11364 896e9b6f 2019-08-26 stsp error = got_object_id_by_path(&id, repo,
11365 896e9b6f 2019-08-26 stsp commit_id, argv[i]);
11366 896e9b6f 2019-08-26 stsp if (error)
11367 896e9b6f 2019-08-26 stsp break;
11368 896e9b6f 2019-08-26 stsp }
11369 896e9b6f 2019-08-26 stsp }
11370 01073a5d 2019-08-22 stsp
11371 01073a5d 2019-08-22 stsp error = got_object_get_type(&obj_type, repo, id);
11372 01073a5d 2019-08-22 stsp if (error)
11373 01073a5d 2019-08-22 stsp break;
11374 01073a5d 2019-08-22 stsp
11375 01073a5d 2019-08-22 stsp switch (obj_type) {
11376 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
11377 01073a5d 2019-08-22 stsp error = cat_blob(id, repo, stdout);
11378 01073a5d 2019-08-22 stsp break;
11379 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
11380 01073a5d 2019-08-22 stsp error = cat_tree(id, repo, stdout);
11381 01073a5d 2019-08-22 stsp break;
11382 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
11383 01073a5d 2019-08-22 stsp error = cat_commit(id, repo, stdout);
11384 01073a5d 2019-08-22 stsp break;
11385 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
11386 01073a5d 2019-08-22 stsp error = cat_tag(id, repo, stdout);
11387 01073a5d 2019-08-22 stsp break;
11388 01073a5d 2019-08-22 stsp default:
11389 01073a5d 2019-08-22 stsp error = got_error(GOT_ERR_OBJ_TYPE);
11390 01073a5d 2019-08-22 stsp break;
11391 01073a5d 2019-08-22 stsp }
11392 01073a5d 2019-08-22 stsp if (error)
11393 01073a5d 2019-08-22 stsp break;
11394 01073a5d 2019-08-22 stsp free(label);
11395 01073a5d 2019-08-22 stsp label = NULL;
11396 01073a5d 2019-08-22 stsp free(id);
11397 01073a5d 2019-08-22 stsp id = NULL;
11398 01073a5d 2019-08-22 stsp }
11399 01073a5d 2019-08-22 stsp done:
11400 01073a5d 2019-08-22 stsp free(label);
11401 01073a5d 2019-08-22 stsp free(id);
11402 896e9b6f 2019-08-26 stsp free(commit_id);
11403 01073a5d 2019-08-22 stsp if (worktree)
11404 01073a5d 2019-08-22 stsp got_worktree_close(worktree);
11405 01073a5d 2019-08-22 stsp if (repo) {
11406 1d0f4054 2021-06-17 stsp const struct got_error *close_err = got_repo_close(repo);
11407 01073a5d 2019-08-22 stsp if (error == NULL)
11408 1d0f4054 2021-06-17 stsp error = close_err;
11409 b2118c49 2020-07-28 stsp }
11410 84de9106 2020-12-26 stsp got_ref_list_free(&refs);
11411 b2118c49 2020-07-28 stsp return error;
11412 b2118c49 2020-07-28 stsp }
11413 b2118c49 2020-07-28 stsp
11414 b2118c49 2020-07-28 stsp __dead static void
11415 b2118c49 2020-07-28 stsp usage_info(void)
11416 b2118c49 2020-07-28 stsp {
11417 b2118c49 2020-07-28 stsp fprintf(stderr, "usage: %s info [path ...]\n",
11418 b2118c49 2020-07-28 stsp getprogname());
11419 b2118c49 2020-07-28 stsp exit(1);
11420 b2118c49 2020-07-28 stsp }
11421 b2118c49 2020-07-28 stsp
11422 b2118c49 2020-07-28 stsp static const struct got_error *
11423 b2118c49 2020-07-28 stsp print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
11424 b2118c49 2020-07-28 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
11425 b2118c49 2020-07-28 stsp struct got_object_id *commit_id)
11426 b2118c49 2020-07-28 stsp {
11427 b2118c49 2020-07-28 stsp const struct got_error *err = NULL;
11428 b2118c49 2020-07-28 stsp char *id_str = NULL;
11429 b2118c49 2020-07-28 stsp char datebuf[128];
11430 b2118c49 2020-07-28 stsp struct tm mytm, *tm;
11431 b2118c49 2020-07-28 stsp struct got_pathlist_head *paths = arg;
11432 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
11433 b2118c49 2020-07-28 stsp
11434 b2118c49 2020-07-28 stsp /*
11435 b2118c49 2020-07-28 stsp * Clear error indication from any of the path arguments which
11436 b2118c49 2020-07-28 stsp * would cause this file index entry to be displayed.
11437 b2118c49 2020-07-28 stsp */
11438 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, paths, entry) {
11439 b2118c49 2020-07-28 stsp if (got_path_cmp(path, pe->path, strlen(path),
11440 b2118c49 2020-07-28 stsp pe->path_len) == 0 ||
11441 b2118c49 2020-07-28 stsp got_path_is_child(path, pe->path, pe->path_len))
11442 b2118c49 2020-07-28 stsp pe->data = NULL; /* no error */
11443 b2118c49 2020-07-28 stsp }
11444 b2118c49 2020-07-28 stsp
11445 b2118c49 2020-07-28 stsp printf(GOT_COMMIT_SEP_STR);
11446 b2118c49 2020-07-28 stsp if (S_ISLNK(mode))
11447 b2118c49 2020-07-28 stsp printf("symlink: %s\n", path);
11448 b2118c49 2020-07-28 stsp else if (S_ISREG(mode)) {
11449 b2118c49 2020-07-28 stsp printf("file: %s\n", path);
11450 b2118c49 2020-07-28 stsp printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO));
11451 b2118c49 2020-07-28 stsp } else if (S_ISDIR(mode))
11452 b2118c49 2020-07-28 stsp printf("directory: %s\n", path);
11453 b2118c49 2020-07-28 stsp else
11454 b2118c49 2020-07-28 stsp printf("something: %s\n", path);
11455 b2118c49 2020-07-28 stsp
11456 b2118c49 2020-07-28 stsp tm = localtime_r(&mtime, &mytm);
11457 b2118c49 2020-07-28 stsp if (tm == NULL)
11458 b2118c49 2020-07-28 stsp return NULL;
11459 ec6d1a36 2021-03-21 jrick if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0)
11460 b2118c49 2020-07-28 stsp return got_error(GOT_ERR_NO_SPACE);
11461 b2118c49 2020-07-28 stsp printf("timestamp: %s\n", datebuf);
11462 b2118c49 2020-07-28 stsp
11463 b2118c49 2020-07-28 stsp if (blob_id) {
11464 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, blob_id);
11465 b2118c49 2020-07-28 stsp if (err)
11466 b2118c49 2020-07-28 stsp return err;
11467 b2118c49 2020-07-28 stsp printf("based on blob: %s\n", id_str);
11468 b2118c49 2020-07-28 stsp free(id_str);
11469 b2118c49 2020-07-28 stsp }
11470 b2118c49 2020-07-28 stsp
11471 b2118c49 2020-07-28 stsp if (staged_blob_id) {
11472 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, staged_blob_id);
11473 b2118c49 2020-07-28 stsp if (err)
11474 b2118c49 2020-07-28 stsp return err;
11475 b2118c49 2020-07-28 stsp printf("based on staged blob: %s\n", id_str);
11476 b2118c49 2020-07-28 stsp free(id_str);
11477 b2118c49 2020-07-28 stsp }
11478 b2118c49 2020-07-28 stsp
11479 b2118c49 2020-07-28 stsp if (commit_id) {
11480 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, commit_id);
11481 b2118c49 2020-07-28 stsp if (err)
11482 b2118c49 2020-07-28 stsp return err;
11483 b2118c49 2020-07-28 stsp printf("based on commit: %s\n", id_str);
11484 b2118c49 2020-07-28 stsp free(id_str);
11485 b2118c49 2020-07-28 stsp }
11486 b2118c49 2020-07-28 stsp
11487 b2118c49 2020-07-28 stsp return NULL;
11488 b2118c49 2020-07-28 stsp }
11489 b2118c49 2020-07-28 stsp
11490 b2118c49 2020-07-28 stsp static const struct got_error *
11491 b2118c49 2020-07-28 stsp cmd_info(int argc, char *argv[])
11492 b2118c49 2020-07-28 stsp {
11493 b2118c49 2020-07-28 stsp const struct got_error *error = NULL;
11494 b2118c49 2020-07-28 stsp struct got_worktree *worktree = NULL;
11495 b2118c49 2020-07-28 stsp char *cwd = NULL, *id_str = NULL;
11496 b2118c49 2020-07-28 stsp struct got_pathlist_head paths;
11497 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
11498 b2118c49 2020-07-28 stsp char *uuidstr = NULL;
11499 b2118c49 2020-07-28 stsp int ch, show_files = 0;
11500 b2118c49 2020-07-28 stsp
11501 b2118c49 2020-07-28 stsp TAILQ_INIT(&paths);
11502 b2118c49 2020-07-28 stsp
11503 b2118c49 2020-07-28 stsp while ((ch = getopt(argc, argv, "")) != -1) {
11504 b2118c49 2020-07-28 stsp switch (ch) {
11505 b2118c49 2020-07-28 stsp default:
11506 b2118c49 2020-07-28 stsp usage_info();
11507 b2118c49 2020-07-28 stsp /* NOTREACHED */
11508 b2118c49 2020-07-28 stsp }
11509 01073a5d 2019-08-22 stsp }
11510 b2118c49 2020-07-28 stsp
11511 b2118c49 2020-07-28 stsp argc -= optind;
11512 b2118c49 2020-07-28 stsp argv += optind;
11513 b2118c49 2020-07-28 stsp
11514 b2118c49 2020-07-28 stsp #ifndef PROFILE
11515 b2118c49 2020-07-28 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
11516 b2118c49 2020-07-28 stsp NULL) == -1)
11517 b2118c49 2020-07-28 stsp err(1, "pledge");
11518 b2118c49 2020-07-28 stsp #endif
11519 b2118c49 2020-07-28 stsp cwd = getcwd(NULL, 0);
11520 b2118c49 2020-07-28 stsp if (cwd == NULL) {
11521 b2118c49 2020-07-28 stsp error = got_error_from_errno("getcwd");
11522 b2118c49 2020-07-28 stsp goto done;
11523 b2118c49 2020-07-28 stsp }
11524 b2118c49 2020-07-28 stsp
11525 b2118c49 2020-07-28 stsp error = got_worktree_open(&worktree, cwd);
11526 b2118c49 2020-07-28 stsp if (error) {
11527 b2118c49 2020-07-28 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
11528 8ea5c997 2021-02-07 naddy error = wrap_not_worktree_error(error, "info", cwd);
11529 b2118c49 2020-07-28 stsp goto done;
11530 b2118c49 2020-07-28 stsp }
11531 b2118c49 2020-07-28 stsp
11532 b2118c49 2020-07-28 stsp error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree));
11533 b2118c49 2020-07-28 stsp if (error)
11534 b2118c49 2020-07-28 stsp goto done;
11535 b2118c49 2020-07-28 stsp
11536 b2118c49 2020-07-28 stsp if (argc >= 1) {
11537 b2118c49 2020-07-28 stsp error = get_worktree_paths_from_argv(&paths, argc, argv,
11538 b2118c49 2020-07-28 stsp worktree);
11539 b2118c49 2020-07-28 stsp if (error)
11540 b2118c49 2020-07-28 stsp goto done;
11541 b2118c49 2020-07-28 stsp show_files = 1;
11542 b2118c49 2020-07-28 stsp }
11543 b2118c49 2020-07-28 stsp
11544 b2118c49 2020-07-28 stsp error = got_object_id_str(&id_str,
11545 b2118c49 2020-07-28 stsp got_worktree_get_base_commit_id(worktree));
11546 b2118c49 2020-07-28 stsp if (error)
11547 b2118c49 2020-07-28 stsp goto done;
11548 b2118c49 2020-07-28 stsp
11549 b2118c49 2020-07-28 stsp error = got_worktree_get_uuid(&uuidstr, worktree);
11550 b2118c49 2020-07-28 stsp if (error)
11551 b2118c49 2020-07-28 stsp goto done;
11552 b2118c49 2020-07-28 stsp
11553 b2118c49 2020-07-28 stsp printf("work tree: %s\n", got_worktree_get_root_path(worktree));
11554 b2118c49 2020-07-28 stsp printf("work tree base commit: %s\n", id_str);
11555 b2118c49 2020-07-28 stsp printf("work tree path prefix: %s\n",
11556 b2118c49 2020-07-28 stsp got_worktree_get_path_prefix(worktree));
11557 b2118c49 2020-07-28 stsp printf("work tree branch reference: %s\n",
11558 b2118c49 2020-07-28 stsp got_worktree_get_head_ref_name(worktree));
11559 b2118c49 2020-07-28 stsp printf("work tree UUID: %s\n", uuidstr);
11560 b2118c49 2020-07-28 stsp printf("repository: %s\n", got_worktree_get_repo_path(worktree));
11561 b2118c49 2020-07-28 stsp
11562 b2118c49 2020-07-28 stsp if (show_files) {
11563 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
11564 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
11565 b2118c49 2020-07-28 stsp if (pe->path_len == 0)
11566 b2118c49 2020-07-28 stsp continue;
11567 b2118c49 2020-07-28 stsp /*
11568 b2118c49 2020-07-28 stsp * Assume this path will fail. This will be corrected
11569 b2118c49 2020-07-28 stsp * in print_path_info() in case the path does suceeed.
11570 b2118c49 2020-07-28 stsp */
11571 b2118c49 2020-07-28 stsp pe->data = (void *)got_error_path(pe->path,
11572 b2118c49 2020-07-28 stsp GOT_ERR_BAD_PATH);
11573 b2118c49 2020-07-28 stsp }
11574 b2118c49 2020-07-28 stsp error = got_worktree_path_info(worktree, &paths,
11575 b2118c49 2020-07-28 stsp print_path_info, &paths, check_cancelled, NULL);
11576 b2118c49 2020-07-28 stsp if (error)
11577 b2118c49 2020-07-28 stsp goto done;
11578 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
11579 b2118c49 2020-07-28 stsp if (pe->data != NULL) {
11580 b2118c49 2020-07-28 stsp error = pe->data; /* bad path */
11581 b2118c49 2020-07-28 stsp break;
11582 b2118c49 2020-07-28 stsp }
11583 b2118c49 2020-07-28 stsp }
11584 b2118c49 2020-07-28 stsp }
11585 b2118c49 2020-07-28 stsp done:
11586 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry)
11587 b2118c49 2020-07-28 stsp free((char *)pe->path);
11588 b2118c49 2020-07-28 stsp got_pathlist_free(&paths);
11589 b2118c49 2020-07-28 stsp free(cwd);
11590 b2118c49 2020-07-28 stsp free(id_str);
11591 b2118c49 2020-07-28 stsp free(uuidstr);
11592 0ebf8283 2019-07-24 stsp return error;
11593 0ebf8283 2019-07-24 stsp }