Blame


1 5c860e29 2018-03-12 stsp /*
2 f42b1b34 2018-03-12 stsp * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 5aa81393 2020-01-06 stsp * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 93658fb9 2020-03-18 stsp * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 5c860e29 2018-03-12 stsp *
6 5c860e29 2018-03-12 stsp * Permission to use, copy, modify, and distribute this software for any
7 5c860e29 2018-03-12 stsp * purpose with or without fee is hereby granted, provided that the above
8 5c860e29 2018-03-12 stsp * copyright notice and this permission notice appear in all copies.
9 5c860e29 2018-03-12 stsp *
10 5c860e29 2018-03-12 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 5c860e29 2018-03-12 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 5c860e29 2018-03-12 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 5c860e29 2018-03-12 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 5c860e29 2018-03-12 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 5c860e29 2018-03-12 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 5c860e29 2018-03-12 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 5c860e29 2018-03-12 stsp */
18 5c860e29 2018-03-12 stsp
19 f42b1b34 2018-03-12 stsp #include <sys/queue.h>
20 c0768b0f 2018-06-10 stsp #include <sys/types.h>
21 5de5890b 2018-10-18 stsp #include <sys/stat.h>
22 3c45a30a 2019-05-12 jcs #include <sys/param.h>
23 33ad4cbe 2019-05-12 jcs #include <sys/wait.h>
24 f42b1b34 2018-03-12 stsp
25 5c860e29 2018-03-12 stsp #include <err.h>
26 5c860e29 2018-03-12 stsp #include <errno.h>
27 12463d8b 2019-12-13 stsp #include <fcntl.h>
28 12ce7a6c 2019-08-12 stsp #include <limits.h>
29 5c860e29 2018-03-12 stsp #include <locale.h>
30 818c7501 2019-07-11 stsp #include <ctype.h>
31 99437157 2018-11-11 stsp #include <signal.h>
32 5c860e29 2018-03-12 stsp #include <stdio.h>
33 5c860e29 2018-03-12 stsp #include <stdlib.h>
34 5c860e29 2018-03-12 stsp #include <string.h>
35 5c860e29 2018-03-12 stsp #include <unistd.h>
36 c09a553d 2018-03-12 stsp #include <libgen.h>
37 c0768b0f 2018-06-10 stsp #include <time.h>
38 33ad4cbe 2019-05-12 jcs #include <paths.h>
39 6841bf13 2019-11-29 kn #include <regex.h>
40 83cd27f8 2020-01-13 stsp #include <getopt.h>
41 d2cdc636 2020-03-18 stsp #include <util.h>
42 5c860e29 2018-03-12 stsp
43 53ccebc2 2019-07-30 stsp #include "got_version.h"
44 f42b1b34 2018-03-12 stsp #include "got_error.h"
45 f42b1b34 2018-03-12 stsp #include "got_object.h"
46 5261c201 2018-04-01 stsp #include "got_reference.h"
47 f42b1b34 2018-03-12 stsp #include "got_repository.h"
48 1dd54920 2019-05-11 stsp #include "got_path.h"
49 e6209546 2019-08-22 stsp #include "got_cancel.h"
50 c09a553d 2018-03-12 stsp #include "got_worktree.h"
51 79109fed 2018-03-27 stsp #include "got_diff.h"
52 372ccdbb 2018-06-10 stsp #include "got_commit_graph.h"
53 6f23baec 2020-03-18 stsp #include "got_fetch.h"
54 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 5c860e29 2018-03-12 stsp
58 5c860e29 2018-03-12 stsp #ifndef nitems
59 5c860e29 2018-03-12 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
60 5c860e29 2018-03-12 stsp #endif
61 99437157 2018-11-11 stsp
62 99437157 2018-11-11 stsp static volatile sig_atomic_t sigint_received;
63 99437157 2018-11-11 stsp static volatile sig_atomic_t sigpipe_received;
64 99437157 2018-11-11 stsp
65 99437157 2018-11-11 stsp static void
66 99437157 2018-11-11 stsp catch_sigint(int signo)
67 99437157 2018-11-11 stsp {
68 99437157 2018-11-11 stsp sigint_received = 1;
69 99437157 2018-11-11 stsp }
70 99437157 2018-11-11 stsp
71 99437157 2018-11-11 stsp static void
72 99437157 2018-11-11 stsp catch_sigpipe(int signo)
73 99437157 2018-11-11 stsp {
74 99437157 2018-11-11 stsp sigpipe_received = 1;
75 99437157 2018-11-11 stsp }
76 5c860e29 2018-03-12 stsp
77 99437157 2018-11-11 stsp
78 8cfb4057 2019-07-09 stsp struct got_cmd {
79 5c860e29 2018-03-12 stsp const char *cmd_name;
80 d7d4f210 2018-03-12 stsp const struct got_error *(*cmd_main)(int, char *[]);
81 1b6b95a8 2018-03-12 stsp void (*cmd_usage)(void);
82 97b3a7be 2019-07-09 stsp const char *cmd_alias;
83 5c860e29 2018-03-12 stsp };
84 5c860e29 2018-03-12 stsp
85 ce5b7c56 2019-07-09 stsp __dead static void usage(int);
86 2c7829a4 2019-06-17 stsp __dead static void usage_init(void);
87 3ce1b845 2019-07-15 stsp __dead static void usage_import(void);
88 93658fb9 2020-03-18 stsp __dead static void usage_clone(void);
89 7848a0e1 2020-03-19 stsp __dead static void usage_fetch(void);
90 2ab43947 2020-03-18 stsp __dead static void usage_checkout(void);
91 507dc3bb 2018-12-29 stsp __dead static void usage_update(void);
92 4ed7e80c 2018-05-20 stsp __dead static void usage_log(void);
93 4ed7e80c 2018-05-20 stsp __dead static void usage_diff(void);
94 404c43c4 2018-06-21 stsp __dead static void usage_blame(void);
95 5de5890b 2018-10-18 stsp __dead static void usage_tree(void);
96 6bad629b 2019-02-04 stsp __dead static void usage_status(void);
97 d0eebce4 2019-03-11 stsp __dead static void usage_ref(void);
98 4e759de4 2019-06-26 stsp __dead static void usage_branch(void);
99 8e7bd50a 2019-08-22 stsp __dead static void usage_tag(void);
100 d00136be 2019-03-26 stsp __dead static void usage_add(void);
101 648e4ef7 2019-07-09 stsp __dead static void usage_remove(void);
102 a129376b 2019-03-28 stsp __dead static void usage_revert(void);
103 c4296144 2019-05-09 stsp __dead static void usage_commit(void);
104 234035bc 2019-06-01 stsp __dead static void usage_cherrypick(void);
105 5ef14e63 2019-06-02 stsp __dead static void usage_backout(void);
106 818c7501 2019-07-11 stsp __dead static void usage_rebase(void);
107 0ebf8283 2019-07-24 stsp __dead static void usage_histedit(void);
108 2822a352 2019-10-15 stsp __dead static void usage_integrate(void);
109 715dc77e 2019-08-03 stsp __dead static void usage_stage(void);
110 ad493afc 2019-08-03 stsp __dead static void usage_unstage(void);
111 01073a5d 2019-08-22 stsp __dead static void usage_cat(void);
112 b2118c49 2020-07-28 stsp __dead static void usage_info(void);
113 5c860e29 2018-03-12 stsp
114 2c7829a4 2019-06-17 stsp static const struct got_error* cmd_init(int, char *[]);
115 3ce1b845 2019-07-15 stsp static const struct got_error* cmd_import(int, char *[]);
116 93658fb9 2020-03-18 stsp static const struct got_error* cmd_clone(int, char *[]);
117 7848a0e1 2020-03-19 stsp static const struct got_error* cmd_fetch(int, char *[]);
118 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_checkout(int, char *[]);
119 507dc3bb 2018-12-29 stsp static const struct got_error* cmd_update(int, char *[]);
120 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_log(int, char *[]);
121 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_diff(int, char *[]);
122 404c43c4 2018-06-21 stsp static const struct got_error* cmd_blame(int, char *[]);
123 5de5890b 2018-10-18 stsp static const struct got_error* cmd_tree(int, char *[]);
124 4ed7e80c 2018-05-20 stsp static const struct got_error* cmd_status(int, char *[]);
125 d0eebce4 2019-03-11 stsp static const struct got_error* cmd_ref(int, char *[]);
126 4e759de4 2019-06-26 stsp static const struct got_error* cmd_branch(int, char *[]);
127 8e7bd50a 2019-08-22 stsp static const struct got_error* cmd_tag(int, char *[]);
128 d00136be 2019-03-26 stsp static const struct got_error* cmd_add(int, char *[]);
129 648e4ef7 2019-07-09 stsp static const struct got_error* cmd_remove(int, char *[]);
130 a129376b 2019-03-28 stsp static const struct got_error* cmd_revert(int, char *[]);
131 c4296144 2019-05-09 stsp static const struct got_error* cmd_commit(int, char *[]);
132 234035bc 2019-06-01 stsp static const struct got_error* cmd_cherrypick(int, char *[]);
133 5ef14e63 2019-06-02 stsp static const struct got_error* cmd_backout(int, char *[]);
134 818c7501 2019-07-11 stsp static const struct got_error* cmd_rebase(int, char *[]);
135 0ebf8283 2019-07-24 stsp static const struct got_error* cmd_histedit(int, char *[]);
136 2822a352 2019-10-15 stsp static const struct got_error* cmd_integrate(int, char *[]);
137 715dc77e 2019-08-03 stsp static const struct got_error* cmd_stage(int, char *[]);
138 ad493afc 2019-08-03 stsp static const struct got_error* cmd_unstage(int, char *[]);
139 01073a5d 2019-08-22 stsp static const struct got_error* cmd_cat(int, char *[]);
140 b2118c49 2020-07-28 stsp static const struct got_error* cmd_info(int, char *[]);
141 5c860e29 2018-03-12 stsp
142 8cfb4057 2019-07-09 stsp static struct got_cmd got_commands[] = {
143 b2118c49 2020-07-28 stsp { "init", cmd_init, usage_init, "" },
144 bc26cce8 2019-08-04 stsp { "import", cmd_import, usage_import, "im" },
145 93658fb9 2020-03-18 stsp { "clone", cmd_clone, usage_clone, "cl" },
146 7848a0e1 2020-03-19 stsp { "fetch", cmd_fetch, usage_fetch, "fe" },
147 2ab43947 2020-03-18 stsp { "checkout", cmd_checkout, usage_checkout, "co" },
148 97b3a7be 2019-07-09 stsp { "update", cmd_update, usage_update, "up" },
149 97b3a7be 2019-07-09 stsp { "log", cmd_log, usage_log, "" },
150 bc26cce8 2019-08-04 stsp { "diff", cmd_diff, usage_diff, "di" },
151 bc26cce8 2019-08-04 stsp { "blame", cmd_blame, usage_blame, "bl" },
152 bc26cce8 2019-08-04 stsp { "tree", cmd_tree, usage_tree, "tr" },
153 97b3a7be 2019-07-09 stsp { "status", cmd_status, usage_status, "st" },
154 97b3a7be 2019-07-09 stsp { "ref", cmd_ref, usage_ref, "" },
155 97b3a7be 2019-07-09 stsp { "branch", cmd_branch, usage_branch, "br" },
156 8e7bd50a 2019-08-22 stsp { "tag", cmd_tag, usage_tag, "" },
157 97b3a7be 2019-07-09 stsp { "add", cmd_add, usage_add, "" },
158 648e4ef7 2019-07-09 stsp { "remove", cmd_remove, usage_remove, "rm" },
159 97b3a7be 2019-07-09 stsp { "revert", cmd_revert, usage_revert, "rv" },
160 97b3a7be 2019-07-09 stsp { "commit", cmd_commit, usage_commit, "ci" },
161 016477fd 2019-07-09 stsp { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
162 97b3a7be 2019-07-09 stsp { "backout", cmd_backout, usage_backout, "bo" },
163 818c7501 2019-07-11 stsp { "rebase", cmd_rebase, usage_rebase, "rb" },
164 0ebf8283 2019-07-24 stsp { "histedit", cmd_histedit, usage_histedit, "he" },
165 2822a352 2019-10-15 stsp { "integrate", cmd_integrate, usage_integrate,"ig" },
166 715dc77e 2019-08-03 stsp { "stage", cmd_stage, usage_stage, "sg" },
167 ad493afc 2019-08-03 stsp { "unstage", cmd_unstage, usage_unstage, "ug" },
168 01073a5d 2019-08-22 stsp { "cat", cmd_cat, usage_cat, "" },
169 b2118c49 2020-07-28 stsp { "info", cmd_info, usage_info, "" },
170 5c860e29 2018-03-12 stsp };
171 ce5b7c56 2019-07-09 stsp
172 ce5b7c56 2019-07-09 stsp static void
173 ce5b7c56 2019-07-09 stsp list_commands(void)
174 ce5b7c56 2019-07-09 stsp {
175 ce5b7c56 2019-07-09 stsp int i;
176 ce5b7c56 2019-07-09 stsp
177 ce5b7c56 2019-07-09 stsp fprintf(stderr, "commands:");
178 ce5b7c56 2019-07-09 stsp for (i = 0; i < nitems(got_commands); i++) {
179 ce5b7c56 2019-07-09 stsp struct got_cmd *cmd = &got_commands[i];
180 ce5b7c56 2019-07-09 stsp fprintf(stderr, " %s", cmd->cmd_name);
181 ce5b7c56 2019-07-09 stsp }
182 ce5b7c56 2019-07-09 stsp fputc('\n', stderr);
183 ce5b7c56 2019-07-09 stsp }
184 5c860e29 2018-03-12 stsp
185 5c860e29 2018-03-12 stsp int
186 5c860e29 2018-03-12 stsp main(int argc, char *argv[])
187 5c860e29 2018-03-12 stsp {
188 8cfb4057 2019-07-09 stsp struct got_cmd *cmd;
189 5c860e29 2018-03-12 stsp unsigned int i;
190 5c860e29 2018-03-12 stsp int ch;
191 53ccebc2 2019-07-30 stsp int hflag = 0, Vflag = 0;
192 83cd27f8 2020-01-13 stsp static struct option longopts[] = {
193 83cd27f8 2020-01-13 stsp { "version", no_argument, NULL, 'V' },
194 83cd27f8 2020-01-13 stsp { NULL, 0, NULL, 0}
195 83cd27f8 2020-01-13 stsp };
196 5c860e29 2018-03-12 stsp
197 289e3cbf 2019-02-04 stsp setlocale(LC_CTYPE, "");
198 5c860e29 2018-03-12 stsp
199 6586ea88 2020-01-13 stsp while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
200 5c860e29 2018-03-12 stsp switch (ch) {
201 1b6b95a8 2018-03-12 stsp case 'h':
202 1b6b95a8 2018-03-12 stsp hflag = 1;
203 53ccebc2 2019-07-30 stsp break;
204 53ccebc2 2019-07-30 stsp case 'V':
205 53ccebc2 2019-07-30 stsp Vflag = 1;
206 1b6b95a8 2018-03-12 stsp break;
207 5c860e29 2018-03-12 stsp default:
208 ce5b7c56 2019-07-09 stsp usage(hflag);
209 5c860e29 2018-03-12 stsp /* NOTREACHED */
210 5c860e29 2018-03-12 stsp }
211 5c860e29 2018-03-12 stsp }
212 5c860e29 2018-03-12 stsp
213 5c860e29 2018-03-12 stsp argc -= optind;
214 5c860e29 2018-03-12 stsp argv += optind;
215 1e70621d 2018-03-27 stsp optind = 0;
216 53ccebc2 2019-07-30 stsp
217 53ccebc2 2019-07-30 stsp if (Vflag) {
218 53ccebc2 2019-07-30 stsp got_version_print_str();
219 53ccebc2 2019-07-30 stsp return 1;
220 53ccebc2 2019-07-30 stsp }
221 5c860e29 2018-03-12 stsp
222 5c860e29 2018-03-12 stsp if (argc <= 0)
223 ce5b7c56 2019-07-09 stsp usage(hflag);
224 5c860e29 2018-03-12 stsp
225 99437157 2018-11-11 stsp signal(SIGINT, catch_sigint);
226 99437157 2018-11-11 stsp signal(SIGPIPE, catch_sigpipe);
227 99437157 2018-11-11 stsp
228 5c860e29 2018-03-12 stsp for (i = 0; i < nitems(got_commands); i++) {
229 d7d4f210 2018-03-12 stsp const struct got_error *error;
230 d7d4f210 2018-03-12 stsp
231 5c860e29 2018-03-12 stsp cmd = &got_commands[i];
232 5c860e29 2018-03-12 stsp
233 97b3a7be 2019-07-09 stsp if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
234 97b3a7be 2019-07-09 stsp strcmp(cmd->cmd_alias, argv[0]) != 0)
235 5c860e29 2018-03-12 stsp continue;
236 5c860e29 2018-03-12 stsp
237 1b6b95a8 2018-03-12 stsp if (hflag)
238 1b6b95a8 2018-03-12 stsp got_commands[i].cmd_usage();
239 1b6b95a8 2018-03-12 stsp
240 d7d4f210 2018-03-12 stsp error = got_commands[i].cmd_main(argc, argv);
241 f8afbdc8 2019-11-08 stsp if (error && error->code != GOT_ERR_CANCELLED &&
242 f8afbdc8 2019-11-08 stsp error->code != GOT_ERR_PRIVSEP_EXIT &&
243 f8afbdc8 2019-11-08 stsp !(sigpipe_received &&
244 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
245 70015d7a 2019-11-08 stsp !(sigint_received &&
246 70015d7a 2019-11-08 stsp error->code == GOT_ERR_ERRNO && errno == EINTR)) {
247 d7d4f210 2018-03-12 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
248 d7d4f210 2018-03-12 stsp return 1;
249 d7d4f210 2018-03-12 stsp }
250 d7d4f210 2018-03-12 stsp
251 d7d4f210 2018-03-12 stsp return 0;
252 5c860e29 2018-03-12 stsp }
253 5c860e29 2018-03-12 stsp
254 20ecf764 2018-03-12 stsp fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
255 ce5b7c56 2019-07-09 stsp list_commands();
256 5c860e29 2018-03-12 stsp return 1;
257 5c860e29 2018-03-12 stsp }
258 5c860e29 2018-03-12 stsp
259 4ed7e80c 2018-05-20 stsp __dead static void
260 ce5b7c56 2019-07-09 stsp usage(int hflag)
261 5c860e29 2018-03-12 stsp {
262 e801a566 2020-01-13 stsp fprintf(stderr, "usage: %s [-h] [-V | --version] command [arg ...]\n",
263 53ccebc2 2019-07-30 stsp getprogname());
264 ce5b7c56 2019-07-09 stsp if (hflag)
265 ce5b7c56 2019-07-09 stsp list_commands();
266 5c860e29 2018-03-12 stsp exit(1);
267 5c860e29 2018-03-12 stsp }
268 5c860e29 2018-03-12 stsp
269 0266afb7 2019-01-04 stsp static const struct got_error *
270 0ee7065d 2019-05-13 stsp get_editor(char **abspath)
271 e2ba3d07 2019-05-13 stsp {
272 0ee7065d 2019-05-13 stsp const struct got_error *err = NULL;
273 e2ba3d07 2019-05-13 stsp const char *editor;
274 8920fa04 2019-08-18 stsp
275 8920fa04 2019-08-18 stsp *abspath = NULL;
276 e2ba3d07 2019-05-13 stsp
277 e2ba3d07 2019-05-13 stsp editor = getenv("VISUAL");
278 e2ba3d07 2019-05-13 stsp if (editor == NULL)
279 e2ba3d07 2019-05-13 stsp editor = getenv("EDITOR");
280 e2ba3d07 2019-05-13 stsp
281 0ee7065d 2019-05-13 stsp if (editor) {
282 0ee7065d 2019-05-13 stsp err = got_path_find_prog(abspath, editor);
283 0ee7065d 2019-05-13 stsp if (err)
284 0ee7065d 2019-05-13 stsp return err;
285 0ee7065d 2019-05-13 stsp }
286 e2ba3d07 2019-05-13 stsp
287 0ee7065d 2019-05-13 stsp if (*abspath == NULL) {
288 0ee7065d 2019-05-13 stsp *abspath = strdup("/bin/ed");
289 0ee7065d 2019-05-13 stsp if (*abspath == NULL)
290 0ee7065d 2019-05-13 stsp return got_error_from_errno("strdup");
291 0ee7065d 2019-05-13 stsp }
292 0ee7065d 2019-05-13 stsp
293 e2ba3d07 2019-05-13 stsp return NULL;
294 e2ba3d07 2019-05-13 stsp }
295 e2ba3d07 2019-05-13 stsp
296 e2ba3d07 2019-05-13 stsp static const struct got_error *
297 d0eebce4 2019-03-11 stsp apply_unveil(const char *repo_path, int repo_read_only,
298 c530dc23 2019-07-23 stsp const char *worktree_path)
299 0266afb7 2019-01-04 stsp {
300 163ce85a 2019-05-13 stsp const struct got_error *err;
301 0266afb7 2019-01-04 stsp
302 37c06ea4 2019-07-15 stsp #ifdef PROFILE
303 37c06ea4 2019-07-15 stsp if (unveil("gmon.out", "rwc") != 0)
304 37c06ea4 2019-07-15 stsp return got_error_from_errno2("unveil", "gmon.out");
305 37c06ea4 2019-07-15 stsp #endif
306 d0eebce4 2019-03-11 stsp if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
307 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", repo_path);
308 0266afb7 2019-01-04 stsp
309 0266afb7 2019-01-04 stsp if (worktree_path && unveil(worktree_path, "rwc") != 0)
310 638f9024 2019-05-13 stsp return got_error_from_errno2("unveil", worktree_path);
311 0266afb7 2019-01-04 stsp
312 bb63914a 2020-02-17 stsp if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
313 bb63914a 2020-02-17 stsp return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
314 0266afb7 2019-01-04 stsp
315 163ce85a 2019-05-13 stsp err = got_privsep_unveil_exec_helpers();
316 163ce85a 2019-05-13 stsp if (err != NULL)
317 163ce85a 2019-05-13 stsp return err;
318 0266afb7 2019-01-04 stsp
319 0266afb7 2019-01-04 stsp if (unveil(NULL, NULL) != 0)
320 638f9024 2019-05-13 stsp return got_error_from_errno("unveil");
321 0266afb7 2019-01-04 stsp
322 0266afb7 2019-01-04 stsp return NULL;
323 2c7829a4 2019-06-17 stsp }
324 2c7829a4 2019-06-17 stsp
325 2c7829a4 2019-06-17 stsp __dead static void
326 2c7829a4 2019-06-17 stsp usage_init(void)
327 2c7829a4 2019-06-17 stsp {
328 09ea71ba 2019-07-27 stsp fprintf(stderr, "usage: %s init repository-path\n", getprogname());
329 2c7829a4 2019-06-17 stsp exit(1);
330 2c7829a4 2019-06-17 stsp }
331 2c7829a4 2019-06-17 stsp
332 2c7829a4 2019-06-17 stsp static const struct got_error *
333 2c7829a4 2019-06-17 stsp cmd_init(int argc, char *argv[])
334 2c7829a4 2019-06-17 stsp {
335 2c7829a4 2019-06-17 stsp const struct got_error *error = NULL;
336 2c7829a4 2019-06-17 stsp char *repo_path = NULL;
337 2c7829a4 2019-06-17 stsp int ch;
338 2c7829a4 2019-06-17 stsp
339 2c7829a4 2019-06-17 stsp while ((ch = getopt(argc, argv, "")) != -1) {
340 2c7829a4 2019-06-17 stsp switch (ch) {
341 2c7829a4 2019-06-17 stsp default:
342 2c7829a4 2019-06-17 stsp usage_init();
343 2c7829a4 2019-06-17 stsp /* NOTREACHED */
344 2c7829a4 2019-06-17 stsp }
345 2c7829a4 2019-06-17 stsp }
346 2c7829a4 2019-06-17 stsp
347 2c7829a4 2019-06-17 stsp argc -= optind;
348 2c7829a4 2019-06-17 stsp argv += optind;
349 2c7829a4 2019-06-17 stsp
350 2c7829a4 2019-06-17 stsp #ifndef PROFILE
351 2c7829a4 2019-06-17 stsp if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
352 2c7829a4 2019-06-17 stsp err(1, "pledge");
353 2c7829a4 2019-06-17 stsp #endif
354 2c7829a4 2019-06-17 stsp if (argc != 1)
355 bc20e173 2019-06-17 stsp usage_init();
356 2c7829a4 2019-06-17 stsp
357 2c7829a4 2019-06-17 stsp repo_path = strdup(argv[0]);
358 2c7829a4 2019-06-17 stsp if (repo_path == NULL)
359 2c7829a4 2019-06-17 stsp return got_error_from_errno("strdup");
360 2c7829a4 2019-06-17 stsp
361 2c7829a4 2019-06-17 stsp got_path_strip_trailing_slashes(repo_path);
362 2c7829a4 2019-06-17 stsp
363 2c7829a4 2019-06-17 stsp error = got_path_mkdir(repo_path);
364 2c7829a4 2019-06-17 stsp if (error &&
365 2c7829a4 2019-06-17 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
366 2c7829a4 2019-06-17 stsp goto done;
367 2c7829a4 2019-06-17 stsp
368 c530dc23 2019-07-23 stsp error = apply_unveil(repo_path, 0, NULL);
369 2c7829a4 2019-06-17 stsp if (error)
370 2c7829a4 2019-06-17 stsp goto done;
371 2c7829a4 2019-06-17 stsp
372 2c7829a4 2019-06-17 stsp error = got_repo_init(repo_path);
373 3ce1b845 2019-07-15 stsp done:
374 3ce1b845 2019-07-15 stsp free(repo_path);
375 3ce1b845 2019-07-15 stsp return error;
376 3ce1b845 2019-07-15 stsp }
377 3ce1b845 2019-07-15 stsp
378 3ce1b845 2019-07-15 stsp __dead static void
379 3ce1b845 2019-07-15 stsp usage_import(void)
380 3ce1b845 2019-07-15 stsp {
381 3ce1b845 2019-07-15 stsp fprintf(stderr, "usage: %s import [-b branch] [-m message] "
382 3ce1b845 2019-07-15 stsp "[-r repository-path] [-I pattern] path\n", getprogname());
383 3ce1b845 2019-07-15 stsp exit(1);
384 3ce1b845 2019-07-15 stsp }
385 3ce1b845 2019-07-15 stsp
386 3ce1b845 2019-07-15 stsp int
387 3ce1b845 2019-07-15 stsp spawn_editor(const char *editor, const char *file)
388 3ce1b845 2019-07-15 stsp {
389 3ce1b845 2019-07-15 stsp pid_t pid;
390 3ce1b845 2019-07-15 stsp sig_t sighup, sigint, sigquit;
391 3ce1b845 2019-07-15 stsp int st = -1;
392 3ce1b845 2019-07-15 stsp
393 3ce1b845 2019-07-15 stsp sighup = signal(SIGHUP, SIG_IGN);
394 3ce1b845 2019-07-15 stsp sigint = signal(SIGINT, SIG_IGN);
395 3ce1b845 2019-07-15 stsp sigquit = signal(SIGQUIT, SIG_IGN);
396 3ce1b845 2019-07-15 stsp
397 3ce1b845 2019-07-15 stsp switch (pid = fork()) {
398 3ce1b845 2019-07-15 stsp case -1:
399 3ce1b845 2019-07-15 stsp goto doneediting;
400 3ce1b845 2019-07-15 stsp case 0:
401 3ce1b845 2019-07-15 stsp execl(editor, editor, file, (char *)NULL);
402 3ce1b845 2019-07-15 stsp _exit(127);
403 3ce1b845 2019-07-15 stsp }
404 3ce1b845 2019-07-15 stsp
405 3ce1b845 2019-07-15 stsp while (waitpid(pid, &st, 0) == -1)
406 3ce1b845 2019-07-15 stsp if (errno != EINTR)
407 3ce1b845 2019-07-15 stsp break;
408 3ce1b845 2019-07-15 stsp
409 3ce1b845 2019-07-15 stsp doneediting:
410 3ce1b845 2019-07-15 stsp (void)signal(SIGHUP, sighup);
411 3ce1b845 2019-07-15 stsp (void)signal(SIGINT, sigint);
412 3ce1b845 2019-07-15 stsp (void)signal(SIGQUIT, sigquit);
413 3ce1b845 2019-07-15 stsp
414 3ce1b845 2019-07-15 stsp if (!WIFEXITED(st)) {
415 3ce1b845 2019-07-15 stsp errno = EINTR;
416 3ce1b845 2019-07-15 stsp return -1;
417 3ce1b845 2019-07-15 stsp }
418 3ce1b845 2019-07-15 stsp
419 3ce1b845 2019-07-15 stsp return WEXITSTATUS(st);
420 3ce1b845 2019-07-15 stsp }
421 3ce1b845 2019-07-15 stsp
422 3ce1b845 2019-07-15 stsp static const struct got_error *
423 3ce1b845 2019-07-15 stsp edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
424 3ce1b845 2019-07-15 stsp const char *initial_content)
425 3ce1b845 2019-07-15 stsp {
426 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
427 3ce1b845 2019-07-15 stsp char buf[1024];
428 3ce1b845 2019-07-15 stsp struct stat st, st2;
429 3ce1b845 2019-07-15 stsp FILE *fp;
430 3ce1b845 2019-07-15 stsp int content_changed = 0;
431 3ce1b845 2019-07-15 stsp size_t len;
432 3ce1b845 2019-07-15 stsp
433 3ce1b845 2019-07-15 stsp *logmsg = NULL;
434 3ce1b845 2019-07-15 stsp
435 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st) == -1)
436 3ce1b845 2019-07-15 stsp return got_error_from_errno2("stat", logmsg_path);
437 3ce1b845 2019-07-15 stsp
438 3ce1b845 2019-07-15 stsp if (spawn_editor(editor, logmsg_path) == -1)
439 3ce1b845 2019-07-15 stsp return got_error_from_errno("failed spawning editor");
440 3ce1b845 2019-07-15 stsp
441 3ce1b845 2019-07-15 stsp if (stat(logmsg_path, &st2) == -1)
442 3ce1b845 2019-07-15 stsp return got_error_from_errno("stat");
443 3ce1b845 2019-07-15 stsp
444 3ce1b845 2019-07-15 stsp if (st.st_mtime == st2.st_mtime && st.st_size == st2.st_size)
445 3ce1b845 2019-07-15 stsp return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
446 3ce1b845 2019-07-15 stsp "no changes made to commit message, aborting");
447 3ce1b845 2019-07-15 stsp
448 3ce1b845 2019-07-15 stsp *logmsg = malloc(st2.st_size + 1);
449 3ce1b845 2019-07-15 stsp if (*logmsg == NULL)
450 3ce1b845 2019-07-15 stsp return got_error_from_errno("malloc");
451 3ce1b845 2019-07-15 stsp (*logmsg)[0] = '\0';
452 3ce1b845 2019-07-15 stsp len = 0;
453 3ce1b845 2019-07-15 stsp
454 3ce1b845 2019-07-15 stsp fp = fopen(logmsg_path, "r");
455 3ce1b845 2019-07-15 stsp if (fp == NULL) {
456 3ce1b845 2019-07-15 stsp err = got_error_from_errno("fopen");
457 3ce1b845 2019-07-15 stsp goto done;
458 3ce1b845 2019-07-15 stsp }
459 3ce1b845 2019-07-15 stsp while (fgets(buf, sizeof(buf), fp) != NULL) {
460 3ce1b845 2019-07-15 stsp if (!content_changed && strcmp(buf, initial_content) != 0)
461 3ce1b845 2019-07-15 stsp content_changed = 1;
462 3ce1b845 2019-07-15 stsp if (buf[0] == '#' || (len == 0 && buf[0] == '\n'))
463 3ce1b845 2019-07-15 stsp continue; /* remove comments and leading empty lines */
464 3ce1b845 2019-07-15 stsp len = strlcat(*logmsg, buf, st2.st_size);
465 3ce1b845 2019-07-15 stsp }
466 3ce1b845 2019-07-15 stsp fclose(fp);
467 3ce1b845 2019-07-15 stsp
468 3ce1b845 2019-07-15 stsp while (len > 0 && (*logmsg)[len - 1] == '\n') {
469 3ce1b845 2019-07-15 stsp (*logmsg)[len - 1] = '\0';
470 3ce1b845 2019-07-15 stsp len--;
471 3ce1b845 2019-07-15 stsp }
472 3ce1b845 2019-07-15 stsp
473 3ce1b845 2019-07-15 stsp if (len == 0 || !content_changed)
474 3ce1b845 2019-07-15 stsp err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
475 3ce1b845 2019-07-15 stsp "commit message cannot be empty, aborting");
476 3ce1b845 2019-07-15 stsp done:
477 3ce1b845 2019-07-15 stsp if (err) {
478 3ce1b845 2019-07-15 stsp free(*logmsg);
479 3ce1b845 2019-07-15 stsp *logmsg = NULL;
480 3ce1b845 2019-07-15 stsp }
481 3ce1b845 2019-07-15 stsp return err;
482 3ce1b845 2019-07-15 stsp }
483 3ce1b845 2019-07-15 stsp
484 3ce1b845 2019-07-15 stsp static const struct got_error *
485 ef293bdd 2019-10-21 stsp collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
486 ef293bdd 2019-10-21 stsp const char *path_dir, const char *branch_name)
487 3ce1b845 2019-07-15 stsp {
488 ef293bdd 2019-10-21 stsp char *initial_content = NULL;
489 3ce1b845 2019-07-15 stsp const struct got_error *err = NULL;
490 3ce1b845 2019-07-15 stsp int fd;
491 3ce1b845 2019-07-15 stsp
492 3ce1b845 2019-07-15 stsp if (asprintf(&initial_content,
493 3ce1b845 2019-07-15 stsp "\n# %s to be imported to branch %s\n", path_dir,
494 3ce1b845 2019-07-15 stsp branch_name) == -1)
495 3ce1b845 2019-07-15 stsp return got_error_from_errno("asprintf");
496 3ce1b845 2019-07-15 stsp
497 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(logmsg_path, &fd,
498 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-importmsg");
499 3ce1b845 2019-07-15 stsp if (err)
500 3ce1b845 2019-07-15 stsp goto done;
501 3ce1b845 2019-07-15 stsp
502 3ce1b845 2019-07-15 stsp dprintf(fd, initial_content);
503 3ce1b845 2019-07-15 stsp close(fd);
504 3ce1b845 2019-07-15 stsp
505 ef293bdd 2019-10-21 stsp err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content);
506 3ce1b845 2019-07-15 stsp done:
507 3ce1b845 2019-07-15 stsp free(initial_content);
508 3ce1b845 2019-07-15 stsp return err;
509 3ce1b845 2019-07-15 stsp }
510 3ce1b845 2019-07-15 stsp
511 3ce1b845 2019-07-15 stsp static const struct got_error *
512 3ce1b845 2019-07-15 stsp import_progress(void *arg, const char *path)
513 3ce1b845 2019-07-15 stsp {
514 3ce1b845 2019-07-15 stsp printf("A %s\n", path);
515 3ce1b845 2019-07-15 stsp return NULL;
516 3ce1b845 2019-07-15 stsp }
517 3ce1b845 2019-07-15 stsp
518 3ce1b845 2019-07-15 stsp static const struct got_error *
519 aba9c984 2019-09-08 stsp get_author(char **author, struct got_repository *repo)
520 84792843 2019-08-09 stsp {
521 aba9c984 2019-09-08 stsp const struct got_error *err = NULL;
522 c9956ddf 2019-09-08 stsp const char *got_author, *name, *email;
523 84792843 2019-08-09 stsp
524 84792843 2019-08-09 stsp *author = NULL;
525 aba9c984 2019-09-08 stsp
526 c9956ddf 2019-09-08 stsp name = got_repo_get_gitconfig_author_name(repo);
527 c9956ddf 2019-09-08 stsp email = got_repo_get_gitconfig_author_email(repo);
528 c9956ddf 2019-09-08 stsp if (name && email) {
529 c9956ddf 2019-09-08 stsp if (asprintf(author, "%s <%s>", name, email) == -1)
530 aba9c984 2019-09-08 stsp return got_error_from_errno("asprintf");
531 aba9c984 2019-09-08 stsp return NULL;
532 aba9c984 2019-09-08 stsp }
533 84792843 2019-08-09 stsp
534 84792843 2019-08-09 stsp got_author = getenv("GOT_AUTHOR");
535 84792843 2019-08-09 stsp if (got_author == NULL) {
536 c9956ddf 2019-09-08 stsp name = got_repo_get_global_gitconfig_author_name(repo);
537 c9956ddf 2019-09-08 stsp email = got_repo_get_global_gitconfig_author_email(repo);
538 c9956ddf 2019-09-08 stsp if (name && email) {
539 c9956ddf 2019-09-08 stsp if (asprintf(author, "%s <%s>", name, email) == -1)
540 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
541 c9956ddf 2019-09-08 stsp return NULL;
542 c9956ddf 2019-09-08 stsp }
543 84792843 2019-08-09 stsp /* TODO: Look up user in password database? */
544 84792843 2019-08-09 stsp return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
545 84792843 2019-08-09 stsp }
546 84792843 2019-08-09 stsp
547 aba9c984 2019-09-08 stsp *author = strdup(got_author);
548 aba9c984 2019-09-08 stsp if (*author == NULL)
549 aba9c984 2019-09-08 stsp return got_error_from_errno("strdup");
550 84792843 2019-08-09 stsp
551 84792843 2019-08-09 stsp /*
552 84792843 2019-08-09 stsp * Really dumb email address check; we're only doing this to
553 84792843 2019-08-09 stsp * avoid git's object parser breaking on commits we create.
554 84792843 2019-08-09 stsp */
555 84792843 2019-08-09 stsp while (*got_author && *got_author != '<')
556 84792843 2019-08-09 stsp got_author++;
557 aba9c984 2019-09-08 stsp if (*got_author != '<') {
558 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
559 aba9c984 2019-09-08 stsp goto done;
560 aba9c984 2019-09-08 stsp }
561 84792843 2019-08-09 stsp while (*got_author && *got_author != '@')
562 84792843 2019-08-09 stsp got_author++;
563 aba9c984 2019-09-08 stsp if (*got_author != '@') {
564 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
565 aba9c984 2019-09-08 stsp goto done;
566 aba9c984 2019-09-08 stsp }
567 84792843 2019-08-09 stsp while (*got_author && *got_author != '>')
568 84792843 2019-08-09 stsp got_author++;
569 84792843 2019-08-09 stsp if (*got_author != '>')
570 aba9c984 2019-09-08 stsp err = got_error(GOT_ERR_COMMIT_NO_EMAIL);
571 aba9c984 2019-09-08 stsp done:
572 aba9c984 2019-09-08 stsp if (err) {
573 aba9c984 2019-09-08 stsp free(*author);
574 aba9c984 2019-09-08 stsp *author = NULL;
575 aba9c984 2019-09-08 stsp }
576 aba9c984 2019-09-08 stsp return err;
577 c9956ddf 2019-09-08 stsp }
578 c9956ddf 2019-09-08 stsp
579 c9956ddf 2019-09-08 stsp static const struct got_error *
580 c9956ddf 2019-09-08 stsp get_gitconfig_path(char **gitconfig_path)
581 c9956ddf 2019-09-08 stsp {
582 c9956ddf 2019-09-08 stsp const char *homedir = getenv("HOME");
583 c9956ddf 2019-09-08 stsp
584 c9956ddf 2019-09-08 stsp *gitconfig_path = NULL;
585 c9956ddf 2019-09-08 stsp if (homedir) {
586 c9956ddf 2019-09-08 stsp if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
587 c9956ddf 2019-09-08 stsp return got_error_from_errno("asprintf");
588 c9956ddf 2019-09-08 stsp
589 c9956ddf 2019-09-08 stsp }
590 c9956ddf 2019-09-08 stsp return NULL;
591 84792843 2019-08-09 stsp }
592 84792843 2019-08-09 stsp
593 84792843 2019-08-09 stsp static const struct got_error *
594 3ce1b845 2019-07-15 stsp cmd_import(int argc, char *argv[])
595 3ce1b845 2019-07-15 stsp {
596 3ce1b845 2019-07-15 stsp const struct got_error *error = NULL;
597 3ce1b845 2019-07-15 stsp char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
598 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
599 5d67f40d 2019-11-08 stsp const char *branch_name = "main";
600 ef293bdd 2019-10-21 stsp char *refname = NULL, *id_str = NULL, *logmsg_path = NULL;
601 3ce1b845 2019-07-15 stsp struct got_repository *repo = NULL;
602 3ce1b845 2019-07-15 stsp struct got_reference *branch_ref = NULL, *head_ref = NULL;
603 3ce1b845 2019-07-15 stsp struct got_object_id *new_commit_id = NULL;
604 3ce1b845 2019-07-15 stsp int ch;
605 3ce1b845 2019-07-15 stsp struct got_pathlist_head ignores;
606 3ce1b845 2019-07-15 stsp struct got_pathlist_entry *pe;
607 ef293bdd 2019-10-21 stsp int preserve_logmsg = 0;
608 3ce1b845 2019-07-15 stsp
609 3ce1b845 2019-07-15 stsp TAILQ_INIT(&ignores);
610 3ce1b845 2019-07-15 stsp
611 3ce1b845 2019-07-15 stsp while ((ch = getopt(argc, argv, "b:m:r:I:")) != -1) {
612 3ce1b845 2019-07-15 stsp switch (ch) {
613 3ce1b845 2019-07-15 stsp case 'b':
614 3ce1b845 2019-07-15 stsp branch_name = optarg;
615 3ce1b845 2019-07-15 stsp break;
616 3ce1b845 2019-07-15 stsp case 'm':
617 3ce1b845 2019-07-15 stsp logmsg = strdup(optarg);
618 3ce1b845 2019-07-15 stsp if (logmsg == NULL) {
619 3ce1b845 2019-07-15 stsp error = got_error_from_errno("strdup");
620 3ce1b845 2019-07-15 stsp goto done;
621 3ce1b845 2019-07-15 stsp }
622 3ce1b845 2019-07-15 stsp break;
623 3ce1b845 2019-07-15 stsp case 'r':
624 3ce1b845 2019-07-15 stsp repo_path = realpath(optarg, NULL);
625 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
626 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath",
627 9ba1d308 2019-10-21 stsp optarg);
628 3ce1b845 2019-07-15 stsp goto done;
629 3ce1b845 2019-07-15 stsp }
630 3ce1b845 2019-07-15 stsp break;
631 3ce1b845 2019-07-15 stsp case 'I':
632 3ce1b845 2019-07-15 stsp if (optarg[0] == '\0')
633 3ce1b845 2019-07-15 stsp break;
634 3ce1b845 2019-07-15 stsp error = got_pathlist_insert(&pe, &ignores, optarg,
635 3ce1b845 2019-07-15 stsp NULL);
636 3ce1b845 2019-07-15 stsp if (error)
637 3ce1b845 2019-07-15 stsp goto done;
638 3ce1b845 2019-07-15 stsp break;
639 3ce1b845 2019-07-15 stsp default:
640 b2b65d18 2019-08-22 stsp usage_import();
641 3ce1b845 2019-07-15 stsp /* NOTREACHED */
642 3ce1b845 2019-07-15 stsp }
643 3ce1b845 2019-07-15 stsp }
644 3ce1b845 2019-07-15 stsp
645 3ce1b845 2019-07-15 stsp argc -= optind;
646 3ce1b845 2019-07-15 stsp argv += optind;
647 3ce1b845 2019-07-15 stsp
648 3ce1b845 2019-07-15 stsp #ifndef PROFILE
649 aba9c984 2019-09-08 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
650 aba9c984 2019-09-08 stsp "unveil",
651 3ce1b845 2019-07-15 stsp NULL) == -1)
652 3ce1b845 2019-07-15 stsp err(1, "pledge");
653 3ce1b845 2019-07-15 stsp #endif
654 3ce1b845 2019-07-15 stsp if (argc != 1)
655 3ce1b845 2019-07-15 stsp usage_import();
656 2c7829a4 2019-06-17 stsp
657 3ce1b845 2019-07-15 stsp if (repo_path == NULL) {
658 3ce1b845 2019-07-15 stsp repo_path = getcwd(NULL, 0);
659 3ce1b845 2019-07-15 stsp if (repo_path == NULL)
660 3ce1b845 2019-07-15 stsp return got_error_from_errno("getcwd");
661 3ce1b845 2019-07-15 stsp }
662 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(repo_path);
663 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
664 c9956ddf 2019-09-08 stsp if (error)
665 c9956ddf 2019-09-08 stsp goto done;
666 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
667 3ce1b845 2019-07-15 stsp if (error)
668 3ce1b845 2019-07-15 stsp goto done;
669 aba9c984 2019-09-08 stsp
670 aba9c984 2019-09-08 stsp error = get_author(&author, repo);
671 aba9c984 2019-09-08 stsp if (error)
672 aba9c984 2019-09-08 stsp return error;
673 e560b7e0 2019-11-28 stsp
674 e560b7e0 2019-11-28 stsp /*
675 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
676 e560b7e0 2019-11-28 stsp * While technically a valid reference name, this case is usually
677 e560b7e0 2019-11-28 stsp * an unintended typo.
678 e560b7e0 2019-11-28 stsp */
679 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
680 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
681 3ce1b845 2019-07-15 stsp
682 3ce1b845 2019-07-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
683 3ce1b845 2019-07-15 stsp error = got_error_from_errno("asprintf");
684 3ce1b845 2019-07-15 stsp goto done;
685 3ce1b845 2019-07-15 stsp }
686 3ce1b845 2019-07-15 stsp
687 3ce1b845 2019-07-15 stsp error = got_ref_open(&branch_ref, repo, refname, 0);
688 3ce1b845 2019-07-15 stsp if (error) {
689 3ce1b845 2019-07-15 stsp if (error->code != GOT_ERR_NOT_REF)
690 3ce1b845 2019-07-15 stsp goto done;
691 3ce1b845 2019-07-15 stsp } else {
692 3ce1b845 2019-07-15 stsp error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
693 3ce1b845 2019-07-15 stsp "import target branch already exists");
694 3ce1b845 2019-07-15 stsp goto done;
695 3ce1b845 2019-07-15 stsp }
696 3ce1b845 2019-07-15 stsp
697 3ce1b845 2019-07-15 stsp path_dir = realpath(argv[0], NULL);
698 3ce1b845 2019-07-15 stsp if (path_dir == NULL) {
699 9ba1d308 2019-10-21 stsp error = got_error_from_errno2("realpath", argv[0]);
700 3ce1b845 2019-07-15 stsp goto done;
701 3ce1b845 2019-07-15 stsp }
702 3ce1b845 2019-07-15 stsp got_path_strip_trailing_slashes(path_dir);
703 3ce1b845 2019-07-15 stsp
704 3ce1b845 2019-07-15 stsp /*
705 3ce1b845 2019-07-15 stsp * unveil(2) traverses exec(2); if an editor is used we have
706 3ce1b845 2019-07-15 stsp * to apply unveil after the log message has been written.
707 3ce1b845 2019-07-15 stsp */
708 3ce1b845 2019-07-15 stsp if (logmsg == NULL || strlen(logmsg) == 0) {
709 3ce1b845 2019-07-15 stsp error = get_editor(&editor);
710 3ce1b845 2019-07-15 stsp if (error)
711 3ce1b845 2019-07-15 stsp goto done;
712 8e158b01 2019-09-22 stsp free(logmsg);
713 ef293bdd 2019-10-21 stsp error = collect_import_msg(&logmsg, &logmsg_path, editor,
714 ef293bdd 2019-10-21 stsp path_dir, refname);
715 ef293bdd 2019-10-21 stsp if (error) {
716 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
717 ef293bdd 2019-10-21 stsp logmsg_path != NULL)
718 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
719 3ce1b845 2019-07-15 stsp goto done;
720 ef293bdd 2019-10-21 stsp }
721 3ce1b845 2019-07-15 stsp }
722 3ce1b845 2019-07-15 stsp
723 ef293bdd 2019-10-21 stsp if (unveil(path_dir, "r") != 0) {
724 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unveil", path_dir);
725 ef293bdd 2019-10-21 stsp if (logmsg_path)
726 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
727 3ce1b845 2019-07-15 stsp goto done;
728 ef293bdd 2019-10-21 stsp }
729 3ce1b845 2019-07-15 stsp
730 ef293bdd 2019-10-21 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
731 ef293bdd 2019-10-21 stsp if (error) {
732 ef293bdd 2019-10-21 stsp if (logmsg_path)
733 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
734 ef293bdd 2019-10-21 stsp goto done;
735 ef293bdd 2019-10-21 stsp }
736 ef293bdd 2019-10-21 stsp
737 3ce1b845 2019-07-15 stsp error = got_repo_import(&new_commit_id, path_dir, logmsg,
738 84792843 2019-08-09 stsp author, &ignores, repo, import_progress, NULL);
739 ef293bdd 2019-10-21 stsp if (error) {
740 ef293bdd 2019-10-21 stsp if (logmsg_path)
741 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
742 3ce1b845 2019-07-15 stsp goto done;
743 ef293bdd 2019-10-21 stsp }
744 3ce1b845 2019-07-15 stsp
745 3ce1b845 2019-07-15 stsp error = got_ref_alloc(&branch_ref, refname, new_commit_id);
746 ef293bdd 2019-10-21 stsp if (error) {
747 ef293bdd 2019-10-21 stsp if (logmsg_path)
748 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
749 3ce1b845 2019-07-15 stsp goto done;
750 ef293bdd 2019-10-21 stsp }
751 3ce1b845 2019-07-15 stsp
752 3ce1b845 2019-07-15 stsp error = got_ref_write(branch_ref, repo);
753 ef293bdd 2019-10-21 stsp if (error) {
754 ef293bdd 2019-10-21 stsp if (logmsg_path)
755 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
756 3ce1b845 2019-07-15 stsp goto done;
757 ef293bdd 2019-10-21 stsp }
758 3ce1b845 2019-07-15 stsp
759 3ce1b845 2019-07-15 stsp error = got_object_id_str(&id_str, new_commit_id);
760 ef293bdd 2019-10-21 stsp if (error) {
761 ef293bdd 2019-10-21 stsp if (logmsg_path)
762 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
763 3ce1b845 2019-07-15 stsp goto done;
764 ef293bdd 2019-10-21 stsp }
765 3ce1b845 2019-07-15 stsp
766 3ce1b845 2019-07-15 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
767 3ce1b845 2019-07-15 stsp if (error) {
768 ef293bdd 2019-10-21 stsp if (error->code != GOT_ERR_NOT_REF) {
769 ef293bdd 2019-10-21 stsp if (logmsg_path)
770 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
771 3ce1b845 2019-07-15 stsp goto done;
772 ef293bdd 2019-10-21 stsp }
773 3ce1b845 2019-07-15 stsp
774 3ce1b845 2019-07-15 stsp error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
775 3ce1b845 2019-07-15 stsp branch_ref);
776 ef293bdd 2019-10-21 stsp if (error) {
777 ef293bdd 2019-10-21 stsp if (logmsg_path)
778 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
779 3ce1b845 2019-07-15 stsp goto done;
780 ef293bdd 2019-10-21 stsp }
781 3ce1b845 2019-07-15 stsp
782 3ce1b845 2019-07-15 stsp error = got_ref_write(head_ref, repo);
783 ef293bdd 2019-10-21 stsp if (error) {
784 ef293bdd 2019-10-21 stsp if (logmsg_path)
785 ef293bdd 2019-10-21 stsp preserve_logmsg = 1;
786 3ce1b845 2019-07-15 stsp goto done;
787 ef293bdd 2019-10-21 stsp }
788 3ce1b845 2019-07-15 stsp }
789 3ce1b845 2019-07-15 stsp
790 3ce1b845 2019-07-15 stsp printf("Created branch %s with commit %s\n",
791 3ce1b845 2019-07-15 stsp got_ref_get_name(branch_ref), id_str);
792 2c7829a4 2019-06-17 stsp done:
793 ef293bdd 2019-10-21 stsp if (preserve_logmsg) {
794 ef293bdd 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
795 ef293bdd 2019-10-21 stsp getprogname(), logmsg_path);
796 ef293bdd 2019-10-21 stsp } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
797 ef293bdd 2019-10-21 stsp error = got_error_from_errno2("unlink", logmsg_path);
798 8e158b01 2019-09-22 stsp free(logmsg);
799 ef293bdd 2019-10-21 stsp free(logmsg_path);
800 2c7829a4 2019-06-17 stsp free(repo_path);
801 3ce1b845 2019-07-15 stsp free(editor);
802 3ce1b845 2019-07-15 stsp free(refname);
803 3ce1b845 2019-07-15 stsp free(new_commit_id);
804 3ce1b845 2019-07-15 stsp free(id_str);
805 aba9c984 2019-09-08 stsp free(author);
806 c9956ddf 2019-09-08 stsp free(gitconfig_path);
807 3ce1b845 2019-07-15 stsp if (branch_ref)
808 3ce1b845 2019-07-15 stsp got_ref_close(branch_ref);
809 3ce1b845 2019-07-15 stsp if (head_ref)
810 3ce1b845 2019-07-15 stsp got_ref_close(head_ref);
811 2c7829a4 2019-06-17 stsp return error;
812 93658fb9 2020-03-18 stsp }
813 93658fb9 2020-03-18 stsp
814 93658fb9 2020-03-18 stsp __dead static void
815 93658fb9 2020-03-18 stsp usage_clone(void)
816 93658fb9 2020-03-18 stsp {
817 13f12b09 2020-03-21 stsp fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
818 0e4002ca 2020-03-21 stsp "[-R reference] repository-url [directory]\n", getprogname());
819 93658fb9 2020-03-18 stsp exit(1);
820 93658fb9 2020-03-18 stsp }
821 892ac3b6 2020-03-18 stsp
822 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg {
823 892ac3b6 2020-03-18 stsp char last_scaled_size[FMT_SCALED_STRSIZE];
824 892ac3b6 2020-03-18 stsp int last_p_indexed;
825 892ac3b6 2020-03-18 stsp int last_p_resolved;
826 68999b92 2020-03-18 stsp int verbosity;
827 892ac3b6 2020-03-18 stsp };
828 93658fb9 2020-03-18 stsp
829 93658fb9 2020-03-18 stsp static const struct got_error *
830 baa9fea0 2020-03-18 stsp fetch_progress(void *arg, const char *message, off_t packfile_size,
831 668a20f6 2020-03-18 stsp int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
832 531c3985 2020-03-18 stsp {
833 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg *a = arg;
834 892ac3b6 2020-03-18 stsp char scaled_size[FMT_SCALED_STRSIZE];
835 892ac3b6 2020-03-18 stsp int p_indexed, p_resolved;
836 892ac3b6 2020-03-18 stsp int print_size = 0, print_indexed = 0, print_resolved = 0;
837 b2409d58 2020-03-18 stsp
838 68999b92 2020-03-18 stsp if (a->verbosity < 0)
839 68999b92 2020-03-18 stsp return NULL;
840 68999b92 2020-03-18 stsp
841 fd843b58 2020-03-18 stsp if (message && message[0] != '\0') {
842 d2cdc636 2020-03-18 stsp printf("\rserver: %s", message);
843 892ac3b6 2020-03-18 stsp fflush(stdout);
844 12d1281e 2020-03-19 stsp return NULL;
845 b2409d58 2020-03-18 stsp }
846 b2409d58 2020-03-18 stsp
847 b2409d58 2020-03-18 stsp if (packfile_size > 0 || nobj_indexed > 0) {
848 892ac3b6 2020-03-18 stsp if (fmt_scaled(packfile_size, scaled_size) == 0 &&
849 892ac3b6 2020-03-18 stsp (a->last_scaled_size[0] == '\0' ||
850 892ac3b6 2020-03-18 stsp strcmp(scaled_size, a->last_scaled_size)) != 0) {
851 892ac3b6 2020-03-18 stsp print_size = 1;
852 892ac3b6 2020-03-18 stsp if (strlcpy(a->last_scaled_size, scaled_size,
853 892ac3b6 2020-03-18 stsp FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
854 892ac3b6 2020-03-18 stsp return got_error(GOT_ERR_NO_SPACE);
855 892ac3b6 2020-03-18 stsp }
856 61cc1a7a 2020-03-18 stsp if (nobj_indexed > 0) {
857 892ac3b6 2020-03-18 stsp p_indexed = (nobj_indexed * 100) / nobj_total;
858 892ac3b6 2020-03-18 stsp if (p_indexed != a->last_p_indexed) {
859 892ac3b6 2020-03-18 stsp a->last_p_indexed = p_indexed;
860 892ac3b6 2020-03-18 stsp print_indexed = 1;
861 892ac3b6 2020-03-18 stsp print_size = 1;
862 892ac3b6 2020-03-18 stsp }
863 61cc1a7a 2020-03-18 stsp }
864 61cc1a7a 2020-03-18 stsp if (nobj_resolved > 0) {
865 892ac3b6 2020-03-18 stsp p_resolved = (nobj_resolved * 100) /
866 892ac3b6 2020-03-18 stsp (nobj_total - nobj_loose);
867 892ac3b6 2020-03-18 stsp if (p_resolved != a->last_p_resolved) {
868 892ac3b6 2020-03-18 stsp a->last_p_resolved = p_resolved;
869 892ac3b6 2020-03-18 stsp print_resolved = 1;
870 892ac3b6 2020-03-18 stsp print_indexed = 1;
871 892ac3b6 2020-03-18 stsp print_size = 1;
872 892ac3b6 2020-03-18 stsp }
873 61cc1a7a 2020-03-18 stsp }
874 b2409d58 2020-03-18 stsp
875 d2cdc636 2020-03-18 stsp }
876 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
877 892ac3b6 2020-03-18 stsp printf("\r");
878 892ac3b6 2020-03-18 stsp if (print_size)
879 892ac3b6 2020-03-18 stsp printf("%*s fetched", FMT_SCALED_STRSIZE, scaled_size);
880 d715f13e 2020-03-19 stsp if (print_indexed)
881 892ac3b6 2020-03-18 stsp printf("; indexing %d%%", p_indexed);
882 d715f13e 2020-03-19 stsp if (print_resolved)
883 892ac3b6 2020-03-18 stsp printf("; resolving deltas %d%%", p_resolved);
884 892ac3b6 2020-03-18 stsp if (print_size || print_indexed || print_resolved)
885 892ac3b6 2020-03-18 stsp fflush(stdout);
886 892ac3b6 2020-03-18 stsp
887 531c3985 2020-03-18 stsp return NULL;
888 531c3985 2020-03-18 stsp }
889 531c3985 2020-03-18 stsp
890 531c3985 2020-03-18 stsp static const struct got_error *
891 f298ae0f 2020-03-25 stsp create_symref(const char *refname, struct got_reference *target_ref,
892 f298ae0f 2020-03-25 stsp int verbosity, struct got_repository *repo)
893 4ba14133 2020-03-20 stsp {
894 4ba14133 2020-03-20 stsp const struct got_error *err;
895 4ba14133 2020-03-20 stsp struct got_reference *head_symref;
896 4ba14133 2020-03-20 stsp
897 f298ae0f 2020-03-25 stsp err = got_ref_alloc_symref(&head_symref, refname, target_ref);
898 4ba14133 2020-03-20 stsp if (err)
899 4ba14133 2020-03-20 stsp return err;
900 4ba14133 2020-03-20 stsp
901 4ba14133 2020-03-20 stsp err = got_ref_write(head_symref, repo);
902 4ba14133 2020-03-20 stsp got_ref_close(head_symref);
903 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity > 0) {
904 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", GOT_REF_HEAD,
905 6338a6a1 2020-03-21 stsp got_ref_get_name(target_ref));
906 6338a6a1 2020-03-21 stsp }
907 4ba14133 2020-03-20 stsp return err;
908 4ba14133 2020-03-20 stsp }
909 4ba14133 2020-03-20 stsp
910 4ba14133 2020-03-20 stsp static const struct got_error *
911 41b0de12 2020-03-21 stsp list_remote_refs(struct got_pathlist_head *symrefs,
912 41b0de12 2020-03-21 stsp struct got_pathlist_head *refs)
913 41b0de12 2020-03-21 stsp {
914 41b0de12 2020-03-21 stsp const struct got_error *err;
915 41b0de12 2020-03-21 stsp struct got_pathlist_entry *pe;
916 41b0de12 2020-03-21 stsp
917 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, symrefs, entry) {
918 41b0de12 2020-03-21 stsp const char *refname = pe->path;
919 41b0de12 2020-03-21 stsp const char *targetref = pe->data;
920 41b0de12 2020-03-21 stsp
921 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, targetref);
922 41b0de12 2020-03-21 stsp }
923 41b0de12 2020-03-21 stsp
924 41b0de12 2020-03-21 stsp TAILQ_FOREACH(pe, refs, entry) {
925 41b0de12 2020-03-21 stsp const char *refname = pe->path;
926 41b0de12 2020-03-21 stsp struct got_object_id *id = pe->data;
927 41b0de12 2020-03-21 stsp char *id_str;
928 41b0de12 2020-03-21 stsp
929 41b0de12 2020-03-21 stsp err = got_object_id_str(&id_str, id);
930 41b0de12 2020-03-21 stsp if (err)
931 41b0de12 2020-03-21 stsp return err;
932 41b0de12 2020-03-21 stsp printf("%s: %s\n", refname, id_str);
933 41b0de12 2020-03-21 stsp free(id_str);
934 41b0de12 2020-03-21 stsp }
935 41b0de12 2020-03-21 stsp
936 41b0de12 2020-03-21 stsp return NULL;
937 6338a6a1 2020-03-21 stsp }
938 6338a6a1 2020-03-21 stsp
939 6338a6a1 2020-03-21 stsp static const struct got_error *
940 6338a6a1 2020-03-21 stsp create_ref(const char *refname, struct got_object_id *id,
941 6338a6a1 2020-03-21 stsp int verbosity, struct got_repository *repo)
942 6338a6a1 2020-03-21 stsp {
943 6338a6a1 2020-03-21 stsp const struct got_error *err = NULL;
944 6338a6a1 2020-03-21 stsp struct got_reference *ref;
945 6338a6a1 2020-03-21 stsp char *id_str;
946 6338a6a1 2020-03-21 stsp
947 6338a6a1 2020-03-21 stsp err = got_object_id_str(&id_str, id);
948 6338a6a1 2020-03-21 stsp if (err)
949 6338a6a1 2020-03-21 stsp return err;
950 6338a6a1 2020-03-21 stsp
951 6338a6a1 2020-03-21 stsp err = got_ref_alloc(&ref, refname, id);
952 6338a6a1 2020-03-21 stsp if (err)
953 6338a6a1 2020-03-21 stsp goto done;
954 6338a6a1 2020-03-21 stsp
955 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
956 6338a6a1 2020-03-21 stsp got_ref_close(ref);
957 6338a6a1 2020-03-21 stsp
958 6338a6a1 2020-03-21 stsp if (err == NULL && verbosity >= 0)
959 6338a6a1 2020-03-21 stsp printf("Created reference %s: %s\n", refname, id_str);
960 6338a6a1 2020-03-21 stsp done:
961 6338a6a1 2020-03-21 stsp free(id_str);
962 6338a6a1 2020-03-21 stsp return err;
963 0e4002ca 2020-03-21 stsp }
964 0e4002ca 2020-03-21 stsp
965 0e4002ca 2020-03-21 stsp static int
966 0e4002ca 2020-03-21 stsp match_wanted_ref(const char *refname, const char *wanted_ref)
967 0e4002ca 2020-03-21 stsp {
968 0e4002ca 2020-03-21 stsp if (strncmp(refname, "refs/", 5) != 0)
969 0e4002ca 2020-03-21 stsp return 0;
970 0e4002ca 2020-03-21 stsp refname += 5;
971 0e4002ca 2020-03-21 stsp
972 0e4002ca 2020-03-21 stsp /*
973 0e4002ca 2020-03-21 stsp * Prevent fetching of references that won't make any
974 0e4002ca 2020-03-21 stsp * sense outside of the remote repository's context.
975 0e4002ca 2020-03-21 stsp */
976 0e4002ca 2020-03-21 stsp if (strncmp(refname, "got/", 4) == 0)
977 0e4002ca 2020-03-21 stsp return 0;
978 0e4002ca 2020-03-21 stsp if (strncmp(refname, "remotes/", 8) == 0)
979 0e4002ca 2020-03-21 stsp return 0;
980 0e4002ca 2020-03-21 stsp
981 0e4002ca 2020-03-21 stsp if (strncmp(wanted_ref, "refs/", 5) == 0)
982 0e4002ca 2020-03-21 stsp wanted_ref += 5;
983 0e4002ca 2020-03-21 stsp
984 0e4002ca 2020-03-21 stsp /* Allow prefix match. */
985 0e4002ca 2020-03-21 stsp if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
986 0e4002ca 2020-03-21 stsp return 1;
987 0e4002ca 2020-03-21 stsp
988 0e4002ca 2020-03-21 stsp /* Allow exact match. */
989 0e4002ca 2020-03-21 stsp return (strcmp(refname, wanted_ref) == 0);
990 41b0de12 2020-03-21 stsp }
991 41b0de12 2020-03-21 stsp
992 0e4002ca 2020-03-21 stsp static int
993 0e4002ca 2020-03-21 stsp is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
994 0e4002ca 2020-03-21 stsp {
995 0e4002ca 2020-03-21 stsp struct got_pathlist_entry *pe;
996 0e4002ca 2020-03-21 stsp
997 0e4002ca 2020-03-21 stsp TAILQ_FOREACH(pe, wanted_refs, entry) {
998 0e4002ca 2020-03-21 stsp if (match_wanted_ref(refname, pe->path))
999 0e4002ca 2020-03-21 stsp return 1;
1000 0e4002ca 2020-03-21 stsp }
1001 0e4002ca 2020-03-21 stsp
1002 0e4002ca 2020-03-21 stsp return 0;
1003 0e4002ca 2020-03-21 stsp }
1004 0e4002ca 2020-03-21 stsp
1005 41b0de12 2020-03-21 stsp static const struct got_error *
1006 0e4002ca 2020-03-21 stsp create_wanted_ref(const char *refname, struct got_object_id *id,
1007 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
1008 0e4002ca 2020-03-21 stsp {
1009 0e4002ca 2020-03-21 stsp const struct got_error *err;
1010 0e4002ca 2020-03-21 stsp char *remote_refname;
1011 0e4002ca 2020-03-21 stsp
1012 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
1013 0e4002ca 2020-03-21 stsp refname += 5;
1014 0e4002ca 2020-03-21 stsp
1015 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1016 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
1017 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
1018 0e4002ca 2020-03-21 stsp
1019 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
1020 0e4002ca 2020-03-21 stsp free(remote_refname);
1021 0e4002ca 2020-03-21 stsp return err;
1022 0e4002ca 2020-03-21 stsp }
1023 0e4002ca 2020-03-21 stsp
1024 0e4002ca 2020-03-21 stsp static const struct got_error *
1025 93658fb9 2020-03-18 stsp cmd_clone(int argc, char *argv[])
1026 93658fb9 2020-03-18 stsp {
1027 39c64a6a 2020-03-18 stsp const struct got_error *error = NULL;
1028 9df6f38b 2020-03-18 stsp const char *uri, *dirname;
1029 09838ffc 2020-03-18 stsp char *proto, *host, *port, *repo_name, *server_path;
1030 d9b4d0c0 2020-03-18 stsp char *default_destdir = NULL, *id_str = NULL;
1031 bb64b798 2020-03-18 stsp const char *repo_path;
1032 bb64b798 2020-03-18 stsp struct got_repository *repo = NULL;
1033 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1034 d9b4d0c0 2020-03-18 stsp struct got_pathlist_entry *pe;
1035 d9b4d0c0 2020-03-18 stsp struct got_object_id *pack_hash = NULL;
1036 9c52365f 2020-03-21 stsp int ch, fetchfd = -1, fetchstatus;
1037 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
1038 892ac3b6 2020-03-18 stsp struct got_fetch_progress_arg fpa;
1039 b46f3e71 2020-03-18 stsp char *git_url = NULL;
1040 b46f3e71 2020-03-18 stsp char *gitconfig_path = NULL;
1041 b46f3e71 2020-03-18 stsp char *gitconfig = NULL;
1042 b46f3e71 2020-03-18 stsp FILE *gitconfig_file = NULL;
1043 b46f3e71 2020-03-18 stsp ssize_t n;
1044 659e7fbd 2020-03-20 stsp int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1045 41b0de12 2020-03-21 stsp int list_refs_only = 0;
1046 659e7fbd 2020-03-20 stsp struct got_reference *head_symref = NULL;
1047 93658fb9 2020-03-18 stsp
1048 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&refs);
1049 d9b4d0c0 2020-03-18 stsp TAILQ_INIT(&symrefs);
1050 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
1051 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
1052 d9b4d0c0 2020-03-18 stsp
1053 0e4002ca 2020-03-21 stsp while ((ch = getopt(argc, argv, "ab:lmvqR:")) != -1) {
1054 93658fb9 2020-03-18 stsp switch (ch) {
1055 659e7fbd 2020-03-20 stsp case 'a':
1056 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
1057 4ba14133 2020-03-20 stsp break;
1058 4ba14133 2020-03-20 stsp case 'b':
1059 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
1060 4ba14133 2020-03-20 stsp optarg, NULL);
1061 4ba14133 2020-03-20 stsp if (error)
1062 4ba14133 2020-03-20 stsp return error;
1063 659e7fbd 2020-03-20 stsp break;
1064 41b0de12 2020-03-21 stsp case 'l':
1065 41b0de12 2020-03-21 stsp list_refs_only = 1;
1066 41b0de12 2020-03-21 stsp break;
1067 469dd726 2020-03-20 stsp case 'm':
1068 469dd726 2020-03-20 stsp mirror_references = 1;
1069 469dd726 2020-03-20 stsp break;
1070 68999b92 2020-03-18 stsp case 'v':
1071 68999b92 2020-03-18 stsp if (verbosity < 0)
1072 68999b92 2020-03-18 stsp verbosity = 0;
1073 68999b92 2020-03-18 stsp else if (verbosity < 3)
1074 68999b92 2020-03-18 stsp verbosity++;
1075 68999b92 2020-03-18 stsp break;
1076 68999b92 2020-03-18 stsp case 'q':
1077 68999b92 2020-03-18 stsp verbosity = -1;
1078 68999b92 2020-03-18 stsp break;
1079 0e4002ca 2020-03-21 stsp case 'R':
1080 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
1081 0e4002ca 2020-03-21 stsp optarg, NULL);
1082 0e4002ca 2020-03-21 stsp if (error)
1083 0e4002ca 2020-03-21 stsp return error;
1084 0e4002ca 2020-03-21 stsp break;
1085 93658fb9 2020-03-18 stsp default:
1086 93658fb9 2020-03-18 stsp usage_clone();
1087 93658fb9 2020-03-18 stsp break;
1088 93658fb9 2020-03-18 stsp }
1089 93658fb9 2020-03-18 stsp }
1090 93658fb9 2020-03-18 stsp argc -= optind;
1091 93658fb9 2020-03-18 stsp argv += optind;
1092 39c64a6a 2020-03-18 stsp
1093 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1094 41b0de12 2020-03-21 stsp errx(1, "-a and -b options are mutually exclusive");
1095 41b0de12 2020-03-21 stsp if (list_refs_only) {
1096 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
1097 41b0de12 2020-03-21 stsp errx(1, "-l and -b options are mutually exclusive");
1098 41b0de12 2020-03-21 stsp if (fetch_all_branches)
1099 41b0de12 2020-03-21 stsp errx(1, "-l and -a options are mutually exclusive");
1100 41b0de12 2020-03-21 stsp if (mirror_references)
1101 41b0de12 2020-03-21 stsp errx(1, "-l and -m options are mutually exclusive");
1102 41b0de12 2020-03-21 stsp if (verbosity == -1)
1103 41b0de12 2020-03-21 stsp errx(1, "-l and -q options are mutually exclusive");
1104 0e4002ca 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_refs))
1105 0e4002ca 2020-03-21 stsp errx(1, "-l and -R options are mutually exclusive");
1106 41b0de12 2020-03-21 stsp }
1107 4ba14133 2020-03-20 stsp
1108 93658fb9 2020-03-18 stsp uri = argv[0];
1109 9df6f38b 2020-03-18 stsp
1110 9df6f38b 2020-03-18 stsp if (argc == 1)
1111 93658fb9 2020-03-18 stsp dirname = NULL;
1112 9df6f38b 2020-03-18 stsp else if (argc == 2)
1113 93658fb9 2020-03-18 stsp dirname = argv[1];
1114 93658fb9 2020-03-18 stsp else
1115 93658fb9 2020-03-18 stsp usage_clone();
1116 09838ffc 2020-03-18 stsp
1117 39c64a6a 2020-03-18 stsp error = got_fetch_parse_uri(&proto, &host, &port, &server_path,
1118 09838ffc 2020-03-18 stsp &repo_name, argv[0]);
1119 39c64a6a 2020-03-18 stsp if (error)
1120 09f63084 2020-03-20 stsp goto done;
1121 09f63084 2020-03-20 stsp
1122 09f63084 2020-03-20 stsp if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1123 09f63084 2020-03-20 stsp host, port ? ":" : "", port ? port : "",
1124 09f63084 2020-03-20 stsp server_path[0] != '/' ? "/" : "", server_path) == -1) {
1125 09f63084 2020-03-20 stsp error = got_error_from_errno("asprintf");
1126 09838ffc 2020-03-18 stsp goto done;
1127 09f63084 2020-03-20 stsp }
1128 09838ffc 2020-03-18 stsp
1129 39c64a6a 2020-03-18 stsp if (strcmp(proto, "git") == 0) {
1130 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1131 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1132 39c64a6a 2020-03-18 stsp "sendfd dns inet unveil", NULL) == -1)
1133 39c64a6a 2020-03-18 stsp err(1, "pledge");
1134 b46f3e71 2020-03-18 stsp #endif
1135 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
1136 39c64a6a 2020-03-18 stsp strcmp(proto, "ssh") == 0) {
1137 b46f3e71 2020-03-18 stsp #ifndef PROFILE
1138 39c64a6a 2020-03-18 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1139 39c64a6a 2020-03-18 stsp "sendfd unveil", NULL) == -1)
1140 39c64a6a 2020-03-18 stsp err(1, "pledge");
1141 b46f3e71 2020-03-18 stsp #endif
1142 39c64a6a 2020-03-18 stsp } else if (strcmp(proto, "http") == 0 ||
1143 39c64a6a 2020-03-18 stsp strcmp(proto, "git+http") == 0) {
1144 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1145 39c64a6a 2020-03-18 stsp goto done;
1146 39c64a6a 2020-03-18 stsp } else {
1147 39c64a6a 2020-03-18 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1148 39c64a6a 2020-03-18 stsp goto done;
1149 39c64a6a 2020-03-18 stsp }
1150 bb64b798 2020-03-18 stsp if (dirname == NULL) {
1151 bb64b798 2020-03-18 stsp if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1152 39c64a6a 2020-03-18 stsp error = got_error_from_errno("asprintf");
1153 bb64b798 2020-03-18 stsp goto done;
1154 bb64b798 2020-03-18 stsp }
1155 bb64b798 2020-03-18 stsp repo_path = default_destdir;
1156 bb64b798 2020-03-18 stsp } else
1157 bb64b798 2020-03-18 stsp repo_path = dirname;
1158 bb64b798 2020-03-18 stsp
1159 41b0de12 2020-03-21 stsp if (!list_refs_only) {
1160 41b0de12 2020-03-21 stsp error = got_path_mkdir(repo_path);
1161 41b0de12 2020-03-21 stsp if (error)
1162 41b0de12 2020-03-21 stsp goto done;
1163 bb64b798 2020-03-18 stsp
1164 41b0de12 2020-03-21 stsp error = got_repo_init(repo_path);
1165 41b0de12 2020-03-21 stsp if (error)
1166 41b0de12 2020-03-21 stsp goto done;
1167 41b0de12 2020-03-21 stsp error = got_repo_open(&repo, repo_path, NULL);
1168 41b0de12 2020-03-21 stsp if (error)
1169 41b0de12 2020-03-21 stsp goto done;
1170 41b0de12 2020-03-21 stsp }
1171 bb64b798 2020-03-18 stsp
1172 ee448f5f 2020-03-18 stsp if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) {
1173 ee448f5f 2020-03-18 stsp if (unveil(GOT_FETCH_PATH_SSH, "x") != 0) {
1174 ee448f5f 2020-03-18 stsp error = got_error_from_errno2("unveil",
1175 ee448f5f 2020-03-18 stsp GOT_FETCH_PATH_SSH);
1176 ee448f5f 2020-03-18 stsp goto done;
1177 ee448f5f 2020-03-18 stsp }
1178 ee448f5f 2020-03-18 stsp }
1179 41b0de12 2020-03-21 stsp error = apply_unveil(repo ? got_repo_get_path(repo) : NULL, 0, NULL);
1180 ee448f5f 2020-03-18 stsp if (error)
1181 ee448f5f 2020-03-18 stsp goto done;
1182 f79e6490 2020-04-19 stsp
1183 f79e6490 2020-04-19 stsp if (verbosity >= 0)
1184 f79e6490 2020-04-19 stsp printf("Connecting to %s%s%s\n", host,
1185 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
1186 ee448f5f 2020-03-18 stsp
1187 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1188 9c52365f 2020-03-21 stsp server_path, verbosity);
1189 39c64a6a 2020-03-18 stsp if (error)
1190 bb64b798 2020-03-18 stsp goto done;
1191 bb64b798 2020-03-18 stsp
1192 892ac3b6 2020-03-18 stsp fpa.last_scaled_size[0] = '\0';
1193 892ac3b6 2020-03-18 stsp fpa.last_p_indexed = -1;
1194 892ac3b6 2020-03-18 stsp fpa.last_p_resolved = -1;
1195 68999b92 2020-03-18 stsp fpa.verbosity = verbosity;
1196 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1197 469dd726 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1198 0e4002ca 2020-03-21 stsp fetch_all_branches, &wanted_branches, &wanted_refs,
1199 0e4002ca 2020-03-21 stsp list_refs_only, verbosity, fetchfd, repo,
1200 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
1201 39c64a6a 2020-03-18 stsp if (error)
1202 d9b4d0c0 2020-03-18 stsp goto done;
1203 d9b4d0c0 2020-03-18 stsp
1204 41b0de12 2020-03-21 stsp if (list_refs_only) {
1205 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
1206 41b0de12 2020-03-21 stsp goto done;
1207 41b0de12 2020-03-21 stsp }
1208 41b0de12 2020-03-21 stsp
1209 39c64a6a 2020-03-18 stsp error = got_object_id_str(&id_str, pack_hash);
1210 39c64a6a 2020-03-18 stsp if (error)
1211 d9b4d0c0 2020-03-18 stsp goto done;
1212 68999b92 2020-03-18 stsp if (verbosity >= 0)
1213 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
1214 d9b4d0c0 2020-03-18 stsp free(id_str);
1215 d9b4d0c0 2020-03-18 stsp
1216 d9b4d0c0 2020-03-18 stsp /* Set up references provided with the pack file. */
1217 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1218 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1219 d9b4d0c0 2020-03-18 stsp struct got_object_id *id = pe->data;
1220 7ebc0570 2020-03-18 stsp char *remote_refname;
1221 0e4002ca 2020-03-21 stsp
1222 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
1223 0e4002ca 2020-03-21 stsp !mirror_references) {
1224 0e4002ca 2020-03-21 stsp error = create_wanted_ref(refname, id,
1225 0e4002ca 2020-03-21 stsp GOT_FETCH_DEFAULT_REMOTE_NAME,
1226 0e4002ca 2020-03-21 stsp verbosity - 1, repo);
1227 0e4002ca 2020-03-21 stsp if (error)
1228 0e4002ca 2020-03-21 stsp goto done;
1229 0e4002ca 2020-03-21 stsp continue;
1230 0e4002ca 2020-03-21 stsp }
1231 668a20f6 2020-03-18 stsp
1232 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity - 1, repo);
1233 39c64a6a 2020-03-18 stsp if (error)
1234 d9b4d0c0 2020-03-18 stsp goto done;
1235 d9b4d0c0 2020-03-18 stsp
1236 469dd726 2020-03-20 stsp if (mirror_references)
1237 469dd726 2020-03-20 stsp continue;
1238 469dd726 2020-03-20 stsp
1239 7ebc0570 2020-03-18 stsp if (strncmp("refs/heads/", refname, 11) != 0)
1240 7ebc0570 2020-03-18 stsp continue;
1241 7ebc0570 2020-03-18 stsp
1242 7ebc0570 2020-03-18 stsp if (asprintf(&remote_refname,
1243 7ebc0570 2020-03-18 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1244 7ebc0570 2020-03-18 stsp refname + 11) == -1) {
1245 7ebc0570 2020-03-18 stsp error = got_error_from_errno("asprintf");
1246 7ebc0570 2020-03-18 stsp goto done;
1247 7ebc0570 2020-03-18 stsp }
1248 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id, verbosity - 1, repo);
1249 f298ae0f 2020-03-25 stsp free(remote_refname);
1250 39c64a6a 2020-03-18 stsp if (error)
1251 d9b4d0c0 2020-03-18 stsp goto done;
1252 d9b4d0c0 2020-03-18 stsp }
1253 d9b4d0c0 2020-03-18 stsp
1254 d9b4d0c0 2020-03-18 stsp /* Set the HEAD reference if the server provided one. */
1255 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1256 659e7fbd 2020-03-20 stsp struct got_reference *target_ref;
1257 d9b4d0c0 2020-03-18 stsp const char *refname = pe->path;
1258 d9b4d0c0 2020-03-18 stsp const char *target = pe->data;
1259 f298ae0f 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
1260 d9b4d0c0 2020-03-18 stsp
1261 d9b4d0c0 2020-03-18 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
1262 d9b4d0c0 2020-03-18 stsp continue;
1263 d9b4d0c0 2020-03-18 stsp
1264 39c64a6a 2020-03-18 stsp error = got_ref_open(&target_ref, repo, target, 0);
1265 39c64a6a 2020-03-18 stsp if (error) {
1266 55330abe 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1267 55330abe 2020-03-20 stsp error = NULL;
1268 d9b4d0c0 2020-03-18 stsp continue;
1269 55330abe 2020-03-20 stsp }
1270 d9b4d0c0 2020-03-18 stsp goto done;
1271 d9b4d0c0 2020-03-18 stsp }
1272 d9b4d0c0 2020-03-18 stsp
1273 f298ae0f 2020-03-25 stsp error = create_symref(refname, target_ref, verbosity, repo);
1274 f298ae0f 2020-03-25 stsp got_ref_close(target_ref);
1275 f298ae0f 2020-03-25 stsp if (error)
1276 f298ae0f 2020-03-25 stsp goto done;
1277 f298ae0f 2020-03-25 stsp
1278 f298ae0f 2020-03-25 stsp if (mirror_references)
1279 f298ae0f 2020-03-25 stsp continue;
1280 f298ae0f 2020-03-25 stsp
1281 f298ae0f 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
1282 f298ae0f 2020-03-25 stsp continue;
1283 f298ae0f 2020-03-25 stsp
1284 f298ae0f 2020-03-25 stsp if (asprintf(&remote_refname,
1285 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1286 f298ae0f 2020-03-25 stsp refname) == -1) {
1287 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1288 f298ae0f 2020-03-25 stsp goto done;
1289 f298ae0f 2020-03-25 stsp }
1290 f298ae0f 2020-03-25 stsp if (asprintf(&remote_target,
1291 f298ae0f 2020-03-25 stsp "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1292 f298ae0f 2020-03-25 stsp target + 11) == -1) {
1293 f298ae0f 2020-03-25 stsp error = got_error_from_errno("asprintf");
1294 f298ae0f 2020-03-25 stsp free(remote_refname);
1295 f298ae0f 2020-03-25 stsp goto done;
1296 f298ae0f 2020-03-25 stsp }
1297 f298ae0f 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target, 0);
1298 f298ae0f 2020-03-25 stsp if (error) {
1299 f298ae0f 2020-03-25 stsp free(remote_refname);
1300 f298ae0f 2020-03-25 stsp free(remote_target);
1301 f298ae0f 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
1302 f298ae0f 2020-03-25 stsp error = NULL;
1303 f298ae0f 2020-03-25 stsp continue;
1304 f298ae0f 2020-03-25 stsp }
1305 f298ae0f 2020-03-25 stsp goto done;
1306 f298ae0f 2020-03-25 stsp }
1307 f298ae0f 2020-03-25 stsp error = create_symref(remote_refname, target_ref,
1308 f298ae0f 2020-03-25 stsp verbosity - 1, repo);
1309 f298ae0f 2020-03-25 stsp free(remote_refname);
1310 f298ae0f 2020-03-25 stsp free(remote_target);
1311 d9b4d0c0 2020-03-18 stsp got_ref_close(target_ref);
1312 39c64a6a 2020-03-18 stsp if (error)
1313 d9b4d0c0 2020-03-18 stsp goto done;
1314 4ba14133 2020-03-20 stsp }
1315 4ba14133 2020-03-20 stsp if (pe == NULL) {
1316 4ba14133 2020-03-20 stsp /*
1317 4ba14133 2020-03-20 stsp * We failed to set the HEAD reference. If we asked for
1318 4ba14133 2020-03-20 stsp * a set of wanted branches use the first of one of those
1319 4ba14133 2020-03-20 stsp * which could be fetched instead.
1320 4ba14133 2020-03-20 stsp */
1321 4ba14133 2020-03-20 stsp TAILQ_FOREACH(pe, &wanted_branches, entry) {
1322 4ba14133 2020-03-20 stsp const char *target = pe->path;
1323 4ba14133 2020-03-20 stsp struct got_reference *target_ref;
1324 d9b4d0c0 2020-03-18 stsp
1325 4ba14133 2020-03-20 stsp error = got_ref_open(&target_ref, repo, target, 0);
1326 4ba14133 2020-03-20 stsp if (error) {
1327 4ba14133 2020-03-20 stsp if (error->code == GOT_ERR_NOT_REF) {
1328 4ba14133 2020-03-20 stsp error = NULL;
1329 4ba14133 2020-03-20 stsp continue;
1330 4ba14133 2020-03-20 stsp }
1331 4ba14133 2020-03-20 stsp goto done;
1332 4ba14133 2020-03-20 stsp }
1333 4ba14133 2020-03-20 stsp
1334 f298ae0f 2020-03-25 stsp error = create_symref(GOT_REF_HEAD, target_ref,
1335 f298ae0f 2020-03-25 stsp verbosity, repo);
1336 4ba14133 2020-03-20 stsp got_ref_close(target_ref);
1337 4ba14133 2020-03-20 stsp if (error)
1338 4ba14133 2020-03-20 stsp goto done;
1339 4ba14133 2020-03-20 stsp break;
1340 4ba14133 2020-03-20 stsp }
1341 659e7fbd 2020-03-20 stsp }
1342 659e7fbd 2020-03-20 stsp
1343 659e7fbd 2020-03-20 stsp /* Create a config file git-fetch(1) can understand. */
1344 659e7fbd 2020-03-20 stsp gitconfig_path = got_repo_get_path_gitconfig(repo);
1345 659e7fbd 2020-03-20 stsp if (gitconfig_path == NULL) {
1346 659e7fbd 2020-03-20 stsp error = got_error_from_errno("got_repo_get_path_gitconfig");
1347 659e7fbd 2020-03-20 stsp goto done;
1348 659e7fbd 2020-03-20 stsp }
1349 659e7fbd 2020-03-20 stsp gitconfig_file = fopen(gitconfig_path, "a");
1350 659e7fbd 2020-03-20 stsp if (gitconfig_file == NULL) {
1351 659e7fbd 2020-03-20 stsp error = got_error_from_errno2("fopen", gitconfig_path);
1352 659e7fbd 2020-03-20 stsp goto done;
1353 b46f3e71 2020-03-18 stsp }
1354 659e7fbd 2020-03-20 stsp if (mirror_references) {
1355 659e7fbd 2020-03-20 stsp if (asprintf(&gitconfig,
1356 659e7fbd 2020-03-20 stsp "[remote \"%s\"]\n"
1357 659e7fbd 2020-03-20 stsp "\turl = %s\n"
1358 8ceee112 2020-03-20 stsp "\tfetch = +refs/*:refs/*\n"
1359 659e7fbd 2020-03-20 stsp "\tmirror = true\n",
1360 659e7fbd 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, git_url) == -1) {
1361 659e7fbd 2020-03-20 stsp error = got_error_from_errno("asprintf");
1362 659e7fbd 2020-03-20 stsp goto done;
1363 659e7fbd 2020-03-20 stsp }
1364 659e7fbd 2020-03-20 stsp } else if (fetch_all_branches) {
1365 659e7fbd 2020-03-20 stsp if (asprintf(&gitconfig,
1366 659e7fbd 2020-03-20 stsp "[remote \"%s\"]\n"
1367 659e7fbd 2020-03-20 stsp "\turl = %s\n"
1368 659e7fbd 2020-03-20 stsp "\tfetch = +refs/heads/*:refs/remotes/%s/*\n",
1369 659e7fbd 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, git_url,
1370 659e7fbd 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1371 659e7fbd 2020-03-20 stsp error = got_error_from_errno("asprintf");
1372 659e7fbd 2020-03-20 stsp goto done;
1373 659e7fbd 2020-03-20 stsp }
1374 659e7fbd 2020-03-20 stsp } else {
1375 659e7fbd 2020-03-20 stsp const char *branchname;
1376 d715f13e 2020-03-19 stsp
1377 659e7fbd 2020-03-20 stsp /*
1378 659e7fbd 2020-03-20 stsp * If the server specified a default branch, use just that one.
1379 659e7fbd 2020-03-20 stsp * Otherwise fall back to fetching all branches on next fetch.
1380 659e7fbd 2020-03-20 stsp */
1381 659e7fbd 2020-03-20 stsp if (head_symref) {
1382 659e7fbd 2020-03-20 stsp branchname = got_ref_get_symref_target(head_symref);
1383 659e7fbd 2020-03-20 stsp if (strncmp(branchname, "refs/heads/", 11) == 0)
1384 659e7fbd 2020-03-20 stsp branchname += 11;
1385 659e7fbd 2020-03-20 stsp } else
1386 659e7fbd 2020-03-20 stsp branchname = "*"; /* fall back to all branches */
1387 659e7fbd 2020-03-20 stsp if (asprintf(&gitconfig,
1388 659e7fbd 2020-03-20 stsp "[remote \"%s\"]\n"
1389 659e7fbd 2020-03-20 stsp "\turl = %s\n"
1390 659e7fbd 2020-03-20 stsp "\tfetch = +refs/heads/%s:refs/remotes/%s/%s\n",
1391 659e7fbd 2020-03-20 stsp GOT_FETCH_DEFAULT_REMOTE_NAME, git_url,
1392 659e7fbd 2020-03-20 stsp branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1393 659e7fbd 2020-03-20 stsp branchname) == -1) {
1394 659e7fbd 2020-03-20 stsp error = got_error_from_errno("asprintf");
1395 659e7fbd 2020-03-20 stsp goto done;
1396 659e7fbd 2020-03-20 stsp }
1397 659e7fbd 2020-03-20 stsp }
1398 659e7fbd 2020-03-20 stsp n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1399 659e7fbd 2020-03-20 stsp if (n != strlen(gitconfig)) {
1400 659e7fbd 2020-03-20 stsp error = got_ferror(gitconfig_file, GOT_ERR_IO);
1401 659e7fbd 2020-03-20 stsp goto done;
1402 659e7fbd 2020-03-20 stsp }
1403 659e7fbd 2020-03-20 stsp
1404 d715f13e 2020-03-19 stsp if (verbosity >= 0)
1405 469dd726 2020-03-20 stsp printf("Created %s repository '%s'\n",
1406 469dd726 2020-03-20 stsp mirror_references ? "mirrored" : "cloned", repo_path);
1407 09838ffc 2020-03-18 stsp done:
1408 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
1409 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
1410 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
1411 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1412 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
1413 9c52365f 2020-03-21 stsp }
1414 39c64a6a 2020-03-18 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1415 39c64a6a 2020-03-18 stsp error = got_error_from_errno("close");
1416 b46f3e71 2020-03-18 stsp if (gitconfig_file && fclose(gitconfig_file) == EOF && error == NULL)
1417 b46f3e71 2020-03-18 stsp error = got_error_from_errno("fclose");
1418 bb64b798 2020-03-18 stsp if (repo)
1419 bb64b798 2020-03-18 stsp got_repo_close(repo);
1420 659e7fbd 2020-03-20 stsp if (head_symref)
1421 659e7fbd 2020-03-20 stsp got_ref_close(head_symref);
1422 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &refs, entry) {
1423 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1424 d9b4d0c0 2020-03-18 stsp free(pe->data);
1425 d9b4d0c0 2020-03-18 stsp }
1426 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&refs);
1427 d9b4d0c0 2020-03-18 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
1428 d9b4d0c0 2020-03-18 stsp free((void *)pe->path);
1429 d9b4d0c0 2020-03-18 stsp free(pe->data);
1430 d9b4d0c0 2020-03-18 stsp }
1431 d9b4d0c0 2020-03-18 stsp got_pathlist_free(&symrefs);
1432 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
1433 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
1434 d9b4d0c0 2020-03-18 stsp free(pack_hash);
1435 09838ffc 2020-03-18 stsp free(proto);
1436 09838ffc 2020-03-18 stsp free(host);
1437 09838ffc 2020-03-18 stsp free(port);
1438 09838ffc 2020-03-18 stsp free(server_path);
1439 09838ffc 2020-03-18 stsp free(repo_name);
1440 bb64b798 2020-03-18 stsp free(default_destdir);
1441 b46f3e71 2020-03-18 stsp free(gitconfig_path);
1442 b46f3e71 2020-03-18 stsp free(git_url);
1443 39c64a6a 2020-03-18 stsp return error;
1444 7848a0e1 2020-03-19 stsp }
1445 7848a0e1 2020-03-19 stsp
1446 7848a0e1 2020-03-19 stsp static const struct got_error *
1447 7848a0e1 2020-03-19 stsp update_ref(struct got_reference *ref, struct got_object_id *new_id,
1448 db6d8ad8 2020-03-21 stsp int replace_tags, int verbosity, struct got_repository *repo)
1449 7848a0e1 2020-03-19 stsp {
1450 7848a0e1 2020-03-19 stsp const struct got_error *err = NULL;
1451 7848a0e1 2020-03-19 stsp char *new_id_str = NULL;
1452 7848a0e1 2020-03-19 stsp struct got_object_id *old_id = NULL;
1453 7848a0e1 2020-03-19 stsp
1454 7848a0e1 2020-03-19 stsp err = got_object_id_str(&new_id_str, new_id);
1455 7848a0e1 2020-03-19 stsp if (err)
1456 7848a0e1 2020-03-19 stsp goto done;
1457 7848a0e1 2020-03-19 stsp
1458 db6d8ad8 2020-03-21 stsp if (!replace_tags &&
1459 db6d8ad8 2020-03-21 stsp strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1460 88609724 2020-03-21 stsp err = got_ref_resolve(&old_id, repo, ref);
1461 88609724 2020-03-21 stsp if (err)
1462 88609724 2020-03-21 stsp goto done;
1463 88609724 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1464 88609724 2020-03-21 stsp goto done;
1465 db6d8ad8 2020-03-21 stsp if (verbosity >= 0) {
1466 db6d8ad8 2020-03-21 stsp printf("Rejecting update of existing tag %s: %s\n",
1467 db6d8ad8 2020-03-21 stsp got_ref_get_name(ref), new_id_str);
1468 db6d8ad8 2020-03-21 stsp }
1469 db6d8ad8 2020-03-21 stsp goto done;
1470 db6d8ad8 2020-03-21 stsp }
1471 db6d8ad8 2020-03-21 stsp
1472 7848a0e1 2020-03-19 stsp if (got_ref_is_symbolic(ref)) {
1473 688f11b3 2020-03-21 stsp if (verbosity >= 0) {
1474 e8a967e0 2020-03-21 stsp printf("Replacing reference %s: %s\n",
1475 6338a6a1 2020-03-21 stsp got_ref_get_name(ref),
1476 6338a6a1 2020-03-21 stsp got_ref_get_symref_target(ref));
1477 688f11b3 2020-03-21 stsp }
1478 e8a967e0 2020-03-21 stsp err = got_ref_change_symref_to_ref(ref, new_id);
1479 7848a0e1 2020-03-19 stsp if (err)
1480 7848a0e1 2020-03-19 stsp goto done;
1481 e8a967e0 2020-03-21 stsp err = got_ref_write(ref, repo);
1482 e8a967e0 2020-03-21 stsp if (err)
1483 e8a967e0 2020-03-21 stsp goto done;
1484 7848a0e1 2020-03-19 stsp } else {
1485 7848a0e1 2020-03-19 stsp err = got_ref_resolve(&old_id, repo, ref);
1486 7848a0e1 2020-03-19 stsp if (err)
1487 7848a0e1 2020-03-19 stsp goto done;
1488 6338a6a1 2020-03-21 stsp if (got_object_id_cmp(old_id, new_id) == 0)
1489 6338a6a1 2020-03-21 stsp goto done;
1490 6338a6a1 2020-03-21 stsp
1491 6338a6a1 2020-03-21 stsp err = got_ref_change_ref(ref, new_id);
1492 6338a6a1 2020-03-21 stsp if (err)
1493 6338a6a1 2020-03-21 stsp goto done;
1494 6338a6a1 2020-03-21 stsp err = got_ref_write(ref, repo);
1495 6338a6a1 2020-03-21 stsp if (err)
1496 6338a6a1 2020-03-21 stsp goto done;
1497 7848a0e1 2020-03-19 stsp }
1498 6338a6a1 2020-03-21 stsp
1499 6338a6a1 2020-03-21 stsp if (verbosity >= 0)
1500 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(ref),
1501 6338a6a1 2020-03-21 stsp new_id_str);
1502 7848a0e1 2020-03-19 stsp done:
1503 7848a0e1 2020-03-19 stsp free(old_id);
1504 7848a0e1 2020-03-19 stsp free(new_id_str);
1505 7848a0e1 2020-03-19 stsp return err;
1506 2ab43947 2020-03-18 stsp }
1507 f1bcca34 2020-03-25 stsp
1508 f1bcca34 2020-03-25 stsp static const struct got_error *
1509 f1bcca34 2020-03-25 stsp update_symref(const char *refname, struct got_reference *target_ref,
1510 f1bcca34 2020-03-25 stsp int verbosity, struct got_repository *repo)
1511 f1bcca34 2020-03-25 stsp {
1512 f1bcca34 2020-03-25 stsp const struct got_error *err = NULL, *unlock_err;
1513 f1bcca34 2020-03-25 stsp struct got_reference *symref;
1514 bcf34b0e 2020-03-26 stsp int symref_is_locked = 0;
1515 f1bcca34 2020-03-25 stsp
1516 f1bcca34 2020-03-25 stsp err = got_ref_open(&symref, repo, refname, 1);
1517 bcf34b0e 2020-03-26 stsp if (err) {
1518 bcf34b0e 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
1519 bcf34b0e 2020-03-26 stsp return err;
1520 bcf34b0e 2020-03-26 stsp err = got_ref_alloc_symref(&symref, refname, target_ref);
1521 bcf34b0e 2020-03-26 stsp if (err)
1522 bcf34b0e 2020-03-26 stsp goto done;
1523 2ab43947 2020-03-18 stsp
1524 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1525 bcf34b0e 2020-03-26 stsp if (err)
1526 bcf34b0e 2020-03-26 stsp goto done;
1527 f1bcca34 2020-03-25 stsp
1528 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1529 bcf34b0e 2020-03-26 stsp printf("Created reference %s: %s\n",
1530 bcf34b0e 2020-03-26 stsp got_ref_get_name(symref),
1531 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1532 bcf34b0e 2020-03-26 stsp } else {
1533 bcf34b0e 2020-03-26 stsp symref_is_locked = 1;
1534 f1bcca34 2020-03-25 stsp
1535 bcf34b0e 2020-03-26 stsp if (strcmp(got_ref_get_symref_target(symref),
1536 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref)) == 0)
1537 bcf34b0e 2020-03-26 stsp goto done;
1538 bcf34b0e 2020-03-26 stsp
1539 bcf34b0e 2020-03-26 stsp err = got_ref_change_symref(symref,
1540 bcf34b0e 2020-03-26 stsp got_ref_get_name(target_ref));
1541 bcf34b0e 2020-03-26 stsp if (err)
1542 bcf34b0e 2020-03-26 stsp goto done;
1543 bcf34b0e 2020-03-26 stsp
1544 bcf34b0e 2020-03-26 stsp err = got_ref_write(symref, repo);
1545 bcf34b0e 2020-03-26 stsp if (err)
1546 bcf34b0e 2020-03-26 stsp goto done;
1547 bcf34b0e 2020-03-26 stsp
1548 bcf34b0e 2020-03-26 stsp if (verbosity >= 0)
1549 f4d0e3fb 2020-05-15 stsp printf("Updated %s: %s\n", got_ref_get_name(symref),
1550 bcf34b0e 2020-03-26 stsp got_ref_get_symref_target(symref));
1551 bcf34b0e 2020-03-26 stsp
1552 bcf34b0e 2020-03-26 stsp }
1553 f1bcca34 2020-03-25 stsp done:
1554 bcf34b0e 2020-03-26 stsp if (symref_is_locked) {
1555 bcf34b0e 2020-03-26 stsp unlock_err = got_ref_unlock(symref);
1556 bcf34b0e 2020-03-26 stsp if (unlock_err && err == NULL)
1557 bcf34b0e 2020-03-26 stsp err = unlock_err;
1558 bcf34b0e 2020-03-26 stsp }
1559 f1bcca34 2020-03-25 stsp got_ref_close(symref);
1560 f1bcca34 2020-03-25 stsp return err;
1561 f1bcca34 2020-03-25 stsp }
1562 f1bcca34 2020-03-25 stsp
1563 2ab43947 2020-03-18 stsp __dead static void
1564 7848a0e1 2020-03-19 stsp usage_fetch(void)
1565 7848a0e1 2020-03-19 stsp {
1566 f21ec2f0 2020-03-21 stsp fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
1567 0e4002ca 2020-03-21 stsp "[-r repository-path] [-t] [-q] [-v] [-R reference] "
1568 0e4002ca 2020-03-21 stsp "[remote-repository-name]\n",
1569 13f12b09 2020-03-21 stsp getprogname());
1570 7848a0e1 2020-03-19 stsp exit(1);
1571 7848a0e1 2020-03-19 stsp }
1572 7848a0e1 2020-03-19 stsp
1573 7848a0e1 2020-03-19 stsp static const struct got_error *
1574 3789fd73 2020-03-26 stsp delete_missing_ref(struct got_reference *ref,
1575 688f11b3 2020-03-21 stsp int verbosity, struct got_repository *repo)
1576 f21ec2f0 2020-03-21 stsp {
1577 f21ec2f0 2020-03-21 stsp const struct got_error *err = NULL;
1578 3789fd73 2020-03-26 stsp struct got_object_id *id = NULL;
1579 3789fd73 2020-03-26 stsp char *id_str = NULL;
1580 3789fd73 2020-03-26 stsp
1581 3789fd73 2020-03-26 stsp if (got_ref_is_symbolic(ref)) {
1582 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1583 3789fd73 2020-03-26 stsp if (err)
1584 3789fd73 2020-03-26 stsp return err;
1585 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
1586 3789fd73 2020-03-26 stsp printf("Deleted reference %s: %s\n",
1587 3789fd73 2020-03-26 stsp got_ref_get_name(ref),
1588 3789fd73 2020-03-26 stsp got_ref_get_symref_target(ref));
1589 3789fd73 2020-03-26 stsp }
1590 3789fd73 2020-03-26 stsp } else {
1591 3789fd73 2020-03-26 stsp err = got_ref_resolve(&id, repo, ref);
1592 3789fd73 2020-03-26 stsp if (err)
1593 3789fd73 2020-03-26 stsp return err;
1594 3789fd73 2020-03-26 stsp err = got_object_id_str(&id_str, id);
1595 3789fd73 2020-03-26 stsp if (err)
1596 3789fd73 2020-03-26 stsp goto done;
1597 3789fd73 2020-03-26 stsp
1598 3789fd73 2020-03-26 stsp err = got_ref_delete(ref, repo);
1599 3789fd73 2020-03-26 stsp if (err)
1600 3789fd73 2020-03-26 stsp goto done;
1601 3789fd73 2020-03-26 stsp if (verbosity >= 0) {
1602 3789fd73 2020-03-26 stsp printf("Deleted reference %s: %s\n",
1603 3789fd73 2020-03-26 stsp got_ref_get_name(ref), id_str);
1604 3789fd73 2020-03-26 stsp }
1605 3789fd73 2020-03-26 stsp }
1606 3789fd73 2020-03-26 stsp done:
1607 3789fd73 2020-03-26 stsp free(id);
1608 3789fd73 2020-03-26 stsp free(id_str);
1609 3789fd73 2020-03-26 stsp return NULL;
1610 3789fd73 2020-03-26 stsp }
1611 3789fd73 2020-03-26 stsp
1612 3789fd73 2020-03-26 stsp static const struct got_error *
1613 3789fd73 2020-03-26 stsp delete_missing_refs(struct got_pathlist_head *their_refs,
1614 3789fd73 2020-03-26 stsp struct got_pathlist_head *their_symrefs, struct got_remote_repo *remote,
1615 3789fd73 2020-03-26 stsp int verbosity, struct got_repository *repo)
1616 3789fd73 2020-03-26 stsp {
1617 3789fd73 2020-03-26 stsp const struct got_error *err = NULL, *unlock_err;
1618 f21ec2f0 2020-03-21 stsp struct got_reflist_head my_refs;
1619 f21ec2f0 2020-03-21 stsp struct got_reflist_entry *re;
1620 f21ec2f0 2020-03-21 stsp struct got_pathlist_entry *pe;
1621 3789fd73 2020-03-26 stsp char *remote_namespace = NULL;
1622 3789fd73 2020-03-26 stsp char *local_refname = NULL;
1623 f21ec2f0 2020-03-21 stsp
1624 f21ec2f0 2020-03-21 stsp SIMPLEQ_INIT(&my_refs);
1625 f21ec2f0 2020-03-21 stsp
1626 3789fd73 2020-03-26 stsp if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
1627 3789fd73 2020-03-26 stsp == -1)
1628 3789fd73 2020-03-26 stsp return got_error_from_errno("asprintf");
1629 3789fd73 2020-03-26 stsp
1630 f21ec2f0 2020-03-21 stsp err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
1631 f21ec2f0 2020-03-21 stsp if (err)
1632 3789fd73 2020-03-26 stsp goto done;
1633 f21ec2f0 2020-03-21 stsp
1634 f21ec2f0 2020-03-21 stsp SIMPLEQ_FOREACH(re, &my_refs, entry) {
1635 f21ec2f0 2020-03-21 stsp const char *refname = got_ref_get_name(re->ref);
1636 f21ec2f0 2020-03-21 stsp
1637 3789fd73 2020-03-26 stsp if (!remote->mirror_references) {
1638 3789fd73 2020-03-26 stsp if (strncmp(refname, remote_namespace,
1639 3789fd73 2020-03-26 stsp strlen(remote_namespace)) == 0) {
1640 3789fd73 2020-03-26 stsp if (strcmp(refname + strlen(remote_namespace),
1641 3789fd73 2020-03-26 stsp GOT_REF_HEAD) == 0)
1642 3789fd73 2020-03-26 stsp continue;
1643 3789fd73 2020-03-26 stsp if (asprintf(&local_refname, "refs/heads/%s",
1644 3789fd73 2020-03-26 stsp refname + strlen(remote_namespace)) == -1) {
1645 3789fd73 2020-03-26 stsp err = got_error_from_errno("asprintf");
1646 3789fd73 2020-03-26 stsp goto done;
1647 3789fd73 2020-03-26 stsp }
1648 3789fd73 2020-03-26 stsp } else if (strncmp(refname, "refs/tags/", 10) != 0)
1649 3789fd73 2020-03-26 stsp continue;
1650 3789fd73 2020-03-26 stsp }
1651 f21ec2f0 2020-03-21 stsp
1652 f21ec2f0 2020-03-21 stsp TAILQ_FOREACH(pe, their_refs, entry) {
1653 3789fd73 2020-03-26 stsp if (strcmp(local_refname, pe->path) == 0)
1654 f21ec2f0 2020-03-21 stsp break;
1655 f21ec2f0 2020-03-21 stsp }
1656 f21ec2f0 2020-03-21 stsp if (pe != NULL)
1657 f21ec2f0 2020-03-21 stsp continue;
1658 f21ec2f0 2020-03-21 stsp
1659 3789fd73 2020-03-26 stsp TAILQ_FOREACH(pe, their_symrefs, entry) {
1660 3789fd73 2020-03-26 stsp if (strcmp(local_refname, pe->path) == 0)
1661 3789fd73 2020-03-26 stsp break;
1662 3789fd73 2020-03-26 stsp }
1663 3789fd73 2020-03-26 stsp if (pe != NULL)
1664 3789fd73 2020-03-26 stsp continue;
1665 f21ec2f0 2020-03-21 stsp
1666 3789fd73 2020-03-26 stsp err = delete_missing_ref(re->ref, verbosity, repo);
1667 f21ec2f0 2020-03-21 stsp if (err)
1668 f21ec2f0 2020-03-21 stsp break;
1669 3789fd73 2020-03-26 stsp
1670 3789fd73 2020-03-26 stsp if (local_refname) {
1671 3789fd73 2020-03-26 stsp struct got_reference *ref;
1672 3789fd73 2020-03-26 stsp err = got_ref_open(&ref, repo, local_refname, 1);
1673 3789fd73 2020-03-26 stsp if (err) {
1674 3789fd73 2020-03-26 stsp if (err->code != GOT_ERR_NOT_REF)
1675 3789fd73 2020-03-26 stsp break;
1676 3789fd73 2020-03-26 stsp free(local_refname);
1677 3789fd73 2020-03-26 stsp local_refname = NULL;
1678 3789fd73 2020-03-26 stsp continue;
1679 3789fd73 2020-03-26 stsp }
1680 3789fd73 2020-03-26 stsp err = delete_missing_ref(ref, verbosity, repo);
1681 3789fd73 2020-03-26 stsp if (err)
1682 3789fd73 2020-03-26 stsp break;
1683 3789fd73 2020-03-26 stsp unlock_err = got_ref_unlock(ref);
1684 3789fd73 2020-03-26 stsp got_ref_close(ref);
1685 3789fd73 2020-03-26 stsp if (unlock_err && err == NULL) {
1686 3789fd73 2020-03-26 stsp err = unlock_err;
1687 3789fd73 2020-03-26 stsp break;
1688 3789fd73 2020-03-26 stsp }
1689 3789fd73 2020-03-26 stsp
1690 3789fd73 2020-03-26 stsp free(local_refname);
1691 3789fd73 2020-03-26 stsp local_refname = NULL;
1692 6338a6a1 2020-03-21 stsp }
1693 f21ec2f0 2020-03-21 stsp }
1694 3789fd73 2020-03-26 stsp done:
1695 3789fd73 2020-03-26 stsp free(remote_namespace);
1696 3789fd73 2020-03-26 stsp free(local_refname);
1697 0e4002ca 2020-03-21 stsp return err;
1698 0e4002ca 2020-03-21 stsp }
1699 0e4002ca 2020-03-21 stsp
1700 0e4002ca 2020-03-21 stsp static const struct got_error *
1701 0e4002ca 2020-03-21 stsp update_wanted_ref(const char *refname, struct got_object_id *id,
1702 0e4002ca 2020-03-21 stsp const char *remote_repo_name, int verbosity, struct got_repository *repo)
1703 0e4002ca 2020-03-21 stsp {
1704 9f142382 2020-03-21 stsp const struct got_error *err, *unlock_err;
1705 0e4002ca 2020-03-21 stsp char *remote_refname;
1706 0e4002ca 2020-03-21 stsp struct got_reference *ref;
1707 0e4002ca 2020-03-21 stsp
1708 0e4002ca 2020-03-21 stsp if (strncmp("refs/", refname, 5) == 0)
1709 0e4002ca 2020-03-21 stsp refname += 5;
1710 0e4002ca 2020-03-21 stsp
1711 0e4002ca 2020-03-21 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1712 0e4002ca 2020-03-21 stsp remote_repo_name, refname) == -1)
1713 0e4002ca 2020-03-21 stsp return got_error_from_errno("asprintf");
1714 f21ec2f0 2020-03-21 stsp
1715 9f142382 2020-03-21 stsp err = got_ref_open(&ref, repo, remote_refname, 1);
1716 0e4002ca 2020-03-21 stsp if (err) {
1717 0e4002ca 2020-03-21 stsp if (err->code != GOT_ERR_NOT_REF)
1718 0e4002ca 2020-03-21 stsp goto done;
1719 0e4002ca 2020-03-21 stsp err = create_ref(remote_refname, id, verbosity, repo);
1720 0e4002ca 2020-03-21 stsp } else {
1721 0e4002ca 2020-03-21 stsp err = update_ref(ref, id, 0, verbosity, repo);
1722 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
1723 9f142382 2020-03-21 stsp if (unlock_err && err == NULL)
1724 9f142382 2020-03-21 stsp err = unlock_err;
1725 0e4002ca 2020-03-21 stsp got_ref_close(ref);
1726 0e4002ca 2020-03-21 stsp }
1727 0e4002ca 2020-03-21 stsp done:
1728 0e4002ca 2020-03-21 stsp free(remote_refname);
1729 f21ec2f0 2020-03-21 stsp return err;
1730 f21ec2f0 2020-03-21 stsp }
1731 f21ec2f0 2020-03-21 stsp
1732 f21ec2f0 2020-03-21 stsp static const struct got_error *
1733 7848a0e1 2020-03-19 stsp cmd_fetch(int argc, char *argv[])
1734 7848a0e1 2020-03-19 stsp {
1735 9f142382 2020-03-21 stsp const struct got_error *error = NULL, *unlock_err;
1736 7848a0e1 2020-03-19 stsp char *cwd = NULL, *repo_path = NULL;
1737 7848a0e1 2020-03-19 stsp const char *remote_name;
1738 7848a0e1 2020-03-19 stsp char *proto = NULL, *host = NULL, *port = NULL;
1739 7848a0e1 2020-03-19 stsp char *repo_name = NULL, *server_path = NULL;
1740 7848a0e1 2020-03-19 stsp struct got_remote_repo *remotes, *remote = NULL;
1741 7848a0e1 2020-03-19 stsp int nremotes;
1742 7848a0e1 2020-03-19 stsp char *id_str = NULL;
1743 7848a0e1 2020-03-19 stsp struct got_repository *repo = NULL;
1744 7848a0e1 2020-03-19 stsp struct got_worktree *worktree = NULL;
1745 0e4002ca 2020-03-21 stsp struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1746 7848a0e1 2020-03-19 stsp struct got_pathlist_entry *pe;
1747 7848a0e1 2020-03-19 stsp struct got_object_id *pack_hash = NULL;
1748 9c52365f 2020-03-21 stsp int i, ch, fetchfd = -1, fetchstatus;
1749 9c52365f 2020-03-21 stsp pid_t fetchpid = -1;
1750 7848a0e1 2020-03-19 stsp struct got_fetch_progress_arg fpa;
1751 41b0de12 2020-03-21 stsp int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
1752 db6d8ad8 2020-03-21 stsp int delete_refs = 0, replace_tags = 0;
1753 7848a0e1 2020-03-19 stsp
1754 7848a0e1 2020-03-19 stsp TAILQ_INIT(&refs);
1755 7848a0e1 2020-03-19 stsp TAILQ_INIT(&symrefs);
1756 4ba14133 2020-03-20 stsp TAILQ_INIT(&wanted_branches);
1757 0e4002ca 2020-03-21 stsp TAILQ_INIT(&wanted_refs);
1758 7848a0e1 2020-03-19 stsp
1759 0e4002ca 2020-03-21 stsp while ((ch = getopt(argc, argv, "ab:dlr:tvqR:")) != -1) {
1760 7848a0e1 2020-03-19 stsp switch (ch) {
1761 659e7fbd 2020-03-20 stsp case 'a':
1762 659e7fbd 2020-03-20 stsp fetch_all_branches = 1;
1763 4ba14133 2020-03-20 stsp break;
1764 4ba14133 2020-03-20 stsp case 'b':
1765 4ba14133 2020-03-20 stsp error = got_pathlist_append(&wanted_branches,
1766 4ba14133 2020-03-20 stsp optarg, NULL);
1767 4ba14133 2020-03-20 stsp if (error)
1768 4ba14133 2020-03-20 stsp return error;
1769 41b0de12 2020-03-21 stsp break;
1770 f21ec2f0 2020-03-21 stsp case 'd':
1771 f21ec2f0 2020-03-21 stsp delete_refs = 1;
1772 f21ec2f0 2020-03-21 stsp break;
1773 41b0de12 2020-03-21 stsp case 'l':
1774 41b0de12 2020-03-21 stsp list_refs_only = 1;
1775 659e7fbd 2020-03-20 stsp break;
1776 7848a0e1 2020-03-19 stsp case 'r':
1777 7848a0e1 2020-03-19 stsp repo_path = realpath(optarg, NULL);
1778 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
1779 7848a0e1 2020-03-19 stsp return got_error_from_errno2("realpath",
1780 7848a0e1 2020-03-19 stsp optarg);
1781 7848a0e1 2020-03-19 stsp got_path_strip_trailing_slashes(repo_path);
1782 7848a0e1 2020-03-19 stsp break;
1783 db6d8ad8 2020-03-21 stsp case 't':
1784 db6d8ad8 2020-03-21 stsp replace_tags = 1;
1785 db6d8ad8 2020-03-21 stsp break;
1786 7848a0e1 2020-03-19 stsp case 'v':
1787 7848a0e1 2020-03-19 stsp if (verbosity < 0)
1788 7848a0e1 2020-03-19 stsp verbosity = 0;
1789 7848a0e1 2020-03-19 stsp else if (verbosity < 3)
1790 7848a0e1 2020-03-19 stsp verbosity++;
1791 7848a0e1 2020-03-19 stsp break;
1792 7848a0e1 2020-03-19 stsp case 'q':
1793 7848a0e1 2020-03-19 stsp verbosity = -1;
1794 7848a0e1 2020-03-19 stsp break;
1795 0e4002ca 2020-03-21 stsp case 'R':
1796 0e4002ca 2020-03-21 stsp error = got_pathlist_append(&wanted_refs,
1797 0e4002ca 2020-03-21 stsp optarg, NULL);
1798 0e4002ca 2020-03-21 stsp if (error)
1799 0e4002ca 2020-03-21 stsp return error;
1800 0e4002ca 2020-03-21 stsp break;
1801 7848a0e1 2020-03-19 stsp default:
1802 7848a0e1 2020-03-19 stsp usage_fetch();
1803 7848a0e1 2020-03-19 stsp break;
1804 7848a0e1 2020-03-19 stsp }
1805 7848a0e1 2020-03-19 stsp }
1806 7848a0e1 2020-03-19 stsp argc -= optind;
1807 7848a0e1 2020-03-19 stsp argv += optind;
1808 7848a0e1 2020-03-19 stsp
1809 4ba14133 2020-03-20 stsp if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1810 41b0de12 2020-03-21 stsp errx(1, "-a and -b options are mutually exclusive");
1811 41b0de12 2020-03-21 stsp if (list_refs_only) {
1812 41b0de12 2020-03-21 stsp if (!TAILQ_EMPTY(&wanted_branches))
1813 41b0de12 2020-03-21 stsp errx(1, "-l and -b options are mutually exclusive");
1814 41b0de12 2020-03-21 stsp if (fetch_all_branches)
1815 41b0de12 2020-03-21 stsp errx(1, "-l and -a options are mutually exclusive");
1816 f21ec2f0 2020-03-21 stsp if (delete_refs)
1817 f21ec2f0 2020-03-21 stsp errx(1, "-l and -d options are mutually exclusive");
1818 41b0de12 2020-03-21 stsp if (verbosity == -1)
1819 41b0de12 2020-03-21 stsp errx(1, "-l and -q options are mutually exclusive");
1820 41b0de12 2020-03-21 stsp }
1821 4ba14133 2020-03-20 stsp
1822 7848a0e1 2020-03-19 stsp if (argc == 0)
1823 7848a0e1 2020-03-19 stsp remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
1824 7848a0e1 2020-03-19 stsp else if (argc == 1)
1825 7848a0e1 2020-03-19 stsp remote_name = argv[0];
1826 7848a0e1 2020-03-19 stsp else
1827 7848a0e1 2020-03-19 stsp usage_fetch();
1828 7848a0e1 2020-03-19 stsp
1829 7848a0e1 2020-03-19 stsp cwd = getcwd(NULL, 0);
1830 7848a0e1 2020-03-19 stsp if (cwd == NULL) {
1831 7848a0e1 2020-03-19 stsp error = got_error_from_errno("getcwd");
1832 7848a0e1 2020-03-19 stsp goto done;
1833 7848a0e1 2020-03-19 stsp }
1834 7848a0e1 2020-03-19 stsp
1835 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
1836 7848a0e1 2020-03-19 stsp error = got_worktree_open(&worktree, cwd);
1837 7848a0e1 2020-03-19 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
1838 7848a0e1 2020-03-19 stsp goto done;
1839 7848a0e1 2020-03-19 stsp else
1840 7848a0e1 2020-03-19 stsp error = NULL;
1841 7848a0e1 2020-03-19 stsp if (worktree) {
1842 7848a0e1 2020-03-19 stsp repo_path =
1843 7848a0e1 2020-03-19 stsp strdup(got_worktree_get_repo_path(worktree));
1844 7848a0e1 2020-03-19 stsp if (repo_path == NULL)
1845 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
1846 7848a0e1 2020-03-19 stsp if (error)
1847 7848a0e1 2020-03-19 stsp goto done;
1848 7848a0e1 2020-03-19 stsp } else {
1849 7848a0e1 2020-03-19 stsp repo_path = strdup(cwd);
1850 7848a0e1 2020-03-19 stsp if (repo_path == NULL) {
1851 7848a0e1 2020-03-19 stsp error = got_error_from_errno("strdup");
1852 7848a0e1 2020-03-19 stsp goto done;
1853 7848a0e1 2020-03-19 stsp }
1854 7848a0e1 2020-03-19 stsp }
1855 7848a0e1 2020-03-19 stsp }
1856 7848a0e1 2020-03-19 stsp
1857 7848a0e1 2020-03-19 stsp error = got_repo_open(&repo, repo_path, NULL);
1858 7848a0e1 2020-03-19 stsp if (error)
1859 7848a0e1 2020-03-19 stsp goto done;
1860 7848a0e1 2020-03-19 stsp
1861 7848a0e1 2020-03-19 stsp got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
1862 7848a0e1 2020-03-19 stsp for (i = 0; i < nremotes; i++) {
1863 7848a0e1 2020-03-19 stsp remote = &remotes[i];
1864 7848a0e1 2020-03-19 stsp if (strcmp(remote->name, remote_name) == 0)
1865 7848a0e1 2020-03-19 stsp break;
1866 7848a0e1 2020-03-19 stsp }
1867 7848a0e1 2020-03-19 stsp if (i == nremotes) {
1868 7848a0e1 2020-03-19 stsp error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
1869 7848a0e1 2020-03-19 stsp goto done;
1870 7848a0e1 2020-03-19 stsp }
1871 7848a0e1 2020-03-19 stsp
1872 7848a0e1 2020-03-19 stsp error = got_fetch_parse_uri(&proto, &host, &port, &server_path,
1873 7848a0e1 2020-03-19 stsp &repo_name, remote->url);
1874 7848a0e1 2020-03-19 stsp if (error)
1875 7848a0e1 2020-03-19 stsp goto done;
1876 7848a0e1 2020-03-19 stsp
1877 7848a0e1 2020-03-19 stsp if (strcmp(proto, "git") == 0) {
1878 7848a0e1 2020-03-19 stsp #ifndef PROFILE
1879 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1880 7848a0e1 2020-03-19 stsp "sendfd dns inet unveil", NULL) == -1)
1881 7848a0e1 2020-03-19 stsp err(1, "pledge");
1882 7848a0e1 2020-03-19 stsp #endif
1883 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "git+ssh") == 0 ||
1884 7848a0e1 2020-03-19 stsp strcmp(proto, "ssh") == 0) {
1885 7848a0e1 2020-03-19 stsp #ifndef PROFILE
1886 7848a0e1 2020-03-19 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1887 7848a0e1 2020-03-19 stsp "sendfd unveil", NULL) == -1)
1888 7848a0e1 2020-03-19 stsp err(1, "pledge");
1889 7848a0e1 2020-03-19 stsp #endif
1890 7848a0e1 2020-03-19 stsp } else if (strcmp(proto, "http") == 0 ||
1891 7848a0e1 2020-03-19 stsp strcmp(proto, "git+http") == 0) {
1892 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1893 7848a0e1 2020-03-19 stsp goto done;
1894 7848a0e1 2020-03-19 stsp } else {
1895 7848a0e1 2020-03-19 stsp error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1896 7848a0e1 2020-03-19 stsp goto done;
1897 7848a0e1 2020-03-19 stsp }
1898 7848a0e1 2020-03-19 stsp
1899 7848a0e1 2020-03-19 stsp if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) {
1900 7848a0e1 2020-03-19 stsp if (unveil(GOT_FETCH_PATH_SSH, "x") != 0) {
1901 7848a0e1 2020-03-19 stsp error = got_error_from_errno2("unveil",
1902 7848a0e1 2020-03-19 stsp GOT_FETCH_PATH_SSH);
1903 7848a0e1 2020-03-19 stsp goto done;
1904 7848a0e1 2020-03-19 stsp }
1905 7848a0e1 2020-03-19 stsp }
1906 7848a0e1 2020-03-19 stsp error = apply_unveil(got_repo_get_path(repo), 0, NULL);
1907 7848a0e1 2020-03-19 stsp if (error)
1908 7848a0e1 2020-03-19 stsp goto done;
1909 f79e6490 2020-04-19 stsp
1910 f79e6490 2020-04-19 stsp if (verbosity >= 0)
1911 f79e6490 2020-04-19 stsp printf("Connecting to \"%s\" %s%s%s\n", remote->name, host,
1912 f79e6490 2020-04-19 stsp port ? ":" : "", port ? port : "");
1913 7848a0e1 2020-03-19 stsp
1914 9c52365f 2020-03-21 stsp error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1915 9c52365f 2020-03-21 stsp server_path, verbosity);
1916 7848a0e1 2020-03-19 stsp if (error)
1917 7848a0e1 2020-03-19 stsp goto done;
1918 7848a0e1 2020-03-19 stsp
1919 7848a0e1 2020-03-19 stsp fpa.last_scaled_size[0] = '\0';
1920 7848a0e1 2020-03-19 stsp fpa.last_p_indexed = -1;
1921 7848a0e1 2020-03-19 stsp fpa.last_p_resolved = -1;
1922 7848a0e1 2020-03-19 stsp fpa.verbosity = verbosity;
1923 7848a0e1 2020-03-19 stsp error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
1924 4ba14133 2020-03-20 stsp remote->mirror_references, fetch_all_branches, &wanted_branches,
1925 0e4002ca 2020-03-21 stsp &wanted_refs, list_refs_only, verbosity, fetchfd, repo,
1926 0e4002ca 2020-03-21 stsp fetch_progress, &fpa);
1927 7848a0e1 2020-03-19 stsp if (error)
1928 7848a0e1 2020-03-19 stsp goto done;
1929 7848a0e1 2020-03-19 stsp
1930 41b0de12 2020-03-21 stsp if (list_refs_only) {
1931 41b0de12 2020-03-21 stsp error = list_remote_refs(&symrefs, &refs);
1932 41b0de12 2020-03-21 stsp goto done;
1933 41b0de12 2020-03-21 stsp }
1934 41b0de12 2020-03-21 stsp
1935 7848a0e1 2020-03-19 stsp if (pack_hash == NULL) {
1936 7848a0e1 2020-03-19 stsp if (verbosity >= 0)
1937 7848a0e1 2020-03-19 stsp printf("Already up-to-date\n");
1938 bcf34b0e 2020-03-26 stsp } else if (verbosity >= 0) {
1939 984065c8 2020-03-19 stsp error = got_object_id_str(&id_str, pack_hash);
1940 984065c8 2020-03-19 stsp if (error)
1941 984065c8 2020-03-19 stsp goto done;
1942 e69674d8 2020-03-19 stsp printf("\nFetched %s.pack\n", id_str);
1943 984065c8 2020-03-19 stsp free(id_str);
1944 984065c8 2020-03-19 stsp id_str = NULL;
1945 984065c8 2020-03-19 stsp }
1946 7848a0e1 2020-03-19 stsp
1947 7848a0e1 2020-03-19 stsp /* Update references provided with the pack file. */
1948 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
1949 7848a0e1 2020-03-19 stsp const char *refname = pe->path;
1950 7848a0e1 2020-03-19 stsp struct got_object_id *id = pe->data;
1951 7848a0e1 2020-03-19 stsp struct got_reference *ref;
1952 7848a0e1 2020-03-19 stsp char *remote_refname;
1953 7848a0e1 2020-03-19 stsp
1954 0e4002ca 2020-03-21 stsp if (is_wanted_ref(&wanted_refs, refname) &&
1955 0e4002ca 2020-03-21 stsp !remote->mirror_references) {
1956 0e4002ca 2020-03-21 stsp error = update_wanted_ref(refname, id,
1957 0e4002ca 2020-03-21 stsp remote->name, verbosity, repo);
1958 0e4002ca 2020-03-21 stsp if (error)
1959 0e4002ca 2020-03-21 stsp goto done;
1960 0e4002ca 2020-03-21 stsp continue;
1961 0e4002ca 2020-03-21 stsp }
1962 0e4002ca 2020-03-21 stsp
1963 1510c839 2020-03-20 stsp if (remote->mirror_references ||
1964 1510c839 2020-03-20 stsp strncmp("refs/tags/", refname, 10) == 0) {
1965 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
1966 7848a0e1 2020-03-19 stsp if (error) {
1967 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
1968 7848a0e1 2020-03-19 stsp goto done;
1969 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
1970 6338a6a1 2020-03-21 stsp repo);
1971 7848a0e1 2020-03-19 stsp if (error)
1972 7848a0e1 2020-03-19 stsp goto done;
1973 7848a0e1 2020-03-19 stsp } else {
1974 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
1975 db6d8ad8 2020-03-21 stsp verbosity, repo);
1976 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
1977 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
1978 9f142382 2020-03-21 stsp error = unlock_err;
1979 7848a0e1 2020-03-19 stsp got_ref_close(ref);
1980 7848a0e1 2020-03-19 stsp if (error)
1981 7848a0e1 2020-03-19 stsp goto done;
1982 7848a0e1 2020-03-19 stsp }
1983 7848a0e1 2020-03-19 stsp } else if (strncmp("refs/heads/", refname, 11) == 0) {
1984 7848a0e1 2020-03-19 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1985 7848a0e1 2020-03-19 stsp remote_name, refname + 11) == -1) {
1986 7848a0e1 2020-03-19 stsp error = got_error_from_errno("asprintf");
1987 7848a0e1 2020-03-19 stsp goto done;
1988 7848a0e1 2020-03-19 stsp }
1989 7848a0e1 2020-03-19 stsp
1990 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, remote_refname, 1);
1991 7848a0e1 2020-03-19 stsp if (error) {
1992 7848a0e1 2020-03-19 stsp if (error->code != GOT_ERR_NOT_REF)
1993 7848a0e1 2020-03-19 stsp goto done;
1994 6338a6a1 2020-03-21 stsp error = create_ref(remote_refname, id,
1995 688f11b3 2020-03-21 stsp verbosity, repo);
1996 7848a0e1 2020-03-19 stsp if (error)
1997 7848a0e1 2020-03-19 stsp goto done;
1998 7848a0e1 2020-03-19 stsp } else {
1999 db6d8ad8 2020-03-21 stsp error = update_ref(ref, id, replace_tags,
2000 db6d8ad8 2020-03-21 stsp verbosity, repo);
2001 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2002 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2003 9f142382 2020-03-21 stsp error = unlock_err;
2004 7848a0e1 2020-03-19 stsp got_ref_close(ref);
2005 7848a0e1 2020-03-19 stsp if (error)
2006 7848a0e1 2020-03-19 stsp goto done;
2007 7848a0e1 2020-03-19 stsp }
2008 2ec30c80 2020-03-20 stsp
2009 2ec30c80 2020-03-20 stsp /* Also create a local branch if none exists yet. */
2010 9f142382 2020-03-21 stsp error = got_ref_open(&ref, repo, refname, 1);
2011 2ec30c80 2020-03-20 stsp if (error) {
2012 2ec30c80 2020-03-20 stsp if (error->code != GOT_ERR_NOT_REF)
2013 2ec30c80 2020-03-20 stsp goto done;
2014 6338a6a1 2020-03-21 stsp error = create_ref(refname, id, verbosity,
2015 6338a6a1 2020-03-21 stsp repo);
2016 2ec30c80 2020-03-20 stsp if (error)
2017 2ec30c80 2020-03-20 stsp goto done;
2018 9f142382 2020-03-21 stsp } else {
2019 9f142382 2020-03-21 stsp unlock_err = got_ref_unlock(ref);
2020 9f142382 2020-03-21 stsp if (unlock_err && error == NULL)
2021 9f142382 2020-03-21 stsp error = unlock_err;
2022 2ec30c80 2020-03-20 stsp got_ref_close(ref);
2023 9f142382 2020-03-21 stsp }
2024 7848a0e1 2020-03-19 stsp }
2025 7848a0e1 2020-03-19 stsp }
2026 f1bcca34 2020-03-25 stsp if (delete_refs) {
2027 3789fd73 2020-03-26 stsp error = delete_missing_refs(&refs, &symrefs, remote,
2028 3789fd73 2020-03-26 stsp verbosity, repo);
2029 f1bcca34 2020-03-25 stsp if (error)
2030 f1bcca34 2020-03-25 stsp goto done;
2031 f1bcca34 2020-03-25 stsp }
2032 f1bcca34 2020-03-25 stsp
2033 f1bcca34 2020-03-25 stsp if (!remote->mirror_references) {
2034 f1bcca34 2020-03-25 stsp /* Update remote HEAD reference if the server provided one. */
2035 f1bcca34 2020-03-25 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2036 f1bcca34 2020-03-25 stsp struct got_reference *target_ref;
2037 f1bcca34 2020-03-25 stsp const char *refname = pe->path;
2038 f1bcca34 2020-03-25 stsp const char *target = pe->data;
2039 f1bcca34 2020-03-25 stsp char *remote_refname = NULL, *remote_target = NULL;
2040 f1bcca34 2020-03-25 stsp
2041 f1bcca34 2020-03-25 stsp if (strcmp(refname, GOT_REF_HEAD) != 0)
2042 f1bcca34 2020-03-25 stsp continue;
2043 f1bcca34 2020-03-25 stsp
2044 f1bcca34 2020-03-25 stsp if (strncmp("refs/heads/", target, 11) != 0)
2045 f1bcca34 2020-03-25 stsp continue;
2046 f1bcca34 2020-03-25 stsp
2047 f1bcca34 2020-03-25 stsp if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2048 f1bcca34 2020-03-25 stsp remote->name, refname) == -1) {
2049 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2050 f1bcca34 2020-03-25 stsp goto done;
2051 f1bcca34 2020-03-25 stsp }
2052 f1bcca34 2020-03-25 stsp if (asprintf(&remote_target, "refs/remotes/%s/%s",
2053 f1bcca34 2020-03-25 stsp remote->name, target + 11) == -1) {
2054 f1bcca34 2020-03-25 stsp error = got_error_from_errno("asprintf");
2055 f1bcca34 2020-03-25 stsp free(remote_refname);
2056 f1bcca34 2020-03-25 stsp goto done;
2057 f1bcca34 2020-03-25 stsp }
2058 f1bcca34 2020-03-25 stsp
2059 f1bcca34 2020-03-25 stsp error = got_ref_open(&target_ref, repo, remote_target,
2060 f1bcca34 2020-03-25 stsp 0);
2061 f1bcca34 2020-03-25 stsp if (error) {
2062 f1bcca34 2020-03-25 stsp free(remote_refname);
2063 f1bcca34 2020-03-25 stsp free(remote_target);
2064 f1bcca34 2020-03-25 stsp if (error->code == GOT_ERR_NOT_REF) {
2065 f1bcca34 2020-03-25 stsp error = NULL;
2066 f1bcca34 2020-03-25 stsp continue;
2067 f1bcca34 2020-03-25 stsp }
2068 f1bcca34 2020-03-25 stsp goto done;
2069 f1bcca34 2020-03-25 stsp }
2070 f1bcca34 2020-03-25 stsp error = update_symref(remote_refname, target_ref,
2071 f1bcca34 2020-03-25 stsp verbosity, repo);
2072 f1bcca34 2020-03-25 stsp free(remote_refname);
2073 f1bcca34 2020-03-25 stsp free(remote_target);
2074 f1bcca34 2020-03-25 stsp got_ref_close(target_ref);
2075 f1bcca34 2020-03-25 stsp if (error)
2076 f1bcca34 2020-03-25 stsp goto done;
2077 f1bcca34 2020-03-25 stsp }
2078 f1bcca34 2020-03-25 stsp }
2079 7848a0e1 2020-03-19 stsp done:
2080 9c52365f 2020-03-21 stsp if (fetchpid > 0) {
2081 9c52365f 2020-03-21 stsp if (kill(fetchpid, SIGTERM) == -1)
2082 9c52365f 2020-03-21 stsp error = got_error_from_errno("kill");
2083 9c52365f 2020-03-21 stsp if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
2084 9c52365f 2020-03-21 stsp error = got_error_from_errno("waitpid");
2085 9c52365f 2020-03-21 stsp }
2086 7848a0e1 2020-03-19 stsp if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
2087 7848a0e1 2020-03-19 stsp error = got_error_from_errno("close");
2088 7848a0e1 2020-03-19 stsp if (repo)
2089 7848a0e1 2020-03-19 stsp got_repo_close(repo);
2090 7848a0e1 2020-03-19 stsp if (worktree)
2091 7848a0e1 2020-03-19 stsp got_worktree_close(worktree);
2092 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &refs, entry) {
2093 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2094 7848a0e1 2020-03-19 stsp free(pe->data);
2095 7848a0e1 2020-03-19 stsp }
2096 7848a0e1 2020-03-19 stsp got_pathlist_free(&refs);
2097 7848a0e1 2020-03-19 stsp TAILQ_FOREACH(pe, &symrefs, entry) {
2098 7848a0e1 2020-03-19 stsp free((void *)pe->path);
2099 7848a0e1 2020-03-19 stsp free(pe->data);
2100 7848a0e1 2020-03-19 stsp }
2101 7848a0e1 2020-03-19 stsp got_pathlist_free(&symrefs);
2102 4ba14133 2020-03-20 stsp got_pathlist_free(&wanted_branches);
2103 0e4002ca 2020-03-21 stsp got_pathlist_free(&wanted_refs);
2104 7848a0e1 2020-03-19 stsp free(id_str);
2105 7848a0e1 2020-03-19 stsp free(cwd);
2106 7848a0e1 2020-03-19 stsp free(repo_path);
2107 7848a0e1 2020-03-19 stsp free(pack_hash);
2108 7848a0e1 2020-03-19 stsp free(proto);
2109 7848a0e1 2020-03-19 stsp free(host);
2110 7848a0e1 2020-03-19 stsp free(port);
2111 7848a0e1 2020-03-19 stsp free(server_path);
2112 7848a0e1 2020-03-19 stsp free(repo_name);
2113 7848a0e1 2020-03-19 stsp return error;
2114 7848a0e1 2020-03-19 stsp }
2115 7848a0e1 2020-03-19 stsp
2116 7848a0e1 2020-03-19 stsp
2117 7848a0e1 2020-03-19 stsp __dead static void
2118 2ab43947 2020-03-18 stsp usage_checkout(void)
2119 2ab43947 2020-03-18 stsp {
2120 2ab43947 2020-03-18 stsp fprintf(stderr, "usage: %s checkout [-E] [-b branch] [-c commit] "
2121 2ab43947 2020-03-18 stsp "[-p prefix] repository-path [worktree-path]\n", getprogname());
2122 2ab43947 2020-03-18 stsp exit(1);
2123 2ab43947 2020-03-18 stsp }
2124 2ab43947 2020-03-18 stsp
2125 2ab43947 2020-03-18 stsp static void
2126 2ab43947 2020-03-18 stsp show_worktree_base_ref_warning(void)
2127 2ab43947 2020-03-18 stsp {
2128 2ab43947 2020-03-18 stsp fprintf(stderr, "%s: warning: could not create a reference "
2129 2ab43947 2020-03-18 stsp "to the work tree's base commit; the commit could be "
2130 2ab43947 2020-03-18 stsp "garbage-collected by Git; making the repository "
2131 2ab43947 2020-03-18 stsp "writable and running 'got update' will prevent this\n",
2132 2ab43947 2020-03-18 stsp getprogname());
2133 2ab43947 2020-03-18 stsp }
2134 2ab43947 2020-03-18 stsp
2135 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg {
2136 2ab43947 2020-03-18 stsp const char *worktree_path;
2137 2ab43947 2020-03-18 stsp int had_base_commit_ref_error;
2138 2ab43947 2020-03-18 stsp };
2139 2ab43947 2020-03-18 stsp
2140 2ab43947 2020-03-18 stsp static const struct got_error *
2141 2ab43947 2020-03-18 stsp checkout_progress(void *arg, unsigned char status, const char *path)
2142 2ab43947 2020-03-18 stsp {
2143 2ab43947 2020-03-18 stsp struct got_checkout_progress_arg *a = arg;
2144 2ab43947 2020-03-18 stsp
2145 2ab43947 2020-03-18 stsp /* Base commit bump happens silently. */
2146 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BUMP_BASE)
2147 2ab43947 2020-03-18 stsp return NULL;
2148 2ab43947 2020-03-18 stsp
2149 2ab43947 2020-03-18 stsp if (status == GOT_STATUS_BASE_REF_ERR) {
2150 2ab43947 2020-03-18 stsp a->had_base_commit_ref_error = 1;
2151 2ab43947 2020-03-18 stsp return NULL;
2152 2ab43947 2020-03-18 stsp }
2153 2ab43947 2020-03-18 stsp
2154 2ab43947 2020-03-18 stsp while (path[0] == '/')
2155 2ab43947 2020-03-18 stsp path++;
2156 2ab43947 2020-03-18 stsp
2157 2ab43947 2020-03-18 stsp printf("%c %s/%s\n", status, a->worktree_path, path);
2158 2ab43947 2020-03-18 stsp return NULL;
2159 2ab43947 2020-03-18 stsp }
2160 2ab43947 2020-03-18 stsp
2161 2ab43947 2020-03-18 stsp static const struct got_error *
2162 2ab43947 2020-03-18 stsp check_cancelled(void *arg)
2163 2ab43947 2020-03-18 stsp {
2164 2ab43947 2020-03-18 stsp if (sigint_received || sigpipe_received)
2165 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_CANCELLED);
2166 2ab43947 2020-03-18 stsp return NULL;
2167 2ab43947 2020-03-18 stsp }
2168 2ab43947 2020-03-18 stsp
2169 2ab43947 2020-03-18 stsp static const struct got_error *
2170 2ab43947 2020-03-18 stsp check_linear_ancestry(struct got_object_id *commit_id,
2171 2ab43947 2020-03-18 stsp struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2172 2ab43947 2020-03-18 stsp struct got_repository *repo)
2173 2ab43947 2020-03-18 stsp {
2174 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2175 2ab43947 2020-03-18 stsp struct got_object_id *yca_id;
2176 2ab43947 2020-03-18 stsp
2177 2ab43947 2020-03-18 stsp err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2178 2ab43947 2020-03-18 stsp commit_id, base_commit_id, repo, check_cancelled, NULL);
2179 2ab43947 2020-03-18 stsp if (err)
2180 2ab43947 2020-03-18 stsp return err;
2181 2ab43947 2020-03-18 stsp
2182 2ab43947 2020-03-18 stsp if (yca_id == NULL)
2183 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2184 2ab43947 2020-03-18 stsp
2185 2ab43947 2020-03-18 stsp /*
2186 2ab43947 2020-03-18 stsp * Require a straight line of history between the target commit
2187 2ab43947 2020-03-18 stsp * and the work tree's base commit.
2188 2ab43947 2020-03-18 stsp *
2189 2ab43947 2020-03-18 stsp * Non-linear situations such as this require a rebase:
2190 2ab43947 2020-03-18 stsp *
2191 2ab43947 2020-03-18 stsp * (commit) D F (base_commit)
2192 2ab43947 2020-03-18 stsp * \ /
2193 2ab43947 2020-03-18 stsp * C E
2194 2ab43947 2020-03-18 stsp * \ /
2195 2ab43947 2020-03-18 stsp * B (yca)
2196 2ab43947 2020-03-18 stsp * |
2197 2ab43947 2020-03-18 stsp * A
2198 2ab43947 2020-03-18 stsp *
2199 2ab43947 2020-03-18 stsp * 'got update' only handles linear cases:
2200 2ab43947 2020-03-18 stsp * Update forwards in time: A (base/yca) - B - C - D (commit)
2201 2ab43947 2020-03-18 stsp * Update backwards in time: D (base) - C - B - A (commit/yca)
2202 2ab43947 2020-03-18 stsp */
2203 2ab43947 2020-03-18 stsp if (allow_forwards_in_time_only) {
2204 2ab43947 2020-03-18 stsp if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2205 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2206 2ab43947 2020-03-18 stsp } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2207 2ab43947 2020-03-18 stsp got_object_id_cmp(base_commit_id, yca_id) != 0)
2208 2ab43947 2020-03-18 stsp return got_error(GOT_ERR_ANCESTRY);
2209 2ab43947 2020-03-18 stsp
2210 2ab43947 2020-03-18 stsp free(yca_id);
2211 2ab43947 2020-03-18 stsp return NULL;
2212 2ab43947 2020-03-18 stsp }
2213 2ab43947 2020-03-18 stsp
2214 2ab43947 2020-03-18 stsp static const struct got_error *
2215 2ab43947 2020-03-18 stsp check_same_branch(struct got_object_id *commit_id,
2216 2ab43947 2020-03-18 stsp struct got_reference *head_ref, struct got_object_id *yca_id,
2217 2ab43947 2020-03-18 stsp struct got_repository *repo)
2218 2ab43947 2020-03-18 stsp {
2219 2ab43947 2020-03-18 stsp const struct got_error *err = NULL;
2220 2ab43947 2020-03-18 stsp struct got_commit_graph *graph = NULL;
2221 2ab43947 2020-03-18 stsp struct got_object_id *head_commit_id = NULL;
2222 2ab43947 2020-03-18 stsp int is_same_branch = 0;
2223 2ab43947 2020-03-18 stsp
2224 2ab43947 2020-03-18 stsp err = got_ref_resolve(&head_commit_id, repo, head_ref);
2225 2ab43947 2020-03-18 stsp if (err)
2226 2ab43947 2020-03-18 stsp goto done;
2227 2ab43947 2020-03-18 stsp
2228 2ab43947 2020-03-18 stsp if (got_object_id_cmp(head_commit_id, commit_id) == 0) {
2229 2ab43947 2020-03-18 stsp is_same_branch = 1;
2230 2ab43947 2020-03-18 stsp goto done;
2231 2ab43947 2020-03-18 stsp }
2232 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(commit_id, yca_id) == 0) {
2233 2ab43947 2020-03-18 stsp is_same_branch = 1;
2234 2ab43947 2020-03-18 stsp goto done;
2235 2ab43947 2020-03-18 stsp }
2236 2ab43947 2020-03-18 stsp
2237 2ab43947 2020-03-18 stsp err = got_commit_graph_open(&graph, "/", 1);
2238 2ab43947 2020-03-18 stsp if (err)
2239 2ab43947 2020-03-18 stsp goto done;
2240 2ab43947 2020-03-18 stsp
2241 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2242 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2243 2ab43947 2020-03-18 stsp if (err)
2244 2ab43947 2020-03-18 stsp goto done;
2245 2ab43947 2020-03-18 stsp
2246 2ab43947 2020-03-18 stsp for (;;) {
2247 2ab43947 2020-03-18 stsp struct got_object_id *id;
2248 2ab43947 2020-03-18 stsp err = got_commit_graph_iter_next(&id, graph, repo,
2249 2ab43947 2020-03-18 stsp check_cancelled, NULL);
2250 2ab43947 2020-03-18 stsp if (err) {
2251 2ab43947 2020-03-18 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
2252 2ab43947 2020-03-18 stsp err = NULL;
2253 2ab43947 2020-03-18 stsp break;
2254 2ab43947 2020-03-18 stsp }
2255 2ab43947 2020-03-18 stsp
2256 2ab43947 2020-03-18 stsp if (id) {
2257 2ab43947 2020-03-18 stsp if (yca_id && got_object_id_cmp(id, yca_id) == 0)
2258 2ab43947 2020-03-18 stsp break;
2259 2ab43947 2020-03-18 stsp if (got_object_id_cmp(id, commit_id) == 0) {
2260 2ab43947 2020-03-18 stsp is_same_branch = 1;
2261 2ab43947 2020-03-18 stsp break;
2262 2ab43947 2020-03-18 stsp }
2263 2ab43947 2020-03-18 stsp }
2264 2ab43947 2020-03-18 stsp }
2265 2ab43947 2020-03-18 stsp done:
2266 2ab43947 2020-03-18 stsp if (graph)
2267 2ab43947 2020-03-18 stsp got_commit_graph_close(graph);
2268 2ab43947 2020-03-18 stsp free(head_commit_id);
2269 2ab43947 2020-03-18 stsp if (!err && !is_same_branch)
2270 2ab43947 2020-03-18 stsp err = got_error(GOT_ERR_ANCESTRY);
2271 2ab43947 2020-03-18 stsp return err;
2272 a367ff0f 2019-05-14 stsp }
2273 8069f636 2019-01-12 stsp
2274 4ed7e80c 2018-05-20 stsp static const struct got_error *
2275 4b6c9460 2020-03-05 stsp checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2276 4b6c9460 2020-03-05 stsp {
2277 4b6c9460 2020-03-05 stsp static char msg[512];
2278 4b6c9460 2020-03-05 stsp const char *branch_name;
2279 4b6c9460 2020-03-05 stsp
2280 4b6c9460 2020-03-05 stsp if (got_ref_is_symbolic(ref))
2281 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_symref_target(ref);
2282 4b6c9460 2020-03-05 stsp else
2283 4b6c9460 2020-03-05 stsp branch_name = got_ref_get_name(ref);
2284 4b6c9460 2020-03-05 stsp
2285 4b6c9460 2020-03-05 stsp if (strncmp("refs/heads/", branch_name, 11) == 0)
2286 4b6c9460 2020-03-05 stsp branch_name += 11;
2287 4b6c9460 2020-03-05 stsp
2288 4b6c9460 2020-03-05 stsp snprintf(msg, sizeof(msg),
2289 4b6c9460 2020-03-05 stsp "target commit is not contained in branch '%s'; "
2290 4b6c9460 2020-03-05 stsp "the branch to use must be specified with -b; "
2291 4b6c9460 2020-03-05 stsp "if necessary a new branch can be created for "
2292 4b6c9460 2020-03-05 stsp "this commit with 'got branch -c %s BRANCH_NAME'",
2293 4b6c9460 2020-03-05 stsp branch_name, commit_id_str);
2294 4b6c9460 2020-03-05 stsp
2295 4b6c9460 2020-03-05 stsp return got_error_msg(GOT_ERR_ANCESTRY, msg);
2296 4b6c9460 2020-03-05 stsp }
2297 4b6c9460 2020-03-05 stsp
2298 4b6c9460 2020-03-05 stsp static const struct got_error *
2299 c09a553d 2018-03-12 stsp cmd_checkout(int argc, char *argv[])
2300 c09a553d 2018-03-12 stsp {
2301 c09a553d 2018-03-12 stsp const struct got_error *error = NULL;
2302 c09a553d 2018-03-12 stsp struct got_repository *repo = NULL;
2303 c09a553d 2018-03-12 stsp struct got_reference *head_ref = NULL;
2304 c09a553d 2018-03-12 stsp struct got_worktree *worktree = NULL;
2305 c09a553d 2018-03-12 stsp char *repo_path = NULL;
2306 c09a553d 2018-03-12 stsp char *worktree_path = NULL;
2307 0bb8a95e 2018-03-12 stsp const char *path_prefix = "";
2308 08573d5b 2019-05-14 stsp const char *branch_name = GOT_REF_HEAD;
2309 8069f636 2019-01-12 stsp char *commit_id_str = NULL;
2310 bb51a5b4 2020-01-13 stsp int ch, same_path_prefix, allow_nonempty = 0;
2311 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
2312 7f47418f 2019-12-20 stsp struct got_checkout_progress_arg cpa;
2313 f2ea84fa 2019-07-27 stsp
2314 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
2315 c09a553d 2018-03-12 stsp
2316 bb51a5b4 2020-01-13 stsp while ((ch = getopt(argc, argv, "b:c:Ep:")) != -1) {
2317 0bb8a95e 2018-03-12 stsp switch (ch) {
2318 08573d5b 2019-05-14 stsp case 'b':
2319 08573d5b 2019-05-14 stsp branch_name = optarg;
2320 08573d5b 2019-05-14 stsp break;
2321 8069f636 2019-01-12 stsp case 'c':
2322 8069f636 2019-01-12 stsp commit_id_str = strdup(optarg);
2323 8069f636 2019-01-12 stsp if (commit_id_str == NULL)
2324 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
2325 bb51a5b4 2020-01-13 stsp break;
2326 bb51a5b4 2020-01-13 stsp case 'E':
2327 bb51a5b4 2020-01-13 stsp allow_nonempty = 1;
2328 8069f636 2019-01-12 stsp break;
2329 0bb8a95e 2018-03-12 stsp case 'p':
2330 0bb8a95e 2018-03-12 stsp path_prefix = optarg;
2331 0bb8a95e 2018-03-12 stsp break;
2332 0bb8a95e 2018-03-12 stsp default:
2333 2deda0b9 2019-03-07 stsp usage_checkout();
2334 0bb8a95e 2018-03-12 stsp /* NOTREACHED */
2335 0bb8a95e 2018-03-12 stsp }
2336 0bb8a95e 2018-03-12 stsp }
2337 0bb8a95e 2018-03-12 stsp
2338 0bb8a95e 2018-03-12 stsp argc -= optind;
2339 0bb8a95e 2018-03-12 stsp argv += optind;
2340 0bb8a95e 2018-03-12 stsp
2341 6715a751 2018-03-16 stsp #ifndef PROFILE
2342 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2343 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
2344 c09a553d 2018-03-12 stsp err(1, "pledge");
2345 6715a751 2018-03-16 stsp #endif
2346 0bb8a95e 2018-03-12 stsp if (argc == 1) {
2347 c09a553d 2018-03-12 stsp char *cwd, *base, *dotgit;
2348 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2349 76089277 2018-04-01 stsp if (repo_path == NULL)
2350 638f9024 2019-05-13 stsp return got_error_from_errno2("realpath", argv[0]);
2351 c09a553d 2018-03-12 stsp cwd = getcwd(NULL, 0);
2352 76089277 2018-04-01 stsp if (cwd == NULL) {
2353 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
2354 76089277 2018-04-01 stsp goto done;
2355 76089277 2018-04-01 stsp }
2356 230a42bd 2019-05-11 jcs if (path_prefix[0]) {
2357 230a42bd 2019-05-11 jcs base = basename(path_prefix);
2358 230a42bd 2019-05-11 jcs if (base == NULL) {
2359 638f9024 2019-05-13 stsp error = got_error_from_errno2("basename",
2360 230a42bd 2019-05-11 jcs path_prefix);
2361 230a42bd 2019-05-11 jcs goto done;
2362 230a42bd 2019-05-11 jcs }
2363 230a42bd 2019-05-11 jcs } else {
2364 5d7c1dab 2018-04-01 stsp base = basename(repo_path);
2365 230a42bd 2019-05-11 jcs if (base == NULL) {
2366 638f9024 2019-05-13 stsp error = got_error_from_errno2("basename",
2367 230a42bd 2019-05-11 jcs repo_path);
2368 230a42bd 2019-05-11 jcs goto done;
2369 230a42bd 2019-05-11 jcs }
2370 76089277 2018-04-01 stsp }
2371 c09a553d 2018-03-12 stsp dotgit = strstr(base, ".git");
2372 c09a553d 2018-03-12 stsp if (dotgit)
2373 c09a553d 2018-03-12 stsp *dotgit = '\0';
2374 c09a553d 2018-03-12 stsp if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2375 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
2376 c09a553d 2018-03-12 stsp free(cwd);
2377 76089277 2018-04-01 stsp goto done;
2378 c09a553d 2018-03-12 stsp }
2379 c09a553d 2018-03-12 stsp free(cwd);
2380 0bb8a95e 2018-03-12 stsp } else if (argc == 2) {
2381 76089277 2018-04-01 stsp repo_path = realpath(argv[0], NULL);
2382 76089277 2018-04-01 stsp if (repo_path == NULL) {
2383 638f9024 2019-05-13 stsp error = got_error_from_errno2("realpath", argv[0]);
2384 76089277 2018-04-01 stsp goto done;
2385 76089277 2018-04-01 stsp }
2386 f7b38925 2018-04-01 stsp worktree_path = realpath(argv[1], NULL);
2387 76089277 2018-04-01 stsp if (worktree_path == NULL) {
2388 b4b3a7dd 2019-07-22 stsp if (errno != ENOENT) {
2389 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno2("realpath",
2390 b4b3a7dd 2019-07-22 stsp argv[1]);
2391 b4b3a7dd 2019-07-22 stsp goto done;
2392 b4b3a7dd 2019-07-22 stsp }
2393 b4b3a7dd 2019-07-22 stsp worktree_path = strdup(argv[1]);
2394 b4b3a7dd 2019-07-22 stsp if (worktree_path == NULL) {
2395 b4b3a7dd 2019-07-22 stsp error = got_error_from_errno("strdup");
2396 b4b3a7dd 2019-07-22 stsp goto done;
2397 b4b3a7dd 2019-07-22 stsp }
2398 76089277 2018-04-01 stsp }
2399 c09a553d 2018-03-12 stsp } else
2400 c09a553d 2018-03-12 stsp usage_checkout();
2401 c09a553d 2018-03-12 stsp
2402 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
2403 72151b04 2019-05-11 stsp got_path_strip_trailing_slashes(worktree_path);
2404 13bfb272 2019-05-10 jcs
2405 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
2406 c09a553d 2018-03-12 stsp if (error != NULL)
2407 c02c541e 2019-03-29 stsp goto done;
2408 c02c541e 2019-03-29 stsp
2409 c530dc23 2019-07-23 stsp /* Pre-create work tree path for unveil(2) */
2410 c530dc23 2019-07-23 stsp error = got_path_mkdir(worktree_path);
2411 c530dc23 2019-07-23 stsp if (error) {
2412 80c1b583 2019-08-07 stsp if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2413 80c1b583 2019-08-07 stsp !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2414 c530dc23 2019-07-23 stsp goto done;
2415 bb51a5b4 2020-01-13 stsp if (!allow_nonempty &&
2416 bb51a5b4 2020-01-13 stsp !got_path_dir_is_empty(worktree_path)) {
2417 c530dc23 2019-07-23 stsp error = got_error_path(worktree_path,
2418 c530dc23 2019-07-23 stsp GOT_ERR_DIR_NOT_EMPTY);
2419 c530dc23 2019-07-23 stsp goto done;
2420 c530dc23 2019-07-23 stsp }
2421 c530dc23 2019-07-23 stsp }
2422 c530dc23 2019-07-23 stsp
2423 c530dc23 2019-07-23 stsp error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2424 c02c541e 2019-03-29 stsp if (error)
2425 c09a553d 2018-03-12 stsp goto done;
2426 8069f636 2019-01-12 stsp
2427 08573d5b 2019-05-14 stsp error = got_ref_open(&head_ref, repo, branch_name, 0);
2428 c09a553d 2018-03-12 stsp if (error != NULL)
2429 c09a553d 2018-03-12 stsp goto done;
2430 c09a553d 2018-03-12 stsp
2431 0bb8a95e 2018-03-12 stsp error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2432 d70b8e30 2018-12-27 stsp if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2433 c09a553d 2018-03-12 stsp goto done;
2434 c09a553d 2018-03-12 stsp
2435 c09a553d 2018-03-12 stsp error = got_worktree_open(&worktree, worktree_path);
2436 c09a553d 2018-03-12 stsp if (error != NULL)
2437 c09a553d 2018-03-12 stsp goto done;
2438 c09a553d 2018-03-12 stsp
2439 e5dc7198 2018-12-29 stsp error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2440 e5dc7198 2018-12-29 stsp path_prefix);
2441 e5dc7198 2018-12-29 stsp if (error != NULL)
2442 e5dc7198 2018-12-29 stsp goto done;
2443 e5dc7198 2018-12-29 stsp if (!same_path_prefix) {
2444 49520a32 2018-12-29 stsp error = got_error(GOT_ERR_PATH_PREFIX);
2445 49520a32 2018-12-29 stsp goto done;
2446 49520a32 2018-12-29 stsp }
2447 49520a32 2018-12-29 stsp
2448 8069f636 2019-01-12 stsp if (commit_id_str) {
2449 04f57cb3 2019-07-25 stsp struct got_object_id *commit_id;
2450 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
2451 71a27632 2020-01-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, 1, repo);
2452 30837e32 2019-07-25 stsp if (error)
2453 8069f636 2019-01-12 stsp goto done;
2454 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
2455 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
2456 8069f636 2019-01-12 stsp if (error != NULL) {
2457 8069f636 2019-01-12 stsp free(commit_id);
2458 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
2459 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
2460 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
2461 4b6c9460 2020-03-05 stsp }
2462 8069f636 2019-01-12 stsp goto done;
2463 8069f636 2019-01-12 stsp }
2464 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
2465 4b6c9460 2020-03-05 stsp if (error) {
2466 4b6c9460 2020-03-05 stsp if (error->code == GOT_ERR_ANCESTRY) {
2467 4b6c9460 2020-03-05 stsp error = checkout_ancestry_error(
2468 4b6c9460 2020-03-05 stsp head_ref, commit_id_str);
2469 4b6c9460 2020-03-05 stsp }
2470 45d344f6 2019-05-14 stsp goto done;
2471 4b6c9460 2020-03-05 stsp }
2472 8069f636 2019-01-12 stsp error = got_worktree_set_base_commit_id(worktree, repo,
2473 8069f636 2019-01-12 stsp commit_id);
2474 8069f636 2019-01-12 stsp free(commit_id);
2475 8069f636 2019-01-12 stsp if (error)
2476 8069f636 2019-01-12 stsp goto done;
2477 8069f636 2019-01-12 stsp }
2478 8069f636 2019-01-12 stsp
2479 adc19d55 2019-07-28 stsp error = got_pathlist_append(&paths, "", NULL);
2480 f2ea84fa 2019-07-27 stsp if (error)
2481 f2ea84fa 2019-07-27 stsp goto done;
2482 7f47418f 2019-12-20 stsp cpa.worktree_path = worktree_path;
2483 7f47418f 2019-12-20 stsp cpa.had_base_commit_ref_error = 0;
2484 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
2485 7f47418f 2019-12-20 stsp checkout_progress, &cpa, check_cancelled, NULL);
2486 c09a553d 2018-03-12 stsp if (error != NULL)
2487 c09a553d 2018-03-12 stsp goto done;
2488 c09a553d 2018-03-12 stsp
2489 b65ae19a 2018-04-24 stsp printf("Now shut up and hack\n");
2490 7f47418f 2019-12-20 stsp if (cpa.had_base_commit_ref_error)
2491 7f47418f 2019-12-20 stsp show_worktree_base_ref_warning();
2492 c09a553d 2018-03-12 stsp done:
2493 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
2494 8069f636 2019-01-12 stsp free(commit_id_str);
2495 76089277 2018-04-01 stsp free(repo_path);
2496 507dc3bb 2018-12-29 stsp free(worktree_path);
2497 507dc3bb 2018-12-29 stsp return error;
2498 9627c110 2020-04-18 stsp }
2499 9627c110 2020-04-18 stsp
2500 9627c110 2020-04-18 stsp struct got_update_progress_arg {
2501 9627c110 2020-04-18 stsp int did_something;
2502 9627c110 2020-04-18 stsp int conflicts;
2503 9627c110 2020-04-18 stsp int obstructed;
2504 9627c110 2020-04-18 stsp int not_updated;
2505 9627c110 2020-04-18 stsp };
2506 9627c110 2020-04-18 stsp
2507 9627c110 2020-04-18 stsp void
2508 9627c110 2020-04-18 stsp print_update_progress_stats(struct got_update_progress_arg *upa)
2509 9627c110 2020-04-18 stsp {
2510 9627c110 2020-04-18 stsp if (!upa->did_something)
2511 9627c110 2020-04-18 stsp return;
2512 9627c110 2020-04-18 stsp
2513 9627c110 2020-04-18 stsp if (upa->conflicts > 0)
2514 9627c110 2020-04-18 stsp printf("Files with new merge conflicts: %d\n", upa->conflicts);
2515 9627c110 2020-04-18 stsp if (upa->obstructed > 0)
2516 9627c110 2020-04-18 stsp printf("File paths obstructed by a non-regular file: %d\n",
2517 9627c110 2020-04-18 stsp upa->obstructed);
2518 9627c110 2020-04-18 stsp if (upa->not_updated > 0)
2519 9627c110 2020-04-18 stsp printf("Files not updated because of existing merge "
2520 9627c110 2020-04-18 stsp "conflicts: %d\n", upa->not_updated);
2521 507dc3bb 2018-12-29 stsp }
2522 507dc3bb 2018-12-29 stsp
2523 507dc3bb 2018-12-29 stsp __dead static void
2524 507dc3bb 2018-12-29 stsp usage_update(void)
2525 507dc3bb 2018-12-29 stsp {
2526 f2ea84fa 2019-07-27 stsp fprintf(stderr, "usage: %s update [-b branch] [-c commit] [path ...]\n",
2527 507dc3bb 2018-12-29 stsp getprogname());
2528 507dc3bb 2018-12-29 stsp exit(1);
2529 507dc3bb 2018-12-29 stsp }
2530 507dc3bb 2018-12-29 stsp
2531 1ee397ad 2019-07-12 stsp static const struct got_error *
2532 507dc3bb 2018-12-29 stsp update_progress(void *arg, unsigned char status, const char *path)
2533 507dc3bb 2018-12-29 stsp {
2534 9627c110 2020-04-18 stsp struct got_update_progress_arg *upa = arg;
2535 784955db 2019-01-12 stsp
2536 7f47418f 2019-12-20 stsp if (status == GOT_STATUS_EXISTS ||
2537 7f47418f 2019-12-20 stsp status == GOT_STATUS_BASE_REF_ERR)
2538 1ee397ad 2019-07-12 stsp return NULL;
2539 507dc3bb 2018-12-29 stsp
2540 9627c110 2020-04-18 stsp upa->did_something = 1;
2541 a484d721 2019-06-10 stsp
2542 a484d721 2019-06-10 stsp /* Base commit bump happens silently. */
2543 a484d721 2019-06-10 stsp if (status == GOT_STATUS_BUMP_BASE)
2544 1ee397ad 2019-07-12 stsp return NULL;
2545 a484d721 2019-06-10 stsp
2546 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CONFLICT)
2547 9627c110 2020-04-18 stsp upa->conflicts++;
2548 9627c110 2020-04-18 stsp if (status == GOT_STATUS_OBSTRUCTED)
2549 9627c110 2020-04-18 stsp upa->obstructed++;
2550 9627c110 2020-04-18 stsp if (status == GOT_STATUS_CANNOT_UPDATE)
2551 9627c110 2020-04-18 stsp upa->not_updated++;
2552 9627c110 2020-04-18 stsp
2553 507dc3bb 2018-12-29 stsp while (path[0] == '/')
2554 507dc3bb 2018-12-29 stsp path++;
2555 507dc3bb 2018-12-29 stsp printf("%c %s\n", status, path);
2556 1ee397ad 2019-07-12 stsp return NULL;
2557 be7061eb 2018-12-30 stsp }
2558 be7061eb 2018-12-30 stsp
2559 be7061eb 2018-12-30 stsp static const struct got_error *
2560 a1fb16d8 2019-05-24 stsp switch_head_ref(struct got_reference *head_ref,
2561 a1fb16d8 2019-05-24 stsp struct got_object_id *commit_id, struct got_worktree *worktree,
2562 a1fb16d8 2019-05-24 stsp struct got_repository *repo)
2563 a1fb16d8 2019-05-24 stsp {
2564 a1fb16d8 2019-05-24 stsp const struct got_error *err = NULL;
2565 a1fb16d8 2019-05-24 stsp char *base_id_str;
2566 a1fb16d8 2019-05-24 stsp int ref_has_moved = 0;
2567 a1fb16d8 2019-05-24 stsp
2568 a1fb16d8 2019-05-24 stsp /* Trivial case: switching between two different references. */
2569 a1fb16d8 2019-05-24 stsp if (strcmp(got_ref_get_name(head_ref),
2570 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree)) != 0) {
2571 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n",
2572 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree),
2573 a1fb16d8 2019-05-24 stsp got_ref_get_name(head_ref));
2574 a1fb16d8 2019-05-24 stsp return got_worktree_set_head_ref(worktree, head_ref);
2575 a1fb16d8 2019-05-24 stsp }
2576 a1fb16d8 2019-05-24 stsp
2577 a1fb16d8 2019-05-24 stsp err = check_linear_ancestry(commit_id,
2578 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
2579 a1fb16d8 2019-05-24 stsp if (err) {
2580 a1fb16d8 2019-05-24 stsp if (err->code != GOT_ERR_ANCESTRY)
2581 a1fb16d8 2019-05-24 stsp return err;
2582 a1fb16d8 2019-05-24 stsp ref_has_moved = 1;
2583 a1fb16d8 2019-05-24 stsp }
2584 a1fb16d8 2019-05-24 stsp if (!ref_has_moved)
2585 a1fb16d8 2019-05-24 stsp return NULL;
2586 a1fb16d8 2019-05-24 stsp
2587 a1fb16d8 2019-05-24 stsp /* Switching to a rebased branch with the same reference name. */
2588 a1fb16d8 2019-05-24 stsp err = got_object_id_str(&base_id_str,
2589 a1fb16d8 2019-05-24 stsp got_worktree_get_base_commit_id(worktree));
2590 a1fb16d8 2019-05-24 stsp if (err)
2591 a1fb16d8 2019-05-24 stsp return err;
2592 a1fb16d8 2019-05-24 stsp printf("Reference %s now points at a different branch\n",
2593 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
2594 a1fb16d8 2019-05-24 stsp printf("Switching work tree from %s to %s\n", base_id_str,
2595 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree));
2596 0ebf8283 2019-07-24 stsp return NULL;
2597 0ebf8283 2019-07-24 stsp }
2598 0ebf8283 2019-07-24 stsp
2599 0ebf8283 2019-07-24 stsp static const struct got_error *
2600 0ebf8283 2019-07-24 stsp check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
2601 0ebf8283 2019-07-24 stsp {
2602 0ebf8283 2019-07-24 stsp const struct got_error *err;
2603 0ebf8283 2019-07-24 stsp int in_progress;
2604 0ebf8283 2019-07-24 stsp
2605 0ebf8283 2019-07-24 stsp err = got_worktree_rebase_in_progress(&in_progress, worktree);
2606 0ebf8283 2019-07-24 stsp if (err)
2607 0ebf8283 2019-07-24 stsp return err;
2608 0ebf8283 2019-07-24 stsp if (in_progress)
2609 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_REBASING);
2610 0ebf8283 2019-07-24 stsp
2611 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_in_progress(&in_progress, worktree);
2612 0ebf8283 2019-07-24 stsp if (err)
2613 0ebf8283 2019-07-24 stsp return err;
2614 0ebf8283 2019-07-24 stsp if (in_progress)
2615 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_BUSY);
2616 0ebf8283 2019-07-24 stsp
2617 a1fb16d8 2019-05-24 stsp return NULL;
2618 a5edda0a 2019-07-27 stsp }
2619 a5edda0a 2019-07-27 stsp
2620 a5edda0a 2019-07-27 stsp static const struct got_error *
2621 a5edda0a 2019-07-27 stsp get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
2622 a5edda0a 2019-07-27 stsp char *argv[], struct got_worktree *worktree)
2623 a5edda0a 2019-07-27 stsp {
2624 a0de39f3 2019-08-09 stsp const struct got_error *err = NULL;
2625 a5edda0a 2019-07-27 stsp char *path;
2626 a5edda0a 2019-07-27 stsp int i;
2627 a5edda0a 2019-07-27 stsp
2628 a5edda0a 2019-07-27 stsp if (argc == 0) {
2629 a5edda0a 2019-07-27 stsp path = strdup("");
2630 a5edda0a 2019-07-27 stsp if (path == NULL)
2631 a5edda0a 2019-07-27 stsp return got_error_from_errno("strdup");
2632 adc19d55 2019-07-28 stsp return got_pathlist_append(paths, path, NULL);
2633 a5edda0a 2019-07-27 stsp }
2634 a5edda0a 2019-07-27 stsp
2635 a5edda0a 2019-07-27 stsp for (i = 0; i < argc; i++) {
2636 a5edda0a 2019-07-27 stsp err = got_worktree_resolve_path(&path, worktree, argv[i]);
2637 a5edda0a 2019-07-27 stsp if (err)
2638 a5edda0a 2019-07-27 stsp break;
2639 adc19d55 2019-07-28 stsp err = got_pathlist_append(paths, path, NULL);
2640 a5edda0a 2019-07-27 stsp if (err) {
2641 a5edda0a 2019-07-27 stsp free(path);
2642 a5edda0a 2019-07-27 stsp break;
2643 a5edda0a 2019-07-27 stsp }
2644 a5edda0a 2019-07-27 stsp }
2645 a5edda0a 2019-07-27 stsp
2646 a5edda0a 2019-07-27 stsp return err;
2647 a1fb16d8 2019-05-24 stsp }
2648 a1fb16d8 2019-05-24 stsp
2649 a1fb16d8 2019-05-24 stsp static const struct got_error *
2650 fa51e947 2020-03-27 stsp wrap_not_worktree_error(const struct got_error *orig_err,
2651 fa51e947 2020-03-27 stsp const char *cmdname, const char *path)
2652 fa51e947 2020-03-27 stsp {
2653 fa51e947 2020-03-27 stsp const struct got_error *err;
2654 fa51e947 2020-03-27 stsp struct got_repository *repo;
2655 fa51e947 2020-03-27 stsp static char msg[512];
2656 fa51e947 2020-03-27 stsp
2657 fa51e947 2020-03-27 stsp err = got_repo_open(&repo, path, NULL);
2658 fa51e947 2020-03-27 stsp if (err)
2659 fa51e947 2020-03-27 stsp return orig_err;
2660 fa51e947 2020-03-27 stsp
2661 fa51e947 2020-03-27 stsp snprintf(msg, sizeof(msg),
2662 fa51e947 2020-03-27 stsp "'got %s' needs a work tree in addition to a git repository\n"
2663 fa51e947 2020-03-27 stsp "Work trees can be checked out from this Git repository with "
2664 fa51e947 2020-03-27 stsp "'got checkout'.\n"
2665 fa51e947 2020-03-27 stsp "The got(1) manual page contains more information.", cmdname);
2666 fa51e947 2020-03-27 stsp err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
2667 fa51e947 2020-03-27 stsp got_repo_close(repo);
2668 fa51e947 2020-03-27 stsp return err;
2669 fa51e947 2020-03-27 stsp }
2670 fa51e947 2020-03-27 stsp
2671 fa51e947 2020-03-27 stsp static const struct got_error *
2672 507dc3bb 2018-12-29 stsp cmd_update(int argc, char *argv[])
2673 507dc3bb 2018-12-29 stsp {
2674 507dc3bb 2018-12-29 stsp const struct got_error *error = NULL;
2675 507dc3bb 2018-12-29 stsp struct got_repository *repo = NULL;
2676 507dc3bb 2018-12-29 stsp struct got_worktree *worktree = NULL;
2677 f2ea84fa 2019-07-27 stsp char *worktree_path = NULL;
2678 507dc3bb 2018-12-29 stsp struct got_object_id *commit_id = NULL;
2679 9c4b8182 2019-01-02 stsp char *commit_id_str = NULL;
2680 024e9686 2019-05-14 stsp const char *branch_name = NULL;
2681 024e9686 2019-05-14 stsp struct got_reference *head_ref = NULL;
2682 f2ea84fa 2019-07-27 stsp struct got_pathlist_head paths;
2683 f2ea84fa 2019-07-27 stsp struct got_pathlist_entry *pe;
2684 9627c110 2020-04-18 stsp int ch;
2685 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
2686 507dc3bb 2018-12-29 stsp
2687 f2ea84fa 2019-07-27 stsp TAILQ_INIT(&paths);
2688 f2ea84fa 2019-07-27 stsp
2689 024e9686 2019-05-14 stsp while ((ch = getopt(argc, argv, "b:c:")) != -1) {
2690 507dc3bb 2018-12-29 stsp switch (ch) {
2691 024e9686 2019-05-14 stsp case 'b':
2692 024e9686 2019-05-14 stsp branch_name = optarg;
2693 024e9686 2019-05-14 stsp break;
2694 507dc3bb 2018-12-29 stsp case 'c':
2695 9c4b8182 2019-01-02 stsp commit_id_str = strdup(optarg);
2696 9c4b8182 2019-01-02 stsp if (commit_id_str == NULL)
2697 638f9024 2019-05-13 stsp return got_error_from_errno("strdup");
2698 507dc3bb 2018-12-29 stsp break;
2699 507dc3bb 2018-12-29 stsp default:
2700 2deda0b9 2019-03-07 stsp usage_update();
2701 507dc3bb 2018-12-29 stsp /* NOTREACHED */
2702 507dc3bb 2018-12-29 stsp }
2703 507dc3bb 2018-12-29 stsp }
2704 507dc3bb 2018-12-29 stsp
2705 507dc3bb 2018-12-29 stsp argc -= optind;
2706 507dc3bb 2018-12-29 stsp argv += optind;
2707 507dc3bb 2018-12-29 stsp
2708 507dc3bb 2018-12-29 stsp #ifndef PROFILE
2709 68ed9ba5 2019-02-10 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2710 68ed9ba5 2019-02-10 stsp "unveil", NULL) == -1)
2711 507dc3bb 2018-12-29 stsp err(1, "pledge");
2712 507dc3bb 2018-12-29 stsp #endif
2713 c4cdcb68 2019-04-03 stsp worktree_path = getcwd(NULL, 0);
2714 c4cdcb68 2019-04-03 stsp if (worktree_path == NULL) {
2715 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
2716 c4cdcb68 2019-04-03 stsp goto done;
2717 c4cdcb68 2019-04-03 stsp }
2718 c4cdcb68 2019-04-03 stsp error = got_worktree_open(&worktree, worktree_path);
2719 fa51e947 2020-03-27 stsp if (error) {
2720 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
2721 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "update",
2722 fa51e947 2020-03-27 stsp worktree_path);
2723 7d5807f4 2019-07-11 stsp goto done;
2724 fa51e947 2020-03-27 stsp }
2725 7d5807f4 2019-07-11 stsp
2726 0ebf8283 2019-07-24 stsp error = check_rebase_or_histedit_in_progress(worktree);
2727 f2ea84fa 2019-07-27 stsp if (error)
2728 f2ea84fa 2019-07-27 stsp goto done;
2729 507dc3bb 2018-12-29 stsp
2730 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
2731 c9956ddf 2019-09-08 stsp NULL);
2732 507dc3bb 2018-12-29 stsp if (error != NULL)
2733 507dc3bb 2018-12-29 stsp goto done;
2734 507dc3bb 2018-12-29 stsp
2735 97430839 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
2736 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
2737 087fb88c 2019-08-04 stsp if (error)
2738 087fb88c 2019-08-04 stsp goto done;
2739 087fb88c 2019-08-04 stsp
2740 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
2741 0266afb7 2019-01-04 stsp if (error)
2742 0266afb7 2019-01-04 stsp goto done;
2743 0266afb7 2019-01-04 stsp
2744 a1fb16d8 2019-05-24 stsp error = got_ref_open(&head_ref, repo, branch_name ? branch_name :
2745 a1fb16d8 2019-05-24 stsp got_worktree_get_head_ref_name(worktree), 0);
2746 024e9686 2019-05-14 stsp if (error != NULL)
2747 024e9686 2019-05-14 stsp goto done;
2748 507dc3bb 2018-12-29 stsp if (commit_id_str == NULL) {
2749 507dc3bb 2018-12-29 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
2750 9c4b8182 2019-01-02 stsp if (error != NULL)
2751 9c4b8182 2019-01-02 stsp goto done;
2752 9c4b8182 2019-01-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
2753 507dc3bb 2018-12-29 stsp if (error != NULL)
2754 507dc3bb 2018-12-29 stsp goto done;
2755 507dc3bb 2018-12-29 stsp } else {
2756 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
2757 71a27632 2020-01-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, 1, repo);
2758 04f57cb3 2019-07-25 stsp free(commit_id_str);
2759 bb787f09 2019-07-25 stsp commit_id_str = NULL;
2760 30837e32 2019-07-25 stsp if (error)
2761 a297e751 2019-07-11 stsp goto done;
2762 a297e751 2019-07-11 stsp error = got_object_id_str(&commit_id_str, commit_id);
2763 a297e751 2019-07-11 stsp if (error)
2764 507dc3bb 2018-12-29 stsp goto done;
2765 507dc3bb 2018-12-29 stsp }
2766 35c965b2 2018-12-29 stsp
2767 a1fb16d8 2019-05-24 stsp if (branch_name) {
2768 024e9686 2019-05-14 stsp struct got_object_id *head_commit_id;
2769 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry) {
2770 f2b16ada 2019-08-02 stsp if (pe->path_len == 0)
2771 f2ea84fa 2019-07-27 stsp continue;
2772 f2ea84fa 2019-07-27 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
2773 f2ea84fa 2019-07-27 stsp "switching between branches requires that "
2774 f2ea84fa 2019-07-27 stsp "the entire work tree gets updated");
2775 024e9686 2019-05-14 stsp goto done;
2776 024e9686 2019-05-14 stsp }
2777 024e9686 2019-05-14 stsp error = got_ref_resolve(&head_commit_id, repo, head_ref);
2778 024e9686 2019-05-14 stsp if (error)
2779 024e9686 2019-05-14 stsp goto done;
2780 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, head_commit_id, 0,
2781 3aef623b 2019-10-15 stsp repo);
2782 a367ff0f 2019-05-14 stsp free(head_commit_id);
2783 024e9686 2019-05-14 stsp if (error != NULL)
2784 024e9686 2019-05-14 stsp goto done;
2785 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
2786 a367ff0f 2019-05-14 stsp if (error)
2787 a367ff0f 2019-05-14 stsp goto done;
2788 a1fb16d8 2019-05-24 stsp error = switch_head_ref(head_ref, commit_id, worktree, repo);
2789 024e9686 2019-05-14 stsp if (error)
2790 024e9686 2019-05-14 stsp goto done;
2791 024e9686 2019-05-14 stsp } else {
2792 024e9686 2019-05-14 stsp error = check_linear_ancestry(commit_id,
2793 3aef623b 2019-10-15 stsp got_worktree_get_base_commit_id(worktree), 0, repo);
2794 a367ff0f 2019-05-14 stsp if (error != NULL) {
2795 a367ff0f 2019-05-14 stsp if (error->code == GOT_ERR_ANCESTRY)
2796 a367ff0f 2019-05-14 stsp error = got_error(GOT_ERR_BRANCH_MOVED);
2797 024e9686 2019-05-14 stsp goto done;
2798 a367ff0f 2019-05-14 stsp }
2799 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
2800 a367ff0f 2019-05-14 stsp if (error)
2801 a367ff0f 2019-05-14 stsp goto done;
2802 024e9686 2019-05-14 stsp }
2803 507dc3bb 2018-12-29 stsp
2804 507dc3bb 2018-12-29 stsp if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
2805 507dc3bb 2018-12-29 stsp commit_id) != 0) {
2806 507dc3bb 2018-12-29 stsp error = got_worktree_set_base_commit_id(worktree, repo,
2807 507dc3bb 2018-12-29 stsp commit_id);
2808 507dc3bb 2018-12-29 stsp if (error)
2809 507dc3bb 2018-12-29 stsp goto done;
2810 507dc3bb 2018-12-29 stsp }
2811 507dc3bb 2018-12-29 stsp
2812 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
2813 f2ea84fa 2019-07-27 stsp error = got_worktree_checkout_files(worktree, &paths, repo,
2814 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
2815 507dc3bb 2018-12-29 stsp if (error != NULL)
2816 507dc3bb 2018-12-29 stsp goto done;
2817 9c4b8182 2019-01-02 stsp
2818 9627c110 2020-04-18 stsp if (upa.did_something)
2819 784955db 2019-01-12 stsp printf("Updated to commit %s\n", commit_id_str);
2820 784955db 2019-01-12 stsp else
2821 784955db 2019-01-12 stsp printf("Already up-to-date\n");
2822 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
2823 507dc3bb 2018-12-29 stsp done:
2824 c09a553d 2018-03-12 stsp free(worktree_path);
2825 f2ea84fa 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
2826 f2ea84fa 2019-07-27 stsp free((char *)pe->path);
2827 f2ea84fa 2019-07-27 stsp got_pathlist_free(&paths);
2828 507dc3bb 2018-12-29 stsp free(commit_id);
2829 9c4b8182 2019-01-02 stsp free(commit_id_str);
2830 c09a553d 2018-03-12 stsp return error;
2831 c09a553d 2018-03-12 stsp }
2832 c09a553d 2018-03-12 stsp
2833 f42b1b34 2018-03-12 stsp static const struct got_error *
2834 44392932 2019-08-25 stsp diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
2835 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
2836 63035f9f 2019-10-06 stsp struct got_repository *repo)
2837 5c860e29 2018-03-12 stsp {
2838 f42b1b34 2018-03-12 stsp const struct got_error *err = NULL;
2839 44392932 2019-08-25 stsp struct got_blob_object *blob1 = NULL, *blob2 = NULL;
2840 79109fed 2018-03-27 stsp
2841 44392932 2019-08-25 stsp if (blob_id1) {
2842 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192);
2843 44392932 2019-08-25 stsp if (err)
2844 44392932 2019-08-25 stsp goto done;
2845 44392932 2019-08-25 stsp }
2846 79109fed 2018-03-27 stsp
2847 44392932 2019-08-25 stsp err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192);
2848 44392932 2019-08-25 stsp if (err)
2849 44392932 2019-08-25 stsp goto done;
2850 79109fed 2018-03-27 stsp
2851 44392932 2019-08-25 stsp while (path[0] == '/')
2852 44392932 2019-08-25 stsp path++;
2853 44392932 2019-08-25 stsp err = got_diff_blob(blob1, blob2, path, path, diff_context,
2854 63035f9f 2019-10-06 stsp ignore_whitespace, stdout);
2855 44392932 2019-08-25 stsp done:
2856 44392932 2019-08-25 stsp if (blob1)
2857 44392932 2019-08-25 stsp got_object_blob_close(blob1);
2858 44392932 2019-08-25 stsp got_object_blob_close(blob2);
2859 44392932 2019-08-25 stsp return err;
2860 44392932 2019-08-25 stsp }
2861 44392932 2019-08-25 stsp
2862 44392932 2019-08-25 stsp static const struct got_error *
2863 44392932 2019-08-25 stsp diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
2864 63035f9f 2019-10-06 stsp const char *path, int diff_context, int ignore_whitespace,
2865 63035f9f 2019-10-06 stsp struct got_repository *repo)
2866 44392932 2019-08-25 stsp {
2867 44392932 2019-08-25 stsp const struct got_error *err = NULL;
2868 44392932 2019-08-25 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
2869 44392932 2019-08-25 stsp struct got_diff_blob_output_unidiff_arg arg;
2870 44392932 2019-08-25 stsp
2871 44392932 2019-08-25 stsp if (tree_id1) {
2872 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
2873 79109fed 2018-03-27 stsp if (err)
2874 44392932 2019-08-25 stsp goto done;
2875 79109fed 2018-03-27 stsp }
2876 79109fed 2018-03-27 stsp
2877 44392932 2019-08-25 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
2878 0f2b3dca 2018-12-22 stsp if (err)
2879 0f2b3dca 2018-12-22 stsp goto done;
2880 0f2b3dca 2018-12-22 stsp
2881 aaa13589 2019-06-01 stsp arg.diff_context = diff_context;
2882 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
2883 aaa13589 2019-06-01 stsp arg.outfile = stdout;
2884 44392932 2019-08-25 stsp while (path[0] == '/')
2885 44392932 2019-08-25 stsp path++;
2886 44392932 2019-08-25 stsp err = got_diff_tree(tree1, tree2, path, path, repo,
2887 31b4484f 2019-07-27 stsp got_diff_blob_output_unidiff, &arg, 1);
2888 0f2b3dca 2018-12-22 stsp done:
2889 79109fed 2018-03-27 stsp if (tree1)
2890 79109fed 2018-03-27 stsp got_object_tree_close(tree1);
2891 366e0a5f 2019-10-10 stsp if (tree2)
2892 366e0a5f 2019-10-10 stsp got_object_tree_close(tree2);
2893 44392932 2019-08-25 stsp return err;
2894 44392932 2019-08-25 stsp }
2895 44392932 2019-08-25 stsp
2896 44392932 2019-08-25 stsp static const struct got_error *
2897 0208f208 2020-05-05 stsp get_changed_paths(struct got_pathlist_head *paths,
2898 0208f208 2020-05-05 stsp struct got_commit_object *commit, struct got_repository *repo)
2899 0208f208 2020-05-05 stsp {
2900 0208f208 2020-05-05 stsp const struct got_error *err = NULL;
2901 0208f208 2020-05-05 stsp struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
2902 0208f208 2020-05-05 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
2903 0208f208 2020-05-05 stsp struct got_object_qid *qid;
2904 0208f208 2020-05-05 stsp
2905 0208f208 2020-05-05 stsp qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
2906 0208f208 2020-05-05 stsp if (qid != NULL) {
2907 0208f208 2020-05-05 stsp struct got_commit_object *pcommit;
2908 0208f208 2020-05-05 stsp err = got_object_open_as_commit(&pcommit, repo,
2909 0208f208 2020-05-05 stsp qid->id);
2910 0208f208 2020-05-05 stsp if (err)
2911 0208f208 2020-05-05 stsp return err;
2912 0208f208 2020-05-05 stsp
2913 0208f208 2020-05-05 stsp tree_id1 = got_object_commit_get_tree_id(pcommit);
2914 0208f208 2020-05-05 stsp got_object_commit_close(pcommit);
2915 0208f208 2020-05-05 stsp
2916 0208f208 2020-05-05 stsp }
2917 0208f208 2020-05-05 stsp
2918 0208f208 2020-05-05 stsp if (tree_id1) {
2919 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree1, repo, tree_id1);
2920 0208f208 2020-05-05 stsp if (err)
2921 0208f208 2020-05-05 stsp goto done;
2922 0208f208 2020-05-05 stsp }
2923 0208f208 2020-05-05 stsp
2924 0208f208 2020-05-05 stsp tree_id2 = got_object_commit_get_tree_id(commit);
2925 0208f208 2020-05-05 stsp err = got_object_open_as_tree(&tree2, repo, tree_id2);
2926 0208f208 2020-05-05 stsp if (err)
2927 0208f208 2020-05-05 stsp goto done;
2928 0208f208 2020-05-05 stsp
2929 0208f208 2020-05-05 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
2930 0208f208 2020-05-05 stsp got_diff_tree_collect_changed_paths, paths, 0);
2931 0208f208 2020-05-05 stsp done:
2932 0208f208 2020-05-05 stsp if (tree1)
2933 0208f208 2020-05-05 stsp got_object_tree_close(tree1);
2934 0208f208 2020-05-05 stsp if (tree2)
2935 0208f208 2020-05-05 stsp got_object_tree_close(tree2);
2936 0208f208 2020-05-05 stsp return err;
2937 0208f208 2020-05-05 stsp }
2938 0208f208 2020-05-05 stsp
2939 0208f208 2020-05-05 stsp static const struct got_error *
2940 44392932 2019-08-25 stsp print_patch(struct got_commit_object *commit, struct got_object_id *id,
2941 44392932 2019-08-25 stsp const char *path, int diff_context, struct got_repository *repo)
2942 44392932 2019-08-25 stsp {
2943 44392932 2019-08-25 stsp const struct got_error *err = NULL;
2944 44392932 2019-08-25 stsp struct got_commit_object *pcommit = NULL;
2945 44392932 2019-08-25 stsp char *id_str1 = NULL, *id_str2 = NULL;
2946 44392932 2019-08-25 stsp struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL;
2947 44392932 2019-08-25 stsp struct got_object_qid *qid;
2948 44392932 2019-08-25 stsp
2949 44392932 2019-08-25 stsp qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
2950 44392932 2019-08-25 stsp if (qid != NULL) {
2951 44392932 2019-08-25 stsp err = got_object_open_as_commit(&pcommit, repo,
2952 44392932 2019-08-25 stsp qid->id);
2953 44392932 2019-08-25 stsp if (err)
2954 44392932 2019-08-25 stsp return err;
2955 44392932 2019-08-25 stsp }
2956 44392932 2019-08-25 stsp
2957 44392932 2019-08-25 stsp if (path && path[0] != '\0') {
2958 44392932 2019-08-25 stsp int obj_type;
2959 44392932 2019-08-25 stsp err = got_object_id_by_path(&obj_id2, repo, id, path);
2960 44392932 2019-08-25 stsp if (err)
2961 44392932 2019-08-25 stsp goto done;
2962 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
2963 44392932 2019-08-25 stsp if (err) {
2964 44392932 2019-08-25 stsp free(obj_id2);
2965 44392932 2019-08-25 stsp goto done;
2966 44392932 2019-08-25 stsp }
2967 44392932 2019-08-25 stsp if (pcommit) {
2968 44392932 2019-08-25 stsp err = got_object_id_by_path(&obj_id1, repo,
2969 44392932 2019-08-25 stsp qid->id, path);
2970 44392932 2019-08-25 stsp if (err) {
2971 2e8c69d1 2020-05-04 stsp if (err->code != GOT_ERR_NO_TREE_ENTRY) {
2972 2e8c69d1 2020-05-04 stsp free(obj_id2);
2973 2e8c69d1 2020-05-04 stsp goto done;
2974 2e8c69d1 2020-05-04 stsp }
2975 2e8c69d1 2020-05-04 stsp } else {
2976 2e8c69d1 2020-05-04 stsp err = got_object_id_str(&id_str1, obj_id1);
2977 2e8c69d1 2020-05-04 stsp if (err) {
2978 2e8c69d1 2020-05-04 stsp free(obj_id2);
2979 2e8c69d1 2020-05-04 stsp goto done;
2980 2e8c69d1 2020-05-04 stsp }
2981 44392932 2019-08-25 stsp }
2982 44392932 2019-08-25 stsp }
2983 44392932 2019-08-25 stsp err = got_object_get_type(&obj_type, repo, obj_id2);
2984 44392932 2019-08-25 stsp if (err) {
2985 44392932 2019-08-25 stsp free(obj_id2);
2986 44392932 2019-08-25 stsp goto done;
2987 44392932 2019-08-25 stsp }
2988 44392932 2019-08-25 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
2989 44392932 2019-08-25 stsp switch (obj_type) {
2990 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_BLOB:
2991 44392932 2019-08-25 stsp err = diff_blobs(obj_id1, obj_id2, path, diff_context,
2992 63035f9f 2019-10-06 stsp 0, repo);
2993 44392932 2019-08-25 stsp break;
2994 44392932 2019-08-25 stsp case GOT_OBJ_TYPE_TREE:
2995 44392932 2019-08-25 stsp err = diff_trees(obj_id1, obj_id2, path, diff_context,
2996 63035f9f 2019-10-06 stsp 0, repo);
2997 44392932 2019-08-25 stsp break;
2998 44392932 2019-08-25 stsp default:
2999 44392932 2019-08-25 stsp err = got_error(GOT_ERR_OBJ_TYPE);
3000 44392932 2019-08-25 stsp break;
3001 44392932 2019-08-25 stsp }
3002 44392932 2019-08-25 stsp free(obj_id1);
3003 44392932 2019-08-25 stsp free(obj_id2);
3004 44392932 2019-08-25 stsp } else {
3005 44392932 2019-08-25 stsp obj_id2 = got_object_commit_get_tree_id(commit);
3006 44392932 2019-08-25 stsp err = got_object_id_str(&id_str2, obj_id2);
3007 44392932 2019-08-25 stsp if (err)
3008 44392932 2019-08-25 stsp goto done;
3009 44392932 2019-08-25 stsp obj_id1 = got_object_commit_get_tree_id(pcommit);
3010 44392932 2019-08-25 stsp err = got_object_id_str(&id_str1, obj_id1);
3011 44392932 2019-08-25 stsp if (err)
3012 44392932 2019-08-25 stsp goto done;
3013 44392932 2019-08-25 stsp printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3014 63035f9f 2019-10-06 stsp err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, repo);
3015 44392932 2019-08-25 stsp }
3016 44392932 2019-08-25 stsp done:
3017 0f2b3dca 2018-12-22 stsp free(id_str1);
3018 0f2b3dca 2018-12-22 stsp free(id_str2);
3019 44392932 2019-08-25 stsp if (pcommit)
3020 44392932 2019-08-25 stsp got_object_commit_close(pcommit);
3021 79109fed 2018-03-27 stsp return err;
3022 79109fed 2018-03-27 stsp }
3023 79109fed 2018-03-27 stsp
3024 4bb494d5 2018-06-16 stsp static char *
3025 6c281f94 2018-06-11 stsp get_datestr(time_t *time, char *datebuf)
3026 6c281f94 2018-06-11 stsp {
3027 09867e48 2019-08-13 stsp struct tm mytm, *tm;
3028 09867e48 2019-08-13 stsp char *p, *s;
3029 09867e48 2019-08-13 stsp
3030 09867e48 2019-08-13 stsp tm = gmtime_r(time, &mytm);
3031 09867e48 2019-08-13 stsp if (tm == NULL)
3032 09867e48 2019-08-13 stsp return NULL;
3033 09867e48 2019-08-13 stsp s = asctime_r(tm, datebuf);
3034 09867e48 2019-08-13 stsp if (s == NULL)
3035 09867e48 2019-08-13 stsp return NULL;
3036 6c281f94 2018-06-11 stsp p = strchr(s, '\n');
3037 6c281f94 2018-06-11 stsp if (p)
3038 6c281f94 2018-06-11 stsp *p = '\0';
3039 6c281f94 2018-06-11 stsp return s;
3040 6c281f94 2018-06-11 stsp }
3041 dc424a06 2019-08-07 stsp
3042 6841bf13 2019-11-29 kn static const struct got_error *
3043 6841bf13 2019-11-29 kn match_logmsg(int *have_match, struct got_object_id *id,
3044 6841bf13 2019-11-29 kn struct got_commit_object *commit, regex_t *regex)
3045 6841bf13 2019-11-29 kn {
3046 6841bf13 2019-11-29 kn const struct got_error *err = NULL;
3047 6841bf13 2019-11-29 kn regmatch_t regmatch;
3048 6841bf13 2019-11-29 kn char *id_str = NULL, *logmsg = NULL;
3049 6841bf13 2019-11-29 kn
3050 6841bf13 2019-11-29 kn *have_match = 0;
3051 6841bf13 2019-11-29 kn
3052 6841bf13 2019-11-29 kn err = got_object_id_str(&id_str, id);
3053 6841bf13 2019-11-29 kn if (err)
3054 6841bf13 2019-11-29 kn return err;
3055 6841bf13 2019-11-29 kn
3056 6841bf13 2019-11-29 kn err = got_object_commit_get_logmsg(&logmsg, commit);
3057 6841bf13 2019-11-29 kn if (err)
3058 6841bf13 2019-11-29 kn goto done;
3059 6841bf13 2019-11-29 kn
3060 6841bf13 2019-11-29 kn if (regexec(regex, logmsg, 1, &regmatch, 0) == 0)
3061 6841bf13 2019-11-29 kn *have_match = 1;
3062 6841bf13 2019-11-29 kn done:
3063 6841bf13 2019-11-29 kn free(id_str);
3064 6841bf13 2019-11-29 kn free(logmsg);
3065 6841bf13 2019-11-29 kn return err;
3066 6841bf13 2019-11-29 kn }
3067 6841bf13 2019-11-29 kn
3068 0208f208 2020-05-05 stsp static void
3069 0208f208 2020-05-05 stsp match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3070 0208f208 2020-05-05 stsp regex_t *regex)
3071 0208f208 2020-05-05 stsp {
3072 0208f208 2020-05-05 stsp regmatch_t regmatch;
3073 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3074 0208f208 2020-05-05 stsp
3075 0208f208 2020-05-05 stsp *have_match = 0;
3076 0208f208 2020-05-05 stsp
3077 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3078 0208f208 2020-05-05 stsp if (regexec(regex, pe->path, 1, &regmatch, 0) == 0) {
3079 0208f208 2020-05-05 stsp *have_match = 1;
3080 0208f208 2020-05-05 stsp break;
3081 0208f208 2020-05-05 stsp }
3082 0208f208 2020-05-05 stsp }
3083 0208f208 2020-05-05 stsp }
3084 0208f208 2020-05-05 stsp
3085 dc424a06 2019-08-07 stsp #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3086 6c281f94 2018-06-11 stsp
3087 79109fed 2018-03-27 stsp static const struct got_error *
3088 79109fed 2018-03-27 stsp print_commit(struct got_commit_object *commit, struct got_object_id *id,
3089 0208f208 2020-05-05 stsp struct got_repository *repo, const char *path,
3090 0208f208 2020-05-05 stsp struct got_pathlist_head *changed_paths, int show_patch,
3091 44392932 2019-08-25 stsp int diff_context, struct got_reflist_head *refs)
3092 79109fed 2018-03-27 stsp {
3093 79109fed 2018-03-27 stsp const struct got_error *err = NULL;
3094 621015ac 2018-07-23 stsp char *id_str, *datestr, *logmsg0, *logmsg, *line;
3095 6c281f94 2018-06-11 stsp char datebuf[26];
3096 45d799e2 2018-12-23 stsp time_t committer_time;
3097 45d799e2 2018-12-23 stsp const char *author, *committer;
3098 199a4027 2019-02-02 stsp char *refs_str = NULL;
3099 199a4027 2019-02-02 stsp struct got_reflist_entry *re;
3100 5c860e29 2018-03-12 stsp
3101 199a4027 2019-02-02 stsp SIMPLEQ_FOREACH(re, refs, entry) {
3102 199a4027 2019-02-02 stsp char *s;
3103 199a4027 2019-02-02 stsp const char *name;
3104 a436ad14 2019-08-13 stsp struct got_tag_object *tag = NULL;
3105 a436ad14 2019-08-13 stsp int cmp;
3106 a436ad14 2019-08-13 stsp
3107 199a4027 2019-02-02 stsp name = got_ref_get_name(re->ref);
3108 d9498b20 2019-02-05 stsp if (strcmp(name, GOT_REF_HEAD) == 0)
3109 d9498b20 2019-02-05 stsp continue;
3110 199a4027 2019-02-02 stsp if (strncmp(name, "refs/", 5) == 0)
3111 199a4027 2019-02-02 stsp name += 5;
3112 7143d404 2019-03-12 stsp if (strncmp(name, "got/", 4) == 0)
3113 7143d404 2019-03-12 stsp continue;
3114 e34f9ed6 2019-02-02 stsp if (strncmp(name, "heads/", 6) == 0)
3115 e34f9ed6 2019-02-02 stsp name += 6;
3116 4343a07f 2020-04-24 stsp if (strncmp(name, "remotes/", 8) == 0) {
3117 141c2bff 2019-02-04 stsp name += 8;
3118 4343a07f 2020-04-24 stsp s = strstr(name, "/" GOT_REF_HEAD);
3119 4343a07f 2020-04-24 stsp if (s != NULL && s[strlen(s)] == '\0')
3120 4343a07f 2020-04-24 stsp continue;
3121 4343a07f 2020-04-24 stsp }
3122 a436ad14 2019-08-13 stsp if (strncmp(name, "tags/", 5) == 0) {
3123 a436ad14 2019-08-13 stsp err = got_object_open_as_tag(&tag, repo, re->id);
3124 5d844a1e 2019-08-13 stsp if (err) {
3125 5d844a1e 2019-08-13 stsp if (err->code != GOT_ERR_OBJ_TYPE)
3126 5d844a1e 2019-08-13 stsp return err;
3127 5d844a1e 2019-08-13 stsp /* Ref points at something other than a tag. */
3128 5d844a1e 2019-08-13 stsp err = NULL;
3129 5d844a1e 2019-08-13 stsp tag = NULL;
3130 5d844a1e 2019-08-13 stsp }
3131 a436ad14 2019-08-13 stsp }
3132 a436ad14 2019-08-13 stsp cmp = got_object_id_cmp(tag ?
3133 a436ad14 2019-08-13 stsp got_object_tag_get_object_id(tag) : re->id, id);
3134 a436ad14 2019-08-13 stsp if (tag)
3135 a436ad14 2019-08-13 stsp got_object_tag_close(tag);
3136 a436ad14 2019-08-13 stsp if (cmp != 0)
3137 a436ad14 2019-08-13 stsp continue;
3138 199a4027 2019-02-02 stsp s = refs_str;
3139 199a4027 2019-02-02 stsp if (asprintf(&refs_str, "%s%s%s", s ? s : "", s ? ", " : "",
3140 199a4027 2019-02-02 stsp name) == -1) {
3141 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
3142 199a4027 2019-02-02 stsp free(s);
3143 34ca4898 2019-08-13 stsp return err;
3144 199a4027 2019-02-02 stsp }
3145 199a4027 2019-02-02 stsp free(s);
3146 199a4027 2019-02-02 stsp }
3147 832c249c 2018-06-10 stsp err = got_object_id_str(&id_str, id);
3148 8bf5b3c9 2018-03-17 stsp if (err)
3149 8bf5b3c9 2018-03-17 stsp return err;
3150 788c352e 2018-06-16 stsp
3151 dc424a06 2019-08-07 stsp printf(GOT_COMMIT_SEP_STR);
3152 199a4027 2019-02-02 stsp printf("commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
3153 199a4027 2019-02-02 stsp refs_str ? refs_str : "", refs_str ? ")" : "");
3154 832c249c 2018-06-10 stsp free(id_str);
3155 d3d493d7 2019-02-21 stsp id_str = NULL;
3156 d3d493d7 2019-02-21 stsp free(refs_str);
3157 d3d493d7 2019-02-21 stsp refs_str = NULL;
3158 45d799e2 2018-12-23 stsp printf("from: %s\n", got_object_commit_get_author(commit));
3159 45d799e2 2018-12-23 stsp committer_time = got_object_commit_get_committer_time(commit);
3160 45d799e2 2018-12-23 stsp datestr = get_datestr(&committer_time, datebuf);
3161 09867e48 2019-08-13 stsp if (datestr)
3162 09867e48 2019-08-13 stsp printf("date: %s UTC\n", datestr);
3163 45d799e2 2018-12-23 stsp author = got_object_commit_get_author(commit);
3164 45d799e2 2018-12-23 stsp committer = got_object_commit_get_committer(commit);
3165 45d799e2 2018-12-23 stsp if (strcmp(author, committer) != 0)
3166 45d799e2 2018-12-23 stsp printf("via: %s\n", committer);
3167 45d799e2 2018-12-23 stsp if (got_object_commit_get_nparents(commit) > 1) {
3168 45d799e2 2018-12-23 stsp const struct got_object_id_queue *parent_ids;
3169 79f35eb3 2018-06-11 stsp struct got_object_qid *qid;
3170 3fe1abad 2018-06-10 stsp int n = 1;
3171 45d799e2 2018-12-23 stsp parent_ids = got_object_commit_get_parent_ids(commit);
3172 45d799e2 2018-12-23 stsp SIMPLEQ_FOREACH(qid, parent_ids, entry) {
3173 79f35eb3 2018-06-11 stsp err = got_object_id_str(&id_str, qid->id);
3174 a0603db2 2018-06-10 stsp if (err)
3175 a0603db2 2018-06-10 stsp return err;
3176 3fe1abad 2018-06-10 stsp printf("parent %d: %s\n", n++, id_str);
3177 a0603db2 2018-06-10 stsp free(id_str);
3178 a0603db2 2018-06-10 stsp }
3179 a0603db2 2018-06-10 stsp }
3180 832c249c 2018-06-10 stsp
3181 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
3182 5943eee2 2019-08-13 stsp if (err)
3183 5943eee2 2019-08-13 stsp return err;
3184 8bf5b3c9 2018-03-17 stsp
3185 621015ac 2018-07-23 stsp logmsg = logmsg0;
3186 832c249c 2018-06-10 stsp do {
3187 832c249c 2018-06-10 stsp line = strsep(&logmsg, "\n");
3188 832c249c 2018-06-10 stsp if (line)
3189 832c249c 2018-06-10 stsp printf(" %s\n", line);
3190 832c249c 2018-06-10 stsp } while (line);
3191 621015ac 2018-07-23 stsp free(logmsg0);
3192 832c249c 2018-06-10 stsp
3193 0208f208 2020-05-05 stsp if (changed_paths) {
3194 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3195 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, changed_paths, entry) {
3196 0208f208 2020-05-05 stsp struct got_diff_changed_path *cp = pe->data;
3197 0208f208 2020-05-05 stsp printf(" %c %s\n", cp->status, pe->path);
3198 0208f208 2020-05-05 stsp }
3199 0208f208 2020-05-05 stsp printf("\n");
3200 0208f208 2020-05-05 stsp }
3201 971751ac 2018-03-27 stsp if (show_patch) {
3202 44392932 2019-08-25 stsp err = print_patch(commit, id, path, diff_context, repo);
3203 971751ac 2018-03-27 stsp if (err == 0)
3204 971751ac 2018-03-27 stsp printf("\n");
3205 971751ac 2018-03-27 stsp }
3206 07862c20 2018-09-15 stsp
3207 cbe7f848 2019-02-11 stsp if (fflush(stdout) != 0 && err == NULL)
3208 638f9024 2019-05-13 stsp err = got_error_from_errno("fflush");
3209 07862c20 2018-09-15 stsp return err;
3210 f42b1b34 2018-03-12 stsp }
3211 5c860e29 2018-03-12 stsp
3212 f42b1b34 2018-03-12 stsp static const struct got_error *
3213 d1fe46f9 2020-04-18 stsp print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
3214 0208f208 2020-05-05 stsp struct got_repository *repo, const char *path, int show_changed_paths,
3215 0208f208 2020-05-05 stsp int show_patch, const char *search_pattern, int diff_context, int limit,
3216 0208f208 2020-05-05 stsp int log_branches, int reverse_display_order, struct got_reflist_head *refs)
3217 f42b1b34 2018-03-12 stsp {
3218 f42b1b34 2018-03-12 stsp const struct got_error *err;
3219 372ccdbb 2018-06-10 stsp struct got_commit_graph *graph;
3220 6841bf13 2019-11-29 kn regex_t regex;
3221 6841bf13 2019-11-29 kn int have_match;
3222 dbec59df 2020-04-18 stsp struct got_object_id_queue reversed_commits;
3223 dbec59df 2020-04-18 stsp struct got_object_qid *qid;
3224 dbec59df 2020-04-18 stsp struct got_commit_object *commit;
3225 0208f208 2020-05-05 stsp struct got_pathlist_head changed_paths;
3226 0208f208 2020-05-05 stsp struct got_pathlist_entry *pe;
3227 dbec59df 2020-04-18 stsp
3228 dbec59df 2020-04-18 stsp SIMPLEQ_INIT(&reversed_commits);
3229 0208f208 2020-05-05 stsp TAILQ_INIT(&changed_paths);
3230 372ccdbb 2018-06-10 stsp
3231 ccecc9fd 2020-04-18 stsp if (search_pattern && regcomp(&regex, search_pattern,
3232 ccecc9fd 2020-04-18 stsp REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
3233 6841bf13 2019-11-29 kn return got_error_msg(GOT_ERR_REGEX, search_pattern);
3234 6841bf13 2019-11-29 kn
3235 48c8c60d 2020-01-27 stsp err = got_commit_graph_open(&graph, path, !log_branches);
3236 f42b1b34 2018-03-12 stsp if (err)
3237 f42b1b34 2018-03-12 stsp return err;
3238 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, root_id, repo,
3239 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
3240 372ccdbb 2018-06-10 stsp if (err)
3241 fcc85cad 2018-07-22 stsp goto done;
3242 656b1f76 2019-05-11 jcs for (;;) {
3243 372ccdbb 2018-06-10 stsp struct got_object_id *id;
3244 8bf5b3c9 2018-03-17 stsp
3245 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
3246 84453469 2018-11-11 stsp break;
3247 84453469 2018-11-11 stsp
3248 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&id, graph, repo,
3249 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
3250 372ccdbb 2018-06-10 stsp if (err) {
3251 ee780d5c 2020-01-04 stsp if (err->code == GOT_ERR_ITER_COMPLETED)
3252 9ba79e04 2018-06-11 stsp err = NULL;
3253 ee780d5c 2020-01-04 stsp break;
3254 7e665116 2018-04-02 stsp }
3255 b43fbaa0 2018-06-11 stsp if (id == NULL)
3256 7e665116 2018-04-02 stsp break;
3257 b43fbaa0 2018-06-11 stsp
3258 f8e900f3 2018-06-11 stsp err = got_object_open_as_commit(&commit, repo, id);
3259 b43fbaa0 2018-06-11 stsp if (err)
3260 fcc85cad 2018-07-22 stsp break;
3261 6841bf13 2019-11-29 kn
3262 502b9684 2020-07-31 stsp if (show_changed_paths && !reverse_display_order) {
3263 0208f208 2020-05-05 stsp err = get_changed_paths(&changed_paths, commit, repo);
3264 0208f208 2020-05-05 stsp if (err)
3265 0208f208 2020-05-05 stsp break;
3266 0208f208 2020-05-05 stsp }
3267 0208f208 2020-05-05 stsp
3268 6841bf13 2019-11-29 kn if (search_pattern) {
3269 6841bf13 2019-11-29 kn err = match_logmsg(&have_match, id, commit, &regex);
3270 6841bf13 2019-11-29 kn if (err) {
3271 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3272 6841bf13 2019-11-29 kn break;
3273 6841bf13 2019-11-29 kn }
3274 0208f208 2020-05-05 stsp if (have_match == 0 && show_changed_paths)
3275 0208f208 2020-05-05 stsp match_changed_paths(&have_match,
3276 0208f208 2020-05-05 stsp &changed_paths, &regex);
3277 6841bf13 2019-11-29 kn if (have_match == 0) {
3278 6841bf13 2019-11-29 kn got_object_commit_close(commit);
3279 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3280 0208f208 2020-05-05 stsp free((char *)pe->path);
3281 0208f208 2020-05-05 stsp free(pe->data);
3282 0208f208 2020-05-05 stsp }
3283 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3284 6841bf13 2019-11-29 kn continue;
3285 6841bf13 2019-11-29 kn }
3286 6841bf13 2019-11-29 kn }
3287 6841bf13 2019-11-29 kn
3288 dbec59df 2020-04-18 stsp if (reverse_display_order) {
3289 dbec59df 2020-04-18 stsp err = got_object_qid_alloc(&qid, id);
3290 dbec59df 2020-04-18 stsp if (err)
3291 dbec59df 2020-04-18 stsp break;
3292 dbec59df 2020-04-18 stsp SIMPLEQ_INSERT_HEAD(&reversed_commits, qid, entry);
3293 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3294 dbec59df 2020-04-18 stsp } else {
3295 0208f208 2020-05-05 stsp err = print_commit(commit, id, repo, path,
3296 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
3297 0208f208 2020-05-05 stsp show_patch, diff_context, refs);
3298 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3299 dbec59df 2020-04-18 stsp if (err)
3300 dbec59df 2020-04-18 stsp break;
3301 dbec59df 2020-04-18 stsp }
3302 dbec59df 2020-04-18 stsp if ((limit && --limit == 0) ||
3303 dbec59df 2020-04-18 stsp (end_id && got_object_id_cmp(id, end_id) == 0))
3304 7e665116 2018-04-02 stsp break;
3305 0208f208 2020-05-05 stsp
3306 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3307 0208f208 2020-05-05 stsp free((char *)pe->path);
3308 0208f208 2020-05-05 stsp free(pe->data);
3309 0208f208 2020-05-05 stsp }
3310 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3311 31cedeaf 2018-09-15 stsp }
3312 dbec59df 2020-04-18 stsp if (reverse_display_order) {
3313 dbec59df 2020-04-18 stsp SIMPLEQ_FOREACH(qid, &reversed_commits, entry) {
3314 dbec59df 2020-04-18 stsp err = got_object_open_as_commit(&commit, repo, qid->id);
3315 dbec59df 2020-04-18 stsp if (err)
3316 dbec59df 2020-04-18 stsp break;
3317 502b9684 2020-07-31 stsp if (show_changed_paths) {
3318 502b9684 2020-07-31 stsp err = get_changed_paths(&changed_paths,
3319 502b9684 2020-07-31 stsp commit, repo);
3320 502b9684 2020-07-31 stsp if (err)
3321 502b9684 2020-07-31 stsp break;
3322 502b9684 2020-07-31 stsp }
3323 dbec59df 2020-04-18 stsp err = print_commit(commit, qid->id, repo, path,
3324 0208f208 2020-05-05 stsp show_changed_paths ? &changed_paths : NULL,
3325 dbec59df 2020-04-18 stsp show_patch, diff_context, refs);
3326 dbec59df 2020-04-18 stsp got_object_commit_close(commit);
3327 dbec59df 2020-04-18 stsp if (err)
3328 dbec59df 2020-04-18 stsp break;
3329 502b9684 2020-07-31 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3330 502b9684 2020-07-31 stsp free((char *)pe->path);
3331 502b9684 2020-07-31 stsp free(pe->data);
3332 502b9684 2020-07-31 stsp }
3333 502b9684 2020-07-31 stsp got_pathlist_free(&changed_paths);
3334 dbec59df 2020-04-18 stsp }
3335 dbec59df 2020-04-18 stsp }
3336 fcc85cad 2018-07-22 stsp done:
3337 dbec59df 2020-04-18 stsp while (!SIMPLEQ_EMPTY(&reversed_commits)) {
3338 dbec59df 2020-04-18 stsp qid = SIMPLEQ_FIRST(&reversed_commits);
3339 dbec59df 2020-04-18 stsp SIMPLEQ_REMOVE_HEAD(&reversed_commits, entry);
3340 dbec59df 2020-04-18 stsp got_object_qid_free(qid);
3341 dbec59df 2020-04-18 stsp }
3342 0208f208 2020-05-05 stsp TAILQ_FOREACH(pe, &changed_paths, entry) {
3343 0208f208 2020-05-05 stsp free((char *)pe->path);
3344 0208f208 2020-05-05 stsp free(pe->data);
3345 0208f208 2020-05-05 stsp }
3346 0208f208 2020-05-05 stsp got_pathlist_free(&changed_paths);
3347 6841bf13 2019-11-29 kn if (search_pattern)
3348 6841bf13 2019-11-29 kn regfree(&regex);
3349 372ccdbb 2018-06-10 stsp got_commit_graph_close(graph);
3350 f42b1b34 2018-03-12 stsp return err;
3351 f42b1b34 2018-03-12 stsp }
3352 5c860e29 2018-03-12 stsp
3353 4ed7e80c 2018-05-20 stsp __dead static void
3354 6f3d1eb0 2018-03-12 stsp usage_log(void)
3355 6f3d1eb0 2018-03-12 stsp {
3356 d1fe46f9 2020-04-18 stsp fprintf(stderr, "usage: %s log [-b] [-c commit] [-C number] [ -l N ] "
3357 0208f208 2020-05-05 stsp "[-p] [-P] [-x commit] [-s search-pattern] [-r repository-path] "
3358 0208f208 2020-05-05 stsp "[-R] [path]\n", getprogname());
3359 6f3d1eb0 2018-03-12 stsp exit(1);
3360 b1ebc001 2019-08-13 stsp }
3361 b1ebc001 2019-08-13 stsp
3362 b1ebc001 2019-08-13 stsp static int
3363 b1ebc001 2019-08-13 stsp get_default_log_limit(void)
3364 b1ebc001 2019-08-13 stsp {
3365 b1ebc001 2019-08-13 stsp const char *got_default_log_limit;
3366 b1ebc001 2019-08-13 stsp long long n;
3367 b1ebc001 2019-08-13 stsp const char *errstr;
3368 b1ebc001 2019-08-13 stsp
3369 b1ebc001 2019-08-13 stsp got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
3370 b1ebc001 2019-08-13 stsp if (got_default_log_limit == NULL)
3371 b1ebc001 2019-08-13 stsp return 0;
3372 b1ebc001 2019-08-13 stsp n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr);
3373 b1ebc001 2019-08-13 stsp if (errstr != NULL)
3374 b1ebc001 2019-08-13 stsp return 0;
3375 b1ebc001 2019-08-13 stsp return n;
3376 d1fe46f9 2020-04-18 stsp }
3377 d1fe46f9 2020-04-18 stsp
3378 d1fe46f9 2020-04-18 stsp static const struct got_error *
3379 d1fe46f9 2020-04-18 stsp resolve_commit_arg(struct got_object_id **id, const char *commit_arg,
3380 d1fe46f9 2020-04-18 stsp struct got_repository *repo)
3381 d1fe46f9 2020-04-18 stsp {
3382 d1fe46f9 2020-04-18 stsp const struct got_error *err = NULL;
3383 d1fe46f9 2020-04-18 stsp struct got_reference *ref;
3384 d1fe46f9 2020-04-18 stsp
3385 d1fe46f9 2020-04-18 stsp *id = NULL;
3386 d1fe46f9 2020-04-18 stsp
3387 d1fe46f9 2020-04-18 stsp err = got_ref_open(&ref, repo, commit_arg, 0);
3388 d1fe46f9 2020-04-18 stsp if (err == NULL) {
3389 d1fe46f9 2020-04-18 stsp int obj_type;
3390 d1fe46f9 2020-04-18 stsp err = got_ref_resolve(id, repo, ref);
3391 d1fe46f9 2020-04-18 stsp got_ref_close(ref);
3392 d1fe46f9 2020-04-18 stsp if (err)
3393 d1fe46f9 2020-04-18 stsp return err;
3394 d1fe46f9 2020-04-18 stsp err = got_object_get_type(&obj_type, repo, *id);
3395 d1fe46f9 2020-04-18 stsp if (err)
3396 d1fe46f9 2020-04-18 stsp return err;
3397 d1fe46f9 2020-04-18 stsp if (obj_type == GOT_OBJ_TYPE_TAG) {
3398 d1fe46f9 2020-04-18 stsp struct got_tag_object *tag;
3399 d1fe46f9 2020-04-18 stsp err = got_object_open_as_tag(&tag, repo, *id);
3400 d1fe46f9 2020-04-18 stsp if (err)
3401 d1fe46f9 2020-04-18 stsp return err;
3402 d1fe46f9 2020-04-18 stsp if (got_object_tag_get_object_type(tag) !=
3403 d1fe46f9 2020-04-18 stsp GOT_OBJ_TYPE_COMMIT) {
3404 d1fe46f9 2020-04-18 stsp got_object_tag_close(tag);
3405 d1fe46f9 2020-04-18 stsp return got_error(GOT_ERR_OBJ_TYPE);
3406 d1fe46f9 2020-04-18 stsp }
3407 d1fe46f9 2020-04-18 stsp free(*id);
3408 d1fe46f9 2020-04-18 stsp *id = got_object_id_dup(
3409 d1fe46f9 2020-04-18 stsp got_object_tag_get_object_id(tag));
3410 d1fe46f9 2020-04-18 stsp if (*id == NULL)
3411 d1fe46f9 2020-04-18 stsp err = got_error_from_errno(
3412 d1fe46f9 2020-04-18 stsp "got_object_id_dup");
3413 d1fe46f9 2020-04-18 stsp got_object_tag_close(tag);
3414 d1fe46f9 2020-04-18 stsp if (err)
3415 d1fe46f9 2020-04-18 stsp return err;
3416 d1fe46f9 2020-04-18 stsp } else if (obj_type != GOT_OBJ_TYPE_COMMIT)
3417 d1fe46f9 2020-04-18 stsp return got_error(GOT_ERR_OBJ_TYPE);
3418 d1fe46f9 2020-04-18 stsp } else {
3419 d1fe46f9 2020-04-18 stsp err = got_repo_match_object_id_prefix(id, commit_arg,
3420 d1fe46f9 2020-04-18 stsp GOT_OBJ_TYPE_COMMIT, repo);
3421 d1fe46f9 2020-04-18 stsp }
3422 d1fe46f9 2020-04-18 stsp
3423 d1fe46f9 2020-04-18 stsp return err;
3424 6f3d1eb0 2018-03-12 stsp }
3425 6f3d1eb0 2018-03-12 stsp
3426 4ed7e80c 2018-05-20 stsp static const struct got_error *
3427 f42b1b34 2018-03-12 stsp cmd_log(int argc, char *argv[])
3428 f42b1b34 2018-03-12 stsp {
3429 f42b1b34 2018-03-12 stsp const struct got_error *error;
3430 04ca23f4 2018-07-16 stsp struct got_repository *repo = NULL;
3431 cffc0aa4 2019-02-05 stsp struct got_worktree *worktree = NULL;
3432 d1fe46f9 2020-04-18 stsp struct got_object_id *start_id = NULL, *end_id = NULL;
3433 04ca23f4 2018-07-16 stsp char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
3434 d1fe46f9 2020-04-18 stsp const char *start_commit = NULL, *end_commit = NULL;
3435 d1fe46f9 2020-04-18 stsp const char *search_pattern = NULL;
3436 dc1edbfa 2019-11-29 kn int diff_context = -1, ch;
3437 0208f208 2020-05-05 stsp int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
3438 dbec59df 2020-04-18 stsp int reverse_display_order = 0;
3439 64a96a6d 2018-04-01 stsp const char *errstr;
3440 199a4027 2019-02-02 stsp struct got_reflist_head refs;
3441 1b3893a2 2019-03-18 stsp
3442 1b3893a2 2019-03-18 stsp SIMPLEQ_INIT(&refs);
3443 5c860e29 2018-03-12 stsp
3444 6715a751 2018-03-16 stsp #ifndef PROFILE
3445 6098196c 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
3446 6098196c 2019-01-04 stsp NULL)
3447 ad242220 2018-09-08 stsp == -1)
3448 f42b1b34 2018-03-12 stsp err(1, "pledge");
3449 6715a751 2018-03-16 stsp #endif
3450 79109fed 2018-03-27 stsp
3451 b1ebc001 2019-08-13 stsp limit = get_default_log_limit();
3452 b1ebc001 2019-08-13 stsp
3453 0208f208 2020-05-05 stsp while ((ch = getopt(argc, argv, "bpPc:C:l:r:Rs:x:")) != -1) {
3454 79109fed 2018-03-27 stsp switch (ch) {
3455 79109fed 2018-03-27 stsp case 'p':
3456 79109fed 2018-03-27 stsp show_patch = 1;
3457 d142fc45 2018-04-01 stsp break;
3458 0208f208 2020-05-05 stsp case 'P':
3459 0208f208 2020-05-05 stsp show_changed_paths = 1;
3460 0208f208 2020-05-05 stsp break;
3461 d142fc45 2018-04-01 stsp case 'c':
3462 d142fc45 2018-04-01 stsp start_commit = optarg;
3463 64a96a6d 2018-04-01 stsp break;
3464 c0cc5c62 2018-10-18 stsp case 'C':
3465 4a8520aa 2018-10-18 stsp diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
3466 4a8520aa 2018-10-18 stsp &errstr);
3467 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
3468 c0cc5c62 2018-10-18 stsp err(1, "-C option %s", errstr);
3469 c0cc5c62 2018-10-18 stsp break;
3470 64a96a6d 2018-04-01 stsp case 'l':
3471 b1ebc001 2019-08-13 stsp limit = strtonum(optarg, 0, INT_MAX, &errstr);
3472 64a96a6d 2018-04-01 stsp if (errstr != NULL)
3473 64a96a6d 2018-04-01 stsp err(1, "-l option %s", errstr);
3474 cc54c501 2019-07-15 stsp break;
3475 48c8c60d 2020-01-27 stsp case 'b':
3476 48c8c60d 2020-01-27 stsp log_branches = 1;
3477 a0603db2 2018-06-10 stsp break;
3478 04ca23f4 2018-07-16 stsp case 'r':
3479 04ca23f4 2018-07-16 stsp repo_path = realpath(optarg, NULL);
3480 04ca23f4 2018-07-16 stsp if (repo_path == NULL)
3481 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
3482 9ba1d308 2019-10-21 stsp optarg);
3483 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
3484 04ca23f4 2018-07-16 stsp break;
3485 dbec59df 2020-04-18 stsp case 'R':
3486 dbec59df 2020-04-18 stsp reverse_display_order = 1;
3487 dbec59df 2020-04-18 stsp break;
3488 6841bf13 2019-11-29 kn case 's':
3489 6841bf13 2019-11-29 kn search_pattern = optarg;
3490 6841bf13 2019-11-29 kn break;
3491 d1fe46f9 2020-04-18 stsp case 'x':
3492 d1fe46f9 2020-04-18 stsp end_commit = optarg;
3493 d1fe46f9 2020-04-18 stsp break;
3494 79109fed 2018-03-27 stsp default:
3495 2deda0b9 2019-03-07 stsp usage_log();
3496 79109fed 2018-03-27 stsp /* NOTREACHED */
3497 79109fed 2018-03-27 stsp }
3498 79109fed 2018-03-27 stsp }
3499 79109fed 2018-03-27 stsp
3500 79109fed 2018-03-27 stsp argc -= optind;
3501 79109fed 2018-03-27 stsp argv += optind;
3502 f42b1b34 2018-03-12 stsp
3503 dc1edbfa 2019-11-29 kn if (diff_context == -1)
3504 dc1edbfa 2019-11-29 kn diff_context = 3;
3505 dc1edbfa 2019-11-29 kn else if (!show_patch)
3506 dc1edbfa 2019-11-29 kn errx(1, "-C reguires -p");
3507 dc1edbfa 2019-11-29 kn
3508 04ca23f4 2018-07-16 stsp cwd = getcwd(NULL, 0);
3509 04ca23f4 2018-07-16 stsp if (cwd == NULL) {
3510 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
3511 04ca23f4 2018-07-16 stsp goto done;
3512 04ca23f4 2018-07-16 stsp }
3513 cffc0aa4 2019-02-05 stsp
3514 50f2fada 2020-04-24 stsp if (repo_path == NULL) {
3515 50f2fada 2020-04-24 stsp error = got_worktree_open(&worktree, cwd);
3516 50f2fada 2020-04-24 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
3517 50f2fada 2020-04-24 stsp goto done;
3518 50f2fada 2020-04-24 stsp error = NULL;
3519 50f2fada 2020-04-24 stsp }
3520 cffc0aa4 2019-02-05 stsp
3521 e7301579 2019-03-18 stsp if (argc == 0) {
3522 cbd1af7a 2019-03-18 stsp path = strdup("");
3523 e7301579 2019-03-18 stsp if (path == NULL) {
3524 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3525 cbd1af7a 2019-03-18 stsp goto done;
3526 e7301579 2019-03-18 stsp }
3527 e7301579 2019-03-18 stsp } else if (argc == 1) {
3528 e7301579 2019-03-18 stsp if (worktree) {
3529 e7301579 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
3530 e7301579 2019-03-18 stsp argv[0]);
3531 e7301579 2019-03-18 stsp if (error)
3532 e7301579 2019-03-18 stsp goto done;
3533 e7301579 2019-03-18 stsp } else {
3534 e7301579 2019-03-18 stsp path = strdup(argv[0]);
3535 e7301579 2019-03-18 stsp if (path == NULL) {
3536 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3537 e7301579 2019-03-18 stsp goto done;
3538 e7301579 2019-03-18 stsp }
3539 e7301579 2019-03-18 stsp }
3540 cbd1af7a 2019-03-18 stsp } else
3541 cbd1af7a 2019-03-18 stsp usage_log();
3542 cbd1af7a 2019-03-18 stsp
3543 5486daa2 2019-05-11 stsp if (repo_path == NULL) {
3544 5486daa2 2019-05-11 stsp repo_path = worktree ?
3545 5486daa2 2019-05-11 stsp strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
3546 5486daa2 2019-05-11 stsp }
3547 04ca23f4 2018-07-16 stsp if (repo_path == NULL) {
3548 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3549 cffc0aa4 2019-02-05 stsp goto done;
3550 04ca23f4 2018-07-16 stsp }
3551 6098196c 2019-01-04 stsp
3552 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
3553 d7d4f210 2018-03-12 stsp if (error != NULL)
3554 04ca23f4 2018-07-16 stsp goto done;
3555 f42b1b34 2018-03-12 stsp
3556 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
3557 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
3558 c02c541e 2019-03-29 stsp if (error)
3559 c02c541e 2019-03-29 stsp goto done;
3560 c02c541e 2019-03-29 stsp
3561 d142fc45 2018-04-01 stsp if (start_commit == NULL) {
3562 3235492e 2018-04-01 stsp struct got_reference *head_ref;
3563 d1fe46f9 2020-04-18 stsp struct got_commit_object *commit = NULL;
3564 1cc14b9f 2019-05-14 stsp error = got_ref_open(&head_ref, repo,
3565 1cc14b9f 2019-05-14 stsp worktree ? got_worktree_get_head_ref_name(worktree)
3566 1cc14b9f 2019-05-14 stsp : GOT_REF_HEAD, 0);
3567 3235492e 2018-04-01 stsp if (error != NULL)
3568 d1fe46f9 2020-04-18 stsp goto done;
3569 d1fe46f9 2020-04-18 stsp error = got_ref_resolve(&start_id, repo, head_ref);
3570 3235492e 2018-04-01 stsp got_ref_close(head_ref);
3571 3235492e 2018-04-01 stsp if (error != NULL)
3572 d1fe46f9 2020-04-18 stsp goto done;
3573 d1fe46f9 2020-04-18 stsp error = got_object_open_as_commit(&commit, repo,
3574 d1fe46f9 2020-04-18 stsp start_id);
3575 d1fe46f9 2020-04-18 stsp if (error != NULL)
3576 d1fe46f9 2020-04-18 stsp goto done;
3577 d1fe46f9 2020-04-18 stsp got_object_commit_close(commit);
3578 3235492e 2018-04-01 stsp } else {
3579 d1fe46f9 2020-04-18 stsp error = resolve_commit_arg(&start_id, start_commit, repo);
3580 d1fe46f9 2020-04-18 stsp if (error != NULL)
3581 d1fe46f9 2020-04-18 stsp goto done;
3582 3235492e 2018-04-01 stsp }
3583 d1fe46f9 2020-04-18 stsp if (end_commit != NULL) {
3584 d1fe46f9 2020-04-18 stsp error = resolve_commit_arg(&end_id, end_commit, repo);
3585 d1fe46f9 2020-04-18 stsp if (error != NULL)
3586 d1fe46f9 2020-04-18 stsp goto done;
3587 d1fe46f9 2020-04-18 stsp }
3588 04ca23f4 2018-07-16 stsp
3589 deeabeae 2019-08-27 stsp if (worktree) {
3590 deeabeae 2019-08-27 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
3591 deeabeae 2019-08-27 stsp char *p;
3592 deeabeae 2019-08-27 stsp if (asprintf(&p, "%s%s%s", prefix,
3593 deeabeae 2019-08-27 stsp (strcmp(prefix, "/") != 0) ? "/" : "", path) == -1) {
3594 deeabeae 2019-08-27 stsp error = got_error_from_errno("asprintf");
3595 deeabeae 2019-08-27 stsp goto done;
3596 deeabeae 2019-08-27 stsp }
3597 f43793a4 2020-01-27 stsp error = got_repo_map_path(&in_repo_path, repo, p, 0);
3598 deeabeae 2019-08-27 stsp free(p);
3599 deeabeae 2019-08-27 stsp } else
3600 deeabeae 2019-08-27 stsp error = got_repo_map_path(&in_repo_path, repo, path, 1);
3601 04ca23f4 2018-07-16 stsp if (error != NULL)
3602 04ca23f4 2018-07-16 stsp goto done;
3603 04ca23f4 2018-07-16 stsp if (in_repo_path) {
3604 04ca23f4 2018-07-16 stsp free(path);
3605 04ca23f4 2018-07-16 stsp path = in_repo_path;
3606 04ca23f4 2018-07-16 stsp }
3607 199a4027 2019-02-02 stsp
3608 b8bad2ba 2019-08-23 stsp error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
3609 199a4027 2019-02-02 stsp if (error)
3610 199a4027 2019-02-02 stsp goto done;
3611 04ca23f4 2018-07-16 stsp
3612 0208f208 2020-05-05 stsp error = print_commits(start_id, end_id, repo, path, show_changed_paths,
3613 0208f208 2020-05-05 stsp show_patch, search_pattern, diff_context, limit, log_branches,
3614 dbec59df 2020-04-18 stsp reverse_display_order, &refs);
3615 04ca23f4 2018-07-16 stsp done:
3616 04ca23f4 2018-07-16 stsp free(path);
3617 04ca23f4 2018-07-16 stsp free(repo_path);
3618 04ca23f4 2018-07-16 stsp free(cwd);
3619 cffc0aa4 2019-02-05 stsp if (worktree)
3620 cffc0aa4 2019-02-05 stsp got_worktree_close(worktree);
3621 ad242220 2018-09-08 stsp if (repo) {
3622 ad242220 2018-09-08 stsp const struct got_error *repo_error;
3623 ad242220 2018-09-08 stsp repo_error = got_repo_close(repo);
3624 ad242220 2018-09-08 stsp if (error == NULL)
3625 ad242220 2018-09-08 stsp error = repo_error;
3626 ad242220 2018-09-08 stsp }
3627 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
3628 8bf5b3c9 2018-03-17 stsp return error;
3629 5c860e29 2018-03-12 stsp }
3630 5c860e29 2018-03-12 stsp
3631 4ed7e80c 2018-05-20 stsp __dead static void
3632 3f8b7d6a 2018-04-01 stsp usage_diff(void)
3633 3f8b7d6a 2018-04-01 stsp {
3634 98eaaa12 2019-08-03 stsp fprintf(stderr, "usage: %s diff [-C number] [-r repository-path] [-s] "
3635 63035f9f 2019-10-06 stsp "[-w] [object1 object2 | path]\n", getprogname());
3636 3f8b7d6a 2018-04-01 stsp exit(1);
3637 b00d56cd 2018-04-01 stsp }
3638 b00d56cd 2018-04-01 stsp
3639 b72f483a 2019-02-05 stsp struct print_diff_arg {
3640 b72f483a 2019-02-05 stsp struct got_repository *repo;
3641 b72f483a 2019-02-05 stsp struct got_worktree *worktree;
3642 b72f483a 2019-02-05 stsp int diff_context;
3643 3fc0c068 2019-02-10 stsp const char *id_str;
3644 3fc0c068 2019-02-10 stsp int header_shown;
3645 98eaaa12 2019-08-03 stsp int diff_staged;
3646 63035f9f 2019-10-06 stsp int ignore_whitespace;
3647 b72f483a 2019-02-05 stsp };
3648 39449a05 2020-07-23 stsp
3649 39449a05 2020-07-23 stsp /*
3650 39449a05 2020-07-23 stsp * Create a file which contains the target path of a symlink so we can feed
3651 39449a05 2020-07-23 stsp * it as content to the diff engine.
3652 39449a05 2020-07-23 stsp */
3653 39449a05 2020-07-23 stsp static const struct got_error *
3654 39449a05 2020-07-23 stsp get_symlink_target_file(int *fd, int dirfd, const char *de_name,
3655 39449a05 2020-07-23 stsp const char *abspath)
3656 39449a05 2020-07-23 stsp {
3657 39449a05 2020-07-23 stsp const struct got_error *err = NULL;
3658 39449a05 2020-07-23 stsp char target_path[PATH_MAX];
3659 39449a05 2020-07-23 stsp ssize_t target_len, outlen;
3660 39449a05 2020-07-23 stsp
3661 39449a05 2020-07-23 stsp *fd = -1;
3662 39449a05 2020-07-23 stsp
3663 39449a05 2020-07-23 stsp if (dirfd != -1) {
3664 39449a05 2020-07-23 stsp target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
3665 39449a05 2020-07-23 stsp if (target_len == -1)
3666 39449a05 2020-07-23 stsp return got_error_from_errno2("readlinkat", abspath);
3667 39449a05 2020-07-23 stsp } else {
3668 39449a05 2020-07-23 stsp target_len = readlink(abspath, target_path, PATH_MAX);
3669 39449a05 2020-07-23 stsp if (target_len == -1)
3670 39449a05 2020-07-23 stsp return got_error_from_errno2("readlink", abspath);
3671 39449a05 2020-07-23 stsp }
3672 39449a05 2020-07-23 stsp
3673 39449a05 2020-07-23 stsp *fd = got_opentempfd();
3674 39449a05 2020-07-23 stsp if (*fd == -1)
3675 39449a05 2020-07-23 stsp return got_error_from_errno("got_opentempfd");
3676 39449a05 2020-07-23 stsp
3677 39449a05 2020-07-23 stsp outlen = write(*fd, target_path, target_len);
3678 39449a05 2020-07-23 stsp if (outlen == -1) {
3679 39449a05 2020-07-23 stsp err = got_error_from_errno("got_opentempfd");
3680 39449a05 2020-07-23 stsp goto done;
3681 39449a05 2020-07-23 stsp }
3682 39449a05 2020-07-23 stsp
3683 39449a05 2020-07-23 stsp if (lseek(*fd, 0, SEEK_SET) == -1) {
3684 39449a05 2020-07-23 stsp err = got_error_from_errno2("lseek", abspath);
3685 39449a05 2020-07-23 stsp goto done;
3686 39449a05 2020-07-23 stsp }
3687 39449a05 2020-07-23 stsp done:
3688 39449a05 2020-07-23 stsp if (err) {
3689 39449a05 2020-07-23 stsp close(*fd);
3690 39449a05 2020-07-23 stsp *fd = -1;
3691 39449a05 2020-07-23 stsp }
3692 39449a05 2020-07-23 stsp return err;
3693 39449a05 2020-07-23 stsp }
3694 b72f483a 2019-02-05 stsp
3695 4ed7e80c 2018-05-20 stsp static const struct got_error *
3696 88d0e355 2019-08-03 stsp print_diff(void *arg, unsigned char status, unsigned char staged_status,
3697 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
3698 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
3699 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
3700 b72f483a 2019-02-05 stsp {
3701 b72f483a 2019-02-05 stsp struct print_diff_arg *a = arg;
3702 b72f483a 2019-02-05 stsp const struct got_error *err = NULL;
3703 b72f483a 2019-02-05 stsp struct got_blob_object *blob1 = NULL;
3704 12463d8b 2019-12-13 stsp int fd = -1;
3705 b72f483a 2019-02-05 stsp FILE *f2 = NULL;
3706 4ce46740 2019-08-08 stsp char *abspath = NULL, *label1 = NULL;
3707 b72f483a 2019-02-05 stsp struct stat sb;
3708 b72f483a 2019-02-05 stsp
3709 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
3710 98eaaa12 2019-08-03 stsp if (staged_status != GOT_STATUS_MODIFY &&
3711 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_ADD &&
3712 98eaaa12 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
3713 98eaaa12 2019-08-03 stsp return NULL;
3714 98eaaa12 2019-08-03 stsp } else {
3715 98eaaa12 2019-08-03 stsp if (staged_status == GOT_STATUS_DELETE)
3716 98eaaa12 2019-08-03 stsp return NULL;
3717 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
3718 2a06fe5f 2019-08-24 stsp return got_error_set_errno(ENOENT, path);
3719 98eaaa12 2019-08-03 stsp if (status != GOT_STATUS_MODIFY &&
3720 98eaaa12 2019-08-03 stsp status != GOT_STATUS_ADD &&
3721 98eaaa12 2019-08-03 stsp status != GOT_STATUS_DELETE &&
3722 98eaaa12 2019-08-03 stsp status != GOT_STATUS_CONFLICT)
3723 98eaaa12 2019-08-03 stsp return NULL;
3724 98eaaa12 2019-08-03 stsp }
3725 3fc0c068 2019-02-10 stsp
3726 3fc0c068 2019-02-10 stsp if (!a->header_shown) {
3727 98eaaa12 2019-08-03 stsp printf("diff %s %s%s\n", a->id_str,
3728 98eaaa12 2019-08-03 stsp got_worktree_get_root_path(a->worktree),
3729 98eaaa12 2019-08-03 stsp a->diff_staged ? " (staged changes)" : "");
3730 3fc0c068 2019-02-10 stsp a->header_shown = 1;
3731 3fc0c068 2019-02-10 stsp }
3732 b72f483a 2019-02-05 stsp
3733 98eaaa12 2019-08-03 stsp if (a->diff_staged) {
3734 98eaaa12 2019-08-03 stsp const char *label1 = NULL, *label2 = NULL;
3735 98eaaa12 2019-08-03 stsp switch (staged_status) {
3736 98eaaa12 2019-08-03 stsp case GOT_STATUS_MODIFY:
3737 98eaaa12 2019-08-03 stsp label1 = path;
3738 98eaaa12 2019-08-03 stsp label2 = path;
3739 98eaaa12 2019-08-03 stsp break;
3740 98eaaa12 2019-08-03 stsp case GOT_STATUS_ADD:
3741 98eaaa12 2019-08-03 stsp label2 = path;
3742 98eaaa12 2019-08-03 stsp break;
3743 98eaaa12 2019-08-03 stsp case GOT_STATUS_DELETE:
3744 98eaaa12 2019-08-03 stsp label1 = path;
3745 98eaaa12 2019-08-03 stsp break;
3746 98eaaa12 2019-08-03 stsp default:
3747 98eaaa12 2019-08-03 stsp return got_error(GOT_ERR_FILE_STATUS);
3748 98eaaa12 2019-08-03 stsp }
3749 98eaaa12 2019-08-03 stsp return got_diff_objects_as_blobs(blob_id, staged_blob_id,
3750 63035f9f 2019-10-06 stsp label1, label2, a->diff_context, a->ignore_whitespace,
3751 63035f9f 2019-10-06 stsp a->repo, stdout);
3752 98eaaa12 2019-08-03 stsp }
3753 98eaaa12 2019-08-03 stsp
3754 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
3755 4ce46740 2019-08-08 stsp staged_status == GOT_STATUS_MODIFY) {
3756 4ce46740 2019-08-08 stsp char *id_str;
3757 408b4ebc 2019-08-03 stsp err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
3758 408b4ebc 2019-08-03 stsp 8192);
3759 4ce46740 2019-08-08 stsp if (err)
3760 4ce46740 2019-08-08 stsp goto done;
3761 4ce46740 2019-08-08 stsp err = got_object_id_str(&id_str, staged_blob_id);
3762 4ce46740 2019-08-08 stsp if (err)
3763 4ce46740 2019-08-08 stsp goto done;
3764 4ce46740 2019-08-08 stsp if (asprintf(&label1, "%s (staged)", id_str) == -1) {
3765 4ce46740 2019-08-08 stsp err = got_error_from_errno("asprintf");
3766 4ce46740 2019-08-08 stsp free(id_str);
3767 4ce46740 2019-08-08 stsp goto done;
3768 4ce46740 2019-08-08 stsp }
3769 4ce46740 2019-08-08 stsp free(id_str);
3770 4ce46740 2019-08-08 stsp } else if (status != GOT_STATUS_ADD) {
3771 016a88dd 2019-05-13 stsp err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192);
3772 4ce46740 2019-08-08 stsp if (err)
3773 4ce46740 2019-08-08 stsp goto done;
3774 4ce46740 2019-08-08 stsp }
3775 d00136be 2019-03-26 stsp
3776 7154f6ce 2019-03-27 stsp if (status != GOT_STATUS_DELETE) {
3777 2ec1f75b 2019-03-26 stsp if (asprintf(&abspath, "%s/%s",
3778 2ec1f75b 2019-03-26 stsp got_worktree_get_root_path(a->worktree), path) == -1) {
3779 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
3780 2ec1f75b 2019-03-26 stsp goto done;
3781 2ec1f75b 2019-03-26 stsp }
3782 b72f483a 2019-02-05 stsp
3783 12463d8b 2019-12-13 stsp if (dirfd != -1) {
3784 12463d8b 2019-12-13 stsp fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
3785 12463d8b 2019-12-13 stsp if (fd == -1) {
3786 39449a05 2020-07-23 stsp if (errno != ELOOP) {
3787 39449a05 2020-07-23 stsp err = got_error_from_errno2("openat",
3788 39449a05 2020-07-23 stsp abspath);
3789 39449a05 2020-07-23 stsp goto done;
3790 39449a05 2020-07-23 stsp }
3791 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
3792 39449a05 2020-07-23 stsp de_name, abspath);
3793 39449a05 2020-07-23 stsp if (err)
3794 39449a05 2020-07-23 stsp goto done;
3795 12463d8b 2019-12-13 stsp }
3796 12463d8b 2019-12-13 stsp } else {
3797 12463d8b 2019-12-13 stsp fd = open(abspath, O_RDONLY | O_NOFOLLOW);
3798 12463d8b 2019-12-13 stsp if (fd == -1) {
3799 39449a05 2020-07-23 stsp if (errno != ELOOP) {
3800 39449a05 2020-07-23 stsp err = got_error_from_errno2("open",
3801 39449a05 2020-07-23 stsp abspath);
3802 39449a05 2020-07-23 stsp goto done;
3803 39449a05 2020-07-23 stsp }
3804 39449a05 2020-07-23 stsp err = get_symlink_target_file(&fd, dirfd,
3805 39449a05 2020-07-23 stsp de_name, abspath);
3806 39449a05 2020-07-23 stsp if (err)
3807 39449a05 2020-07-23 stsp goto done;
3808 12463d8b 2019-12-13 stsp }
3809 12463d8b 2019-12-13 stsp }
3810 12463d8b 2019-12-13 stsp if (fstat(fd, &sb) == -1) {
3811 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fstat", abspath);
3812 2ec1f75b 2019-03-26 stsp goto done;
3813 2ec1f75b 2019-03-26 stsp }
3814 12463d8b 2019-12-13 stsp f2 = fdopen(fd, "r");
3815 12463d8b 2019-12-13 stsp if (f2 == NULL) {
3816 12463d8b 2019-12-13 stsp err = got_error_from_errno2("fdopen", abspath);
3817 2ec1f75b 2019-03-26 stsp goto done;
3818 2ec1f75b 2019-03-26 stsp }
3819 12463d8b 2019-12-13 stsp fd = -1;
3820 2ec1f75b 2019-03-26 stsp } else
3821 2ec1f75b 2019-03-26 stsp sb.st_size = 0;
3822 b72f483a 2019-02-05 stsp
3823 4ce46740 2019-08-08 stsp err = got_diff_blob_file(blob1, label1, f2, sb.st_size, path,
3824 63035f9f 2019-10-06 stsp a->diff_context, a->ignore_whitespace, stdout);
3825 b72f483a 2019-02-05 stsp done:
3826 b72f483a 2019-02-05 stsp if (blob1)
3827 b72f483a 2019-02-05 stsp got_object_blob_close(blob1);
3828 12463d8b 2019-12-13 stsp if (f2 && fclose(f2) == EOF && err == NULL)
3829 638f9024 2019-05-13 stsp err = got_error_from_errno("fclose");
3830 12463d8b 2019-12-13 stsp if (fd != -1 && close(fd) == -1 && err == NULL)
3831 12463d8b 2019-12-13 stsp err = got_error_from_errno("close");
3832 b72f483a 2019-02-05 stsp free(abspath);
3833 927df6b7 2019-02-10 stsp return err;
3834 927df6b7 2019-02-10 stsp }
3835 927df6b7 2019-02-10 stsp
3836 927df6b7 2019-02-10 stsp static const struct got_error *
3837 b00d56cd 2018-04-01 stsp cmd_diff(int argc, char *argv[])
3838 b00d56cd 2018-04-01 stsp {
3839 b00d56cd 2018-04-01 stsp const struct got_error *error;
3840 b00d56cd 2018-04-01 stsp struct got_repository *repo = NULL;
3841 b72f483a 2019-02-05 stsp struct got_worktree *worktree = NULL;
3842 b72f483a 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL;
3843 15a94983 2018-12-23 stsp struct got_object_id *id1 = NULL, *id2 = NULL;
3844 cd628e99 2019-05-28 stsp const char *id_str1 = NULL, *id_str2 = NULL;
3845 5e70831e 2019-05-28 stsp char *label1 = NULL, *label2 = NULL;
3846 15a94983 2018-12-23 stsp int type1, type2;
3847 63035f9f 2019-10-06 stsp int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch;
3848 c0cc5c62 2018-10-18 stsp const char *errstr;
3849 927df6b7 2019-02-10 stsp char *path = NULL;
3850 b00d56cd 2018-04-01 stsp
3851 b00d56cd 2018-04-01 stsp #ifndef PROFILE
3852 25eccc22 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
3853 25eccc22 2019-01-04 stsp NULL) == -1)
3854 b00d56cd 2018-04-01 stsp err(1, "pledge");
3855 b00d56cd 2018-04-01 stsp #endif
3856 b00d56cd 2018-04-01 stsp
3857 63035f9f 2019-10-06 stsp while ((ch = getopt(argc, argv, "C:r:sw")) != -1) {
3858 b00d56cd 2018-04-01 stsp switch (ch) {
3859 c0cc5c62 2018-10-18 stsp case 'C':
3860 dfcab68b 2019-11-29 kn diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
3861 dfcab68b 2019-11-29 kn &errstr);
3862 c0cc5c62 2018-10-18 stsp if (errstr != NULL)
3863 c0cc5c62 2018-10-18 stsp err(1, "-C option %s", errstr);
3864 c0cc5c62 2018-10-18 stsp break;
3865 b72f483a 2019-02-05 stsp case 'r':
3866 b72f483a 2019-02-05 stsp repo_path = realpath(optarg, NULL);
3867 b72f483a 2019-02-05 stsp if (repo_path == NULL)
3868 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
3869 9ba1d308 2019-10-21 stsp optarg);
3870 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
3871 b72f483a 2019-02-05 stsp break;
3872 98eaaa12 2019-08-03 stsp case 's':
3873 98eaaa12 2019-08-03 stsp diff_staged = 1;
3874 63035f9f 2019-10-06 stsp break;
3875 63035f9f 2019-10-06 stsp case 'w':
3876 63035f9f 2019-10-06 stsp ignore_whitespace = 1;
3877 98eaaa12 2019-08-03 stsp break;
3878 b00d56cd 2018-04-01 stsp default:
3879 2deda0b9 2019-03-07 stsp usage_diff();
3880 b00d56cd 2018-04-01 stsp /* NOTREACHED */
3881 b00d56cd 2018-04-01 stsp }
3882 b00d56cd 2018-04-01 stsp }
3883 b00d56cd 2018-04-01 stsp
3884 b00d56cd 2018-04-01 stsp argc -= optind;
3885 b00d56cd 2018-04-01 stsp argv += optind;
3886 b00d56cd 2018-04-01 stsp
3887 b72f483a 2019-02-05 stsp cwd = getcwd(NULL, 0);
3888 b72f483a 2019-02-05 stsp if (cwd == NULL) {
3889 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
3890 b72f483a 2019-02-05 stsp goto done;
3891 b72f483a 2019-02-05 stsp }
3892 927df6b7 2019-02-10 stsp if (argc <= 1) {
3893 b72f483a 2019-02-05 stsp if (repo_path)
3894 b72f483a 2019-02-05 stsp errx(1,
3895 b72f483a 2019-02-05 stsp "-r option can't be used when diffing a work tree");
3896 1f03b8da 2020-03-20 stsp error = got_worktree_open(&worktree, cwd);
3897 fa51e947 2020-03-27 stsp if (error) {
3898 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
3899 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "diff",
3900 fa51e947 2020-03-27 stsp cwd);
3901 1f03b8da 2020-03-20 stsp goto done;
3902 fa51e947 2020-03-27 stsp }
3903 b72f483a 2019-02-05 stsp repo_path = strdup(got_worktree_get_repo_path(worktree));
3904 927df6b7 2019-02-10 stsp if (repo_path == NULL) {
3905 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3906 927df6b7 2019-02-10 stsp goto done;
3907 927df6b7 2019-02-10 stsp }
3908 927df6b7 2019-02-10 stsp if (argc == 1) {
3909 6c7ab921 2019-03-18 stsp error = got_worktree_resolve_path(&path, worktree,
3910 cbd1af7a 2019-03-18 stsp argv[0]);
3911 927df6b7 2019-02-10 stsp if (error)
3912 927df6b7 2019-02-10 stsp goto done;
3913 927df6b7 2019-02-10 stsp } else {
3914 927df6b7 2019-02-10 stsp path = strdup("");
3915 927df6b7 2019-02-10 stsp if (path == NULL) {
3916 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
3917 927df6b7 2019-02-10 stsp goto done;
3918 927df6b7 2019-02-10 stsp }
3919 927df6b7 2019-02-10 stsp }
3920 b72f483a 2019-02-05 stsp } else if (argc == 2) {
3921 98eaaa12 2019-08-03 stsp if (diff_staged)
3922 98eaaa12 2019-08-03 stsp errx(1, "-s option can't be used when diffing "
3923 98eaaa12 2019-08-03 stsp "objects in repository");
3924 15a94983 2018-12-23 stsp id_str1 = argv[0];
3925 15a94983 2018-12-23 stsp id_str2 = argv[1];
3926 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
3927 1f03b8da 2020-03-20 stsp error = got_worktree_open(&worktree, cwd);
3928 1f03b8da 2020-03-20 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
3929 30db809c 2019-06-05 stsp goto done;
3930 1f03b8da 2020-03-20 stsp if (worktree) {
3931 1f03b8da 2020-03-20 stsp repo_path = strdup(
3932 1f03b8da 2020-03-20 stsp got_worktree_get_repo_path(worktree));
3933 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
3934 1f03b8da 2020-03-20 stsp error = got_error_from_errno("strdup");
3935 1f03b8da 2020-03-20 stsp goto done;
3936 1f03b8da 2020-03-20 stsp }
3937 1f03b8da 2020-03-20 stsp } else {
3938 1f03b8da 2020-03-20 stsp repo_path = strdup(cwd);
3939 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
3940 1f03b8da 2020-03-20 stsp error = got_error_from_errno("strdup");
3941 1f03b8da 2020-03-20 stsp goto done;
3942 1f03b8da 2020-03-20 stsp }
3943 30db809c 2019-06-05 stsp }
3944 30db809c 2019-06-05 stsp }
3945 b00d56cd 2018-04-01 stsp } else
3946 b00d56cd 2018-04-01 stsp usage_diff();
3947 b00d56cd 2018-04-01 stsp
3948 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
3949 76089277 2018-04-01 stsp free(repo_path);
3950 b00d56cd 2018-04-01 stsp if (error != NULL)
3951 b00d56cd 2018-04-01 stsp goto done;
3952 b00d56cd 2018-04-01 stsp
3953 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), 1,
3954 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
3955 c02c541e 2019-03-29 stsp if (error)
3956 c02c541e 2019-03-29 stsp goto done;
3957 c02c541e 2019-03-29 stsp
3958 30db809c 2019-06-05 stsp if (argc <= 1) {
3959 b72f483a 2019-02-05 stsp struct print_diff_arg arg;
3960 72ea6654 2019-07-27 stsp struct got_pathlist_head paths;
3961 b72f483a 2019-02-05 stsp char *id_str;
3962 72ea6654 2019-07-27 stsp
3963 72ea6654 2019-07-27 stsp TAILQ_INIT(&paths);
3964 72ea6654 2019-07-27 stsp
3965 b72f483a 2019-02-05 stsp error = got_object_id_str(&id_str,
3966 b72f483a 2019-02-05 stsp got_worktree_get_base_commit_id(worktree));
3967 b72f483a 2019-02-05 stsp if (error)
3968 b72f483a 2019-02-05 stsp goto done;
3969 b72f483a 2019-02-05 stsp arg.repo = repo;
3970 b72f483a 2019-02-05 stsp arg.worktree = worktree;
3971 b72f483a 2019-02-05 stsp arg.diff_context = diff_context;
3972 3fc0c068 2019-02-10 stsp arg.id_str = id_str;
3973 3fc0c068 2019-02-10 stsp arg.header_shown = 0;
3974 98eaaa12 2019-08-03 stsp arg.diff_staged = diff_staged;
3975 63035f9f 2019-10-06 stsp arg.ignore_whitespace = ignore_whitespace;
3976 b72f483a 2019-02-05 stsp
3977 adc19d55 2019-07-28 stsp error = got_pathlist_append(&paths, path, NULL);
3978 72ea6654 2019-07-27 stsp if (error)
3979 72ea6654 2019-07-27 stsp goto done;
3980 72ea6654 2019-07-27 stsp
3981 72ea6654 2019-07-27 stsp error = got_worktree_status(worktree, &paths, repo, print_diff,
3982 b72f483a 2019-02-05 stsp &arg, check_cancelled, NULL);
3983 b72f483a 2019-02-05 stsp free(id_str);
3984 72ea6654 2019-07-27 stsp got_pathlist_free(&paths);
3985 b72f483a 2019-02-05 stsp goto done;
3986 b72f483a 2019-02-05 stsp }
3987 b72f483a 2019-02-05 stsp
3988 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id1, &label1, id_str1,
3989 71a27632 2020-01-15 stsp GOT_OBJ_TYPE_ANY, 1, repo);
3990 0adb7196 2019-08-11 stsp if (error)
3991 0adb7196 2019-08-11 stsp goto done;
3992 b00d56cd 2018-04-01 stsp
3993 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id2, &label2, id_str2,
3994 71a27632 2020-01-15 stsp GOT_OBJ_TYPE_ANY, 1, repo);
3995 0adb7196 2019-08-11 stsp if (error)
3996 0adb7196 2019-08-11 stsp goto done;
3997 b00d56cd 2018-04-01 stsp
3998 15a94983 2018-12-23 stsp error = got_object_get_type(&type1, repo, id1);
3999 15a94983 2018-12-23 stsp if (error)
4000 15a94983 2018-12-23 stsp goto done;
4001 15a94983 2018-12-23 stsp
4002 15a94983 2018-12-23 stsp error = got_object_get_type(&type2, repo, id2);
4003 15a94983 2018-12-23 stsp if (error)
4004 15a94983 2018-12-23 stsp goto done;
4005 15a94983 2018-12-23 stsp
4006 15a94983 2018-12-23 stsp if (type1 != type2) {
4007 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4008 b00d56cd 2018-04-01 stsp goto done;
4009 b00d56cd 2018-04-01 stsp }
4010 b00d56cd 2018-04-01 stsp
4011 15a94983 2018-12-23 stsp switch (type1) {
4012 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_BLOB:
4013 15a94983 2018-12-23 stsp error = got_diff_objects_as_blobs(id1, id2, NULL, NULL,
4014 63035f9f 2019-10-06 stsp diff_context, ignore_whitespace, repo, stdout);
4015 b00d56cd 2018-04-01 stsp break;
4016 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_TREE:
4017 15a94983 2018-12-23 stsp error = got_diff_objects_as_trees(id1, id2, "", "",
4018 63035f9f 2019-10-06 stsp diff_context, ignore_whitespace, repo, stdout);
4019 b00d56cd 2018-04-01 stsp break;
4020 b00d56cd 2018-04-01 stsp case GOT_OBJ_TYPE_COMMIT:
4021 5e70831e 2019-05-28 stsp printf("diff %s %s\n", label1, label2);
4022 15a94983 2018-12-23 stsp error = got_diff_objects_as_commits(id1, id2, diff_context,
4023 63035f9f 2019-10-06 stsp ignore_whitespace, repo, stdout);
4024 b00d56cd 2018-04-01 stsp break;
4025 b00d56cd 2018-04-01 stsp default:
4026 b00d56cd 2018-04-01 stsp error = got_error(GOT_ERR_OBJ_TYPE);
4027 b00d56cd 2018-04-01 stsp }
4028 b00d56cd 2018-04-01 stsp done:
4029 5e70831e 2019-05-28 stsp free(label1);
4030 5e70831e 2019-05-28 stsp free(label2);
4031 15a94983 2018-12-23 stsp free(id1);
4032 15a94983 2018-12-23 stsp free(id2);
4033 927df6b7 2019-02-10 stsp free(path);
4034 b72f483a 2019-02-05 stsp if (worktree)
4035 b72f483a 2019-02-05 stsp got_worktree_close(worktree);
4036 ad242220 2018-09-08 stsp if (repo) {
4037 ad242220 2018-09-08 stsp const struct got_error *repo_error;
4038 ad242220 2018-09-08 stsp repo_error = got_repo_close(repo);
4039 ad242220 2018-09-08 stsp if (error == NULL)
4040 ad242220 2018-09-08 stsp error = repo_error;
4041 ad242220 2018-09-08 stsp }
4042 b00d56cd 2018-04-01 stsp return error;
4043 404c43c4 2018-06-21 stsp }
4044 404c43c4 2018-06-21 stsp
4045 404c43c4 2018-06-21 stsp __dead static void
4046 404c43c4 2018-06-21 stsp usage_blame(void)
4047 404c43c4 2018-06-21 stsp {
4048 9270e621 2019-02-05 stsp fprintf(stderr,
4049 9270e621 2019-02-05 stsp "usage: %s blame [-c commit] [-r repository-path] path\n",
4050 404c43c4 2018-06-21 stsp getprogname());
4051 404c43c4 2018-06-21 stsp exit(1);
4052 b00d56cd 2018-04-01 stsp }
4053 b00d56cd 2018-04-01 stsp
4054 28315671 2019-08-14 stsp struct blame_line {
4055 28315671 2019-08-14 stsp int annotated;
4056 28315671 2019-08-14 stsp char *id_str;
4057 82f6abb8 2019-08-14 stsp char *committer;
4058 11db6024 2019-10-21 stsp char datebuf[11]; /* YYYY-MM-DD + NUL */
4059 28315671 2019-08-14 stsp };
4060 28315671 2019-08-14 stsp
4061 28315671 2019-08-14 stsp struct blame_cb_args {
4062 28315671 2019-08-14 stsp struct blame_line *lines;
4063 28315671 2019-08-14 stsp int nlines;
4064 7ef28ff8 2019-08-14 stsp int nlines_prec;
4065 28315671 2019-08-14 stsp int lineno_cur;
4066 28315671 2019-08-14 stsp off_t *line_offsets;
4067 28315671 2019-08-14 stsp FILE *f;
4068 82f6abb8 2019-08-14 stsp struct got_repository *repo;
4069 28315671 2019-08-14 stsp };
4070 28315671 2019-08-14 stsp
4071 404c43c4 2018-06-21 stsp static const struct got_error *
4072 28315671 2019-08-14 stsp blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
4073 28315671 2019-08-14 stsp {
4074 28315671 2019-08-14 stsp const struct got_error *err = NULL;
4075 28315671 2019-08-14 stsp struct blame_cb_args *a = arg;
4076 28315671 2019-08-14 stsp struct blame_line *bline;
4077 82f6abb8 2019-08-14 stsp char *line = NULL;
4078 28315671 2019-08-14 stsp size_t linesize = 0;
4079 82f6abb8 2019-08-14 stsp struct got_commit_object *commit = NULL;
4080 28315671 2019-08-14 stsp off_t offset;
4081 bcb49d15 2019-08-14 stsp struct tm tm;
4082 bcb49d15 2019-08-14 stsp time_t committer_time;
4083 28315671 2019-08-14 stsp
4084 28315671 2019-08-14 stsp if (nlines != a->nlines ||
4085 28315671 2019-08-14 stsp (lineno != -1 && lineno < 1) || lineno > a->nlines)
4086 28315671 2019-08-14 stsp return got_error(GOT_ERR_RANGE);
4087 28315671 2019-08-14 stsp
4088 28315671 2019-08-14 stsp if (sigint_received)
4089 28315671 2019-08-14 stsp return got_error(GOT_ERR_ITER_COMPLETED);
4090 28315671 2019-08-14 stsp
4091 2839f8b9 2019-08-18 stsp if (lineno == -1)
4092 2839f8b9 2019-08-18 stsp return NULL; /* no change in this commit */
4093 2839f8b9 2019-08-18 stsp
4094 28315671 2019-08-14 stsp /* Annotate this line. */
4095 28315671 2019-08-14 stsp bline = &a->lines[lineno - 1];
4096 28315671 2019-08-14 stsp if (bline->annotated)
4097 28315671 2019-08-14 stsp return NULL;
4098 28315671 2019-08-14 stsp err = got_object_id_str(&bline->id_str, id);
4099 28315671 2019-08-14 stsp if (err)
4100 28315671 2019-08-14 stsp return err;
4101 82f6abb8 2019-08-14 stsp
4102 82f6abb8 2019-08-14 stsp err = got_object_open_as_commit(&commit, a->repo, id);
4103 82f6abb8 2019-08-14 stsp if (err)
4104 82f6abb8 2019-08-14 stsp goto done;
4105 82f6abb8 2019-08-14 stsp
4106 82f6abb8 2019-08-14 stsp bline->committer = strdup(got_object_commit_get_committer(commit));
4107 82f6abb8 2019-08-14 stsp if (bline->committer == NULL) {
4108 82f6abb8 2019-08-14 stsp err = got_error_from_errno("strdup");
4109 bcb49d15 2019-08-14 stsp goto done;
4110 bcb49d15 2019-08-14 stsp }
4111 bcb49d15 2019-08-14 stsp
4112 bcb49d15 2019-08-14 stsp committer_time = got_object_commit_get_committer_time(commit);
4113 bcb49d15 2019-08-14 stsp if (localtime_r(&committer_time, &tm) == NULL)
4114 bcb49d15 2019-08-14 stsp return got_error_from_errno("localtime_r");
4115 6db9f7f6 2019-12-10 stsp if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
4116 bcb49d15 2019-08-14 stsp &tm) >= sizeof(bline->datebuf)) {
4117 bcb49d15 2019-08-14 stsp err = got_error(GOT_ERR_NO_SPACE);
4118 82f6abb8 2019-08-14 stsp goto done;
4119 82f6abb8 2019-08-14 stsp }
4120 28315671 2019-08-14 stsp bline->annotated = 1;
4121 28315671 2019-08-14 stsp
4122 28315671 2019-08-14 stsp /* Print lines annotated so far. */
4123 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4124 28315671 2019-08-14 stsp if (!bline->annotated)
4125 82f6abb8 2019-08-14 stsp goto done;
4126 28315671 2019-08-14 stsp
4127 28315671 2019-08-14 stsp offset = a->line_offsets[a->lineno_cur - 1];
4128 82f6abb8 2019-08-14 stsp if (fseeko(a->f, offset, SEEK_SET) == -1) {
4129 82f6abb8 2019-08-14 stsp err = got_error_from_errno("fseeko");
4130 82f6abb8 2019-08-14 stsp goto done;
4131 82f6abb8 2019-08-14 stsp }
4132 28315671 2019-08-14 stsp
4133 28315671 2019-08-14 stsp while (bline->annotated) {
4134 82f6abb8 2019-08-14 stsp char *smallerthan, *at, *nl, *committer;
4135 82f6abb8 2019-08-14 stsp size_t len;
4136 82f6abb8 2019-08-14 stsp
4137 500467ff 2019-09-25 hiltjo if (getline(&line, &linesize, a->f) == -1) {
4138 28315671 2019-08-14 stsp if (ferror(a->f))
4139 28315671 2019-08-14 stsp err = got_error_from_errno("getline");
4140 28315671 2019-08-14 stsp break;
4141 28315671 2019-08-14 stsp }
4142 82f6abb8 2019-08-14 stsp
4143 82f6abb8 2019-08-14 stsp committer = bline->committer;
4144 82f6abb8 2019-08-14 stsp smallerthan = strchr(committer, '<');
4145 82f6abb8 2019-08-14 stsp if (smallerthan && smallerthan[1] != '\0')
4146 82f6abb8 2019-08-14 stsp committer = smallerthan + 1;
4147 82f6abb8 2019-08-14 stsp at = strchr(committer, '@');
4148 82f6abb8 2019-08-14 stsp if (at)
4149 82f6abb8 2019-08-14 stsp *at = '\0';
4150 82f6abb8 2019-08-14 stsp len = strlen(committer);
4151 82f6abb8 2019-08-14 stsp if (len >= 9)
4152 82f6abb8 2019-08-14 stsp committer[8] = '\0';
4153 28315671 2019-08-14 stsp
4154 28315671 2019-08-14 stsp nl = strchr(line, '\n');
4155 28315671 2019-08-14 stsp if (nl)
4156 28315671 2019-08-14 stsp *nl = '\0';
4157 bcb49d15 2019-08-14 stsp printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
4158 bcb49d15 2019-08-14 stsp bline->id_str, bline->datebuf, committer, line);
4159 28315671 2019-08-14 stsp
4160 28315671 2019-08-14 stsp a->lineno_cur++;
4161 28315671 2019-08-14 stsp bline = &a->lines[a->lineno_cur - 1];
4162 28315671 2019-08-14 stsp }
4163 82f6abb8 2019-08-14 stsp done:
4164 82f6abb8 2019-08-14 stsp if (commit)
4165 82f6abb8 2019-08-14 stsp got_object_commit_close(commit);
4166 28315671 2019-08-14 stsp free(line);
4167 28315671 2019-08-14 stsp return err;
4168 28315671 2019-08-14 stsp }
4169 28315671 2019-08-14 stsp
4170 28315671 2019-08-14 stsp static const struct got_error *
4171 404c43c4 2018-06-21 stsp cmd_blame(int argc, char *argv[])
4172 404c43c4 2018-06-21 stsp {
4173 404c43c4 2018-06-21 stsp const struct got_error *error;
4174 404c43c4 2018-06-21 stsp struct got_repository *repo = NULL;
4175 0c06baac 2019-02-05 stsp struct got_worktree *worktree = NULL;
4176 66bea077 2018-08-02 stsp char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
4177 0587e10c 2020-07-23 stsp char *link_target = NULL;
4178 28315671 2019-08-14 stsp struct got_object_id *obj_id = NULL;
4179 404c43c4 2018-06-21 stsp struct got_object_id *commit_id = NULL;
4180 28315671 2019-08-14 stsp struct got_blob_object *blob = NULL;
4181 404c43c4 2018-06-21 stsp char *commit_id_str = NULL;
4182 28315671 2019-08-14 stsp struct blame_cb_args bca;
4183 28315671 2019-08-14 stsp int ch, obj_type, i;
4184 b02560ec 2019-08-19 stsp size_t filesize;
4185 90f3c347 2019-08-19 stsp
4186 90f3c347 2019-08-19 stsp memset(&bca, 0, sizeof(bca));
4187 404c43c4 2018-06-21 stsp
4188 404c43c4 2018-06-21 stsp #ifndef PROFILE
4189 36e2fb66 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4190 36e2fb66 2019-01-04 stsp NULL) == -1)
4191 404c43c4 2018-06-21 stsp err(1, "pledge");
4192 404c43c4 2018-06-21 stsp #endif
4193 404c43c4 2018-06-21 stsp
4194 66bea077 2018-08-02 stsp while ((ch = getopt(argc, argv, "c:r:")) != -1) {
4195 404c43c4 2018-06-21 stsp switch (ch) {
4196 404c43c4 2018-06-21 stsp case 'c':
4197 404c43c4 2018-06-21 stsp commit_id_str = optarg;
4198 404c43c4 2018-06-21 stsp break;
4199 66bea077 2018-08-02 stsp case 'r':
4200 66bea077 2018-08-02 stsp repo_path = realpath(optarg, NULL);
4201 66bea077 2018-08-02 stsp if (repo_path == NULL)
4202 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4203 9ba1d308 2019-10-21 stsp optarg);
4204 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4205 66bea077 2018-08-02 stsp break;
4206 404c43c4 2018-06-21 stsp default:
4207 2deda0b9 2019-03-07 stsp usage_blame();
4208 404c43c4 2018-06-21 stsp /* NOTREACHED */
4209 404c43c4 2018-06-21 stsp }
4210 404c43c4 2018-06-21 stsp }
4211 404c43c4 2018-06-21 stsp
4212 404c43c4 2018-06-21 stsp argc -= optind;
4213 404c43c4 2018-06-21 stsp argv += optind;
4214 404c43c4 2018-06-21 stsp
4215 a39318fd 2018-08-02 stsp if (argc == 1)
4216 404c43c4 2018-06-21 stsp path = argv[0];
4217 a39318fd 2018-08-02 stsp else
4218 404c43c4 2018-06-21 stsp usage_blame();
4219 404c43c4 2018-06-21 stsp
4220 66bea077 2018-08-02 stsp cwd = getcwd(NULL, 0);
4221 66bea077 2018-08-02 stsp if (cwd == NULL) {
4222 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4223 66bea077 2018-08-02 stsp goto done;
4224 66bea077 2018-08-02 stsp }
4225 66bea077 2018-08-02 stsp if (repo_path == NULL) {
4226 0c06baac 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
4227 0c06baac 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4228 66bea077 2018-08-02 stsp goto done;
4229 0c06baac 2019-02-05 stsp else
4230 0c06baac 2019-02-05 stsp error = NULL;
4231 0c06baac 2019-02-05 stsp if (worktree) {
4232 0c06baac 2019-02-05 stsp repo_path =
4233 0c06baac 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
4234 1f03b8da 2020-03-20 stsp if (repo_path == NULL) {
4235 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4236 1f03b8da 2020-03-20 stsp if (error)
4237 1f03b8da 2020-03-20 stsp goto done;
4238 1f03b8da 2020-03-20 stsp }
4239 0c06baac 2019-02-05 stsp } else {
4240 0c06baac 2019-02-05 stsp repo_path = strdup(cwd);
4241 0c06baac 2019-02-05 stsp if (repo_path == NULL) {
4242 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4243 0c06baac 2019-02-05 stsp goto done;
4244 0c06baac 2019-02-05 stsp }
4245 66bea077 2018-08-02 stsp }
4246 66bea077 2018-08-02 stsp }
4247 36e2fb66 2019-01-04 stsp
4248 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4249 c02c541e 2019-03-29 stsp if (error != NULL)
4250 36e2fb66 2019-01-04 stsp goto done;
4251 66bea077 2018-08-02 stsp
4252 c530dc23 2019-07-23 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
4253 c02c541e 2019-03-29 stsp if (error)
4254 404c43c4 2018-06-21 stsp goto done;
4255 404c43c4 2018-06-21 stsp
4256 0c06baac 2019-02-05 stsp if (worktree) {
4257 6efaaa2d 2019-02-05 stsp const char *prefix = got_worktree_get_path_prefix(worktree);
4258 0c06baac 2019-02-05 stsp char *p, *worktree_subdir = cwd +
4259 0c06baac 2019-02-05 stsp strlen(got_worktree_get_root_path(worktree));
4260 6efaaa2d 2019-02-05 stsp if (asprintf(&p, "%s%s%s%s%s",
4261 6efaaa2d 2019-02-05 stsp prefix, (strcmp(prefix, "/") != 0) ? "/" : "",
4262 6efaaa2d 2019-02-05 stsp worktree_subdir, worktree_subdir[0] ? "/" : "",
4263 6efaaa2d 2019-02-05 stsp path) == -1) {
4264 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
4265 0c06baac 2019-02-05 stsp goto done;
4266 0c06baac 2019-02-05 stsp }
4267 6efaaa2d 2019-02-05 stsp error = got_repo_map_path(&in_repo_path, repo, p, 0);
4268 0c06baac 2019-02-05 stsp free(p);
4269 0c06baac 2019-02-05 stsp } else {
4270 0c06baac 2019-02-05 stsp error = got_repo_map_path(&in_repo_path, repo, path, 1);
4271 0c06baac 2019-02-05 stsp }
4272 0c06baac 2019-02-05 stsp if (error)
4273 66bea077 2018-08-02 stsp goto done;
4274 66bea077 2018-08-02 stsp
4275 404c43c4 2018-06-21 stsp if (commit_id_str == NULL) {
4276 404c43c4 2018-06-21 stsp struct got_reference *head_ref;
4277 a0975128 2020-02-07 stsp error = got_ref_open(&head_ref, repo, worktree ?
4278 a0975128 2020-02-07 stsp got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0);
4279 404c43c4 2018-06-21 stsp if (error != NULL)
4280 66bea077 2018-08-02 stsp goto done;
4281 404c43c4 2018-06-21 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
4282 404c43c4 2018-06-21 stsp got_ref_close(head_ref);
4283 404c43c4 2018-06-21 stsp if (error != NULL)
4284 66bea077 2018-08-02 stsp goto done;
4285 404c43c4 2018-06-21 stsp } else {
4286 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
4287 71a27632 2020-01-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, 1, repo);
4288 30837e32 2019-07-25 stsp if (error)
4289 66bea077 2018-08-02 stsp goto done;
4290 404c43c4 2018-06-21 stsp }
4291 404c43c4 2018-06-21 stsp
4292 0587e10c 2020-07-23 stsp error = got_object_resolve_symlinks(&link_target, in_repo_path,
4293 0587e10c 2020-07-23 stsp commit_id, repo);
4294 0587e10c 2020-07-23 stsp if (error)
4295 0587e10c 2020-07-23 stsp goto done;
4296 0587e10c 2020-07-23 stsp
4297 0587e10c 2020-07-23 stsp error = got_object_id_by_path(&obj_id, repo, commit_id,
4298 0587e10c 2020-07-23 stsp link_target ? link_target : in_repo_path);
4299 28315671 2019-08-14 stsp if (error)
4300 28315671 2019-08-14 stsp goto done;
4301 28315671 2019-08-14 stsp
4302 28315671 2019-08-14 stsp error = got_object_get_type(&obj_type, repo, obj_id);
4303 28315671 2019-08-14 stsp if (error)
4304 28315671 2019-08-14 stsp goto done;
4305 28315671 2019-08-14 stsp
4306 28315671 2019-08-14 stsp if (obj_type != GOT_OBJ_TYPE_BLOB) {
4307 eb59b6d4 2020-07-23 stsp error = got_error_path(link_target ? link_target : in_repo_path,
4308 eb59b6d4 2020-07-23 stsp GOT_ERR_OBJ_TYPE);
4309 28315671 2019-08-14 stsp goto done;
4310 28315671 2019-08-14 stsp }
4311 28315671 2019-08-14 stsp
4312 28315671 2019-08-14 stsp error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
4313 28315671 2019-08-14 stsp if (error)
4314 28315671 2019-08-14 stsp goto done;
4315 28315671 2019-08-14 stsp bca.f = got_opentemp();
4316 28315671 2019-08-14 stsp if (bca.f == NULL) {
4317 28315671 2019-08-14 stsp error = got_error_from_errno("got_opentemp");
4318 28315671 2019-08-14 stsp goto done;
4319 28315671 2019-08-14 stsp }
4320 b02560ec 2019-08-19 stsp error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
4321 28315671 2019-08-14 stsp &bca.line_offsets, bca.f, blob);
4322 7ef28ff8 2019-08-14 stsp if (error || bca.nlines == 0)
4323 28315671 2019-08-14 stsp goto done;
4324 28315671 2019-08-14 stsp
4325 b02560ec 2019-08-19 stsp /* Don't include \n at EOF in the blame line count. */
4326 b02560ec 2019-08-19 stsp if (bca.line_offsets[bca.nlines - 1] == filesize)
4327 b02560ec 2019-08-19 stsp bca.nlines--;
4328 b02560ec 2019-08-19 stsp
4329 28315671 2019-08-14 stsp bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
4330 28315671 2019-08-14 stsp if (bca.lines == NULL) {
4331 28315671 2019-08-14 stsp error = got_error_from_errno("calloc");
4332 28315671 2019-08-14 stsp goto done;
4333 28315671 2019-08-14 stsp }
4334 28315671 2019-08-14 stsp bca.lineno_cur = 1;
4335 7ef28ff8 2019-08-14 stsp bca.nlines_prec = 0;
4336 7ef28ff8 2019-08-14 stsp i = bca.nlines;
4337 7ef28ff8 2019-08-14 stsp while (i > 0) {
4338 7ef28ff8 2019-08-14 stsp i /= 10;
4339 7ef28ff8 2019-08-14 stsp bca.nlines_prec++;
4340 7ef28ff8 2019-08-14 stsp }
4341 82f6abb8 2019-08-14 stsp bca.repo = repo;
4342 7ef28ff8 2019-08-14 stsp
4343 0587e10c 2020-07-23 stsp error = got_blame(link_target ? link_target : in_repo_path, commit_id,
4344 0587e10c 2020-07-23 stsp repo, blame_cb, &bca, check_cancelled, NULL);
4345 404c43c4 2018-06-21 stsp done:
4346 66bea077 2018-08-02 stsp free(in_repo_path);
4347 0587e10c 2020-07-23 stsp free(link_target);
4348 66bea077 2018-08-02 stsp free(repo_path);
4349 66bea077 2018-08-02 stsp free(cwd);
4350 404c43c4 2018-06-21 stsp free(commit_id);
4351 28315671 2019-08-14 stsp free(obj_id);
4352 28315671 2019-08-14 stsp if (blob)
4353 28315671 2019-08-14 stsp got_object_blob_close(blob);
4354 0c06baac 2019-02-05 stsp if (worktree)
4355 0c06baac 2019-02-05 stsp got_worktree_close(worktree);
4356 ad242220 2018-09-08 stsp if (repo) {
4357 ad242220 2018-09-08 stsp const struct got_error *repo_error;
4358 ad242220 2018-09-08 stsp repo_error = got_repo_close(repo);
4359 ad242220 2018-09-08 stsp if (error == NULL)
4360 ad242220 2018-09-08 stsp error = repo_error;
4361 ad242220 2018-09-08 stsp }
4362 3affba96 2019-09-22 stsp if (bca.lines) {
4363 3affba96 2019-09-22 stsp for (i = 0; i < bca.nlines; i++) {
4364 3affba96 2019-09-22 stsp struct blame_line *bline = &bca.lines[i];
4365 3affba96 2019-09-22 stsp free(bline->id_str);
4366 3affba96 2019-09-22 stsp free(bline->committer);
4367 3affba96 2019-09-22 stsp }
4368 3affba96 2019-09-22 stsp free(bca.lines);
4369 28315671 2019-08-14 stsp }
4370 28315671 2019-08-14 stsp free(bca.line_offsets);
4371 28315671 2019-08-14 stsp if (bca.f && fclose(bca.f) == EOF && error == NULL)
4372 28315671 2019-08-14 stsp error = got_error_from_errno("fclose");
4373 404c43c4 2018-06-21 stsp return error;
4374 5de5890b 2018-10-18 stsp }
4375 5de5890b 2018-10-18 stsp
4376 5de5890b 2018-10-18 stsp __dead static void
4377 5de5890b 2018-10-18 stsp usage_tree(void)
4378 5de5890b 2018-10-18 stsp {
4379 c1669e2e 2019-01-09 stsp fprintf(stderr,
4380 5d58be12 2020-05-17 stsp "usage: %s tree [-c commit] [-r repository-path] [-iR] [path]\n",
4381 5de5890b 2018-10-18 stsp getprogname());
4382 5de5890b 2018-10-18 stsp exit(1);
4383 5de5890b 2018-10-18 stsp }
4384 5de5890b 2018-10-18 stsp
4385 0d6c6ee3 2020-05-20 stsp static const struct got_error *
4386 c1669e2e 2019-01-09 stsp print_entry(struct got_tree_entry *te, const char *id, const char *path,
4387 0d6c6ee3 2020-05-20 stsp const char *root_path, struct got_repository *repo)
4388 c1669e2e 2019-01-09 stsp {
4389 0d6c6ee3 2020-05-20 stsp const struct got_error *err = NULL;
4390 c1669e2e 2019-01-09 stsp int is_root_path = (strcmp(path, root_path) == 0);
4391 848d6979 2019-08-12 stsp const char *modestr = "";
4392 56e0773d 2019-11-28 stsp mode_t mode = got_tree_entry_get_mode(te);
4393 0d6c6ee3 2020-05-20 stsp char *link_target = NULL;
4394 5de5890b 2018-10-18 stsp
4395 c1669e2e 2019-01-09 stsp path += strlen(root_path);
4396 c1669e2e 2019-01-09 stsp while (path[0] == '/')
4397 c1669e2e 2019-01-09 stsp path++;
4398 c1669e2e 2019-01-09 stsp
4399 63c5ca5d 2019-08-24 stsp if (got_object_tree_entry_is_submodule(te))
4400 63c5ca5d 2019-08-24 stsp modestr = "$";
4401 0d6c6ee3 2020-05-20 stsp else if (S_ISLNK(mode)) {
4402 0d6c6ee3 2020-05-20 stsp int i;
4403 0d6c6ee3 2020-05-20 stsp
4404 0d6c6ee3 2020-05-20 stsp err = got_tree_entry_get_symlink_target(&link_target, te, repo);
4405 0d6c6ee3 2020-05-20 stsp if (err)
4406 0d6c6ee3 2020-05-20 stsp return err;
4407 0d6c6ee3 2020-05-20 stsp for (i = 0; i < strlen(link_target); i++) {
4408 0d6c6ee3 2020-05-20 stsp if (!isprint((unsigned char)link_target[i]))
4409 0d6c6ee3 2020-05-20 stsp link_target[i] = '?';
4410 0d6c6ee3 2020-05-20 stsp }
4411 0d6c6ee3 2020-05-20 stsp
4412 848d6979 2019-08-12 stsp modestr = "@";
4413 0d6c6ee3 2020-05-20 stsp }
4414 56e0773d 2019-11-28 stsp else if (S_ISDIR(mode))
4415 848d6979 2019-08-12 stsp modestr = "/";
4416 56e0773d 2019-11-28 stsp else if (mode & S_IXUSR)
4417 848d6979 2019-08-12 stsp modestr = "*";
4418 848d6979 2019-08-12 stsp
4419 0d6c6ee3 2020-05-20 stsp printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
4420 0d6c6ee3 2020-05-20 stsp is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
4421 0d6c6ee3 2020-05-20 stsp link_target ? " -> ": "", link_target ? link_target : "");
4422 0d6c6ee3 2020-05-20 stsp
4423 0d6c6ee3 2020-05-20 stsp free(link_target);
4424 0d6c6ee3 2020-05-20 stsp return NULL;
4425 c1669e2e 2019-01-09 stsp }
4426 c1669e2e 2019-01-09 stsp
4427 5de5890b 2018-10-18 stsp static const struct got_error *
4428 5de5890b 2018-10-18 stsp print_tree(const char *path, struct got_object_id *commit_id,
4429 c1669e2e 2019-01-09 stsp int show_ids, int recurse, const char *root_path,
4430 c1669e2e 2019-01-09 stsp struct got_repository *repo)
4431 5de5890b 2018-10-18 stsp {
4432 5de5890b 2018-10-18 stsp const struct got_error *err = NULL;
4433 5de5890b 2018-10-18 stsp struct got_object_id *tree_id = NULL;
4434 5de5890b 2018-10-18 stsp struct got_tree_object *tree = NULL;
4435 56e0773d 2019-11-28 stsp int nentries, i;
4436 5de5890b 2018-10-18 stsp
4437 5de5890b 2018-10-18 stsp err = got_object_id_by_path(&tree_id, repo, commit_id, path);
4438 5de5890b 2018-10-18 stsp if (err)
4439 5de5890b 2018-10-18 stsp goto done;
4440 5de5890b 2018-10-18 stsp
4441 5de5890b 2018-10-18 stsp err = got_object_open_as_tree(&tree, repo, tree_id);
4442 5de5890b 2018-10-18 stsp if (err)
4443 5de5890b 2018-10-18 stsp goto done;
4444 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
4445 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
4446 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
4447 5de5890b 2018-10-18 stsp char *id = NULL;
4448 84453469 2018-11-11 stsp
4449 84453469 2018-11-11 stsp if (sigint_received || sigpipe_received)
4450 84453469 2018-11-11 stsp break;
4451 84453469 2018-11-11 stsp
4452 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
4453 5de5890b 2018-10-18 stsp if (show_ids) {
4454 5de5890b 2018-10-18 stsp char *id_str;
4455 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str,
4456 56e0773d 2019-11-28 stsp got_tree_entry_get_id(te));
4457 5de5890b 2018-10-18 stsp if (err)
4458 5de5890b 2018-10-18 stsp goto done;
4459 5de5890b 2018-10-18 stsp if (asprintf(&id, "%s ", id_str) == -1) {
4460 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
4461 5de5890b 2018-10-18 stsp free(id_str);
4462 5de5890b 2018-10-18 stsp goto done;
4463 5de5890b 2018-10-18 stsp }
4464 5de5890b 2018-10-18 stsp free(id_str);
4465 5de5890b 2018-10-18 stsp }
4466 0d6c6ee3 2020-05-20 stsp err = print_entry(te, id, path, root_path, repo);
4467 5de5890b 2018-10-18 stsp free(id);
4468 0d6c6ee3 2020-05-20 stsp if (err)
4469 0d6c6ee3 2020-05-20 stsp goto done;
4470 c1669e2e 2019-01-09 stsp
4471 56e0773d 2019-11-28 stsp if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
4472 c1669e2e 2019-01-09 stsp char *child_path;
4473 c1669e2e 2019-01-09 stsp if (asprintf(&child_path, "%s%s%s", path,
4474 c1669e2e 2019-01-09 stsp path[0] == '/' && path[1] == '\0' ? "" : "/",
4475 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te)) == -1) {
4476 638f9024 2019-05-13 stsp err = got_error_from_errno("asprintf");
4477 c1669e2e 2019-01-09 stsp goto done;
4478 c1669e2e 2019-01-09 stsp }
4479 c1669e2e 2019-01-09 stsp err = print_tree(child_path, commit_id, show_ids, 1,
4480 c1669e2e 2019-01-09 stsp root_path, repo);
4481 c1669e2e 2019-01-09 stsp free(child_path);
4482 c1669e2e 2019-01-09 stsp if (err)
4483 c1669e2e 2019-01-09 stsp goto done;
4484 c1669e2e 2019-01-09 stsp }
4485 5de5890b 2018-10-18 stsp }
4486 5de5890b 2018-10-18 stsp done:
4487 5de5890b 2018-10-18 stsp if (tree)
4488 5de5890b 2018-10-18 stsp got_object_tree_close(tree);
4489 5de5890b 2018-10-18 stsp free(tree_id);
4490 5de5890b 2018-10-18 stsp return err;
4491 404c43c4 2018-06-21 stsp }
4492 404c43c4 2018-06-21 stsp
4493 5de5890b 2018-10-18 stsp static const struct got_error *
4494 5de5890b 2018-10-18 stsp cmd_tree(int argc, char *argv[])
4495 5de5890b 2018-10-18 stsp {
4496 5de5890b 2018-10-18 stsp const struct got_error *error;
4497 5de5890b 2018-10-18 stsp struct got_repository *repo = NULL;
4498 7a2c19d6 2019-02-05 stsp struct got_worktree *worktree = NULL;
4499 4e0a20a4 2020-03-23 tracey const char *path, *refname = NULL;
4500 7a2c19d6 2019-02-05 stsp char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
4501 5de5890b 2018-10-18 stsp struct got_object_id *commit_id = NULL;
4502 5de5890b 2018-10-18 stsp char *commit_id_str = NULL;
4503 c1669e2e 2019-01-09 stsp int show_ids = 0, recurse = 0;
4504 5de5890b 2018-10-18 stsp int ch;
4505 5de5890b 2018-10-18 stsp
4506 5de5890b 2018-10-18 stsp #ifndef PROFILE
4507 0f8d269b 2019-01-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4508 0f8d269b 2019-01-04 stsp NULL) == -1)
4509 5de5890b 2018-10-18 stsp err(1, "pledge");
4510 5de5890b 2018-10-18 stsp #endif
4511 5de5890b 2018-10-18 stsp
4512 c1669e2e 2019-01-09 stsp while ((ch = getopt(argc, argv, "c:r:iR")) != -1) {
4513 5de5890b 2018-10-18 stsp switch (ch) {
4514 5de5890b 2018-10-18 stsp case 'c':
4515 5de5890b 2018-10-18 stsp commit_id_str = optarg;
4516 5de5890b 2018-10-18 stsp break;
4517 5de5890b 2018-10-18 stsp case 'r':
4518 5de5890b 2018-10-18 stsp repo_path = realpath(optarg, NULL);
4519 5de5890b 2018-10-18 stsp if (repo_path == NULL)
4520 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4521 9ba1d308 2019-10-21 stsp optarg);
4522 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4523 5de5890b 2018-10-18 stsp break;
4524 5de5890b 2018-10-18 stsp case 'i':
4525 5de5890b 2018-10-18 stsp show_ids = 1;
4526 5de5890b 2018-10-18 stsp break;
4527 c1669e2e 2019-01-09 stsp case 'R':
4528 c1669e2e 2019-01-09 stsp recurse = 1;
4529 c1669e2e 2019-01-09 stsp break;
4530 5de5890b 2018-10-18 stsp default:
4531 2deda0b9 2019-03-07 stsp usage_tree();
4532 5de5890b 2018-10-18 stsp /* NOTREACHED */
4533 5de5890b 2018-10-18 stsp }
4534 5de5890b 2018-10-18 stsp }
4535 5de5890b 2018-10-18 stsp
4536 5de5890b 2018-10-18 stsp argc -= optind;
4537 5de5890b 2018-10-18 stsp argv += optind;
4538 5de5890b 2018-10-18 stsp
4539 5de5890b 2018-10-18 stsp if (argc == 1)
4540 5de5890b 2018-10-18 stsp path = argv[0];
4541 5de5890b 2018-10-18 stsp else if (argc > 1)
4542 5de5890b 2018-10-18 stsp usage_tree();
4543 5de5890b 2018-10-18 stsp else
4544 7a2c19d6 2019-02-05 stsp path = NULL;
4545 7a2c19d6 2019-02-05 stsp
4546 9bf7a39b 2019-02-05 stsp cwd = getcwd(NULL, 0);
4547 9bf7a39b 2019-02-05 stsp if (cwd == NULL) {
4548 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4549 9bf7a39b 2019-02-05 stsp goto done;
4550 9bf7a39b 2019-02-05 stsp }
4551 5de5890b 2018-10-18 stsp if (repo_path == NULL) {
4552 7a2c19d6 2019-02-05 stsp error = got_worktree_open(&worktree, cwd);
4553 8994de28 2019-02-05 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4554 7a2c19d6 2019-02-05 stsp goto done;
4555 7a2c19d6 2019-02-05 stsp else
4556 7a2c19d6 2019-02-05 stsp error = NULL;
4557 7a2c19d6 2019-02-05 stsp if (worktree) {
4558 7a2c19d6 2019-02-05 stsp repo_path =
4559 7a2c19d6 2019-02-05 stsp strdup(got_worktree_get_repo_path(worktree));
4560 7a2c19d6 2019-02-05 stsp if (repo_path == NULL)
4561 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4562 7a2c19d6 2019-02-05 stsp if (error)
4563 7a2c19d6 2019-02-05 stsp goto done;
4564 7a2c19d6 2019-02-05 stsp } else {
4565 7a2c19d6 2019-02-05 stsp repo_path = strdup(cwd);
4566 7a2c19d6 2019-02-05 stsp if (repo_path == NULL) {
4567 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4568 7a2c19d6 2019-02-05 stsp goto done;
4569 7a2c19d6 2019-02-05 stsp }
4570 5de5890b 2018-10-18 stsp }
4571 5de5890b 2018-10-18 stsp }
4572 5de5890b 2018-10-18 stsp
4573 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4574 5de5890b 2018-10-18 stsp if (error != NULL)
4575 c02c541e 2019-03-29 stsp goto done;
4576 c02c541e 2019-03-29 stsp
4577 c530dc23 2019-07-23 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
4578 c02c541e 2019-03-29 stsp if (error)
4579 5de5890b 2018-10-18 stsp goto done;
4580 5de5890b 2018-10-18 stsp
4581 9bf7a39b 2019-02-05 stsp if (path == NULL) {
4582 9bf7a39b 2019-02-05 stsp if (worktree) {
4583 9bf7a39b 2019-02-05 stsp char *p, *worktree_subdir = cwd +
4584 9bf7a39b 2019-02-05 stsp strlen(got_worktree_get_root_path(worktree));
4585 9bf7a39b 2019-02-05 stsp if (asprintf(&p, "%s/%s",
4586 9bf7a39b 2019-02-05 stsp got_worktree_get_path_prefix(worktree),
4587 9bf7a39b 2019-02-05 stsp worktree_subdir) == -1) {
4588 638f9024 2019-05-13 stsp error = got_error_from_errno("asprintf");
4589 9bf7a39b 2019-02-05 stsp goto done;
4590 9bf7a39b 2019-02-05 stsp }
4591 f43793a4 2020-01-27 stsp error = got_repo_map_path(&in_repo_path, repo, p, 0);
4592 9bf7a39b 2019-02-05 stsp free(p);
4593 9bf7a39b 2019-02-05 stsp if (error)
4594 9bf7a39b 2019-02-05 stsp goto done;
4595 9bf7a39b 2019-02-05 stsp } else
4596 9bf7a39b 2019-02-05 stsp path = "/";
4597 9bf7a39b 2019-02-05 stsp }
4598 9bf7a39b 2019-02-05 stsp if (in_repo_path == NULL) {
4599 9bf7a39b 2019-02-05 stsp error = got_repo_map_path(&in_repo_path, repo, path, 1);
4600 9bf7a39b 2019-02-05 stsp if (error != NULL)
4601 9bf7a39b 2019-02-05 stsp goto done;
4602 9bf7a39b 2019-02-05 stsp }
4603 5de5890b 2018-10-18 stsp
4604 5de5890b 2018-10-18 stsp if (commit_id_str == NULL) {
4605 5de5890b 2018-10-18 stsp struct got_reference *head_ref;
4606 4e0a20a4 2020-03-23 tracey if (worktree)
4607 4e0a20a4 2020-03-23 tracey refname = got_worktree_get_head_ref_name(worktree);
4608 4e0a20a4 2020-03-23 tracey else
4609 4e0a20a4 2020-03-23 tracey refname = GOT_REF_HEAD;
4610 4e0a20a4 2020-03-23 tracey error = got_ref_open(&head_ref, repo, refname, 0);
4611 5de5890b 2018-10-18 stsp if (error != NULL)
4612 5de5890b 2018-10-18 stsp goto done;
4613 5de5890b 2018-10-18 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
4614 5de5890b 2018-10-18 stsp got_ref_close(head_ref);
4615 5de5890b 2018-10-18 stsp if (error != NULL)
4616 5de5890b 2018-10-18 stsp goto done;
4617 5de5890b 2018-10-18 stsp } else {
4618 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
4619 71a27632 2020-01-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, 1, repo);
4620 30837e32 2019-07-25 stsp if (error)
4621 5de5890b 2018-10-18 stsp goto done;
4622 5de5890b 2018-10-18 stsp }
4623 5de5890b 2018-10-18 stsp
4624 c1669e2e 2019-01-09 stsp error = print_tree(in_repo_path, commit_id, show_ids, recurse,
4625 c1669e2e 2019-01-09 stsp in_repo_path, repo);
4626 5de5890b 2018-10-18 stsp done:
4627 5de5890b 2018-10-18 stsp free(in_repo_path);
4628 5de5890b 2018-10-18 stsp free(repo_path);
4629 5de5890b 2018-10-18 stsp free(cwd);
4630 5de5890b 2018-10-18 stsp free(commit_id);
4631 7a2c19d6 2019-02-05 stsp if (worktree)
4632 7a2c19d6 2019-02-05 stsp got_worktree_close(worktree);
4633 5de5890b 2018-10-18 stsp if (repo) {
4634 5de5890b 2018-10-18 stsp const struct got_error *repo_error;
4635 5de5890b 2018-10-18 stsp repo_error = got_repo_close(repo);
4636 5de5890b 2018-10-18 stsp if (error == NULL)
4637 5de5890b 2018-10-18 stsp error = repo_error;
4638 5de5890b 2018-10-18 stsp }
4639 5de5890b 2018-10-18 stsp return error;
4640 5de5890b 2018-10-18 stsp }
4641 5de5890b 2018-10-18 stsp
4642 6bad629b 2019-02-04 stsp __dead static void
4643 6bad629b 2019-02-04 stsp usage_status(void)
4644 6bad629b 2019-02-04 stsp {
4645 72ea6654 2019-07-27 stsp fprintf(stderr, "usage: %s status [path ...]\n", getprogname());
4646 6bad629b 2019-02-04 stsp exit(1);
4647 6bad629b 2019-02-04 stsp }
4648 5c860e29 2018-03-12 stsp
4649 b72f483a 2019-02-05 stsp static const struct got_error *
4650 88d0e355 2019-08-03 stsp print_status(void *arg, unsigned char status, unsigned char staged_status,
4651 88d0e355 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
4652 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4653 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
4654 6bad629b 2019-02-04 stsp {
4655 244725f2 2019-08-03 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
4656 c363b2c1 2019-08-03 stsp status = GOT_STATUS_NO_CHANGE;
4657 88d0e355 2019-08-03 stsp printf("%c%c %s\n", status, staged_status, path);
4658 b72f483a 2019-02-05 stsp return NULL;
4659 6bad629b 2019-02-04 stsp }
4660 5c860e29 2018-03-12 stsp
4661 6bad629b 2019-02-04 stsp static const struct got_error *
4662 6bad629b 2019-02-04 stsp cmd_status(int argc, char *argv[])
4663 6bad629b 2019-02-04 stsp {
4664 6bad629b 2019-02-04 stsp const struct got_error *error = NULL;
4665 6bad629b 2019-02-04 stsp struct got_repository *repo = NULL;
4666 6bad629b 2019-02-04 stsp struct got_worktree *worktree = NULL;
4667 f86a1bf5 2019-07-27 stsp char *cwd = NULL;
4668 72ea6654 2019-07-27 stsp struct got_pathlist_head paths;
4669 a5edda0a 2019-07-27 stsp struct got_pathlist_entry *pe;
4670 a5edda0a 2019-07-27 stsp int ch;
4671 5c860e29 2018-03-12 stsp
4672 72ea6654 2019-07-27 stsp TAILQ_INIT(&paths);
4673 72ea6654 2019-07-27 stsp
4674 6bad629b 2019-02-04 stsp while ((ch = getopt(argc, argv, "")) != -1) {
4675 6bad629b 2019-02-04 stsp switch (ch) {
4676 5c860e29 2018-03-12 stsp default:
4677 2deda0b9 2019-03-07 stsp usage_status();
4678 6bad629b 2019-02-04 stsp /* NOTREACHED */
4679 5c860e29 2018-03-12 stsp }
4680 5c860e29 2018-03-12 stsp }
4681 5c860e29 2018-03-12 stsp
4682 6bad629b 2019-02-04 stsp argc -= optind;
4683 6bad629b 2019-02-04 stsp argv += optind;
4684 5c860e29 2018-03-12 stsp
4685 6bad629b 2019-02-04 stsp #ifndef PROFILE
4686 6bad629b 2019-02-04 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4687 6bad629b 2019-02-04 stsp NULL) == -1)
4688 6bad629b 2019-02-04 stsp err(1, "pledge");
4689 f42b1b34 2018-03-12 stsp #endif
4690 927df6b7 2019-02-10 stsp cwd = getcwd(NULL, 0);
4691 927df6b7 2019-02-10 stsp if (cwd == NULL) {
4692 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4693 927df6b7 2019-02-10 stsp goto done;
4694 927df6b7 2019-02-10 stsp }
4695 927df6b7 2019-02-10 stsp
4696 927df6b7 2019-02-10 stsp error = got_worktree_open(&worktree, cwd);
4697 fa51e947 2020-03-27 stsp if (error) {
4698 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
4699 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "status", cwd);
4700 a5edda0a 2019-07-27 stsp goto done;
4701 fa51e947 2020-03-27 stsp }
4702 6bad629b 2019-02-04 stsp
4703 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
4704 c9956ddf 2019-09-08 stsp NULL);
4705 6bad629b 2019-02-04 stsp if (error != NULL)
4706 6bad629b 2019-02-04 stsp goto done;
4707 6bad629b 2019-02-04 stsp
4708 d0eebce4 2019-03-11 stsp error = apply_unveil(got_repo_get_path(repo), 1,
4709 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
4710 087fb88c 2019-08-04 stsp if (error)
4711 087fb88c 2019-08-04 stsp goto done;
4712 087fb88c 2019-08-04 stsp
4713 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
4714 6bad629b 2019-02-04 stsp if (error)
4715 6bad629b 2019-02-04 stsp goto done;
4716 6bad629b 2019-02-04 stsp
4717 72ea6654 2019-07-27 stsp error = got_worktree_status(worktree, &paths, repo, print_status, NULL,
4718 6bad629b 2019-02-04 stsp check_cancelled, NULL);
4719 6bad629b 2019-02-04 stsp done:
4720 a5edda0a 2019-07-27 stsp TAILQ_FOREACH(pe, &paths, entry)
4721 a5edda0a 2019-07-27 stsp free((char *)pe->path);
4722 72ea6654 2019-07-27 stsp got_pathlist_free(&paths);
4723 927df6b7 2019-02-10 stsp free(cwd);
4724 d0eebce4 2019-03-11 stsp return error;
4725 d0eebce4 2019-03-11 stsp }
4726 d0eebce4 2019-03-11 stsp
4727 d0eebce4 2019-03-11 stsp __dead static void
4728 d0eebce4 2019-03-11 stsp usage_ref(void)
4729 d0eebce4 2019-03-11 stsp {
4730 d0eebce4 2019-03-11 stsp fprintf(stderr,
4731 e31abbf2 2020-03-22 stsp "usage: %s ref [-r repository] [-l] [-c object] [-s reference] "
4732 e31abbf2 2020-03-22 stsp "[-d] [name]\n",
4733 d0eebce4 2019-03-11 stsp getprogname());
4734 d0eebce4 2019-03-11 stsp exit(1);
4735 d0eebce4 2019-03-11 stsp }
4736 d0eebce4 2019-03-11 stsp
4737 d0eebce4 2019-03-11 stsp static const struct got_error *
4738 b2070a3f 2020-03-22 stsp list_refs(struct got_repository *repo, const char *refname)
4739 d0eebce4 2019-03-11 stsp {
4740 d0eebce4 2019-03-11 stsp static const struct got_error *err = NULL;
4741 d0eebce4 2019-03-11 stsp struct got_reflist_head refs;
4742 d0eebce4 2019-03-11 stsp struct got_reflist_entry *re;
4743 d0eebce4 2019-03-11 stsp
4744 d0eebce4 2019-03-11 stsp SIMPLEQ_INIT(&refs);
4745 b2070a3f 2020-03-22 stsp err = got_ref_list(&refs, repo, refname, got_ref_cmp_by_name, NULL);
4746 d0eebce4 2019-03-11 stsp if (err)
4747 d0eebce4 2019-03-11 stsp return err;
4748 d0eebce4 2019-03-11 stsp
4749 d0eebce4 2019-03-11 stsp SIMPLEQ_FOREACH(re, &refs, entry) {
4750 d0eebce4 2019-03-11 stsp char *refstr;
4751 d0eebce4 2019-03-11 stsp refstr = got_ref_to_str(re->ref);
4752 d0eebce4 2019-03-11 stsp if (refstr == NULL)
4753 638f9024 2019-05-13 stsp return got_error_from_errno("got_ref_to_str");
4754 d0eebce4 2019-03-11 stsp printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
4755 d0eebce4 2019-03-11 stsp free(refstr);
4756 d0eebce4 2019-03-11 stsp }
4757 d0eebce4 2019-03-11 stsp
4758 e2e879a0 2019-03-11 stsp got_ref_list_free(&refs);
4759 d0eebce4 2019-03-11 stsp return NULL;
4760 d0eebce4 2019-03-11 stsp }
4761 d0eebce4 2019-03-11 stsp
4762 d0eebce4 2019-03-11 stsp static const struct got_error *
4763 d0eebce4 2019-03-11 stsp delete_ref(struct got_repository *repo, const char *refname)
4764 d0eebce4 2019-03-11 stsp {
4765 d0eebce4 2019-03-11 stsp const struct got_error *err = NULL;
4766 d0eebce4 2019-03-11 stsp struct got_reference *ref;
4767 d0eebce4 2019-03-11 stsp
4768 2f17228e 2019-05-12 stsp err = got_ref_open(&ref, repo, refname, 0);
4769 d0eebce4 2019-03-11 stsp if (err)
4770 d0eebce4 2019-03-11 stsp return err;
4771 d0eebce4 2019-03-11 stsp
4772 d0eebce4 2019-03-11 stsp err = got_ref_delete(ref, repo);
4773 d0eebce4 2019-03-11 stsp got_ref_close(ref);
4774 d0eebce4 2019-03-11 stsp return err;
4775 d0eebce4 2019-03-11 stsp }
4776 d0eebce4 2019-03-11 stsp
4777 d0eebce4 2019-03-11 stsp static const struct got_error *
4778 d83d9d5c 2019-05-13 stsp add_ref(struct got_repository *repo, const char *refname, const char *target)
4779 d0eebce4 2019-03-11 stsp {
4780 d0eebce4 2019-03-11 stsp const struct got_error *err = NULL;
4781 d0eebce4 2019-03-11 stsp struct got_object_id *id;
4782 d0eebce4 2019-03-11 stsp struct got_reference *ref = NULL;
4783 d1644381 2019-07-14 stsp
4784 d1644381 2019-07-14 stsp /*
4785 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
4786 d1644381 2019-07-14 stsp * While technically a valid reference name, this case is usually
4787 d1644381 2019-07-14 stsp * an unintended typo.
4788 d1644381 2019-07-14 stsp */
4789 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
4790 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
4791 d0eebce4 2019-03-11 stsp
4792 dd88155e 2019-06-29 stsp err = got_repo_match_object_id_prefix(&id, target, GOT_OBJ_TYPE_ANY,
4793 dd88155e 2019-06-29 stsp repo);
4794 d83d9d5c 2019-05-13 stsp if (err) {
4795 d83d9d5c 2019-05-13 stsp struct got_reference *target_ref;
4796 d0eebce4 2019-03-11 stsp
4797 d83d9d5c 2019-05-13 stsp if (err->code != GOT_ERR_BAD_OBJ_ID_STR)
4798 d83d9d5c 2019-05-13 stsp return err;
4799 d83d9d5c 2019-05-13 stsp err = got_ref_open(&target_ref, repo, target, 0);
4800 d83d9d5c 2019-05-13 stsp if (err)
4801 d83d9d5c 2019-05-13 stsp return err;
4802 d83d9d5c 2019-05-13 stsp err = got_ref_resolve(&id, repo, target_ref);
4803 d83d9d5c 2019-05-13 stsp got_ref_close(target_ref);
4804 d83d9d5c 2019-05-13 stsp if (err)
4805 d83d9d5c 2019-05-13 stsp return err;
4806 d83d9d5c 2019-05-13 stsp }
4807 d83d9d5c 2019-05-13 stsp
4808 d0eebce4 2019-03-11 stsp err = got_ref_alloc(&ref, refname, id);
4809 d0eebce4 2019-03-11 stsp if (err)
4810 d0eebce4 2019-03-11 stsp goto done;
4811 d0eebce4 2019-03-11 stsp
4812 d0eebce4 2019-03-11 stsp err = got_ref_write(ref, repo);
4813 d0eebce4 2019-03-11 stsp done:
4814 d0eebce4 2019-03-11 stsp if (ref)
4815 d0eebce4 2019-03-11 stsp got_ref_close(ref);
4816 d0eebce4 2019-03-11 stsp free(id);
4817 d1c1ae5f 2019-08-12 stsp return err;
4818 d1c1ae5f 2019-08-12 stsp }
4819 d1c1ae5f 2019-08-12 stsp
4820 d1c1ae5f 2019-08-12 stsp static const struct got_error *
4821 d1c1ae5f 2019-08-12 stsp add_symref(struct got_repository *repo, const char *refname, const char *target)
4822 d1c1ae5f 2019-08-12 stsp {
4823 d1c1ae5f 2019-08-12 stsp const struct got_error *err = NULL;
4824 d1c1ae5f 2019-08-12 stsp struct got_reference *ref = NULL;
4825 d1c1ae5f 2019-08-12 stsp struct got_reference *target_ref = NULL;
4826 d1c1ae5f 2019-08-12 stsp
4827 d1c1ae5f 2019-08-12 stsp /*
4828 bd5895f3 2019-11-28 stsp * Don't let the user create a reference name with a leading '-'.
4829 d1c1ae5f 2019-08-12 stsp * While technically a valid reference name, this case is usually
4830 d1c1ae5f 2019-08-12 stsp * an unintended typo.
4831 d1c1ae5f 2019-08-12 stsp */
4832 bd5895f3 2019-11-28 stsp if (refname[0] == '-')
4833 bd5895f3 2019-11-28 stsp return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
4834 d1c1ae5f 2019-08-12 stsp
4835 d1c1ae5f 2019-08-12 stsp err = got_ref_open(&target_ref, repo, target, 0);
4836 d1c1ae5f 2019-08-12 stsp if (err)
4837 d1c1ae5f 2019-08-12 stsp return err;
4838 d1c1ae5f 2019-08-12 stsp
4839 d1c1ae5f 2019-08-12 stsp err = got_ref_alloc_symref(&ref, refname, target_ref);
4840 d1c1ae5f 2019-08-12 stsp if (err)
4841 d1c1ae5f 2019-08-12 stsp goto done;
4842 d1c1ae5f 2019-08-12 stsp
4843 d1c1ae5f 2019-08-12 stsp err = got_ref_write(ref, repo);
4844 d1c1ae5f 2019-08-12 stsp done:
4845 d1c1ae5f 2019-08-12 stsp if (target_ref)
4846 d1c1ae5f 2019-08-12 stsp got_ref_close(target_ref);
4847 d1c1ae5f 2019-08-12 stsp if (ref)
4848 d1c1ae5f 2019-08-12 stsp got_ref_close(ref);
4849 d0eebce4 2019-03-11 stsp return err;
4850 d0eebce4 2019-03-11 stsp }
4851 d0eebce4 2019-03-11 stsp
4852 d0eebce4 2019-03-11 stsp static const struct got_error *
4853 d0eebce4 2019-03-11 stsp cmd_ref(int argc, char *argv[])
4854 d0eebce4 2019-03-11 stsp {
4855 d0eebce4 2019-03-11 stsp const struct got_error *error = NULL;
4856 d0eebce4 2019-03-11 stsp struct got_repository *repo = NULL;
4857 d0eebce4 2019-03-11 stsp struct got_worktree *worktree = NULL;
4858 d0eebce4 2019-03-11 stsp char *cwd = NULL, *repo_path = NULL;
4859 e31abbf2 2020-03-22 stsp int ch, do_list = 0, do_delete = 0;
4860 b2070a3f 2020-03-22 stsp const char *obj_arg = NULL, *symref_target= NULL;
4861 b2070a3f 2020-03-22 stsp char *refname = NULL;
4862 d0eebce4 2019-03-11 stsp
4863 e31abbf2 2020-03-22 stsp while ((ch = getopt(argc, argv, "c:dr:ls:")) != -1) {
4864 d0eebce4 2019-03-11 stsp switch (ch) {
4865 e31abbf2 2020-03-22 stsp case 'c':
4866 e31abbf2 2020-03-22 stsp obj_arg = optarg;
4867 e31abbf2 2020-03-22 stsp break;
4868 d0eebce4 2019-03-11 stsp case 'd':
4869 e31abbf2 2020-03-22 stsp do_delete = 1;
4870 d0eebce4 2019-03-11 stsp break;
4871 d0eebce4 2019-03-11 stsp case 'r':
4872 d0eebce4 2019-03-11 stsp repo_path = realpath(optarg, NULL);
4873 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
4874 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
4875 9ba1d308 2019-10-21 stsp optarg);
4876 7fbaa4f3 2019-05-11 stsp got_path_strip_trailing_slashes(repo_path);
4877 d0eebce4 2019-03-11 stsp break;
4878 d0eebce4 2019-03-11 stsp case 'l':
4879 d0eebce4 2019-03-11 stsp do_list = 1;
4880 d1c1ae5f 2019-08-12 stsp break;
4881 d1c1ae5f 2019-08-12 stsp case 's':
4882 e31abbf2 2020-03-22 stsp symref_target = optarg;
4883 d0eebce4 2019-03-11 stsp break;
4884 d0eebce4 2019-03-11 stsp default:
4885 d0eebce4 2019-03-11 stsp usage_ref();
4886 d0eebce4 2019-03-11 stsp /* NOTREACHED */
4887 d0eebce4 2019-03-11 stsp }
4888 d0eebce4 2019-03-11 stsp }
4889 d0eebce4 2019-03-11 stsp
4890 e31abbf2 2020-03-22 stsp if (obj_arg && do_list)
4891 907f15e2 2020-03-22 stsp errx(1, "-c and -l options are mutually exclusive");
4892 e31abbf2 2020-03-22 stsp if (obj_arg && do_delete)
4893 907f15e2 2020-03-22 stsp errx(1, "-c and -d options are mutually exclusive");
4894 907f15e2 2020-03-22 stsp if (obj_arg && symref_target)
4895 907f15e2 2020-03-22 stsp errx(1, "-c and -s options are mutually exclusive");
4896 e31abbf2 2020-03-22 stsp if (symref_target && do_delete)
4897 907f15e2 2020-03-22 stsp errx(1, "-s and -d options are mutually exclusive");
4898 e31abbf2 2020-03-22 stsp if (symref_target && do_list)
4899 907f15e2 2020-03-22 stsp errx(1, "-s and -l options are mutually exclusive");
4900 e31abbf2 2020-03-22 stsp if (do_delete && do_list)
4901 907f15e2 2020-03-22 stsp errx(1, "-d and -l options are mutually exclusive");
4902 d0eebce4 2019-03-11 stsp
4903 d0eebce4 2019-03-11 stsp argc -= optind;
4904 d0eebce4 2019-03-11 stsp argv += optind;
4905 d0eebce4 2019-03-11 stsp
4906 e31abbf2 2020-03-22 stsp if (do_list) {
4907 b2070a3f 2020-03-22 stsp if (argc != 0 && argc != 1)
4908 d0eebce4 2019-03-11 stsp usage_ref();
4909 b2070a3f 2020-03-22 stsp if (argc == 1) {
4910 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
4911 b2070a3f 2020-03-22 stsp if (refname == NULL) {
4912 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
4913 b2070a3f 2020-03-22 stsp goto done;
4914 b2070a3f 2020-03-22 stsp }
4915 b2070a3f 2020-03-22 stsp }
4916 e31abbf2 2020-03-22 stsp } else {
4917 e31abbf2 2020-03-22 stsp if (argc != 1)
4918 e31abbf2 2020-03-22 stsp usage_ref();
4919 b2070a3f 2020-03-22 stsp refname = strdup(argv[0]);
4920 b2070a3f 2020-03-22 stsp if (refname == NULL) {
4921 b2070a3f 2020-03-22 stsp error = got_error_from_errno("strdup");
4922 b2070a3f 2020-03-22 stsp goto done;
4923 b2070a3f 2020-03-22 stsp }
4924 e31abbf2 2020-03-22 stsp }
4925 b2070a3f 2020-03-22 stsp
4926 b2070a3f 2020-03-22 stsp if (refname)
4927 b2070a3f 2020-03-22 stsp got_path_strip_trailing_slashes(refname);
4928 d0eebce4 2019-03-11 stsp
4929 d0eebce4 2019-03-11 stsp #ifndef PROFILE
4930 e0b57350 2019-03-12 stsp if (do_list) {
4931 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
4932 e0b57350 2019-03-12 stsp NULL) == -1)
4933 e0b57350 2019-03-12 stsp err(1, "pledge");
4934 e0b57350 2019-03-12 stsp } else {
4935 e0b57350 2019-03-12 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
4936 e0b57350 2019-03-12 stsp "sendfd unveil", NULL) == -1)
4937 e0b57350 2019-03-12 stsp err(1, "pledge");
4938 e0b57350 2019-03-12 stsp }
4939 d0eebce4 2019-03-11 stsp #endif
4940 d0eebce4 2019-03-11 stsp cwd = getcwd(NULL, 0);
4941 d0eebce4 2019-03-11 stsp if (cwd == NULL) {
4942 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
4943 d0eebce4 2019-03-11 stsp goto done;
4944 d0eebce4 2019-03-11 stsp }
4945 d0eebce4 2019-03-11 stsp
4946 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
4947 d0eebce4 2019-03-11 stsp error = got_worktree_open(&worktree, cwd);
4948 d0eebce4 2019-03-11 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
4949 d0eebce4 2019-03-11 stsp goto done;
4950 d0eebce4 2019-03-11 stsp else
4951 d0eebce4 2019-03-11 stsp error = NULL;
4952 d0eebce4 2019-03-11 stsp if (worktree) {
4953 d0eebce4 2019-03-11 stsp repo_path =
4954 d0eebce4 2019-03-11 stsp strdup(got_worktree_get_repo_path(worktree));
4955 d0eebce4 2019-03-11 stsp if (repo_path == NULL)
4956 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4957 d0eebce4 2019-03-11 stsp if (error)
4958 d0eebce4 2019-03-11 stsp goto done;
4959 d0eebce4 2019-03-11 stsp } else {
4960 d0eebce4 2019-03-11 stsp repo_path = strdup(cwd);
4961 d0eebce4 2019-03-11 stsp if (repo_path == NULL) {
4962 638f9024 2019-05-13 stsp error = got_error_from_errno("strdup");
4963 d0eebce4 2019-03-11 stsp goto done;
4964 d0eebce4 2019-03-11 stsp }
4965 d0eebce4 2019-03-11 stsp }
4966 d0eebce4 2019-03-11 stsp }
4967 d0eebce4 2019-03-11 stsp
4968 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
4969 d0eebce4 2019-03-11 stsp if (error != NULL)
4970 d0eebce4 2019-03-11 stsp goto done;
4971 d0eebce4 2019-03-11 stsp
4972 c02c541e 2019-03-29 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
4973 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
4974 c02c541e 2019-03-29 stsp if (error)
4975 c02c541e 2019-03-29 stsp goto done;
4976 c02c541e 2019-03-29 stsp
4977 d0eebce4 2019-03-11 stsp if (do_list)
4978 b2070a3f 2020-03-22 stsp error = list_refs(repo, refname);
4979 e31abbf2 2020-03-22 stsp else if (do_delete)
4980 e31abbf2 2020-03-22 stsp error = delete_ref(repo, refname);
4981 e31abbf2 2020-03-22 stsp else if (symref_target)
4982 e31abbf2 2020-03-22 stsp error = add_symref(repo, refname, symref_target);
4983 e31abbf2 2020-03-22 stsp else {
4984 e31abbf2 2020-03-22 stsp if (obj_arg == NULL)
4985 e31abbf2 2020-03-22 stsp usage_ref();
4986 e31abbf2 2020-03-22 stsp error = add_ref(repo, refname, obj_arg);
4987 e31abbf2 2020-03-22 stsp }
4988 4e759de4 2019-06-26 stsp done:
4989 b2070a3f 2020-03-22 stsp free(refname);
4990 4e759de4 2019-06-26 stsp if (repo)
4991 4e759de4 2019-06-26 stsp got_repo_close(repo);
4992 4e759de4 2019-06-26 stsp if (worktree)
4993 4e759de4 2019-06-26 stsp got_worktree_close(worktree);
4994 4e759de4 2019-06-26 stsp free(cwd);
4995 4e759de4 2019-06-26 stsp free(repo_path);
4996 4e759de4 2019-06-26 stsp return error;
4997 4e759de4 2019-06-26 stsp }
4998 4e759de4 2019-06-26 stsp
4999 4e759de4 2019-06-26 stsp __dead static void
5000 4e759de4 2019-06-26 stsp usage_branch(void)
5001 4e759de4 2019-06-26 stsp {
5002 4e759de4 2019-06-26 stsp fprintf(stderr,
5003 da76fce2 2020-02-24 stsp "usage: %s branch [-c commit] [-d] [-r repository] [-l] [-n] "
5004 da76fce2 2020-02-24 stsp "[name]\n", getprogname());
5005 4e759de4 2019-06-26 stsp exit(1);
5006 4e759de4 2019-06-26 stsp }
5007 4e759de4 2019-06-26 stsp
5008 4e759de4 2019-06-26 stsp static const struct got_error *
5009 4e99b47e 2019-10-04 stsp list_branch(struct got_repository *repo, struct got_worktree *worktree,
5010 4e99b47e 2019-10-04 stsp struct got_reference *ref)
5011 4e99b47e 2019-10-04 stsp {
5012 4e99b47e 2019-10-04 stsp const struct got_error *err = NULL;
5013 4e99b47e 2019-10-04 stsp const char *refname, *marker = " ";
5014 4e99b47e 2019-10-04 stsp char *refstr;
5015 4e99b47e 2019-10-04 stsp
5016 4e99b47e 2019-10-04 stsp refname = got_ref_get_name(ref);
5017 4e99b47e 2019-10-04 stsp if (worktree && strcmp(refname,
5018 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree)) == 0) {
5019 4e99b47e 2019-10-04 stsp struct got_object_id *id = NULL;
5020 4e99b47e 2019-10-04 stsp
5021 4e99b47e 2019-10-04 stsp err = got_ref_resolve(&id, repo, ref);
5022 4e99b47e 2019-10-04 stsp if (err)
5023 4e99b47e 2019-10-04 stsp return err;
5024 4e99b47e 2019-10-04 stsp if (got_object_id_cmp(id,
5025 4e99b47e 2019-10-04 stsp got_worktree_get_base_commit_id(worktree)) == 0)
5026 4e99b47e 2019-10-04 stsp marker = "* ";
5027 4e99b47e 2019-10-04 stsp else
5028 4e99b47e 2019-10-04 stsp marker = "~ ";
5029 4e99b47e 2019-10-04 stsp free(id);
5030 4e99b47e 2019-10-04 stsp }
5031 4e99b47e 2019-10-04 stsp
5032 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5033 4e99b47e 2019-10-04 stsp refname += 11;
5034 4e99b47e 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5035 4e99b47e 2019-10-04 stsp refname += 18;
5036 4e99b47e 2019-10-04 stsp
5037 4e99b47e 2019-10-04 stsp refstr = got_ref_to_str(ref);
5038 4e99b47e 2019-10-04 stsp if (refstr == NULL)
5039 4e99b47e 2019-10-04 stsp return got_error_from_errno("got_ref_to_str");
5040 4e99b47e 2019-10-04 stsp
5041 4e99b47e 2019-10-04 stsp printf("%s%s: %s\n", marker, refname, refstr);
5042 4e99b47e 2019-10-04 stsp free(refstr);
5043 4e99b47e 2019-10-04 stsp return NULL;
5044 4e99b47e 2019-10-04 stsp }
5045 4e99b47e 2019-10-04 stsp
5046 4e99b47e 2019-10-04 stsp static const struct got_error *
5047 ad89fa31 2019-10-04 stsp show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
5048 ad89fa31 2019-10-04 stsp {
5049 ad89fa31 2019-10-04 stsp const char *refname;
5050 ad89fa31 2019-10-04 stsp
5051 ad89fa31 2019-10-04 stsp if (worktree == NULL)
5052 ad89fa31 2019-10-04 stsp return got_error(GOT_ERR_NOT_WORKTREE);
5053 ad89fa31 2019-10-04 stsp
5054 ad89fa31 2019-10-04 stsp refname = got_worktree_get_head_ref_name(worktree);
5055 ad89fa31 2019-10-04 stsp
5056 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/heads/", 11) == 0)
5057 ad89fa31 2019-10-04 stsp refname += 11;
5058 ad89fa31 2019-10-04 stsp if (strncmp(refname, "refs/got/worktree/", 18) == 0)
5059 ad89fa31 2019-10-04 stsp refname += 18;
5060 ad89fa31 2019-10-04 stsp
5061 ad89fa31 2019-10-04 stsp printf("%s\n", refname);
5062 ad89fa31 2019-10-04 stsp
5063 ad89fa31 2019-10-04 stsp return NULL;
5064 ad89fa31 2019-10-04 stsp }
5065 ad89fa31 2019-10-04 stsp
5066 ad89fa31 2019-10-04 stsp static const struct got_error *
5067 ba882ee3 2019-07-11 stsp list_branches(struct got_repository *repo, struct got_worktree *worktree)
5068 4e759de4 2019-06-26 stsp {
5069 4e759de4 2019-06-26 stsp static const struct got_error *err = NULL;
5070 4e759de4 2019-06-26 stsp struct got_reflist_head refs;
5071 4e759de4 2019-06-26 stsp struct got_reflist_entry *re;
5072 4e99b47e 2019-10-04 stsp struct got_reference *temp_ref = NULL;
5073 4e99b47e 2019-10-04 stsp int rebase_in_progress, histedit_in_progress;
5074 4e759de4 2019-06-26 stsp
5075 4e759de4 2019-06-26 stsp SIMPLEQ_INIT(&refs);
5076 ba882ee3 2019-07-11 stsp
5077 4e99b47e 2019-10-04 stsp if (worktree) {
5078 4e99b47e 2019-10-04 stsp err = got_worktree_rebase_in_progress(&rebase_in_progress,
5079 4e99b47e 2019-10-04 stsp worktree);
5080 4e99b47e 2019-10-04 stsp if (err)
5081 4e99b47e 2019-10-04 stsp return err;
5082 4e99b47e 2019-10-04 stsp
5083 4e99b47e 2019-10-04 stsp err = got_worktree_histedit_in_progress(&histedit_in_progress,
5084 4e99b47e 2019-10-04 stsp worktree);
5085 4e99b47e 2019-10-04 stsp if (err)
5086 4e99b47e 2019-10-04 stsp return err;
5087 4e99b47e 2019-10-04 stsp
5088 4e99b47e 2019-10-04 stsp if (rebase_in_progress || histedit_in_progress) {
5089 4e99b47e 2019-10-04 stsp err = got_ref_open(&temp_ref, repo,
5090 4e99b47e 2019-10-04 stsp got_worktree_get_head_ref_name(worktree), 0);
5091 4e99b47e 2019-10-04 stsp if (err)
5092 4e99b47e 2019-10-04 stsp return err;
5093 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, temp_ref);
5094 4e99b47e 2019-10-04 stsp got_ref_close(temp_ref);
5095 4e99b47e 2019-10-04 stsp }
5096 4e99b47e 2019-10-04 stsp }
5097 4e99b47e 2019-10-04 stsp
5098 b8bad2ba 2019-08-23 stsp err = got_ref_list(&refs, repo, "refs/heads",
5099 b8bad2ba 2019-08-23 stsp got_ref_cmp_by_name, NULL);
5100 4e759de4 2019-06-26 stsp if (err)
5101 4e759de4 2019-06-26 stsp return err;
5102 4e759de4 2019-06-26 stsp
5103 4e99b47e 2019-10-04 stsp SIMPLEQ_FOREACH(re, &refs, entry)
5104 4e99b47e 2019-10-04 stsp list_branch(repo, worktree, re->ref);
5105 4e759de4 2019-06-26 stsp
5106 4e759de4 2019-06-26 stsp got_ref_list_free(&refs);
5107 4e759de4 2019-06-26 stsp return NULL;
5108 4e759de4 2019-06-26 stsp }
5109 4e759de4 2019-06-26 stsp
5110 4e759de4 2019-06-26 stsp static const struct got_error *
5111 45cd4e47 2019-08-25 stsp delete_branch(struct got_repository *repo, struct got_worktree *worktree,
5112 45cd4e47 2019-08-25 stsp const char *branch_name)
5113 4e759de4 2019-06-26 stsp {
5114 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
5115 45cd4e47 2019-08-25 stsp struct got_reference *ref = NULL;
5116 4e759de4 2019-06-26 stsp char *refname;
5117 4e759de4 2019-06-26 stsp
5118 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
5119 4e759de4 2019-06-26 stsp return got_error_from_errno("asprintf");
5120 4e759de4 2019-06-26 stsp
5121 4e759de4 2019-06-26 stsp err = got_ref_open(&ref, repo, refname, 0);
5122 4e759de4 2019-06-26 stsp if (err)
5123 4e759de4 2019-06-26 stsp goto done;
5124 4e759de4 2019-06-26 stsp
5125 45cd4e47 2019-08-25 stsp if (worktree &&
5126 45cd4e47 2019-08-25 stsp strcmp(got_worktree_get_head_ref_name(worktree),
5127 45cd4e47 2019-08-25 stsp got_ref_get_name(ref)) == 0) {
5128 45cd4e47 2019-08-25 stsp err = got_error_msg(GOT_ERR_SAME_BRANCH,
5129 45cd4e47 2019-08-25 stsp "will not delete this work tree's current branch");
5130 45cd4e47 2019-08-25 stsp goto done;
5131 45cd4e47 2019-08-25 stsp }
5132 45cd4e47 2019-08-25 stsp
5133 45cd4e47 2019-08-25 stsp err = got_ref_delete(ref, repo);
5134 4e759de4 2019-06-26 stsp done:
5135 45cd4e47 2019-08-25 stsp if (ref)
5136 45cd4e47 2019-08-25 stsp got_ref_close(ref);
5137 4e759de4 2019-06-26 stsp free(refname);
5138 4e759de4 2019-06-26 stsp return err;
5139 4e759de4 2019-06-26 stsp }
5140 4e759de4 2019-06-26 stsp
5141 4e759de4 2019-06-26 stsp static const struct got_error *
5142 4e759de4 2019-06-26 stsp add_branch(struct got_repository *repo, const char *branch_name,
5143 a74f7e83 2019-11-10 stsp struct got_object_id *base_commit_id)
5144 4e759de4 2019-06-26 stsp {
5145 4e759de4 2019-06-26 stsp const struct got_error *err = NULL;
5146 4e759de4 2019-06-26 stsp struct got_reference *ref = NULL;
5147 4e759de4 2019-06-26 stsp char *base_refname = NULL, *refname = NULL;
5148 d3f84d51 2019-07-11 stsp
5149 d3f84d51 2019-07-11 stsp /*
5150 bd5895f3 2019-11-28 stsp * Don't let the user create a branch name with a leading '-'.
5151 d3f84d51 2019-07-11 stsp * While technically a valid reference name, this case is usually
5152 d3f84d51 2019-07-11 stsp * an unintended typo.
5153 d3f84d51 2019-07-11 stsp */
5154 bd5895f3 2019-11-28 stsp if (branch_name[0] == '-')
5155 bd5895f3 2019-11-28 stsp return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
5156 4e759de4 2019-06-26 stsp
5157 4e759de4 2019-06-26 stsp if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
5158 4e759de4 2019-06-26 stsp err = got_error_from_errno("asprintf");
5159 4e759de4 2019-06-26 stsp goto done;
5160 4e759de4 2019-06-26 stsp }
5161 4e759de4 2019-06-26 stsp
5162 4e759de4 2019-06-26 stsp err = got_ref_open(&ref, repo, refname, 0);
5163 4e759de4 2019-06-26 stsp if (err == NULL) {
5164 4e759de4 2019-06-26 stsp err = got_error(GOT_ERR_BRANCH_EXISTS);
5165 4e759de4 2019-06-26 stsp goto done;
5166 4e759de4 2019-06-26 stsp } else if (err->code != GOT_ERR_NOT_REF)
5167 4e759de4 2019-06-26 stsp goto done;
5168 4e759de4 2019-06-26 stsp
5169 a74f7e83 2019-11-10 stsp err = got_ref_alloc(&ref, refname, base_commit_id);
5170 4e759de4 2019-06-26 stsp if (err)
5171 4e759de4 2019-06-26 stsp goto done;
5172 4e759de4 2019-06-26 stsp
5173 4e759de4 2019-06-26 stsp err = got_ref_write(ref, repo);
5174 d0eebce4 2019-03-11 stsp done:
5175 4e759de4 2019-06-26 stsp if (ref)
5176 4e759de4 2019-06-26 stsp got_ref_close(ref);
5177 4e759de4 2019-06-26 stsp free(base_refname);
5178 4e759de4 2019-06-26 stsp free(refname);
5179 4e759de4 2019-06-26 stsp return err;
5180 4e759de4 2019-06-26 stsp }
5181 4e759de4 2019-06-26 stsp
5182 4e759de4 2019-06-26 stsp static const struct got_error *
5183 4e759de4 2019-06-26 stsp cmd_branch(int argc, char *argv[])
5184 4e759de4 2019-06-26 stsp {
5185 4e759de4 2019-06-26 stsp const struct got_error *error = NULL;
5186 4e759de4 2019-06-26 stsp struct got_repository *repo = NULL;
5187 4e759de4 2019-06-26 stsp struct got_worktree *worktree = NULL;
5188 4e759de4 2019-06-26 stsp char *cwd = NULL, *repo_path = NULL;
5189 da76fce2 2020-02-24 stsp int ch, do_list = 0, do_show = 0, do_update = 1;
5190 a74f7e83 2019-11-10 stsp const char *delref = NULL, *commit_id_arg = NULL;
5191 da76fce2 2020-02-24 stsp struct got_reference *ref = NULL;
5192 da76fce2 2020-02-24 stsp struct got_pathlist_head paths;
5193 da76fce2 2020-02-24 stsp struct got_pathlist_entry *pe;
5194 da76fce2 2020-02-24 stsp struct got_object_id *commit_id = NULL;
5195 da76fce2 2020-02-24 stsp char *commit_id_str = NULL;
5196 4e759de4 2019-06-26 stsp
5197 da76fce2 2020-02-24 stsp TAILQ_INIT(&paths);
5198 da76fce2 2020-02-24 stsp
5199 da76fce2 2020-02-24 stsp while ((ch = getopt(argc, argv, "c:d:r:ln")) != -1) {
5200 4e759de4 2019-06-26 stsp switch (ch) {
5201 a74f7e83 2019-11-10 stsp case 'c':
5202 a74f7e83 2019-11-10 stsp commit_id_arg = optarg;
5203 a74f7e83 2019-11-10 stsp break;
5204 4e759de4 2019-06-26 stsp case 'd':
5205 4e759de4 2019-06-26 stsp delref = optarg;
5206 4e759de4 2019-06-26 stsp break;
5207 4e759de4 2019-06-26 stsp case 'r':
5208 4e759de4 2019-06-26 stsp repo_path = realpath(optarg, NULL);
5209 4e759de4 2019-06-26 stsp if (repo_path == NULL)
5210 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5211 9ba1d308 2019-10-21 stsp optarg);
5212 4e759de4 2019-06-26 stsp got_path_strip_trailing_slashes(repo_path);
5213 4e759de4 2019-06-26 stsp break;
5214 4e759de4 2019-06-26 stsp case 'l':
5215 4e759de4 2019-06-26 stsp do_list = 1;
5216 da76fce2 2020-02-24 stsp break;
5217 da76fce2 2020-02-24 stsp case 'n':
5218 da76fce2 2020-02-24 stsp do_update = 0;
5219 4e759de4 2019-06-26 stsp break;
5220 4e759de4 2019-06-26 stsp default:
5221 4e759de4 2019-06-26 stsp usage_branch();
5222 4e759de4 2019-06-26 stsp /* NOTREACHED */
5223 4e759de4 2019-06-26 stsp }
5224 4e759de4 2019-06-26 stsp }
5225 4e759de4 2019-06-26 stsp
5226 4e759de4 2019-06-26 stsp if (do_list && delref)
5227 907f15e2 2020-03-22 stsp errx(1, "-l and -d options are mutually exclusive");
5228 4e759de4 2019-06-26 stsp
5229 4e759de4 2019-06-26 stsp argc -= optind;
5230 4e759de4 2019-06-26 stsp argv += optind;
5231 ad89fa31 2019-10-04 stsp
5232 ad89fa31 2019-10-04 stsp if (!do_list && !delref && argc == 0)
5233 ad89fa31 2019-10-04 stsp do_show = 1;
5234 4e759de4 2019-06-26 stsp
5235 a74f7e83 2019-11-10 stsp if ((do_list || delref || do_show) && commit_id_arg != NULL)
5236 a74f7e83 2019-11-10 stsp errx(1, "-c option can only be used when creating a branch");
5237 a74f7e83 2019-11-10 stsp
5238 4e759de4 2019-06-26 stsp if (do_list || delref) {
5239 4e759de4 2019-06-26 stsp if (argc > 0)
5240 4e759de4 2019-06-26 stsp usage_branch();
5241 a74f7e83 2019-11-10 stsp } else if (!do_show && argc != 1)
5242 4e759de4 2019-06-26 stsp usage_branch();
5243 4e759de4 2019-06-26 stsp
5244 4e759de4 2019-06-26 stsp #ifndef PROFILE
5245 ad89fa31 2019-10-04 stsp if (do_list || do_show) {
5246 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5247 4e759de4 2019-06-26 stsp NULL) == -1)
5248 4e759de4 2019-06-26 stsp err(1, "pledge");
5249 4e759de4 2019-06-26 stsp } else {
5250 4e759de4 2019-06-26 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5251 4e759de4 2019-06-26 stsp "sendfd unveil", NULL) == -1)
5252 4e759de4 2019-06-26 stsp err(1, "pledge");
5253 4e759de4 2019-06-26 stsp }
5254 4e759de4 2019-06-26 stsp #endif
5255 4e759de4 2019-06-26 stsp cwd = getcwd(NULL, 0);
5256 4e759de4 2019-06-26 stsp if (cwd == NULL) {
5257 4e759de4 2019-06-26 stsp error = got_error_from_errno("getcwd");
5258 4e759de4 2019-06-26 stsp goto done;
5259 4e759de4 2019-06-26 stsp }
5260 4e759de4 2019-06-26 stsp
5261 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
5262 4e759de4 2019-06-26 stsp error = got_worktree_open(&worktree, cwd);
5263 4e759de4 2019-06-26 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5264 4e759de4 2019-06-26 stsp goto done;
5265 4e759de4 2019-06-26 stsp else
5266 4e759de4 2019-06-26 stsp error = NULL;
5267 4e759de4 2019-06-26 stsp if (worktree) {
5268 4e759de4 2019-06-26 stsp repo_path =
5269 4e759de4 2019-06-26 stsp strdup(got_worktree_get_repo_path(worktree));
5270 4e759de4 2019-06-26 stsp if (repo_path == NULL)
5271 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
5272 4e759de4 2019-06-26 stsp if (error)
5273 4e759de4 2019-06-26 stsp goto done;
5274 4e759de4 2019-06-26 stsp } else {
5275 4e759de4 2019-06-26 stsp repo_path = strdup(cwd);
5276 4e759de4 2019-06-26 stsp if (repo_path == NULL) {
5277 4e759de4 2019-06-26 stsp error = got_error_from_errno("strdup");
5278 4e759de4 2019-06-26 stsp goto done;
5279 4e759de4 2019-06-26 stsp }
5280 4e759de4 2019-06-26 stsp }
5281 4e759de4 2019-06-26 stsp }
5282 4e759de4 2019-06-26 stsp
5283 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5284 4e759de4 2019-06-26 stsp if (error != NULL)
5285 4e759de4 2019-06-26 stsp goto done;
5286 4e759de4 2019-06-26 stsp
5287 4e759de4 2019-06-26 stsp error = apply_unveil(got_repo_get_path(repo), do_list,
5288 c530dc23 2019-07-23 stsp worktree ? got_worktree_get_root_path(worktree) : NULL);
5289 4e759de4 2019-06-26 stsp if (error)
5290 4e759de4 2019-06-26 stsp goto done;
5291 4e759de4 2019-06-26 stsp
5292 ad89fa31 2019-10-04 stsp if (do_show)
5293 ad89fa31 2019-10-04 stsp error = show_current_branch(repo, worktree);
5294 ad89fa31 2019-10-04 stsp else if (do_list)
5295 ba882ee3 2019-07-11 stsp error = list_branches(repo, worktree);
5296 4e759de4 2019-06-26 stsp else if (delref)
5297 45cd4e47 2019-08-25 stsp error = delete_branch(repo, worktree, delref);
5298 4e759de4 2019-06-26 stsp else {
5299 a74f7e83 2019-11-10 stsp if (commit_id_arg == NULL)
5300 a74f7e83 2019-11-10 stsp commit_id_arg = worktree ?
5301 4e759de4 2019-06-26 stsp got_worktree_get_head_ref_name(worktree) :
5302 4e759de4 2019-06-26 stsp GOT_REF_HEAD;
5303 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
5304 71a27632 2020-01-15 stsp commit_id_arg, GOT_OBJ_TYPE_COMMIT, 1, repo);
5305 a74f7e83 2019-11-10 stsp if (error)
5306 a74f7e83 2019-11-10 stsp goto done;
5307 a74f7e83 2019-11-10 stsp error = add_branch(repo, argv[0], commit_id);
5308 da76fce2 2020-02-24 stsp if (error)
5309 da76fce2 2020-02-24 stsp goto done;
5310 da76fce2 2020-02-24 stsp if (worktree && do_update) {
5311 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
5312 da76fce2 2020-02-24 stsp char *branch_refname = NULL;
5313 da76fce2 2020-02-24 stsp
5314 da76fce2 2020-02-24 stsp error = got_object_id_str(&commit_id_str, commit_id);
5315 da76fce2 2020-02-24 stsp if (error)
5316 da76fce2 2020-02-24 stsp goto done;
5317 da76fce2 2020-02-24 stsp error = get_worktree_paths_from_argv(&paths, 0, NULL,
5318 da76fce2 2020-02-24 stsp worktree);
5319 da76fce2 2020-02-24 stsp if (error)
5320 da76fce2 2020-02-24 stsp goto done;
5321 da76fce2 2020-02-24 stsp if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
5322 da76fce2 2020-02-24 stsp == -1) {
5323 da76fce2 2020-02-24 stsp error = got_error_from_errno("asprintf");
5324 da76fce2 2020-02-24 stsp goto done;
5325 da76fce2 2020-02-24 stsp }
5326 da76fce2 2020-02-24 stsp error = got_ref_open(&ref, repo, branch_refname, 0);
5327 da76fce2 2020-02-24 stsp free(branch_refname);
5328 da76fce2 2020-02-24 stsp if (error)
5329 da76fce2 2020-02-24 stsp goto done;
5330 da76fce2 2020-02-24 stsp error = switch_head_ref(ref, commit_id, worktree,
5331 da76fce2 2020-02-24 stsp repo);
5332 da76fce2 2020-02-24 stsp if (error)
5333 da76fce2 2020-02-24 stsp goto done;
5334 da76fce2 2020-02-24 stsp error = got_worktree_set_base_commit_id(worktree, repo,
5335 da76fce2 2020-02-24 stsp commit_id);
5336 da76fce2 2020-02-24 stsp if (error)
5337 da76fce2 2020-02-24 stsp goto done;
5338 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
5339 da76fce2 2020-02-24 stsp error = got_worktree_checkout_files(worktree, &paths,
5340 9627c110 2020-04-18 stsp repo, update_progress, &upa, check_cancelled,
5341 9627c110 2020-04-18 stsp NULL);
5342 da76fce2 2020-02-24 stsp if (error)
5343 da76fce2 2020-02-24 stsp goto done;
5344 9627c110 2020-04-18 stsp if (upa.did_something)
5345 da76fce2 2020-02-24 stsp printf("Updated to commit %s\n", commit_id_str);
5346 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
5347 da76fce2 2020-02-24 stsp }
5348 4e759de4 2019-06-26 stsp }
5349 4e759de4 2019-06-26 stsp done:
5350 da76fce2 2020-02-24 stsp if (ref)
5351 da76fce2 2020-02-24 stsp got_ref_close(ref);
5352 d0eebce4 2019-03-11 stsp if (repo)
5353 d0eebce4 2019-03-11 stsp got_repo_close(repo);
5354 d0eebce4 2019-03-11 stsp if (worktree)
5355 d0eebce4 2019-03-11 stsp got_worktree_close(worktree);
5356 d0eebce4 2019-03-11 stsp free(cwd);
5357 d0eebce4 2019-03-11 stsp free(repo_path);
5358 da76fce2 2020-02-24 stsp free(commit_id);
5359 da76fce2 2020-02-24 stsp free(commit_id_str);
5360 da76fce2 2020-02-24 stsp TAILQ_FOREACH(pe, &paths, entry)
5361 da76fce2 2020-02-24 stsp free((char *)pe->path);
5362 da76fce2 2020-02-24 stsp got_pathlist_free(&paths);
5363 d00136be 2019-03-26 stsp return error;
5364 d00136be 2019-03-26 stsp }
5365 d00136be 2019-03-26 stsp
5366 8e7bd50a 2019-08-22 stsp
5367 d00136be 2019-03-26 stsp __dead static void
5368 8e7bd50a 2019-08-22 stsp usage_tag(void)
5369 8e7bd50a 2019-08-22 stsp {
5370 8e7bd50a 2019-08-22 stsp fprintf(stderr,
5371 80106605 2020-02-24 stsp "usage: %s tag [-c commit] [-r repository] [-l] "
5372 80106605 2020-02-24 stsp "[-m message] name\n", getprogname());
5373 8e7bd50a 2019-08-22 stsp exit(1);
5374 b8bad2ba 2019-08-23 stsp }
5375 b8bad2ba 2019-08-23 stsp
5376 b8bad2ba 2019-08-23 stsp #if 0
5377 b8bad2ba 2019-08-23 stsp static const struct got_error *
5378 b8bad2ba 2019-08-23 stsp sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
5379 b8bad2ba 2019-08-23 stsp {
5380 b8bad2ba 2019-08-23 stsp const struct got_error *err = NULL;
5381 b8bad2ba 2019-08-23 stsp struct got_reflist_entry *re, *se, *new;
5382 b8bad2ba 2019-08-23 stsp struct got_object_id *re_id, *se_id;
5383 b8bad2ba 2019-08-23 stsp struct got_tag_object *re_tag, *se_tag;
5384 b8bad2ba 2019-08-23 stsp time_t re_time, se_time;
5385 b8bad2ba 2019-08-23 stsp
5386 b8bad2ba 2019-08-23 stsp SIMPLEQ_FOREACH(re, tags, entry) {
5387 b8bad2ba 2019-08-23 stsp se = SIMPLEQ_FIRST(sorted);
5388 b8bad2ba 2019-08-23 stsp if (se == NULL) {
5389 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
5390 b8bad2ba 2019-08-23 stsp if (err)
5391 b8bad2ba 2019-08-23 stsp return err;
5392 b8bad2ba 2019-08-23 stsp SIMPLEQ_INSERT_HEAD(sorted, new, entry);
5393 b8bad2ba 2019-08-23 stsp continue;
5394 b8bad2ba 2019-08-23 stsp } else {
5395 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&re_id, repo, re->ref);
5396 b8bad2ba 2019-08-23 stsp if (err)
5397 b8bad2ba 2019-08-23 stsp break;
5398 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&re_tag, repo, re_id);
5399 b8bad2ba 2019-08-23 stsp free(re_id);
5400 b8bad2ba 2019-08-23 stsp if (err)
5401 b8bad2ba 2019-08-23 stsp break;
5402 b8bad2ba 2019-08-23 stsp re_time = got_object_tag_get_tagger_time(re_tag);
5403 b8bad2ba 2019-08-23 stsp got_object_tag_close(re_tag);
5404 b8bad2ba 2019-08-23 stsp }
5405 b8bad2ba 2019-08-23 stsp
5406 b8bad2ba 2019-08-23 stsp while (se) {
5407 b8bad2ba 2019-08-23 stsp err = got_ref_resolve(&se_id, repo, re->ref);
5408 b8bad2ba 2019-08-23 stsp if (err)
5409 b8bad2ba 2019-08-23 stsp break;
5410 b8bad2ba 2019-08-23 stsp err = got_object_open_as_tag(&se_tag, repo, se_id);
5411 b8bad2ba 2019-08-23 stsp free(se_id);
5412 b8bad2ba 2019-08-23 stsp if (err)
5413 b8bad2ba 2019-08-23 stsp break;
5414 b8bad2ba 2019-08-23 stsp se_time = got_object_tag_get_tagger_time(se_tag);
5415 b8bad2ba 2019-08-23 stsp got_object_tag_close(se_tag);
5416 b8bad2ba 2019-08-23 stsp
5417 b8bad2ba 2019-08-23 stsp if (se_time > re_time) {
5418 b8bad2ba 2019-08-23 stsp err = got_reflist_entry_dup(&new, re);
5419 b8bad2ba 2019-08-23 stsp if (err)
5420 b8bad2ba 2019-08-23 stsp return err;
5421 b8bad2ba 2019-08-23 stsp SIMPLEQ_INSERT_AFTER(sorted, se, new, entry);
5422 b8bad2ba 2019-08-23 stsp break;
5423 b8bad2ba 2019-08-23 stsp }
5424 b8bad2ba 2019-08-23 stsp se = SIMPLEQ_NEXT(se, entry);
5425 b8bad2ba 2019-08-23 stsp continue;
5426 b8bad2ba 2019-08-23 stsp }
5427 b8bad2ba 2019-08-23 stsp }
5428 b8bad2ba 2019-08-23 stsp done:
5429 b8bad2ba 2019-08-23 stsp return err;
5430 8e7bd50a 2019-08-22 stsp }
5431 b8bad2ba 2019-08-23 stsp #endif
5432 b8bad2ba 2019-08-23 stsp
5433 b8bad2ba 2019-08-23 stsp static const struct got_error *
5434 8e7bd50a 2019-08-22 stsp list_tags(struct got_repository *repo, struct got_worktree *worktree)
5435 8e7bd50a 2019-08-22 stsp {
5436 8e7bd50a 2019-08-22 stsp static const struct got_error *err = NULL;
5437 8e7bd50a 2019-08-22 stsp struct got_reflist_head refs;
5438 8e7bd50a 2019-08-22 stsp struct got_reflist_entry *re;
5439 8e7bd50a 2019-08-22 stsp
5440 8e7bd50a 2019-08-22 stsp SIMPLEQ_INIT(&refs);
5441 8e7bd50a 2019-08-22 stsp
5442 d1f16636 2020-01-15 stsp err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
5443 8e7bd50a 2019-08-22 stsp if (err)
5444 8e7bd50a 2019-08-22 stsp return err;
5445 8e7bd50a 2019-08-22 stsp
5446 8e7bd50a 2019-08-22 stsp SIMPLEQ_FOREACH(re, &refs, entry) {
5447 8e7bd50a 2019-08-22 stsp const char *refname;
5448 8e7bd50a 2019-08-22 stsp char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
5449 8e7bd50a 2019-08-22 stsp char datebuf[26];
5450 d4efa91b 2020-01-14 stsp const char *tagger;
5451 8e7bd50a 2019-08-22 stsp time_t tagger_time;
5452 8e7bd50a 2019-08-22 stsp struct got_object_id *id;
5453 8e7bd50a 2019-08-22 stsp struct got_tag_object *tag;
5454 d4efa91b 2020-01-14 stsp struct got_commit_object *commit = NULL;
5455 8e7bd50a 2019-08-22 stsp
5456 8e7bd50a 2019-08-22 stsp refname = got_ref_get_name(re->ref);
5457 8e7bd50a 2019-08-22 stsp if (strncmp(refname, "refs/tags/", 10) != 0)
5458 8e7bd50a 2019-08-22 stsp continue;
5459 8e7bd50a 2019-08-22 stsp refname += 10;
5460 8e7bd50a 2019-08-22 stsp refstr = got_ref_to_str(re->ref);
5461 8e7bd50a 2019-08-22 stsp if (refstr == NULL) {
5462 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("got_ref_to_str");
5463 8e7bd50a 2019-08-22 stsp break;
5464 8e7bd50a 2019-08-22 stsp }
5465 8e7bd50a 2019-08-22 stsp printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr);
5466 8e7bd50a 2019-08-22 stsp free(refstr);
5467 8e7bd50a 2019-08-22 stsp
5468 8e7bd50a 2019-08-22 stsp err = got_ref_resolve(&id, repo, re->ref);
5469 8e7bd50a 2019-08-22 stsp if (err)
5470 8e7bd50a 2019-08-22 stsp break;
5471 8e7bd50a 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
5472 d4efa91b 2020-01-14 stsp if (err) {
5473 d4efa91b 2020-01-14 stsp if (err->code != GOT_ERR_OBJ_TYPE) {
5474 d4efa91b 2020-01-14 stsp free(id);
5475 d4efa91b 2020-01-14 stsp break;
5476 d4efa91b 2020-01-14 stsp }
5477 d4efa91b 2020-01-14 stsp /* "lightweight" tag */
5478 d4efa91b 2020-01-14 stsp err = got_object_open_as_commit(&commit, repo, id);
5479 d4efa91b 2020-01-14 stsp if (err) {
5480 d4efa91b 2020-01-14 stsp free(id);
5481 d4efa91b 2020-01-14 stsp break;
5482 d4efa91b 2020-01-14 stsp }
5483 d4efa91b 2020-01-14 stsp tagger = got_object_commit_get_committer(commit);
5484 d4efa91b 2020-01-14 stsp tagger_time =
5485 d4efa91b 2020-01-14 stsp got_object_commit_get_committer_time(commit);
5486 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str, id);
5487 d4efa91b 2020-01-14 stsp free(id);
5488 d4efa91b 2020-01-14 stsp if (err)
5489 d4efa91b 2020-01-14 stsp break;
5490 d4efa91b 2020-01-14 stsp } else {
5491 d4efa91b 2020-01-14 stsp free(id);
5492 d4efa91b 2020-01-14 stsp tagger = got_object_tag_get_tagger(tag);
5493 d4efa91b 2020-01-14 stsp tagger_time = got_object_tag_get_tagger_time(tag);
5494 d4efa91b 2020-01-14 stsp err = got_object_id_str(&id_str,
5495 d4efa91b 2020-01-14 stsp got_object_tag_get_object_id(tag));
5496 d4efa91b 2020-01-14 stsp if (err)
5497 d4efa91b 2020-01-14 stsp break;
5498 d4efa91b 2020-01-14 stsp }
5499 d4efa91b 2020-01-14 stsp printf("from: %s\n", tagger);
5500 2417344c 2019-08-23 stsp datestr = get_datestr(&tagger_time, datebuf);
5501 2417344c 2019-08-23 stsp if (datestr)
5502 2417344c 2019-08-23 stsp printf("date: %s UTC\n", datestr);
5503 d4efa91b 2020-01-14 stsp if (commit)
5504 2417344c 2019-08-23 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str);
5505 d4efa91b 2020-01-14 stsp else {
5506 d4efa91b 2020-01-14 stsp switch (got_object_tag_get_object_type(tag)) {
5507 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_BLOB:
5508 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB,
5509 d4efa91b 2020-01-14 stsp id_str);
5510 d4efa91b 2020-01-14 stsp break;
5511 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TREE:
5512 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TREE,
5513 d4efa91b 2020-01-14 stsp id_str);
5514 d4efa91b 2020-01-14 stsp break;
5515 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_COMMIT:
5516 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT,
5517 d4efa91b 2020-01-14 stsp id_str);
5518 d4efa91b 2020-01-14 stsp break;
5519 d4efa91b 2020-01-14 stsp case GOT_OBJ_TYPE_TAG:
5520 d4efa91b 2020-01-14 stsp printf("object: %s %s\n", GOT_OBJ_LABEL_TAG,
5521 d4efa91b 2020-01-14 stsp id_str);
5522 d4efa91b 2020-01-14 stsp break;
5523 d4efa91b 2020-01-14 stsp default:
5524 d4efa91b 2020-01-14 stsp break;
5525 d4efa91b 2020-01-14 stsp }
5526 8e7bd50a 2019-08-22 stsp }
5527 8e7bd50a 2019-08-22 stsp free(id_str);
5528 d4efa91b 2020-01-14 stsp if (commit) {
5529 d4efa91b 2020-01-14 stsp err = got_object_commit_get_logmsg(&tagmsg0, commit);
5530 d4efa91b 2020-01-14 stsp if (err)
5531 d4efa91b 2020-01-14 stsp break;
5532 d4efa91b 2020-01-14 stsp got_object_commit_close(commit);
5533 d4efa91b 2020-01-14 stsp } else {
5534 d4efa91b 2020-01-14 stsp tagmsg0 = strdup(got_object_tag_get_message(tag));
5535 d4efa91b 2020-01-14 stsp got_object_tag_close(tag);
5536 d4efa91b 2020-01-14 stsp if (tagmsg0 == NULL) {
5537 d4efa91b 2020-01-14 stsp err = got_error_from_errno("strdup");
5538 d4efa91b 2020-01-14 stsp break;
5539 d4efa91b 2020-01-14 stsp }
5540 8e7bd50a 2019-08-22 stsp }
5541 8e7bd50a 2019-08-22 stsp
5542 8e7bd50a 2019-08-22 stsp tagmsg = tagmsg0;
5543 8e7bd50a 2019-08-22 stsp do {
5544 8e7bd50a 2019-08-22 stsp line = strsep(&tagmsg, "\n");
5545 8e7bd50a 2019-08-22 stsp if (line)
5546 8e7bd50a 2019-08-22 stsp printf(" %s\n", line);
5547 8e7bd50a 2019-08-22 stsp } while (line);
5548 8e7bd50a 2019-08-22 stsp free(tagmsg0);
5549 8e7bd50a 2019-08-22 stsp }
5550 8e7bd50a 2019-08-22 stsp
5551 8e7bd50a 2019-08-22 stsp got_ref_list_free(&refs);
5552 8e7bd50a 2019-08-22 stsp return NULL;
5553 8e7bd50a 2019-08-22 stsp }
5554 8e7bd50a 2019-08-22 stsp
5555 8e7bd50a 2019-08-22 stsp static const struct got_error *
5556 f372d5cd 2019-10-21 stsp get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
5557 62870f63 2019-08-22 stsp const char *tag_name, const char *repo_path)
5558 8e7bd50a 2019-08-22 stsp {
5559 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
5560 8e7bd50a 2019-08-22 stsp char *template = NULL, *initial_content = NULL;
5561 f372d5cd 2019-10-21 stsp char *editor = NULL;
5562 8e7bd50a 2019-08-22 stsp int fd = -1;
5563 8e7bd50a 2019-08-22 stsp
5564 bb63914a 2020-02-17 stsp if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) {
5565 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
5566 8e7bd50a 2019-08-22 stsp goto done;
5567 8e7bd50a 2019-08-22 stsp }
5568 8e7bd50a 2019-08-22 stsp
5569 62870f63 2019-08-22 stsp if (asprintf(&initial_content, "\n# tagging commit %s as %s\n",
5570 62870f63 2019-08-22 stsp commit_id_str, tag_name) == -1) {
5571 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
5572 8e7bd50a 2019-08-22 stsp goto done;
5573 8e7bd50a 2019-08-22 stsp }
5574 8e7bd50a 2019-08-22 stsp
5575 f372d5cd 2019-10-21 stsp err = got_opentemp_named_fd(tagmsg_path, &fd, template);
5576 8e7bd50a 2019-08-22 stsp if (err)
5577 8e7bd50a 2019-08-22 stsp goto done;
5578 8e7bd50a 2019-08-22 stsp
5579 8e7bd50a 2019-08-22 stsp dprintf(fd, initial_content);
5580 8e7bd50a 2019-08-22 stsp close(fd);
5581 8e7bd50a 2019-08-22 stsp
5582 8e7bd50a 2019-08-22 stsp err = get_editor(&editor);
5583 8e7bd50a 2019-08-22 stsp if (err)
5584 8e7bd50a 2019-08-22 stsp goto done;
5585 f372d5cd 2019-10-21 stsp err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content);
5586 8e7bd50a 2019-08-22 stsp done:
5587 8e7bd50a 2019-08-22 stsp free(initial_content);
5588 8e7bd50a 2019-08-22 stsp free(template);
5589 8e7bd50a 2019-08-22 stsp free(editor);
5590 8e7bd50a 2019-08-22 stsp
5591 8e7bd50a 2019-08-22 stsp /* Editor is done; we can now apply unveil(2) */
5592 8e7bd50a 2019-08-22 stsp if (err == NULL) {
5593 8e7bd50a 2019-08-22 stsp err = apply_unveil(repo_path, 0, NULL);
5594 8e7bd50a 2019-08-22 stsp if (err) {
5595 8e7bd50a 2019-08-22 stsp free(*tagmsg);
5596 8e7bd50a 2019-08-22 stsp *tagmsg = NULL;
5597 8e7bd50a 2019-08-22 stsp }
5598 8e7bd50a 2019-08-22 stsp }
5599 8e7bd50a 2019-08-22 stsp return err;
5600 8e7bd50a 2019-08-22 stsp }
5601 8e7bd50a 2019-08-22 stsp
5602 8e7bd50a 2019-08-22 stsp static const struct got_error *
5603 8e7bd50a 2019-08-22 stsp add_tag(struct got_repository *repo, const char *tag_name,
5604 8e7bd50a 2019-08-22 stsp const char *commit_arg, const char *tagmsg_arg)
5605 8e7bd50a 2019-08-22 stsp {
5606 8e7bd50a 2019-08-22 stsp const struct got_error *err = NULL;
5607 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id = NULL, *tag_id = NULL;
5608 8e7bd50a 2019-08-22 stsp char *label = NULL, *commit_id_str = NULL;
5609 8e7bd50a 2019-08-22 stsp struct got_reference *ref = NULL;
5610 aba9c984 2019-09-08 stsp char *refname = NULL, *tagmsg = NULL, *tagger = NULL;
5611 f372d5cd 2019-10-21 stsp char *tagmsg_path = NULL, *tag_id_str = NULL;
5612 f372d5cd 2019-10-21 stsp int preserve_tagmsg = 0;
5613 8e7bd50a 2019-08-22 stsp
5614 8e7bd50a 2019-08-22 stsp /*
5615 bd5895f3 2019-11-28 stsp * Don't let the user create a tag name with a leading '-'.
5616 8e7bd50a 2019-08-22 stsp * While technically a valid reference name, this case is usually
5617 8e7bd50a 2019-08-22 stsp * an unintended typo.
5618 8e7bd50a 2019-08-22 stsp */
5619 bd5895f3 2019-11-28 stsp if (tag_name[0] == '-')
5620 bd5895f3 2019-11-28 stsp return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS);
5621 8e7bd50a 2019-08-22 stsp
5622 aba9c984 2019-09-08 stsp err = get_author(&tagger, repo);
5623 8e7bd50a 2019-08-22 stsp if (err)
5624 8e7bd50a 2019-08-22 stsp return err;
5625 8e7bd50a 2019-08-22 stsp
5626 71a27632 2020-01-15 stsp err = got_repo_match_object_id(&commit_id, &label, commit_arg,
5627 8e7bd50a 2019-08-22 stsp GOT_OBJ_TYPE_COMMIT, 1, repo);
5628 8e7bd50a 2019-08-22 stsp if (err)
5629 8e7bd50a 2019-08-22 stsp goto done;
5630 8e7bd50a 2019-08-22 stsp
5631 8e7bd50a 2019-08-22 stsp err = got_object_id_str(&commit_id_str, commit_id);
5632 8e7bd50a 2019-08-22 stsp if (err)
5633 8e7bd50a 2019-08-22 stsp goto done;
5634 8e7bd50a 2019-08-22 stsp
5635 8e7bd50a 2019-08-22 stsp if (strncmp("refs/tags/", tag_name, 10) == 0) {
5636 8e7bd50a 2019-08-22 stsp refname = strdup(tag_name);
5637 8e7bd50a 2019-08-22 stsp if (refname == NULL) {
5638 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("strdup");
5639 8e7bd50a 2019-08-22 stsp goto done;
5640 8e7bd50a 2019-08-22 stsp }
5641 8e7bd50a 2019-08-22 stsp tag_name += 10;
5642 8e7bd50a 2019-08-22 stsp } else if (asprintf(&refname, "refs/tags/%s", tag_name) == -1) {
5643 8e7bd50a 2019-08-22 stsp err = got_error_from_errno("asprintf");
5644 8e7bd50a 2019-08-22 stsp goto done;
5645 8e7bd50a 2019-08-22 stsp }
5646 8e7bd50a 2019-08-22 stsp
5647 8e7bd50a 2019-08-22 stsp err = got_ref_open(&ref, repo, refname, 0);
5648 8e7bd50a 2019-08-22 stsp if (err == NULL) {
5649 8e7bd50a 2019-08-22 stsp err = got_error(GOT_ERR_TAG_EXISTS);
5650 8e7bd50a 2019-08-22 stsp goto done;
5651 8e7bd50a 2019-08-22 stsp } else if (err->code != GOT_ERR_NOT_REF)
5652 8e7bd50a 2019-08-22 stsp goto done;
5653 8e7bd50a 2019-08-22 stsp
5654 8e7bd50a 2019-08-22 stsp if (tagmsg_arg == NULL) {
5655 f372d5cd 2019-10-21 stsp err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
5656 62870f63 2019-08-22 stsp tag_name, got_repo_get_path(repo));
5657 f372d5cd 2019-10-21 stsp if (err) {
5658 f372d5cd 2019-10-21 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY &&
5659 f372d5cd 2019-10-21 stsp tagmsg_path != NULL)
5660 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
5661 8e7bd50a 2019-08-22 stsp goto done;
5662 f372d5cd 2019-10-21 stsp }
5663 8e7bd50a 2019-08-22 stsp }
5664 8e7bd50a 2019-08-22 stsp
5665 8e7bd50a 2019-08-22 stsp err = got_object_tag_create(&tag_id, tag_name, commit_id,
5666 8e7bd50a 2019-08-22 stsp tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, repo);
5667 f372d5cd 2019-10-21 stsp if (err) {
5668 f372d5cd 2019-10-21 stsp if (tagmsg_path)
5669 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
5670 8e7bd50a 2019-08-22 stsp goto done;
5671 f372d5cd 2019-10-21 stsp }
5672 8e7bd50a 2019-08-22 stsp
5673 8e7bd50a 2019-08-22 stsp err = got_ref_alloc(&ref, refname, tag_id);
5674 f372d5cd 2019-10-21 stsp if (err) {
5675 f372d5cd 2019-10-21 stsp if (tagmsg_path)
5676 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
5677 8e7bd50a 2019-08-22 stsp goto done;
5678 f372d5cd 2019-10-21 stsp }
5679 8e7bd50a 2019-08-22 stsp
5680 8e7bd50a 2019-08-22 stsp err = got_ref_write(ref, repo);
5681 f372d5cd 2019-10-21 stsp if (err) {
5682 f372d5cd 2019-10-21 stsp if (tagmsg_path)
5683 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
5684 f372d5cd 2019-10-21 stsp goto done;
5685 f372d5cd 2019-10-21 stsp }
5686 8e7bd50a 2019-08-22 stsp
5687 f372d5cd 2019-10-21 stsp err = got_object_id_str(&tag_id_str, tag_id);
5688 f372d5cd 2019-10-21 stsp if (err) {
5689 f372d5cd 2019-10-21 stsp if (tagmsg_path)
5690 f372d5cd 2019-10-21 stsp preserve_tagmsg = 1;
5691 f372d5cd 2019-10-21 stsp goto done;
5692 8e7bd50a 2019-08-22 stsp }
5693 f372d5cd 2019-10-21 stsp printf("Created tag %s\n", tag_id_str);
5694 8e7bd50a 2019-08-22 stsp done:
5695 f372d5cd 2019-10-21 stsp if (preserve_tagmsg) {
5696 f372d5cd 2019-10-21 stsp fprintf(stderr, "%s: tag message preserved in %s\n",
5697 f372d5cd 2019-10-21 stsp getprogname(), tagmsg_path);
5698 f372d5cd 2019-10-21 stsp } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL)
5699 f372d5cd 2019-10-21 stsp err = got_error_from_errno2("unlink", tagmsg_path);
5700 f372d5cd 2019-10-21 stsp free(tag_id_str);
5701 8e7bd50a 2019-08-22 stsp if (ref)
5702 8e7bd50a 2019-08-22 stsp got_ref_close(ref);
5703 8e7bd50a 2019-08-22 stsp free(commit_id);
5704 8e7bd50a 2019-08-22 stsp free(commit_id_str);
5705 8e7bd50a 2019-08-22 stsp free(refname);
5706 8e7bd50a 2019-08-22 stsp free(tagmsg);
5707 f372d5cd 2019-10-21 stsp free(tagmsg_path);
5708 aba9c984 2019-09-08 stsp free(tagger);
5709 8e7bd50a 2019-08-22 stsp return err;
5710 8e7bd50a 2019-08-22 stsp }
5711 8e7bd50a 2019-08-22 stsp
5712 8e7bd50a 2019-08-22 stsp static const struct got_error *
5713 8e7bd50a 2019-08-22 stsp cmd_tag(int argc, char *argv[])
5714 8e7bd50a 2019-08-22 stsp {
5715 8e7bd50a 2019-08-22 stsp const struct got_error *error = NULL;
5716 8e7bd50a 2019-08-22 stsp struct got_repository *repo = NULL;
5717 8e7bd50a 2019-08-22 stsp struct got_worktree *worktree = NULL;
5718 8e7bd50a 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
5719 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL;
5720 8e7bd50a 2019-08-22 stsp const char *tag_name, *commit_id_arg = NULL, *tagmsg = NULL;
5721 8e7bd50a 2019-08-22 stsp int ch, do_list = 0;
5722 8e7bd50a 2019-08-22 stsp
5723 80106605 2020-02-24 stsp while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) {
5724 8e7bd50a 2019-08-22 stsp switch (ch) {
5725 80106605 2020-02-24 stsp case 'c':
5726 80106605 2020-02-24 stsp commit_id_arg = optarg;
5727 80106605 2020-02-24 stsp break;
5728 8e7bd50a 2019-08-22 stsp case 'm':
5729 8e7bd50a 2019-08-22 stsp tagmsg = optarg;
5730 8e7bd50a 2019-08-22 stsp break;
5731 8e7bd50a 2019-08-22 stsp case 'r':
5732 8e7bd50a 2019-08-22 stsp repo_path = realpath(optarg, NULL);
5733 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
5734 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
5735 9ba1d308 2019-10-21 stsp optarg);
5736 8e7bd50a 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
5737 8e7bd50a 2019-08-22 stsp break;
5738 8e7bd50a 2019-08-22 stsp case 'l':
5739 8e7bd50a 2019-08-22 stsp do_list = 1;
5740 8e7bd50a 2019-08-22 stsp break;
5741 8e7bd50a 2019-08-22 stsp default:
5742 8e7bd50a 2019-08-22 stsp usage_tag();
5743 8e7bd50a 2019-08-22 stsp /* NOTREACHED */
5744 8e7bd50a 2019-08-22 stsp }
5745 8e7bd50a 2019-08-22 stsp }
5746 8e7bd50a 2019-08-22 stsp
5747 8e7bd50a 2019-08-22 stsp argc -= optind;
5748 8e7bd50a 2019-08-22 stsp argv += optind;
5749 8e7bd50a 2019-08-22 stsp
5750 8e7bd50a 2019-08-22 stsp if (do_list) {
5751 80106605 2020-02-24 stsp if (commit_id_arg != NULL)
5752 775ce909 2020-03-22 stsp errx(1,
5753 775ce909 2020-03-22 stsp "-c option can only be used when creating a tag");
5754 8e7bd50a 2019-08-22 stsp if (tagmsg)
5755 80106605 2020-02-24 stsp errx(1, "-l and -m options are mutually exclusive");
5756 8e7bd50a 2019-08-22 stsp if (argc > 0)
5757 8e7bd50a 2019-08-22 stsp usage_tag();
5758 80106605 2020-02-24 stsp } else if (argc != 1)
5759 8e7bd50a 2019-08-22 stsp usage_tag();
5760 80106605 2020-02-24 stsp
5761 a2887370 2019-08-23 stsp tag_name = argv[0];
5762 8e7bd50a 2019-08-22 stsp
5763 8e7bd50a 2019-08-22 stsp #ifndef PROFILE
5764 8e7bd50a 2019-08-22 stsp if (do_list) {
5765 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
5766 8e7bd50a 2019-08-22 stsp NULL) == -1)
5767 8e7bd50a 2019-08-22 stsp err(1, "pledge");
5768 8e7bd50a 2019-08-22 stsp } else {
5769 8e7bd50a 2019-08-22 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec "
5770 8e7bd50a 2019-08-22 stsp "sendfd unveil", NULL) == -1)
5771 8e7bd50a 2019-08-22 stsp err(1, "pledge");
5772 8e7bd50a 2019-08-22 stsp }
5773 8e7bd50a 2019-08-22 stsp #endif
5774 8e7bd50a 2019-08-22 stsp cwd = getcwd(NULL, 0);
5775 8e7bd50a 2019-08-22 stsp if (cwd == NULL) {
5776 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("getcwd");
5777 8e7bd50a 2019-08-22 stsp goto done;
5778 8e7bd50a 2019-08-22 stsp }
5779 8e7bd50a 2019-08-22 stsp
5780 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
5781 8e7bd50a 2019-08-22 stsp error = got_worktree_open(&worktree, cwd);
5782 8e7bd50a 2019-08-22 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
5783 8e7bd50a 2019-08-22 stsp goto done;
5784 8e7bd50a 2019-08-22 stsp else
5785 8e7bd50a 2019-08-22 stsp error = NULL;
5786 8e7bd50a 2019-08-22 stsp if (worktree) {
5787 8e7bd50a 2019-08-22 stsp repo_path =
5788 8e7bd50a 2019-08-22 stsp strdup(got_worktree_get_repo_path(worktree));
5789 8e7bd50a 2019-08-22 stsp if (repo_path == NULL)
5790 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
5791 8e7bd50a 2019-08-22 stsp if (error)
5792 8e7bd50a 2019-08-22 stsp goto done;
5793 8e7bd50a 2019-08-22 stsp } else {
5794 8e7bd50a 2019-08-22 stsp repo_path = strdup(cwd);
5795 8e7bd50a 2019-08-22 stsp if (repo_path == NULL) {
5796 8e7bd50a 2019-08-22 stsp error = got_error_from_errno("strdup");
5797 8e7bd50a 2019-08-22 stsp goto done;
5798 8e7bd50a 2019-08-22 stsp }
5799 8e7bd50a 2019-08-22 stsp }
5800 8e7bd50a 2019-08-22 stsp }
5801 8e7bd50a 2019-08-22 stsp
5802 8e7bd50a 2019-08-22 stsp if (do_list) {
5803 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
5804 c9956ddf 2019-09-08 stsp if (error != NULL)
5805 c9956ddf 2019-09-08 stsp goto done;
5806 8e7bd50a 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5807 8e7bd50a 2019-08-22 stsp if (error)
5808 8e7bd50a 2019-08-22 stsp goto done;
5809 8e7bd50a 2019-08-22 stsp error = list_tags(repo, worktree);
5810 8e7bd50a 2019-08-22 stsp } else {
5811 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
5812 c9956ddf 2019-09-08 stsp if (error)
5813 c9956ddf 2019-09-08 stsp goto done;
5814 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, gitconfig_path);
5815 c9956ddf 2019-09-08 stsp if (error != NULL)
5816 c9956ddf 2019-09-08 stsp goto done;
5817 c9956ddf 2019-09-08 stsp
5818 8e7bd50a 2019-08-22 stsp if (tagmsg) {
5819 8e7bd50a 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5820 8e7bd50a 2019-08-22 stsp if (error)
5821 8e7bd50a 2019-08-22 stsp goto done;
5822 8e7bd50a 2019-08-22 stsp }
5823 8e7bd50a 2019-08-22 stsp
5824 8e7bd50a 2019-08-22 stsp if (commit_id_arg == NULL) {
5825 8e7bd50a 2019-08-22 stsp struct got_reference *head_ref;
5826 8e7bd50a 2019-08-22 stsp struct got_object_id *commit_id;
5827 8e7bd50a 2019-08-22 stsp error = got_ref_open(&head_ref, repo,
5828 8e7bd50a 2019-08-22 stsp worktree ? got_worktree_get_head_ref_name(worktree)
5829 8e7bd50a 2019-08-22 stsp : GOT_REF_HEAD, 0);
5830 8e7bd50a 2019-08-22 stsp if (error)
5831 8e7bd50a 2019-08-22 stsp goto done;
5832 8e7bd50a 2019-08-22 stsp error = got_ref_resolve(&commit_id, repo, head_ref);
5833 8e7bd50a 2019-08-22 stsp got_ref_close(head_ref);
5834 8e7bd50a 2019-08-22 stsp if (error)
5835 8e7bd50a 2019-08-22 stsp goto done;
5836 8e7bd50a 2019-08-22 stsp error = got_object_id_str(&commit_id_str, commit_id);
5837 8e7bd50a 2019-08-22 stsp free(commit_id);
5838 8e7bd50a 2019-08-22 stsp if (error)
5839 8e7bd50a 2019-08-22 stsp goto done;
5840 8e7bd50a 2019-08-22 stsp }
5841 8e7bd50a 2019-08-22 stsp
5842 8e7bd50a 2019-08-22 stsp error = add_tag(repo, tag_name,
5843 8e7bd50a 2019-08-22 stsp commit_id_str ? commit_id_str : commit_id_arg, tagmsg);
5844 8e7bd50a 2019-08-22 stsp }
5845 8e7bd50a 2019-08-22 stsp done:
5846 8e7bd50a 2019-08-22 stsp if (repo)
5847 8e7bd50a 2019-08-22 stsp got_repo_close(repo);
5848 8e7bd50a 2019-08-22 stsp if (worktree)
5849 8e7bd50a 2019-08-22 stsp got_worktree_close(worktree);
5850 8e7bd50a 2019-08-22 stsp free(cwd);
5851 8e7bd50a 2019-08-22 stsp free(repo_path);
5852 c9956ddf 2019-09-08 stsp free(gitconfig_path);
5853 8e7bd50a 2019-08-22 stsp free(commit_id_str);
5854 8e7bd50a 2019-08-22 stsp return error;
5855 8e7bd50a 2019-08-22 stsp }
5856 8e7bd50a 2019-08-22 stsp
5857 8e7bd50a 2019-08-22 stsp __dead static void
5858 d00136be 2019-03-26 stsp usage_add(void)
5859 d00136be 2019-03-26 stsp {
5860 c29c428a 2019-12-16 stsp fprintf(stderr, "usage: %s add [-R] [-I] path ...\n",
5861 022fae89 2019-12-06 tracey getprogname());
5862 d00136be 2019-03-26 stsp exit(1);
5863 d00136be 2019-03-26 stsp }
5864 d00136be 2019-03-26 stsp
5865 d00136be 2019-03-26 stsp static const struct got_error *
5866 4e68cba3 2019-11-23 stsp add_progress(void *arg, unsigned char status, const char *path)
5867 4e68cba3 2019-11-23 stsp {
5868 4e68cba3 2019-11-23 stsp while (path[0] == '/')
5869 4e68cba3 2019-11-23 stsp path++;
5870 4e68cba3 2019-11-23 stsp printf("%c %s\n", status, path);
5871 4e68cba3 2019-11-23 stsp return NULL;
5872 4e68cba3 2019-11-23 stsp }
5873 4e68cba3 2019-11-23 stsp
5874 4e68cba3 2019-11-23 stsp static const struct got_error *
5875 d00136be 2019-03-26 stsp cmd_add(int argc, char *argv[])
5876 d00136be 2019-03-26 stsp {
5877 d00136be 2019-03-26 stsp const struct got_error *error = NULL;
5878 031a5338 2019-03-26 stsp struct got_repository *repo = NULL;
5879 d00136be 2019-03-26 stsp struct got_worktree *worktree = NULL;
5880 1dd54920 2019-05-11 stsp char *cwd = NULL;
5881 1dd54920 2019-05-11 stsp struct got_pathlist_head paths;
5882 1dd54920 2019-05-11 stsp struct got_pathlist_entry *pe;
5883 022fae89 2019-12-06 tracey int ch, can_recurse = 0, no_ignores = 0;
5884 1dd54920 2019-05-11 stsp
5885 1dd54920 2019-05-11 stsp TAILQ_INIT(&paths);
5886 d00136be 2019-03-26 stsp
5887 022fae89 2019-12-06 tracey while ((ch = getopt(argc, argv, "IR")) != -1) {
5888 d00136be 2019-03-26 stsp switch (ch) {
5889 022fae89 2019-12-06 tracey case 'I':
5890 022fae89 2019-12-06 tracey no_ignores = 1;
5891 022fae89 2019-12-06 tracey break;
5892 4e68cba3 2019-11-23 stsp case 'R':
5893 4e68cba3 2019-11-23 stsp can_recurse = 1;
5894 4e68cba3 2019-11-23 stsp break;
5895 d00136be 2019-03-26 stsp default:
5896 d00136be 2019-03-26 stsp usage_add();
5897 d00136be 2019-03-26 stsp /* NOTREACHED */
5898 d00136be 2019-03-26 stsp }
5899 d00136be 2019-03-26 stsp }
5900 d00136be 2019-03-26 stsp
5901 d00136be 2019-03-26 stsp argc -= optind;
5902 d00136be 2019-03-26 stsp argv += optind;
5903 d00136be 2019-03-26 stsp
5904 43012d58 2019-07-14 stsp #ifndef PROFILE
5905 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5906 43012d58 2019-07-14 stsp NULL) == -1)
5907 43012d58 2019-07-14 stsp err(1, "pledge");
5908 43012d58 2019-07-14 stsp #endif
5909 723c305c 2019-05-11 jcs if (argc < 1)
5910 d00136be 2019-03-26 stsp usage_add();
5911 d00136be 2019-03-26 stsp
5912 d00136be 2019-03-26 stsp cwd = getcwd(NULL, 0);
5913 d00136be 2019-03-26 stsp if (cwd == NULL) {
5914 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
5915 d00136be 2019-03-26 stsp goto done;
5916 d00136be 2019-03-26 stsp }
5917 723c305c 2019-05-11 jcs
5918 d00136be 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
5919 fa51e947 2020-03-27 stsp if (error) {
5920 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
5921 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "add", cwd);
5922 d00136be 2019-03-26 stsp goto done;
5923 fa51e947 2020-03-27 stsp }
5924 d00136be 2019-03-26 stsp
5925 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
5926 c9956ddf 2019-09-08 stsp NULL);
5927 031a5338 2019-03-26 stsp if (error != NULL)
5928 031a5338 2019-03-26 stsp goto done;
5929 031a5338 2019-03-26 stsp
5930 031a5338 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
5931 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
5932 d00136be 2019-03-26 stsp if (error)
5933 d00136be 2019-03-26 stsp goto done;
5934 d00136be 2019-03-26 stsp
5935 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
5936 6d022e97 2019-08-04 stsp if (error)
5937 022fae89 2019-12-06 tracey goto done;
5938 022fae89 2019-12-06 tracey
5939 022fae89 2019-12-06 tracey if (!can_recurse && no_ignores) {
5940 022fae89 2019-12-06 tracey error = got_error_msg(GOT_ERR_BAD_PATH,
5941 022fae89 2019-12-06 tracey "disregarding ignores requires -R option");
5942 6d022e97 2019-08-04 stsp goto done;
5943 723c305c 2019-05-11 jcs
5944 022fae89 2019-12-06 tracey }
5945 022fae89 2019-12-06 tracey
5946 4e68cba3 2019-11-23 stsp if (!can_recurse) {
5947 4e68cba3 2019-11-23 stsp char *ondisk_path;
5948 4e68cba3 2019-11-23 stsp struct stat sb;
5949 4e68cba3 2019-11-23 stsp TAILQ_FOREACH(pe, &paths, entry) {
5950 4e68cba3 2019-11-23 stsp if (asprintf(&ondisk_path, "%s/%s",
5951 4e68cba3 2019-11-23 stsp got_worktree_get_root_path(worktree),
5952 4e68cba3 2019-11-23 stsp pe->path) == -1) {
5953 4e68cba3 2019-11-23 stsp error = got_error_from_errno("asprintf");
5954 4e68cba3 2019-11-23 stsp goto done;
5955 4e68cba3 2019-11-23 stsp }
5956 4e68cba3 2019-11-23 stsp if (lstat(ondisk_path, &sb) == -1) {
5957 4e68cba3 2019-11-23 stsp if (errno == ENOENT) {
5958 4e68cba3 2019-11-23 stsp free(ondisk_path);
5959 4e68cba3 2019-11-23 stsp continue;
5960 4e68cba3 2019-11-23 stsp }
5961 4e68cba3 2019-11-23 stsp error = got_error_from_errno2("lstat",
5962 4e68cba3 2019-11-23 stsp ondisk_path);
5963 4e68cba3 2019-11-23 stsp free(ondisk_path);
5964 4e68cba3 2019-11-23 stsp goto done;
5965 4e68cba3 2019-11-23 stsp }
5966 4e68cba3 2019-11-23 stsp free(ondisk_path);
5967 4e68cba3 2019-11-23 stsp if (S_ISDIR(sb.st_mode)) {
5968 4e68cba3 2019-11-23 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
5969 4e68cba3 2019-11-23 stsp "adding directories requires -R option");
5970 4e68cba3 2019-11-23 stsp goto done;
5971 4e68cba3 2019-11-23 stsp }
5972 4e68cba3 2019-11-23 stsp }
5973 4e68cba3 2019-11-23 stsp }
5974 022fae89 2019-12-06 tracey
5975 4e68cba3 2019-11-23 stsp error = got_worktree_schedule_add(worktree, &paths, add_progress,
5976 022fae89 2019-12-06 tracey NULL, repo, no_ignores);
5977 d00136be 2019-03-26 stsp done:
5978 031a5338 2019-03-26 stsp if (repo)
5979 031a5338 2019-03-26 stsp got_repo_close(repo);
5980 d00136be 2019-03-26 stsp if (worktree)
5981 d00136be 2019-03-26 stsp got_worktree_close(worktree);
5982 1dd54920 2019-05-11 stsp TAILQ_FOREACH(pe, &paths, entry)
5983 1dd54920 2019-05-11 stsp free((char *)pe->path);
5984 1dd54920 2019-05-11 stsp got_pathlist_free(&paths);
5985 2ec1f75b 2019-03-26 stsp free(cwd);
5986 2ec1f75b 2019-03-26 stsp return error;
5987 2ec1f75b 2019-03-26 stsp }
5988 2ec1f75b 2019-03-26 stsp
5989 2ec1f75b 2019-03-26 stsp __dead static void
5990 648e4ef7 2019-07-09 stsp usage_remove(void)
5991 2ec1f75b 2019-03-26 stsp {
5992 c29c428a 2019-12-16 stsp fprintf(stderr, "usage: %s remove [-f] [-k] [-R] path ...\n",
5993 f2a9dc41 2019-12-13 tracey getprogname());
5994 2ec1f75b 2019-03-26 stsp exit(1);
5995 2a06fe5f 2019-08-24 stsp }
5996 2a06fe5f 2019-08-24 stsp
5997 2a06fe5f 2019-08-24 stsp static const struct got_error *
5998 2a06fe5f 2019-08-24 stsp print_remove_status(void *arg, unsigned char status,
5999 f2a9dc41 2019-12-13 tracey unsigned char staged_status, const char *path)
6000 2a06fe5f 2019-08-24 stsp {
6001 f2a9dc41 2019-12-13 tracey while (path[0] == '/')
6002 f2a9dc41 2019-12-13 tracey path++;
6003 2a06fe5f 2019-08-24 stsp if (status == GOT_STATUS_NONEXISTENT)
6004 2a06fe5f 2019-08-24 stsp return NULL;
6005 2a06fe5f 2019-08-24 stsp if (status == staged_status && (status == GOT_STATUS_DELETE))
6006 2a06fe5f 2019-08-24 stsp status = GOT_STATUS_NO_CHANGE;
6007 2a06fe5f 2019-08-24 stsp printf("%c%c %s\n", status, staged_status, path);
6008 2a06fe5f 2019-08-24 stsp return NULL;
6009 2ec1f75b 2019-03-26 stsp }
6010 2ec1f75b 2019-03-26 stsp
6011 2ec1f75b 2019-03-26 stsp static const struct got_error *
6012 648e4ef7 2019-07-09 stsp cmd_remove(int argc, char *argv[])
6013 2ec1f75b 2019-03-26 stsp {
6014 2ec1f75b 2019-03-26 stsp const struct got_error *error = NULL;
6015 2ec1f75b 2019-03-26 stsp struct got_worktree *worktree = NULL;
6016 2ec1f75b 2019-03-26 stsp struct got_repository *repo = NULL;
6017 17ed4618 2019-06-02 stsp char *cwd = NULL;
6018 17ed4618 2019-06-02 stsp struct got_pathlist_head paths;
6019 17ed4618 2019-06-02 stsp struct got_pathlist_entry *pe;
6020 70e3e7f5 2019-12-13 tracey int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0;
6021 2ec1f75b 2019-03-26 stsp
6022 17ed4618 2019-06-02 stsp TAILQ_INIT(&paths);
6023 17ed4618 2019-06-02 stsp
6024 70e3e7f5 2019-12-13 tracey while ((ch = getopt(argc, argv, "fkR")) != -1) {
6025 2ec1f75b 2019-03-26 stsp switch (ch) {
6026 2ec1f75b 2019-03-26 stsp case 'f':
6027 2ec1f75b 2019-03-26 stsp delete_local_mods = 1;
6028 2ec1f75b 2019-03-26 stsp break;
6029 70e3e7f5 2019-12-13 tracey case 'k':
6030 70e3e7f5 2019-12-13 tracey keep_on_disk = 1;
6031 70e3e7f5 2019-12-13 tracey break;
6032 f2a9dc41 2019-12-13 tracey case 'R':
6033 f2a9dc41 2019-12-13 tracey can_recurse = 1;
6034 f2a9dc41 2019-12-13 tracey break;
6035 2ec1f75b 2019-03-26 stsp default:
6036 f2a9dc41 2019-12-13 tracey usage_remove();
6037 2ec1f75b 2019-03-26 stsp /* NOTREACHED */
6038 2ec1f75b 2019-03-26 stsp }
6039 2ec1f75b 2019-03-26 stsp }
6040 2ec1f75b 2019-03-26 stsp
6041 2ec1f75b 2019-03-26 stsp argc -= optind;
6042 2ec1f75b 2019-03-26 stsp argv += optind;
6043 2ec1f75b 2019-03-26 stsp
6044 43012d58 2019-07-14 stsp #ifndef PROFILE
6045 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6046 43012d58 2019-07-14 stsp NULL) == -1)
6047 43012d58 2019-07-14 stsp err(1, "pledge");
6048 43012d58 2019-07-14 stsp #endif
6049 17ed4618 2019-06-02 stsp if (argc < 1)
6050 648e4ef7 2019-07-09 stsp usage_remove();
6051 2ec1f75b 2019-03-26 stsp
6052 2ec1f75b 2019-03-26 stsp cwd = getcwd(NULL, 0);
6053 2ec1f75b 2019-03-26 stsp if (cwd == NULL) {
6054 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6055 2ec1f75b 2019-03-26 stsp goto done;
6056 2ec1f75b 2019-03-26 stsp }
6057 2ec1f75b 2019-03-26 stsp error = got_worktree_open(&worktree, cwd);
6058 fa51e947 2020-03-27 stsp if (error) {
6059 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6060 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "remove", cwd);
6061 2ec1f75b 2019-03-26 stsp goto done;
6062 fa51e947 2020-03-27 stsp }
6063 2ec1f75b 2019-03-26 stsp
6064 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6065 c9956ddf 2019-09-08 stsp NULL);
6066 2af4a041 2019-05-11 jcs if (error)
6067 2ec1f75b 2019-03-26 stsp goto done;
6068 2ec1f75b 2019-03-26 stsp
6069 c2253644 2019-03-26 stsp error = apply_unveil(got_repo_get_path(repo), 1,
6070 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6071 2ec1f75b 2019-03-26 stsp if (error)
6072 2ec1f75b 2019-03-26 stsp goto done;
6073 2ec1f75b 2019-03-26 stsp
6074 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6075 6d022e97 2019-08-04 stsp if (error)
6076 6d022e97 2019-08-04 stsp goto done;
6077 17ed4618 2019-06-02 stsp
6078 f2a9dc41 2019-12-13 tracey if (!can_recurse) {
6079 f2a9dc41 2019-12-13 tracey char *ondisk_path;
6080 f2a9dc41 2019-12-13 tracey struct stat sb;
6081 f2a9dc41 2019-12-13 tracey TAILQ_FOREACH(pe, &paths, entry) {
6082 f2a9dc41 2019-12-13 tracey if (asprintf(&ondisk_path, "%s/%s",
6083 f2a9dc41 2019-12-13 tracey got_worktree_get_root_path(worktree),
6084 f2a9dc41 2019-12-13 tracey pe->path) == -1) {
6085 f2a9dc41 2019-12-13 tracey error = got_error_from_errno("asprintf");
6086 f2a9dc41 2019-12-13 tracey goto done;
6087 f2a9dc41 2019-12-13 tracey }
6088 f2a9dc41 2019-12-13 tracey if (lstat(ondisk_path, &sb) == -1) {
6089 f2a9dc41 2019-12-13 tracey if (errno == ENOENT) {
6090 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6091 f2a9dc41 2019-12-13 tracey continue;
6092 f2a9dc41 2019-12-13 tracey }
6093 f2a9dc41 2019-12-13 tracey error = got_error_from_errno2("lstat",
6094 f2a9dc41 2019-12-13 tracey ondisk_path);
6095 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6096 f2a9dc41 2019-12-13 tracey goto done;
6097 f2a9dc41 2019-12-13 tracey }
6098 f2a9dc41 2019-12-13 tracey free(ondisk_path);
6099 f2a9dc41 2019-12-13 tracey if (S_ISDIR(sb.st_mode)) {
6100 f2a9dc41 2019-12-13 tracey error = got_error_msg(GOT_ERR_BAD_PATH,
6101 f2a9dc41 2019-12-13 tracey "removing directories requires -R option");
6102 f2a9dc41 2019-12-13 tracey goto done;
6103 f2a9dc41 2019-12-13 tracey }
6104 f2a9dc41 2019-12-13 tracey }
6105 f2a9dc41 2019-12-13 tracey }
6106 f2a9dc41 2019-12-13 tracey
6107 17ed4618 2019-06-02 stsp error = got_worktree_schedule_delete(worktree, &paths,
6108 70e3e7f5 2019-12-13 tracey delete_local_mods, print_remove_status, NULL, repo, keep_on_disk);
6109 a129376b 2019-03-28 stsp done:
6110 a129376b 2019-03-28 stsp if (repo)
6111 a129376b 2019-03-28 stsp got_repo_close(repo);
6112 a129376b 2019-03-28 stsp if (worktree)
6113 a129376b 2019-03-28 stsp got_worktree_close(worktree);
6114 17ed4618 2019-06-02 stsp TAILQ_FOREACH(pe, &paths, entry)
6115 17ed4618 2019-06-02 stsp free((char *)pe->path);
6116 17ed4618 2019-06-02 stsp got_pathlist_free(&paths);
6117 a129376b 2019-03-28 stsp free(cwd);
6118 a129376b 2019-03-28 stsp return error;
6119 a129376b 2019-03-28 stsp }
6120 a129376b 2019-03-28 stsp
6121 a129376b 2019-03-28 stsp __dead static void
6122 a129376b 2019-03-28 stsp usage_revert(void)
6123 a129376b 2019-03-28 stsp {
6124 33aa809d 2019-08-08 stsp fprintf(stderr, "usage: %s revert [-p] [-F response-script] [-R] "
6125 33aa809d 2019-08-08 stsp "path ...\n", getprogname());
6126 a129376b 2019-03-28 stsp exit(1);
6127 a129376b 2019-03-28 stsp }
6128 a129376b 2019-03-28 stsp
6129 1ee397ad 2019-07-12 stsp static const struct got_error *
6130 a129376b 2019-03-28 stsp revert_progress(void *arg, unsigned char status, const char *path)
6131 a129376b 2019-03-28 stsp {
6132 fb9704af 2020-01-27 stsp if (status == GOT_STATUS_UNVERSIONED)
6133 fb9704af 2020-01-27 stsp return NULL;
6134 fb9704af 2020-01-27 stsp
6135 a129376b 2019-03-28 stsp while (path[0] == '/')
6136 a129376b 2019-03-28 stsp path++;
6137 a129376b 2019-03-28 stsp printf("%c %s\n", status, path);
6138 33aa809d 2019-08-08 stsp return NULL;
6139 33aa809d 2019-08-08 stsp }
6140 33aa809d 2019-08-08 stsp
6141 33aa809d 2019-08-08 stsp struct choose_patch_arg {
6142 33aa809d 2019-08-08 stsp FILE *patch_script_file;
6143 33aa809d 2019-08-08 stsp const char *action;
6144 33aa809d 2019-08-08 stsp };
6145 33aa809d 2019-08-08 stsp
6146 33aa809d 2019-08-08 stsp static const struct got_error *
6147 33aa809d 2019-08-08 stsp show_change(unsigned char status, const char *path, FILE *patch_file, int n,
6148 33aa809d 2019-08-08 stsp int nchanges, const char *action)
6149 33aa809d 2019-08-08 stsp {
6150 33aa809d 2019-08-08 stsp char *line = NULL;
6151 33aa809d 2019-08-08 stsp size_t linesize = 0;
6152 33aa809d 2019-08-08 stsp ssize_t linelen;
6153 33aa809d 2019-08-08 stsp
6154 33aa809d 2019-08-08 stsp switch (status) {
6155 33aa809d 2019-08-08 stsp case GOT_STATUS_ADD:
6156 33aa809d 2019-08-08 stsp printf("A %s\n%s this addition? [y/n] ", path, action);
6157 33aa809d 2019-08-08 stsp break;
6158 33aa809d 2019-08-08 stsp case GOT_STATUS_DELETE:
6159 33aa809d 2019-08-08 stsp printf("D %s\n%s this deletion? [y/n] ", path, action);
6160 33aa809d 2019-08-08 stsp break;
6161 33aa809d 2019-08-08 stsp case GOT_STATUS_MODIFY:
6162 33aa809d 2019-08-08 stsp if (fseek(patch_file, 0L, SEEK_SET) == -1)
6163 33aa809d 2019-08-08 stsp return got_error_from_errno("fseek");
6164 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
6165 9516e7cb 2019-08-11 stsp while ((linelen = getline(&line, &linesize, patch_file)) != -1)
6166 33aa809d 2019-08-08 stsp printf("%s", line);
6167 33aa809d 2019-08-08 stsp if (ferror(patch_file))
6168 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
6169 33aa809d 2019-08-08 stsp printf(GOT_COMMIT_SEP_STR);
6170 33aa809d 2019-08-08 stsp printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
6171 33aa809d 2019-08-08 stsp path, n, nchanges, action);
6172 33aa809d 2019-08-08 stsp break;
6173 33aa809d 2019-08-08 stsp default:
6174 33aa809d 2019-08-08 stsp return got_error_path(path, GOT_ERR_FILE_STATUS);
6175 33aa809d 2019-08-08 stsp }
6176 33aa809d 2019-08-08 stsp
6177 33aa809d 2019-08-08 stsp return NULL;
6178 33aa809d 2019-08-08 stsp }
6179 33aa809d 2019-08-08 stsp
6180 33aa809d 2019-08-08 stsp static const struct got_error *
6181 33aa809d 2019-08-08 stsp choose_patch(int *choice, void *arg, unsigned char status, const char *path,
6182 33aa809d 2019-08-08 stsp FILE *patch_file, int n, int nchanges)
6183 33aa809d 2019-08-08 stsp {
6184 33aa809d 2019-08-08 stsp const struct got_error *err = NULL;
6185 33aa809d 2019-08-08 stsp char *line = NULL;
6186 33aa809d 2019-08-08 stsp size_t linesize = 0;
6187 33aa809d 2019-08-08 stsp ssize_t linelen;
6188 33aa809d 2019-08-08 stsp int resp = ' ';
6189 33aa809d 2019-08-08 stsp struct choose_patch_arg *a = arg;
6190 33aa809d 2019-08-08 stsp
6191 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NONE;
6192 33aa809d 2019-08-08 stsp
6193 33aa809d 2019-08-08 stsp if (a->patch_script_file) {
6194 33aa809d 2019-08-08 stsp char *nl;
6195 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
6196 33aa809d 2019-08-08 stsp a->action);
6197 33aa809d 2019-08-08 stsp if (err)
6198 33aa809d 2019-08-08 stsp return err;
6199 33aa809d 2019-08-08 stsp linelen = getline(&line, &linesize, a->patch_script_file);
6200 33aa809d 2019-08-08 stsp if (linelen == -1) {
6201 33aa809d 2019-08-08 stsp if (ferror(a->patch_script_file))
6202 33aa809d 2019-08-08 stsp return got_error_from_errno("getline");
6203 33aa809d 2019-08-08 stsp return NULL;
6204 33aa809d 2019-08-08 stsp }
6205 33aa809d 2019-08-08 stsp nl = strchr(line, '\n');
6206 33aa809d 2019-08-08 stsp if (nl)
6207 33aa809d 2019-08-08 stsp *nl = '\0';
6208 33aa809d 2019-08-08 stsp if (strcmp(line, "y") == 0) {
6209 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
6210 33aa809d 2019-08-08 stsp printf("y\n");
6211 33aa809d 2019-08-08 stsp } else if (strcmp(line, "n") == 0) {
6212 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
6213 33aa809d 2019-08-08 stsp printf("n\n");
6214 33aa809d 2019-08-08 stsp } else if (strcmp(line, "q") == 0 &&
6215 33aa809d 2019-08-08 stsp status == GOT_STATUS_MODIFY) {
6216 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
6217 33aa809d 2019-08-08 stsp printf("q\n");
6218 33aa809d 2019-08-08 stsp } else
6219 33aa809d 2019-08-08 stsp printf("invalid response '%s'\n", line);
6220 33aa809d 2019-08-08 stsp free(line);
6221 33aa809d 2019-08-08 stsp return NULL;
6222 33aa809d 2019-08-08 stsp }
6223 33aa809d 2019-08-08 stsp
6224 33aa809d 2019-08-08 stsp while (resp != 'y' && resp != 'n' && resp != 'q') {
6225 33aa809d 2019-08-08 stsp err = show_change(status, path, patch_file, n, nchanges,
6226 33aa809d 2019-08-08 stsp a->action);
6227 33aa809d 2019-08-08 stsp if (err)
6228 33aa809d 2019-08-08 stsp return err;
6229 33aa809d 2019-08-08 stsp resp = getchar();
6230 33aa809d 2019-08-08 stsp if (resp == '\n')
6231 33aa809d 2019-08-08 stsp resp = getchar();
6232 33aa809d 2019-08-08 stsp if (status == GOT_STATUS_MODIFY) {
6233 33aa809d 2019-08-08 stsp if (resp != 'y' && resp != 'n' && resp != 'q') {
6234 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
6235 33aa809d 2019-08-08 stsp resp = ' ';
6236 33aa809d 2019-08-08 stsp }
6237 33aa809d 2019-08-08 stsp } else if (resp != 'y' && resp != 'n') {
6238 33aa809d 2019-08-08 stsp printf("invalid response '%c'\n", resp);
6239 33aa809d 2019-08-08 stsp resp = ' ';
6240 33aa809d 2019-08-08 stsp }
6241 33aa809d 2019-08-08 stsp }
6242 33aa809d 2019-08-08 stsp
6243 33aa809d 2019-08-08 stsp if (resp == 'y')
6244 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_YES;
6245 33aa809d 2019-08-08 stsp else if (resp == 'n')
6246 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_NO;
6247 33aa809d 2019-08-08 stsp else if (resp == 'q' && status == GOT_STATUS_MODIFY)
6248 33aa809d 2019-08-08 stsp *choice = GOT_PATCH_CHOICE_QUIT;
6249 33aa809d 2019-08-08 stsp
6250 1ee397ad 2019-07-12 stsp return NULL;
6251 a129376b 2019-03-28 stsp }
6252 a129376b 2019-03-28 stsp
6253 33aa809d 2019-08-08 stsp
6254 a129376b 2019-03-28 stsp static const struct got_error *
6255 a129376b 2019-03-28 stsp cmd_revert(int argc, char *argv[])
6256 a129376b 2019-03-28 stsp {
6257 a129376b 2019-03-28 stsp const struct got_error *error = NULL;
6258 a129376b 2019-03-28 stsp struct got_worktree *worktree = NULL;
6259 a129376b 2019-03-28 stsp struct got_repository *repo = NULL;
6260 a129376b 2019-03-28 stsp char *cwd = NULL, *path = NULL;
6261 e20a8b6f 2019-06-04 stsp struct got_pathlist_head paths;
6262 0f6d7415 2019-08-08 stsp struct got_pathlist_entry *pe;
6263 33aa809d 2019-08-08 stsp int ch, can_recurse = 0, pflag = 0;
6264 33aa809d 2019-08-08 stsp FILE *patch_script_file = NULL;
6265 33aa809d 2019-08-08 stsp const char *patch_script_path = NULL;
6266 33aa809d 2019-08-08 stsp struct choose_patch_arg cpa;
6267 a129376b 2019-03-28 stsp
6268 e20a8b6f 2019-06-04 stsp TAILQ_INIT(&paths);
6269 e20a8b6f 2019-06-04 stsp
6270 33aa809d 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:R")) != -1) {
6271 a129376b 2019-03-28 stsp switch (ch) {
6272 33aa809d 2019-08-08 stsp case 'p':
6273 33aa809d 2019-08-08 stsp pflag = 1;
6274 33aa809d 2019-08-08 stsp break;
6275 33aa809d 2019-08-08 stsp case 'F':
6276 33aa809d 2019-08-08 stsp patch_script_path = optarg;
6277 33aa809d 2019-08-08 stsp break;
6278 0f6d7415 2019-08-08 stsp case 'R':
6279 0f6d7415 2019-08-08 stsp can_recurse = 1;
6280 0f6d7415 2019-08-08 stsp break;
6281 a129376b 2019-03-28 stsp default:
6282 a129376b 2019-03-28 stsp usage_revert();
6283 a129376b 2019-03-28 stsp /* NOTREACHED */
6284 a129376b 2019-03-28 stsp }
6285 a129376b 2019-03-28 stsp }
6286 a129376b 2019-03-28 stsp
6287 a129376b 2019-03-28 stsp argc -= optind;
6288 a129376b 2019-03-28 stsp argv += optind;
6289 a129376b 2019-03-28 stsp
6290 43012d58 2019-07-14 stsp #ifndef PROFILE
6291 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
6292 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
6293 43012d58 2019-07-14 stsp err(1, "pledge");
6294 43012d58 2019-07-14 stsp #endif
6295 e20a8b6f 2019-06-04 stsp if (argc < 1)
6296 a129376b 2019-03-28 stsp usage_revert();
6297 33aa809d 2019-08-08 stsp if (patch_script_path && !pflag)
6298 33aa809d 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
6299 a129376b 2019-03-28 stsp
6300 a129376b 2019-03-28 stsp cwd = getcwd(NULL, 0);
6301 a129376b 2019-03-28 stsp if (cwd == NULL) {
6302 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6303 a129376b 2019-03-28 stsp goto done;
6304 a129376b 2019-03-28 stsp }
6305 a129376b 2019-03-28 stsp error = got_worktree_open(&worktree, cwd);
6306 fa51e947 2020-03-27 stsp if (error) {
6307 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6308 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "revert", cwd);
6309 2ec1f75b 2019-03-26 stsp goto done;
6310 fa51e947 2020-03-27 stsp }
6311 a129376b 2019-03-28 stsp
6312 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6313 c9956ddf 2019-09-08 stsp NULL);
6314 a129376b 2019-03-28 stsp if (error != NULL)
6315 a129376b 2019-03-28 stsp goto done;
6316 a129376b 2019-03-28 stsp
6317 33aa809d 2019-08-08 stsp if (patch_script_path) {
6318 33aa809d 2019-08-08 stsp patch_script_file = fopen(patch_script_path, "r");
6319 33aa809d 2019-08-08 stsp if (patch_script_file == NULL) {
6320 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fopen",
6321 33aa809d 2019-08-08 stsp patch_script_path);
6322 33aa809d 2019-08-08 stsp goto done;
6323 33aa809d 2019-08-08 stsp }
6324 33aa809d 2019-08-08 stsp }
6325 a129376b 2019-03-28 stsp error = apply_unveil(got_repo_get_path(repo), 1,
6326 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6327 a129376b 2019-03-28 stsp if (error)
6328 a129376b 2019-03-28 stsp goto done;
6329 a129376b 2019-03-28 stsp
6330 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6331 6d022e97 2019-08-04 stsp if (error)
6332 6d022e97 2019-08-04 stsp goto done;
6333 00db391e 2019-08-03 stsp
6334 0f6d7415 2019-08-08 stsp if (!can_recurse) {
6335 0f6d7415 2019-08-08 stsp char *ondisk_path;
6336 0f6d7415 2019-08-08 stsp struct stat sb;
6337 0f6d7415 2019-08-08 stsp TAILQ_FOREACH(pe, &paths, entry) {
6338 0f6d7415 2019-08-08 stsp if (asprintf(&ondisk_path, "%s/%s",
6339 0f6d7415 2019-08-08 stsp got_worktree_get_root_path(worktree),
6340 0f6d7415 2019-08-08 stsp pe->path) == -1) {
6341 0f6d7415 2019-08-08 stsp error = got_error_from_errno("asprintf");
6342 0f6d7415 2019-08-08 stsp goto done;
6343 0f6d7415 2019-08-08 stsp }
6344 0f6d7415 2019-08-08 stsp if (lstat(ondisk_path, &sb) == -1) {
6345 0f6d7415 2019-08-08 stsp if (errno == ENOENT) {
6346 0f6d7415 2019-08-08 stsp free(ondisk_path);
6347 0f6d7415 2019-08-08 stsp continue;
6348 0f6d7415 2019-08-08 stsp }
6349 0f6d7415 2019-08-08 stsp error = got_error_from_errno2("lstat",
6350 0f6d7415 2019-08-08 stsp ondisk_path);
6351 0f6d7415 2019-08-08 stsp free(ondisk_path);
6352 0f6d7415 2019-08-08 stsp goto done;
6353 0f6d7415 2019-08-08 stsp }
6354 0f6d7415 2019-08-08 stsp free(ondisk_path);
6355 0f6d7415 2019-08-08 stsp if (S_ISDIR(sb.st_mode)) {
6356 0f6d7415 2019-08-08 stsp error = got_error_msg(GOT_ERR_BAD_PATH,
6357 0f6d7415 2019-08-08 stsp "reverting directories requires -R option");
6358 0f6d7415 2019-08-08 stsp goto done;
6359 0f6d7415 2019-08-08 stsp }
6360 0f6d7415 2019-08-08 stsp }
6361 0f6d7415 2019-08-08 stsp }
6362 0f6d7415 2019-08-08 stsp
6363 33aa809d 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
6364 33aa809d 2019-08-08 stsp cpa.action = "revert";
6365 33aa809d 2019-08-08 stsp error = got_worktree_revert(worktree, &paths, revert_progress, NULL,
6366 33aa809d 2019-08-08 stsp pflag ? choose_patch : NULL, &cpa, repo);
6367 2ec1f75b 2019-03-26 stsp done:
6368 33aa809d 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
6369 33aa809d 2019-08-08 stsp error == NULL)
6370 33aa809d 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
6371 2ec1f75b 2019-03-26 stsp if (repo)
6372 2ec1f75b 2019-03-26 stsp got_repo_close(repo);
6373 2ec1f75b 2019-03-26 stsp if (worktree)
6374 2ec1f75b 2019-03-26 stsp got_worktree_close(worktree);
6375 2ec1f75b 2019-03-26 stsp free(path);
6376 d00136be 2019-03-26 stsp free(cwd);
6377 6bad629b 2019-02-04 stsp return error;
6378 c4296144 2019-05-09 stsp }
6379 c4296144 2019-05-09 stsp
6380 c4296144 2019-05-09 stsp __dead static void
6381 c4296144 2019-05-09 stsp usage_commit(void)
6382 c4296144 2019-05-09 stsp {
6383 35213c7c 2020-07-23 stsp fprintf(stderr, "usage: %s commit [-m msg] [-S] [path ...]\n",
6384 5c1e53bc 2019-07-28 stsp getprogname());
6385 c4296144 2019-05-09 stsp exit(1);
6386 33ad4cbe 2019-05-12 jcs }
6387 33ad4cbe 2019-05-12 jcs
6388 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg {
6389 e2ba3d07 2019-05-13 stsp const char *cmdline_log;
6390 e2ba3d07 2019-05-13 stsp const char *editor;
6391 e0870e44 2019-05-13 stsp const char *worktree_path;
6392 76d98825 2019-06-03 stsp const char *branch_name;
6393 314a6357 2019-05-13 stsp const char *repo_path;
6394 e0870e44 2019-05-13 stsp char *logmsg_path;
6395 e2ba3d07 2019-05-13 stsp
6396 e2ba3d07 2019-05-13 stsp };
6397 e0870e44 2019-05-13 stsp
6398 33ad4cbe 2019-05-12 jcs static const struct got_error *
6399 33ad4cbe 2019-05-12 jcs collect_commit_logmsg(struct got_pathlist_head *commitable_paths, char **logmsg,
6400 33ad4cbe 2019-05-12 jcs void *arg)
6401 33ad4cbe 2019-05-12 jcs {
6402 76d98825 2019-06-03 stsp char *initial_content = NULL;
6403 33ad4cbe 2019-05-12 jcs struct got_pathlist_entry *pe;
6404 33ad4cbe 2019-05-12 jcs const struct got_error *err = NULL;
6405 e0870e44 2019-05-13 stsp char *template = NULL;
6406 e2ba3d07 2019-05-13 stsp struct collect_commit_logmsg_arg *a = arg;
6407 3ce1b845 2019-07-15 stsp int fd;
6408 33ad4cbe 2019-05-12 jcs size_t len;
6409 33ad4cbe 2019-05-12 jcs
6410 33ad4cbe 2019-05-12 jcs /* if a message was specified on the command line, just use it */
6411 e2ba3d07 2019-05-13 stsp if (a->cmdline_log != NULL && strlen(a->cmdline_log) != 0) {
6412 e2ba3d07 2019-05-13 stsp len = strlen(a->cmdline_log) + 1;
6413 33ad4cbe 2019-05-12 jcs *logmsg = malloc(len + 1);
6414 9f42ff69 2019-05-13 stsp if (*logmsg == NULL)
6415 638f9024 2019-05-13 stsp return got_error_from_errno("malloc");
6416 e2ba3d07 2019-05-13 stsp strlcpy(*logmsg, a->cmdline_log, len);
6417 33ad4cbe 2019-05-12 jcs return NULL;
6418 33ad4cbe 2019-05-12 jcs }
6419 33ad4cbe 2019-05-12 jcs
6420 e0870e44 2019-05-13 stsp if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
6421 76d98825 2019-06-03 stsp return got_error_from_errno("asprintf");
6422 76d98825 2019-06-03 stsp
6423 76d98825 2019-06-03 stsp if (asprintf(&initial_content,
6424 76d98825 2019-06-03 stsp "\n# changes to be committed on branch %s:\n",
6425 76d98825 2019-06-03 stsp a->branch_name) == -1)
6426 638f9024 2019-05-13 stsp return got_error_from_errno("asprintf");
6427 e0870e44 2019-05-13 stsp
6428 e0870e44 2019-05-13 stsp err = got_opentemp_named_fd(&a->logmsg_path, &fd, template);
6429 793c30b5 2019-05-13 stsp if (err)
6430 e0870e44 2019-05-13 stsp goto done;
6431 33ad4cbe 2019-05-12 jcs
6432 e0870e44 2019-05-13 stsp dprintf(fd, initial_content);
6433 33ad4cbe 2019-05-12 jcs
6434 33ad4cbe 2019-05-12 jcs TAILQ_FOREACH(pe, commitable_paths, entry) {
6435 33ad4cbe 2019-05-12 jcs struct got_commitable *ct = pe->data;
6436 8656d6c4 2019-05-20 stsp dprintf(fd, "# %c %s\n",
6437 8656d6c4 2019-05-20 stsp got_commitable_get_status(ct),
6438 8656d6c4 2019-05-20 stsp got_commitable_get_path(ct));
6439 33ad4cbe 2019-05-12 jcs }
6440 33ad4cbe 2019-05-12 jcs close(fd);
6441 33ad4cbe 2019-05-12 jcs
6442 3ce1b845 2019-07-15 stsp err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content);
6443 33ad4cbe 2019-05-12 jcs done:
6444 76d98825 2019-06-03 stsp free(initial_content);
6445 e0870e44 2019-05-13 stsp free(template);
6446 314a6357 2019-05-13 stsp
6447 314a6357 2019-05-13 stsp /* Editor is done; we can now apply unveil(2) */
6448 3ce1b845 2019-07-15 stsp if (err == NULL) {
6449 c530dc23 2019-07-23 stsp err = apply_unveil(a->repo_path, 0, a->worktree_path);
6450 3ce1b845 2019-07-15 stsp if (err) {
6451 3ce1b845 2019-07-15 stsp free(*logmsg);
6452 3ce1b845 2019-07-15 stsp *logmsg = NULL;
6453 3ce1b845 2019-07-15 stsp }
6454 3ce1b845 2019-07-15 stsp }
6455 33ad4cbe 2019-05-12 jcs return err;
6456 6bad629b 2019-02-04 stsp }
6457 c4296144 2019-05-09 stsp
6458 c4296144 2019-05-09 stsp static const struct got_error *
6459 c4296144 2019-05-09 stsp cmd_commit(int argc, char *argv[])
6460 c4296144 2019-05-09 stsp {
6461 c4296144 2019-05-09 stsp const struct got_error *error = NULL;
6462 c4296144 2019-05-09 stsp struct got_worktree *worktree = NULL;
6463 c4296144 2019-05-09 stsp struct got_repository *repo = NULL;
6464 5c1e53bc 2019-07-28 stsp char *cwd = NULL, *id_str = NULL;
6465 c4296144 2019-05-09 stsp struct got_object_id *id = NULL;
6466 33ad4cbe 2019-05-12 jcs const char *logmsg = NULL;
6467 aba9c984 2019-09-08 stsp struct collect_commit_logmsg_arg cl_arg;
6468 c9956ddf 2019-09-08 stsp char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
6469 7266f21f 2019-10-21 stsp int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
6470 35213c7c 2020-07-23 stsp int allow_bad_symlinks = 0;
6471 5c1e53bc 2019-07-28 stsp struct got_pathlist_head paths;
6472 5c1e53bc 2019-07-28 stsp
6473 5c1e53bc 2019-07-28 stsp TAILQ_INIT(&paths);
6474 6ac5a73c 2019-08-08 stsp cl_arg.logmsg_path = NULL;
6475 c4296144 2019-05-09 stsp
6476 35213c7c 2020-07-23 stsp while ((ch = getopt(argc, argv, "m:S")) != -1) {
6477 c4296144 2019-05-09 stsp switch (ch) {
6478 c4296144 2019-05-09 stsp case 'm':
6479 c4296144 2019-05-09 stsp logmsg = optarg;
6480 c4296144 2019-05-09 stsp break;
6481 35213c7c 2020-07-23 stsp case 'S':
6482 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
6483 35213c7c 2020-07-23 stsp break;
6484 c4296144 2019-05-09 stsp default:
6485 c4296144 2019-05-09 stsp usage_commit();
6486 c4296144 2019-05-09 stsp /* NOTREACHED */
6487 c4296144 2019-05-09 stsp }
6488 c4296144 2019-05-09 stsp }
6489 c4296144 2019-05-09 stsp
6490 c4296144 2019-05-09 stsp argc -= optind;
6491 c4296144 2019-05-09 stsp argv += optind;
6492 c4296144 2019-05-09 stsp
6493 43012d58 2019-07-14 stsp #ifndef PROFILE
6494 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
6495 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
6496 43012d58 2019-07-14 stsp err(1, "pledge");
6497 43012d58 2019-07-14 stsp #endif
6498 c4296144 2019-05-09 stsp cwd = getcwd(NULL, 0);
6499 c4296144 2019-05-09 stsp if (cwd == NULL) {
6500 638f9024 2019-05-13 stsp error = got_error_from_errno("getcwd");
6501 c4296144 2019-05-09 stsp goto done;
6502 c4296144 2019-05-09 stsp }
6503 c4296144 2019-05-09 stsp error = got_worktree_open(&worktree, cwd);
6504 fa51e947 2020-03-27 stsp if (error) {
6505 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6506 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "commit", cwd);
6507 7d5807f4 2019-07-11 stsp goto done;
6508 fa51e947 2020-03-27 stsp }
6509 7d5807f4 2019-07-11 stsp
6510 a698f62e 2019-07-25 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
6511 c4296144 2019-05-09 stsp if (error)
6512 a698f62e 2019-07-25 stsp goto done;
6513 a698f62e 2019-07-25 stsp if (rebase_in_progress) {
6514 a698f62e 2019-07-25 stsp error = got_error(GOT_ERR_REBASING);
6515 c4296144 2019-05-09 stsp goto done;
6516 a698f62e 2019-07-25 stsp }
6517 5c1e53bc 2019-07-28 stsp
6518 916f288c 2019-07-30 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
6519 916f288c 2019-07-30 stsp worktree);
6520 5c1e53bc 2019-07-28 stsp if (error)
6521 5c1e53bc 2019-07-28 stsp goto done;
6522 c4296144 2019-05-09 stsp
6523 c9956ddf 2019-09-08 stsp error = get_gitconfig_path(&gitconfig_path);
6524 c9956ddf 2019-09-08 stsp if (error)
6525 c9956ddf 2019-09-08 stsp goto done;
6526 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6527 c9956ddf 2019-09-08 stsp gitconfig_path);
6528 c4296144 2019-05-09 stsp if (error != NULL)
6529 c4296144 2019-05-09 stsp goto done;
6530 c4296144 2019-05-09 stsp
6531 aba9c984 2019-09-08 stsp error = get_author(&author, repo);
6532 aba9c984 2019-09-08 stsp if (error)
6533 aba9c984 2019-09-08 stsp return error;
6534 aba9c984 2019-09-08 stsp
6535 314a6357 2019-05-13 stsp /*
6536 314a6357 2019-05-13 stsp * unveil(2) traverses exec(2); if an editor is used we have
6537 314a6357 2019-05-13 stsp * to apply unveil after the log message has been written.
6538 314a6357 2019-05-13 stsp */
6539 314a6357 2019-05-13 stsp if (logmsg == NULL || strlen(logmsg) == 0)
6540 314a6357 2019-05-13 stsp error = get_editor(&editor);
6541 314a6357 2019-05-13 stsp else
6542 314a6357 2019-05-13 stsp error = apply_unveil(got_repo_get_path(repo), 0,
6543 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6544 c4296144 2019-05-09 stsp if (error)
6545 c4296144 2019-05-09 stsp goto done;
6546 c4296144 2019-05-09 stsp
6547 087fb88c 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6548 087fb88c 2019-08-04 stsp if (error)
6549 087fb88c 2019-08-04 stsp goto done;
6550 087fb88c 2019-08-04 stsp
6551 e2ba3d07 2019-05-13 stsp cl_arg.editor = editor;
6552 e2ba3d07 2019-05-13 stsp cl_arg.cmdline_log = logmsg;
6553 e0870e44 2019-05-13 stsp cl_arg.worktree_path = got_worktree_get_root_path(worktree);
6554 76d98825 2019-06-03 stsp cl_arg.branch_name = got_worktree_get_head_ref_name(worktree);
6555 916f288c 2019-07-30 stsp if (!histedit_in_progress) {
6556 916f288c 2019-07-30 stsp if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) {
6557 916f288c 2019-07-30 stsp error = got_error(GOT_ERR_COMMIT_BRANCH);
6558 916f288c 2019-07-30 stsp goto done;
6559 916f288c 2019-07-30 stsp }
6560 916f288c 2019-07-30 stsp cl_arg.branch_name += 11;
6561 916f288c 2019-07-30 stsp }
6562 314a6357 2019-05-13 stsp cl_arg.repo_path = got_repo_get_path(repo);
6563 84792843 2019-08-09 stsp error = got_worktree_commit(&id, worktree, &paths, author, NULL,
6564 35213c7c 2020-07-23 stsp allow_bad_symlinks, collect_commit_logmsg, &cl_arg,
6565 35213c7c 2020-07-23 stsp print_status, NULL, repo);
6566 e0870e44 2019-05-13 stsp if (error) {
6567 7266f21f 2019-10-21 stsp if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
6568 7266f21f 2019-10-21 stsp cl_arg.logmsg_path != NULL)
6569 7266f21f 2019-10-21 stsp preserve_logmsg = 1;
6570 c4296144 2019-05-09 stsp goto done;
6571 e0870e44 2019-05-13 stsp }
6572 c4296144 2019-05-09 stsp
6573 c4296144 2019-05-09 stsp error = got_object_id_str(&id_str, id);
6574 c4296144 2019-05-09 stsp if (error)
6575 c4296144 2019-05-09 stsp goto done;
6576 a7648d7a 2019-06-02 stsp printf("Created commit %s\n", id_str);
6577 c4296144 2019-05-09 stsp done:
6578 7266f21f 2019-10-21 stsp if (preserve_logmsg) {
6579 7266f21f 2019-10-21 stsp fprintf(stderr, "%s: log message preserved in %s\n",
6580 7266f21f 2019-10-21 stsp getprogname(), cl_arg.logmsg_path);
6581 7266f21f 2019-10-21 stsp } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
6582 7266f21f 2019-10-21 stsp error == NULL)
6583 7266f21f 2019-10-21 stsp error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
6584 6ac5a73c 2019-08-08 stsp free(cl_arg.logmsg_path);
6585 c4296144 2019-05-09 stsp if (repo)
6586 c4296144 2019-05-09 stsp got_repo_close(repo);
6587 c4296144 2019-05-09 stsp if (worktree)
6588 c4296144 2019-05-09 stsp got_worktree_close(worktree);
6589 c4296144 2019-05-09 stsp free(cwd);
6590 c4296144 2019-05-09 stsp free(id_str);
6591 c9956ddf 2019-09-08 stsp free(gitconfig_path);
6592 e2ba3d07 2019-05-13 stsp free(editor);
6593 aba9c984 2019-09-08 stsp free(author);
6594 234035bc 2019-06-01 stsp return error;
6595 234035bc 2019-06-01 stsp }
6596 234035bc 2019-06-01 stsp
6597 234035bc 2019-06-01 stsp __dead static void
6598 234035bc 2019-06-01 stsp usage_cherrypick(void)
6599 234035bc 2019-06-01 stsp {
6600 234035bc 2019-06-01 stsp fprintf(stderr, "usage: %s cherrypick commit-id\n", getprogname());
6601 234035bc 2019-06-01 stsp exit(1);
6602 234035bc 2019-06-01 stsp }
6603 234035bc 2019-06-01 stsp
6604 234035bc 2019-06-01 stsp static const struct got_error *
6605 234035bc 2019-06-01 stsp cmd_cherrypick(int argc, char *argv[])
6606 234035bc 2019-06-01 stsp {
6607 234035bc 2019-06-01 stsp const struct got_error *error = NULL;
6608 234035bc 2019-06-01 stsp struct got_worktree *worktree = NULL;
6609 234035bc 2019-06-01 stsp struct got_repository *repo = NULL;
6610 234035bc 2019-06-01 stsp char *cwd = NULL, *commit_id_str = NULL;
6611 234035bc 2019-06-01 stsp struct got_object_id *commit_id = NULL;
6612 234035bc 2019-06-01 stsp struct got_commit_object *commit = NULL;
6613 234035bc 2019-06-01 stsp struct got_object_qid *pid;
6614 234035bc 2019-06-01 stsp struct got_reference *head_ref = NULL;
6615 9627c110 2020-04-18 stsp int ch;
6616 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
6617 234035bc 2019-06-01 stsp
6618 234035bc 2019-06-01 stsp while ((ch = getopt(argc, argv, "")) != -1) {
6619 234035bc 2019-06-01 stsp switch (ch) {
6620 234035bc 2019-06-01 stsp default:
6621 234035bc 2019-06-01 stsp usage_cherrypick();
6622 234035bc 2019-06-01 stsp /* NOTREACHED */
6623 234035bc 2019-06-01 stsp }
6624 234035bc 2019-06-01 stsp }
6625 234035bc 2019-06-01 stsp
6626 234035bc 2019-06-01 stsp argc -= optind;
6627 234035bc 2019-06-01 stsp argv += optind;
6628 234035bc 2019-06-01 stsp
6629 43012d58 2019-07-14 stsp #ifndef PROFILE
6630 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
6631 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
6632 43012d58 2019-07-14 stsp err(1, "pledge");
6633 43012d58 2019-07-14 stsp #endif
6634 234035bc 2019-06-01 stsp if (argc != 1)
6635 234035bc 2019-06-01 stsp usage_cherrypick();
6636 234035bc 2019-06-01 stsp
6637 234035bc 2019-06-01 stsp cwd = getcwd(NULL, 0);
6638 234035bc 2019-06-01 stsp if (cwd == NULL) {
6639 234035bc 2019-06-01 stsp error = got_error_from_errno("getcwd");
6640 234035bc 2019-06-01 stsp goto done;
6641 234035bc 2019-06-01 stsp }
6642 234035bc 2019-06-01 stsp error = got_worktree_open(&worktree, cwd);
6643 fa51e947 2020-03-27 stsp if (error) {
6644 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6645 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "cherrypick",
6646 fa51e947 2020-03-27 stsp cwd);
6647 234035bc 2019-06-01 stsp goto done;
6648 fa51e947 2020-03-27 stsp }
6649 234035bc 2019-06-01 stsp
6650 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6651 c9956ddf 2019-09-08 stsp NULL);
6652 234035bc 2019-06-01 stsp if (error != NULL)
6653 234035bc 2019-06-01 stsp goto done;
6654 234035bc 2019-06-01 stsp
6655 234035bc 2019-06-01 stsp error = apply_unveil(got_repo_get_path(repo), 0,
6656 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6657 234035bc 2019-06-01 stsp if (error)
6658 234035bc 2019-06-01 stsp goto done;
6659 234035bc 2019-06-01 stsp
6660 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&commit_id, argv[0],
6661 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_COMMIT, repo);
6662 234035bc 2019-06-01 stsp if (error != NULL) {
6663 234035bc 2019-06-01 stsp struct got_reference *ref;
6664 234035bc 2019-06-01 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
6665 234035bc 2019-06-01 stsp goto done;
6666 234035bc 2019-06-01 stsp error = got_ref_open(&ref, repo, argv[0], 0);
6667 234035bc 2019-06-01 stsp if (error != NULL)
6668 234035bc 2019-06-01 stsp goto done;
6669 234035bc 2019-06-01 stsp error = got_ref_resolve(&commit_id, repo, ref);
6670 234035bc 2019-06-01 stsp got_ref_close(ref);
6671 234035bc 2019-06-01 stsp if (error != NULL)
6672 234035bc 2019-06-01 stsp goto done;
6673 234035bc 2019-06-01 stsp }
6674 234035bc 2019-06-01 stsp error = got_object_id_str(&commit_id_str, commit_id);
6675 234035bc 2019-06-01 stsp if (error)
6676 234035bc 2019-06-01 stsp goto done;
6677 234035bc 2019-06-01 stsp
6678 234035bc 2019-06-01 stsp error = got_ref_open(&head_ref, repo,
6679 234035bc 2019-06-01 stsp got_worktree_get_head_ref_name(worktree), 0);
6680 234035bc 2019-06-01 stsp if (error != NULL)
6681 234035bc 2019-06-01 stsp goto done;
6682 234035bc 2019-06-01 stsp
6683 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
6684 234035bc 2019-06-01 stsp if (error) {
6685 234035bc 2019-06-01 stsp if (error->code != GOT_ERR_ANCESTRY)
6686 234035bc 2019-06-01 stsp goto done;
6687 234035bc 2019-06-01 stsp error = NULL;
6688 234035bc 2019-06-01 stsp } else {
6689 234035bc 2019-06-01 stsp error = got_error(GOT_ERR_SAME_BRANCH);
6690 234035bc 2019-06-01 stsp goto done;
6691 234035bc 2019-06-01 stsp }
6692 234035bc 2019-06-01 stsp
6693 234035bc 2019-06-01 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
6694 234035bc 2019-06-01 stsp if (error)
6695 234035bc 2019-06-01 stsp goto done;
6696 234035bc 2019-06-01 stsp pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
6697 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
6698 03415a1a 2019-06-02 stsp error = got_worktree_merge_files(worktree, pid ? pid->id : NULL,
6699 9627c110 2020-04-18 stsp commit_id, repo, update_progress, &upa, check_cancelled,
6700 03415a1a 2019-06-02 stsp NULL);
6701 234035bc 2019-06-01 stsp if (error != NULL)
6702 234035bc 2019-06-01 stsp goto done;
6703 234035bc 2019-06-01 stsp
6704 9627c110 2020-04-18 stsp if (upa.did_something)
6705 a7648d7a 2019-06-02 stsp printf("Merged commit %s\n", commit_id_str);
6706 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
6707 234035bc 2019-06-01 stsp done:
6708 234035bc 2019-06-01 stsp if (commit)
6709 234035bc 2019-06-01 stsp got_object_commit_close(commit);
6710 234035bc 2019-06-01 stsp free(commit_id_str);
6711 234035bc 2019-06-01 stsp if (head_ref)
6712 234035bc 2019-06-01 stsp got_ref_close(head_ref);
6713 234035bc 2019-06-01 stsp if (worktree)
6714 234035bc 2019-06-01 stsp got_worktree_close(worktree);
6715 234035bc 2019-06-01 stsp if (repo)
6716 234035bc 2019-06-01 stsp got_repo_close(repo);
6717 c4296144 2019-05-09 stsp return error;
6718 c4296144 2019-05-09 stsp }
6719 5ef14e63 2019-06-02 stsp
6720 5ef14e63 2019-06-02 stsp __dead static void
6721 5ef14e63 2019-06-02 stsp usage_backout(void)
6722 5ef14e63 2019-06-02 stsp {
6723 5ef14e63 2019-06-02 stsp fprintf(stderr, "usage: %s backout commit-id\n", getprogname());
6724 5ef14e63 2019-06-02 stsp exit(1);
6725 5ef14e63 2019-06-02 stsp }
6726 5ef14e63 2019-06-02 stsp
6727 5ef14e63 2019-06-02 stsp static const struct got_error *
6728 5ef14e63 2019-06-02 stsp cmd_backout(int argc, char *argv[])
6729 5ef14e63 2019-06-02 stsp {
6730 5ef14e63 2019-06-02 stsp const struct got_error *error = NULL;
6731 5ef14e63 2019-06-02 stsp struct got_worktree *worktree = NULL;
6732 5ef14e63 2019-06-02 stsp struct got_repository *repo = NULL;
6733 5ef14e63 2019-06-02 stsp char *cwd = NULL, *commit_id_str = NULL;
6734 5ef14e63 2019-06-02 stsp struct got_object_id *commit_id = NULL;
6735 5ef14e63 2019-06-02 stsp struct got_commit_object *commit = NULL;
6736 5ef14e63 2019-06-02 stsp struct got_object_qid *pid;
6737 5ef14e63 2019-06-02 stsp struct got_reference *head_ref = NULL;
6738 9627c110 2020-04-18 stsp int ch;
6739 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
6740 5ef14e63 2019-06-02 stsp
6741 5ef14e63 2019-06-02 stsp while ((ch = getopt(argc, argv, "")) != -1) {
6742 5ef14e63 2019-06-02 stsp switch (ch) {
6743 5ef14e63 2019-06-02 stsp default:
6744 5ef14e63 2019-06-02 stsp usage_backout();
6745 5ef14e63 2019-06-02 stsp /* NOTREACHED */
6746 5ef14e63 2019-06-02 stsp }
6747 5ef14e63 2019-06-02 stsp }
6748 5ef14e63 2019-06-02 stsp
6749 5ef14e63 2019-06-02 stsp argc -= optind;
6750 5ef14e63 2019-06-02 stsp argv += optind;
6751 5ef14e63 2019-06-02 stsp
6752 43012d58 2019-07-14 stsp #ifndef PROFILE
6753 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
6754 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
6755 43012d58 2019-07-14 stsp err(1, "pledge");
6756 43012d58 2019-07-14 stsp #endif
6757 5ef14e63 2019-06-02 stsp if (argc != 1)
6758 5ef14e63 2019-06-02 stsp usage_backout();
6759 5ef14e63 2019-06-02 stsp
6760 5ef14e63 2019-06-02 stsp cwd = getcwd(NULL, 0);
6761 5ef14e63 2019-06-02 stsp if (cwd == NULL) {
6762 5ef14e63 2019-06-02 stsp error = got_error_from_errno("getcwd");
6763 5ef14e63 2019-06-02 stsp goto done;
6764 5ef14e63 2019-06-02 stsp }
6765 5ef14e63 2019-06-02 stsp error = got_worktree_open(&worktree, cwd);
6766 fa51e947 2020-03-27 stsp if (error) {
6767 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
6768 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "backout", cwd);
6769 5ef14e63 2019-06-02 stsp goto done;
6770 fa51e947 2020-03-27 stsp }
6771 5ef14e63 2019-06-02 stsp
6772 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6773 c9956ddf 2019-09-08 stsp NULL);
6774 5ef14e63 2019-06-02 stsp if (error != NULL)
6775 5ef14e63 2019-06-02 stsp goto done;
6776 5ef14e63 2019-06-02 stsp
6777 5ef14e63 2019-06-02 stsp error = apply_unveil(got_repo_get_path(repo), 0,
6778 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
6779 5ef14e63 2019-06-02 stsp if (error)
6780 5ef14e63 2019-06-02 stsp goto done;
6781 5ef14e63 2019-06-02 stsp
6782 dd88155e 2019-06-29 stsp error = got_repo_match_object_id_prefix(&commit_id, argv[0],
6783 dd88155e 2019-06-29 stsp GOT_OBJ_TYPE_COMMIT, repo);
6784 5ef14e63 2019-06-02 stsp if (error != NULL) {
6785 5ef14e63 2019-06-02 stsp struct got_reference *ref;
6786 5ef14e63 2019-06-02 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR)
6787 5ef14e63 2019-06-02 stsp goto done;
6788 5ef14e63 2019-06-02 stsp error = got_ref_open(&ref, repo, argv[0], 0);
6789 5ef14e63 2019-06-02 stsp if (error != NULL)
6790 5ef14e63 2019-06-02 stsp goto done;
6791 5ef14e63 2019-06-02 stsp error = got_ref_resolve(&commit_id, repo, ref);
6792 5ef14e63 2019-06-02 stsp got_ref_close(ref);
6793 5ef14e63 2019-06-02 stsp if (error != NULL)
6794 5ef14e63 2019-06-02 stsp goto done;
6795 5ef14e63 2019-06-02 stsp }
6796 5ef14e63 2019-06-02 stsp error = got_object_id_str(&commit_id_str, commit_id);
6797 5ef14e63 2019-06-02 stsp if (error)
6798 5ef14e63 2019-06-02 stsp goto done;
6799 5ef14e63 2019-06-02 stsp
6800 5ef14e63 2019-06-02 stsp error = got_ref_open(&head_ref, repo,
6801 5ef14e63 2019-06-02 stsp got_worktree_get_head_ref_name(worktree), 0);
6802 5ef14e63 2019-06-02 stsp if (error != NULL)
6803 5ef14e63 2019-06-02 stsp goto done;
6804 5ef14e63 2019-06-02 stsp
6805 a51a74b3 2019-07-27 stsp error = check_same_branch(commit_id, head_ref, NULL, repo);
6806 5ef14e63 2019-06-02 stsp if (error)
6807 5ef14e63 2019-06-02 stsp goto done;
6808 5ef14e63 2019-06-02 stsp
6809 5ef14e63 2019-06-02 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
6810 5ef14e63 2019-06-02 stsp if (error)
6811 5ef14e63 2019-06-02 stsp goto done;
6812 5ef14e63 2019-06-02 stsp pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
6813 5ef14e63 2019-06-02 stsp if (pid == NULL) {
6814 5ef14e63 2019-06-02 stsp error = got_error(GOT_ERR_ROOT_COMMIT);
6815 5ef14e63 2019-06-02 stsp goto done;
6816 5ef14e63 2019-06-02 stsp }
6817 5ef14e63 2019-06-02 stsp
6818 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
6819 5ef14e63 2019-06-02 stsp error = got_worktree_merge_files(worktree, commit_id, pid->id, repo,
6820 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
6821 5ef14e63 2019-06-02 stsp if (error != NULL)
6822 5ef14e63 2019-06-02 stsp goto done;
6823 5ef14e63 2019-06-02 stsp
6824 9627c110 2020-04-18 stsp if (upa.did_something)
6825 a7648d7a 2019-06-02 stsp printf("Backed out commit %s\n", commit_id_str);
6826 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
6827 5ef14e63 2019-06-02 stsp done:
6828 5ef14e63 2019-06-02 stsp if (commit)
6829 5ef14e63 2019-06-02 stsp got_object_commit_close(commit);
6830 5ef14e63 2019-06-02 stsp free(commit_id_str);
6831 5ef14e63 2019-06-02 stsp if (head_ref)
6832 5ef14e63 2019-06-02 stsp got_ref_close(head_ref);
6833 818c7501 2019-07-11 stsp if (worktree)
6834 818c7501 2019-07-11 stsp got_worktree_close(worktree);
6835 818c7501 2019-07-11 stsp if (repo)
6836 818c7501 2019-07-11 stsp got_repo_close(repo);
6837 818c7501 2019-07-11 stsp return error;
6838 818c7501 2019-07-11 stsp }
6839 818c7501 2019-07-11 stsp
6840 818c7501 2019-07-11 stsp __dead static void
6841 818c7501 2019-07-11 stsp usage_rebase(void)
6842 818c7501 2019-07-11 stsp {
6843 af54c8f8 2019-07-11 stsp fprintf(stderr, "usage: %s rebase [-a] | [-c] | branch\n",
6844 af54c8f8 2019-07-11 stsp getprogname());
6845 818c7501 2019-07-11 stsp exit(1);
6846 0ebf8283 2019-07-24 stsp }
6847 0ebf8283 2019-07-24 stsp
6848 0ebf8283 2019-07-24 stsp void
6849 0ebf8283 2019-07-24 stsp trim_logmsg(char *logmsg, int limit)
6850 0ebf8283 2019-07-24 stsp {
6851 0ebf8283 2019-07-24 stsp char *nl;
6852 0ebf8283 2019-07-24 stsp size_t len;
6853 0ebf8283 2019-07-24 stsp
6854 0ebf8283 2019-07-24 stsp len = strlen(logmsg);
6855 0ebf8283 2019-07-24 stsp if (len > limit)
6856 0ebf8283 2019-07-24 stsp len = limit;
6857 0ebf8283 2019-07-24 stsp logmsg[len] = '\0';
6858 0ebf8283 2019-07-24 stsp nl = strchr(logmsg, '\n');
6859 0ebf8283 2019-07-24 stsp if (nl)
6860 0ebf8283 2019-07-24 stsp *nl = '\0';
6861 0ebf8283 2019-07-24 stsp }
6862 0ebf8283 2019-07-24 stsp
6863 0ebf8283 2019-07-24 stsp static const struct got_error *
6864 0ebf8283 2019-07-24 stsp get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
6865 0ebf8283 2019-07-24 stsp {
6866 5943eee2 2019-08-13 stsp const struct got_error *err;
6867 5943eee2 2019-08-13 stsp char *logmsg0 = NULL;
6868 5943eee2 2019-08-13 stsp const char *s;
6869 0ebf8283 2019-07-24 stsp
6870 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&logmsg0, commit);
6871 5943eee2 2019-08-13 stsp if (err)
6872 5943eee2 2019-08-13 stsp return err;
6873 0ebf8283 2019-07-24 stsp
6874 5943eee2 2019-08-13 stsp s = logmsg0;
6875 5943eee2 2019-08-13 stsp while (isspace((unsigned char)s[0]))
6876 5943eee2 2019-08-13 stsp s++;
6877 5943eee2 2019-08-13 stsp
6878 5943eee2 2019-08-13 stsp *logmsg = strdup(s);
6879 5943eee2 2019-08-13 stsp if (*logmsg == NULL) {
6880 5943eee2 2019-08-13 stsp err = got_error_from_errno("strdup");
6881 5943eee2 2019-08-13 stsp goto done;
6882 5943eee2 2019-08-13 stsp }
6883 0ebf8283 2019-07-24 stsp
6884 0ebf8283 2019-07-24 stsp trim_logmsg(*logmsg, limit);
6885 5943eee2 2019-08-13 stsp done:
6886 5943eee2 2019-08-13 stsp free(logmsg0);
6887 a0ea4fc0 2020-02-28 stsp return err;
6888 a0ea4fc0 2020-02-28 stsp }
6889 a0ea4fc0 2020-02-28 stsp
6890 a0ea4fc0 2020-02-28 stsp static const struct got_error *
6891 a0ea4fc0 2020-02-28 stsp show_rebase_merge_conflict(struct got_object_id *id, struct got_repository *repo)
6892 a0ea4fc0 2020-02-28 stsp {
6893 a0ea4fc0 2020-02-28 stsp const struct got_error *err;
6894 a0ea4fc0 2020-02-28 stsp struct got_commit_object *commit = NULL;
6895 a0ea4fc0 2020-02-28 stsp char *id_str = NULL, *logmsg = NULL;
6896 a0ea4fc0 2020-02-28 stsp
6897 a0ea4fc0 2020-02-28 stsp err = got_object_open_as_commit(&commit, repo, id);
6898 a0ea4fc0 2020-02-28 stsp if (err)
6899 a0ea4fc0 2020-02-28 stsp return err;
6900 a0ea4fc0 2020-02-28 stsp
6901 a0ea4fc0 2020-02-28 stsp err = got_object_id_str(&id_str, id);
6902 a0ea4fc0 2020-02-28 stsp if (err)
6903 a0ea4fc0 2020-02-28 stsp goto done;
6904 a0ea4fc0 2020-02-28 stsp
6905 a0ea4fc0 2020-02-28 stsp id_str[12] = '\0';
6906 a0ea4fc0 2020-02-28 stsp
6907 a0ea4fc0 2020-02-28 stsp err = get_short_logmsg(&logmsg, 42, commit);
6908 a0ea4fc0 2020-02-28 stsp if (err)
6909 a0ea4fc0 2020-02-28 stsp goto done;
6910 a0ea4fc0 2020-02-28 stsp
6911 a0ea4fc0 2020-02-28 stsp printf("%s -> merge conflict: %s\n", id_str, logmsg);
6912 a0ea4fc0 2020-02-28 stsp done:
6913 a0ea4fc0 2020-02-28 stsp free(id_str);
6914 a0ea4fc0 2020-02-28 stsp got_object_commit_close(commit);
6915 a0ea4fc0 2020-02-28 stsp free(logmsg);
6916 5943eee2 2019-08-13 stsp return err;
6917 818c7501 2019-07-11 stsp }
6918 818c7501 2019-07-11 stsp
6919 818c7501 2019-07-11 stsp static const struct got_error *
6920 818c7501 2019-07-11 stsp show_rebase_progress(struct got_commit_object *commit,
6921 818c7501 2019-07-11 stsp struct got_object_id *old_id, struct got_object_id *new_id)
6922 818c7501 2019-07-11 stsp {
6923 818c7501 2019-07-11 stsp const struct got_error *err;
6924 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
6925 818c7501 2019-07-11 stsp
6926 818c7501 2019-07-11 stsp err = got_object_id_str(&old_id_str, old_id);
6927 818c7501 2019-07-11 stsp if (err)
6928 818c7501 2019-07-11 stsp goto done;
6929 818c7501 2019-07-11 stsp
6930 ff0d2220 2019-07-11 stsp if (new_id) {
6931 ff0d2220 2019-07-11 stsp err = got_object_id_str(&new_id_str, new_id);
6932 ff0d2220 2019-07-11 stsp if (err)
6933 ff0d2220 2019-07-11 stsp goto done;
6934 ff0d2220 2019-07-11 stsp }
6935 818c7501 2019-07-11 stsp
6936 818c7501 2019-07-11 stsp old_id_str[12] = '\0';
6937 ff0d2220 2019-07-11 stsp if (new_id_str)
6938 ff0d2220 2019-07-11 stsp new_id_str[12] = '\0';
6939 0ebf8283 2019-07-24 stsp
6940 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
6941 0ebf8283 2019-07-24 stsp if (err)
6942 0ebf8283 2019-07-24 stsp goto done;
6943 0ebf8283 2019-07-24 stsp
6944 ff0d2220 2019-07-11 stsp printf("%s -> %s: %s\n", old_id_str,
6945 ff0d2220 2019-07-11 stsp new_id_str ? new_id_str : "no-op change", logmsg);
6946 818c7501 2019-07-11 stsp done:
6947 818c7501 2019-07-11 stsp free(old_id_str);
6948 818c7501 2019-07-11 stsp free(new_id_str);
6949 272a1371 2020-02-28 stsp free(logmsg);
6950 818c7501 2019-07-11 stsp return err;
6951 818c7501 2019-07-11 stsp }
6952 818c7501 2019-07-11 stsp
6953 1ee397ad 2019-07-12 stsp static const struct got_error *
6954 3e3a69f1 2019-07-25 stsp rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
6955 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_reference *new_base_branch,
6956 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch, struct got_repository *repo)
6957 818c7501 2019-07-11 stsp {
6958 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n", got_ref_get_name(branch));
6959 3e3a69f1 2019-07-25 stsp return got_worktree_rebase_complete(worktree, fileindex,
6960 818c7501 2019-07-11 stsp new_base_branch, tmp_branch, branch, repo);
6961 818c7501 2019-07-11 stsp }
6962 818c7501 2019-07-11 stsp
6963 818c7501 2019-07-11 stsp static const struct got_error *
6964 01757395 2019-07-12 stsp rebase_commit(struct got_pathlist_head *merged_paths,
6965 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
6966 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch,
6967 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id, struct got_repository *repo)
6968 ff0d2220 2019-07-11 stsp {
6969 ff0d2220 2019-07-11 stsp const struct got_error *error;
6970 ff0d2220 2019-07-11 stsp struct got_commit_object *commit;
6971 ff0d2220 2019-07-11 stsp struct got_object_id *new_commit_id;
6972 ff0d2220 2019-07-11 stsp
6973 ff0d2220 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
6974 ff0d2220 2019-07-11 stsp if (error)
6975 ff0d2220 2019-07-11 stsp return error;
6976 ff0d2220 2019-07-11 stsp
6977 01757395 2019-07-12 stsp error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
6978 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, commit_id, repo);
6979 ff0d2220 2019-07-11 stsp if (error) {
6980 ff0d2220 2019-07-11 stsp if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
6981 ff0d2220 2019-07-11 stsp goto done;
6982 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, NULL);
6983 ff0d2220 2019-07-11 stsp } else {
6984 ff0d2220 2019-07-11 stsp error = show_rebase_progress(commit, commit_id, new_commit_id);
6985 ff0d2220 2019-07-11 stsp free(new_commit_id);
6986 ff0d2220 2019-07-11 stsp }
6987 ff0d2220 2019-07-11 stsp done:
6988 ff0d2220 2019-07-11 stsp got_object_commit_close(commit);
6989 ff0d2220 2019-07-11 stsp return error;
6990 64c6d990 2019-07-11 stsp }
6991 64c6d990 2019-07-11 stsp
6992 64c6d990 2019-07-11 stsp struct check_path_prefix_arg {
6993 64c6d990 2019-07-11 stsp const char *path_prefix;
6994 64c6d990 2019-07-11 stsp size_t len;
6995 8ca9bd68 2019-07-25 stsp int errcode;
6996 64c6d990 2019-07-11 stsp };
6997 64c6d990 2019-07-11 stsp
6998 64c6d990 2019-07-11 stsp static const struct got_error *
6999 8ca9bd68 2019-07-25 stsp check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
7000 64c6d990 2019-07-11 stsp struct got_blob_object *blob2, struct got_object_id *id1,
7001 64c6d990 2019-07-11 stsp struct got_object_id *id2, const char *path1, const char *path2,
7002 46f68b20 2019-10-19 stsp mode_t mode1, mode_t mode2, struct got_repository *repo)
7003 64c6d990 2019-07-11 stsp {
7004 64c6d990 2019-07-11 stsp struct check_path_prefix_arg *a = arg;
7005 64c6d990 2019-07-11 stsp
7006 64c6d990 2019-07-11 stsp if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
7007 64c6d990 2019-07-11 stsp (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
7008 8ca9bd68 2019-07-25 stsp return got_error(a->errcode);
7009 64c6d990 2019-07-11 stsp
7010 64c6d990 2019-07-11 stsp return NULL;
7011 64c6d990 2019-07-11 stsp }
7012 64c6d990 2019-07-11 stsp
7013 64c6d990 2019-07-11 stsp static const struct got_error *
7014 8ca9bd68 2019-07-25 stsp check_path_prefix(struct got_object_id *parent_id,
7015 64c6d990 2019-07-11 stsp struct got_object_id *commit_id, const char *path_prefix,
7016 8ca9bd68 2019-07-25 stsp int errcode, struct got_repository *repo)
7017 64c6d990 2019-07-11 stsp {
7018 64c6d990 2019-07-11 stsp const struct got_error *err;
7019 64c6d990 2019-07-11 stsp struct got_tree_object *tree1 = NULL, *tree2 = NULL;
7020 64c6d990 2019-07-11 stsp struct got_commit_object *commit = NULL, *parent_commit = NULL;
7021 64c6d990 2019-07-11 stsp struct check_path_prefix_arg cpp_arg;
7022 64c6d990 2019-07-11 stsp
7023 64c6d990 2019-07-11 stsp if (got_path_is_root_dir(path_prefix))
7024 64c6d990 2019-07-11 stsp return NULL;
7025 64c6d990 2019-07-11 stsp
7026 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
7027 64c6d990 2019-07-11 stsp if (err)
7028 64c6d990 2019-07-11 stsp goto done;
7029 64c6d990 2019-07-11 stsp
7030 64c6d990 2019-07-11 stsp err = got_object_open_as_commit(&parent_commit, repo, parent_id);
7031 64c6d990 2019-07-11 stsp if (err)
7032 64c6d990 2019-07-11 stsp goto done;
7033 64c6d990 2019-07-11 stsp
7034 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree1, repo,
7035 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(parent_commit));
7036 64c6d990 2019-07-11 stsp if (err)
7037 64c6d990 2019-07-11 stsp goto done;
7038 64c6d990 2019-07-11 stsp
7039 64c6d990 2019-07-11 stsp err = got_object_open_as_tree(&tree2, repo,
7040 64c6d990 2019-07-11 stsp got_object_commit_get_tree_id(commit));
7041 64c6d990 2019-07-11 stsp if (err)
7042 64c6d990 2019-07-11 stsp goto done;
7043 64c6d990 2019-07-11 stsp
7044 64c6d990 2019-07-11 stsp cpp_arg.path_prefix = path_prefix;
7045 d23ace97 2019-07-25 stsp while (cpp_arg.path_prefix[0] == '/')
7046 d23ace97 2019-07-25 stsp cpp_arg.path_prefix++;
7047 d23ace97 2019-07-25 stsp cpp_arg.len = strlen(cpp_arg.path_prefix);
7048 8ca9bd68 2019-07-25 stsp cpp_arg.errcode = errcode;
7049 8ca9bd68 2019-07-25 stsp err = got_diff_tree(tree1, tree2, "", "", repo,
7050 31b4484f 2019-07-27 stsp check_path_prefix_in_diff, &cpp_arg, 0);
7051 64c6d990 2019-07-11 stsp done:
7052 64c6d990 2019-07-11 stsp if (tree1)
7053 64c6d990 2019-07-11 stsp got_object_tree_close(tree1);
7054 64c6d990 2019-07-11 stsp if (tree2)
7055 64c6d990 2019-07-11 stsp got_object_tree_close(tree2);
7056 64c6d990 2019-07-11 stsp if (commit)
7057 64c6d990 2019-07-11 stsp got_object_commit_close(commit);
7058 64c6d990 2019-07-11 stsp if (parent_commit)
7059 64c6d990 2019-07-11 stsp got_object_commit_close(parent_commit);
7060 64c6d990 2019-07-11 stsp return err;
7061 ff0d2220 2019-07-11 stsp }
7062 ff0d2220 2019-07-11 stsp
7063 ff0d2220 2019-07-11 stsp static const struct got_error *
7064 8ca9bd68 2019-07-25 stsp collect_commits(struct got_object_id_queue *commits,
7065 af61c510 2019-07-19 stsp struct got_object_id *initial_commit_id,
7066 af61c510 2019-07-19 stsp struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
7067 8ca9bd68 2019-07-25 stsp const char *path_prefix, int path_prefix_errcode,
7068 8ca9bd68 2019-07-25 stsp struct got_repository *repo)
7069 af61c510 2019-07-19 stsp {
7070 af61c510 2019-07-19 stsp const struct got_error *err = NULL;
7071 af61c510 2019-07-19 stsp struct got_commit_graph *graph = NULL;
7072 af61c510 2019-07-19 stsp struct got_object_id *parent_id = NULL;
7073 af61c510 2019-07-19 stsp struct got_object_qid *qid;
7074 af61c510 2019-07-19 stsp struct got_object_id *commit_id = initial_commit_id;
7075 af61c510 2019-07-19 stsp
7076 3d509237 2020-01-04 stsp err = got_commit_graph_open(&graph, "/", 1);
7077 af61c510 2019-07-19 stsp if (err)
7078 af61c510 2019-07-19 stsp return err;
7079 af61c510 2019-07-19 stsp
7080 6fb7cd11 2019-08-22 stsp err = got_commit_graph_iter_start(graph, iter_start_id, repo,
7081 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
7082 af61c510 2019-07-19 stsp if (err)
7083 af61c510 2019-07-19 stsp goto done;
7084 af61c510 2019-07-19 stsp while (got_object_id_cmp(commit_id, iter_stop_id) != 0) {
7085 ee780d5c 2020-01-04 stsp err = got_commit_graph_iter_next(&parent_id, graph, repo,
7086 ee780d5c 2020-01-04 stsp check_cancelled, NULL);
7087 af61c510 2019-07-19 stsp if (err) {
7088 af61c510 2019-07-19 stsp if (err->code == GOT_ERR_ITER_COMPLETED) {
7089 af61c510 2019-07-19 stsp err = got_error_msg(GOT_ERR_ANCESTRY,
7090 af61c510 2019-07-19 stsp "ran out of commits to rebase before "
7091 af61c510 2019-07-19 stsp "youngest common ancestor commit has "
7092 af61c510 2019-07-19 stsp "been reached?!?");
7093 ee780d5c 2020-01-04 stsp }
7094 ee780d5c 2020-01-04 stsp goto done;
7095 af61c510 2019-07-19 stsp } else {
7096 8ca9bd68 2019-07-25 stsp err = check_path_prefix(parent_id, commit_id,
7097 8ca9bd68 2019-07-25 stsp path_prefix, path_prefix_errcode, repo);
7098 af61c510 2019-07-19 stsp if (err)
7099 af61c510 2019-07-19 stsp goto done;
7100 af61c510 2019-07-19 stsp
7101 af61c510 2019-07-19 stsp err = got_object_qid_alloc(&qid, commit_id);
7102 af61c510 2019-07-19 stsp if (err)
7103 af61c510 2019-07-19 stsp goto done;
7104 af61c510 2019-07-19 stsp SIMPLEQ_INSERT_HEAD(commits, qid, entry);
7105 af61c510 2019-07-19 stsp commit_id = parent_id;
7106 af61c510 2019-07-19 stsp }
7107 af61c510 2019-07-19 stsp }
7108 af61c510 2019-07-19 stsp done:
7109 af61c510 2019-07-19 stsp got_commit_graph_close(graph);
7110 af61c510 2019-07-19 stsp return err;
7111 af61c510 2019-07-19 stsp }
7112 af61c510 2019-07-19 stsp
7113 af61c510 2019-07-19 stsp static const struct got_error *
7114 818c7501 2019-07-11 stsp cmd_rebase(int argc, char *argv[])
7115 818c7501 2019-07-11 stsp {
7116 818c7501 2019-07-11 stsp const struct got_error *error = NULL;
7117 818c7501 2019-07-11 stsp struct got_worktree *worktree = NULL;
7118 818c7501 2019-07-11 stsp struct got_repository *repo = NULL;
7119 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
7120 818c7501 2019-07-11 stsp char *cwd = NULL;
7121 818c7501 2019-07-11 stsp struct got_reference *branch = NULL;
7122 818c7501 2019-07-11 stsp struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
7123 818c7501 2019-07-11 stsp struct got_object_id *commit_id = NULL, *parent_id = NULL;
7124 818c7501 2019-07-11 stsp struct got_object_id *resume_commit_id = NULL;
7125 818c7501 2019-07-11 stsp struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
7126 818c7501 2019-07-11 stsp struct got_commit_object *commit = NULL;
7127 818c7501 2019-07-11 stsp int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
7128 7ef62c4e 2020-02-24 stsp int histedit_in_progress = 0;
7129 818c7501 2019-07-11 stsp unsigned char rebase_status = GOT_STATUS_NO_CHANGE;
7130 818c7501 2019-07-11 stsp struct got_object_id_queue commits;
7131 01757395 2019-07-12 stsp struct got_pathlist_head merged_paths;
7132 818c7501 2019-07-11 stsp const struct got_object_id_queue *parent_ids;
7133 818c7501 2019-07-11 stsp struct got_object_qid *qid, *pid;
7134 818c7501 2019-07-11 stsp
7135 818c7501 2019-07-11 stsp SIMPLEQ_INIT(&commits);
7136 01757395 2019-07-12 stsp TAILQ_INIT(&merged_paths);
7137 818c7501 2019-07-11 stsp
7138 818c7501 2019-07-11 stsp while ((ch = getopt(argc, argv, "ac")) != -1) {
7139 818c7501 2019-07-11 stsp switch (ch) {
7140 818c7501 2019-07-11 stsp case 'a':
7141 818c7501 2019-07-11 stsp abort_rebase = 1;
7142 818c7501 2019-07-11 stsp break;
7143 818c7501 2019-07-11 stsp case 'c':
7144 818c7501 2019-07-11 stsp continue_rebase = 1;
7145 818c7501 2019-07-11 stsp break;
7146 818c7501 2019-07-11 stsp default:
7147 818c7501 2019-07-11 stsp usage_rebase();
7148 818c7501 2019-07-11 stsp /* NOTREACHED */
7149 818c7501 2019-07-11 stsp }
7150 818c7501 2019-07-11 stsp }
7151 818c7501 2019-07-11 stsp
7152 818c7501 2019-07-11 stsp argc -= optind;
7153 818c7501 2019-07-11 stsp argv += optind;
7154 818c7501 2019-07-11 stsp
7155 43012d58 2019-07-14 stsp #ifndef PROFILE
7156 43012d58 2019-07-14 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
7157 43012d58 2019-07-14 stsp "unveil", NULL) == -1)
7158 43012d58 2019-07-14 stsp err(1, "pledge");
7159 43012d58 2019-07-14 stsp #endif
7160 818c7501 2019-07-11 stsp if (abort_rebase && continue_rebase)
7161 818c7501 2019-07-11 stsp usage_rebase();
7162 818c7501 2019-07-11 stsp else if (abort_rebase || continue_rebase) {
7163 818c7501 2019-07-11 stsp if (argc != 0)
7164 818c7501 2019-07-11 stsp usage_rebase();
7165 818c7501 2019-07-11 stsp } else if (argc != 1)
7166 818c7501 2019-07-11 stsp usage_rebase();
7167 818c7501 2019-07-11 stsp
7168 818c7501 2019-07-11 stsp cwd = getcwd(NULL, 0);
7169 818c7501 2019-07-11 stsp if (cwd == NULL) {
7170 818c7501 2019-07-11 stsp error = got_error_from_errno("getcwd");
7171 818c7501 2019-07-11 stsp goto done;
7172 818c7501 2019-07-11 stsp }
7173 818c7501 2019-07-11 stsp error = got_worktree_open(&worktree, cwd);
7174 fa51e947 2020-03-27 stsp if (error) {
7175 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
7176 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "rebase", cwd);
7177 818c7501 2019-07-11 stsp goto done;
7178 fa51e947 2020-03-27 stsp }
7179 818c7501 2019-07-11 stsp
7180 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7181 c9956ddf 2019-09-08 stsp NULL);
7182 818c7501 2019-07-11 stsp if (error != NULL)
7183 818c7501 2019-07-11 stsp goto done;
7184 818c7501 2019-07-11 stsp
7185 818c7501 2019-07-11 stsp error = apply_unveil(got_repo_get_path(repo), 0,
7186 c530dc23 2019-07-23 stsp got_worktree_get_root_path(worktree));
7187 7ef62c4e 2020-02-24 stsp if (error)
7188 7ef62c4e 2020-02-24 stsp goto done;
7189 7ef62c4e 2020-02-24 stsp
7190 7ef62c4e 2020-02-24 stsp error = got_worktree_histedit_in_progress(&histedit_in_progress,
7191 7ef62c4e 2020-02-24 stsp worktree);
7192 818c7501 2019-07-11 stsp if (error)
7193 7ef62c4e 2020-02-24 stsp goto done;
7194 7ef62c4e 2020-02-24 stsp if (histedit_in_progress) {
7195 7ef62c4e 2020-02-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
7196 818c7501 2019-07-11 stsp goto done;
7197 7ef62c4e 2020-02-24 stsp }
7198 818c7501 2019-07-11 stsp
7199 818c7501 2019-07-11 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
7200 818c7501 2019-07-11 stsp if (error)
7201 818c7501 2019-07-11 stsp goto done;
7202 818c7501 2019-07-11 stsp
7203 f6794adc 2019-07-23 stsp if (abort_rebase) {
7204 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
7205 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
7206 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
7207 f6794adc 2019-07-23 stsp goto done;
7208 f6794adc 2019-07-23 stsp }
7209 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
7210 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
7211 3e3a69f1 2019-07-25 stsp worktree, repo);
7212 818c7501 2019-07-11 stsp if (error)
7213 818c7501 2019-07-11 stsp goto done;
7214 818c7501 2019-07-11 stsp printf("Switching work tree to %s\n",
7215 818c7501 2019-07-11 stsp got_ref_get_symref_target(new_base_branch));
7216 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
7217 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_abort(worktree, fileindex, repo,
7218 9627c110 2020-04-18 stsp new_base_branch, update_progress, &upa);
7219 818c7501 2019-07-11 stsp if (error)
7220 818c7501 2019-07-11 stsp goto done;
7221 818c7501 2019-07-11 stsp printf("Rebase of %s aborted\n", got_ref_get_name(branch));
7222 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
7223 818c7501 2019-07-11 stsp goto done; /* nothing else to do */
7224 818c7501 2019-07-11 stsp }
7225 818c7501 2019-07-11 stsp
7226 818c7501 2019-07-11 stsp if (continue_rebase) {
7227 f6794adc 2019-07-23 stsp if (!rebase_in_progress) {
7228 f6794adc 2019-07-23 stsp error = got_error(GOT_ERR_NOT_REBASING);
7229 f6794adc 2019-07-23 stsp goto done;
7230 f6794adc 2019-07-23 stsp }
7231 818c7501 2019-07-11 stsp error = got_worktree_rebase_continue(&resume_commit_id,
7232 3e3a69f1 2019-07-25 stsp &new_base_branch, &tmp_branch, &branch, &fileindex,
7233 3e3a69f1 2019-07-25 stsp worktree, repo);
7234 818c7501 2019-07-11 stsp if (error)
7235 818c7501 2019-07-11 stsp goto done;
7236 818c7501 2019-07-11 stsp
7237 3e3a69f1 2019-07-25 stsp error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
7238 01757395 2019-07-12 stsp resume_commit_id, repo);
7239 818c7501 2019-07-11 stsp if (error)
7240 818c7501 2019-07-11 stsp goto done;
7241 818c7501 2019-07-11 stsp
7242 ff0d2220 2019-07-11 stsp yca_id = got_object_id_dup(resume_commit_id);
7243 ff0d2220 2019-07-11 stsp if (yca_id == NULL) {
7244 818c7501 2019-07-11 stsp error = got_error_from_errno("got_object_id_dup");
7245 818c7501 2019-07-11 stsp goto done;
7246 818c7501 2019-07-11 stsp }
7247 818c7501 2019-07-11 stsp } else {
7248 818c7501 2019-07-11 stsp error = got_ref_open(&branch, repo, argv[0], 0);
7249 818c7501 2019-07-11 stsp if (error != NULL)
7250 818c7501 2019-07-11 stsp goto done;
7251 ff0d2220 2019-07-11 stsp }
7252 818c7501 2019-07-11 stsp
7253 ff0d2220 2019-07-11 stsp error = got_ref_resolve(&branch_head_commit_id, repo, branch);
7254 ff0d2220 2019-07-11 stsp if (error)
7255 ff0d2220 2019-07-11 stsp goto done;
7256 ff0d2220 2019-07-11 stsp
7257 ff0d2220 2019-07-11 stsp if (!continue_rebase) {
7258 a51a74b3 2019-07-27 stsp struct got_object_id *base_commit_id;
7259 a51a74b3 2019-07-27 stsp
7260 a51a74b3 2019-07-27 stsp base_commit_id = got_worktree_get_base_commit_id(worktree);
7261 818c7501 2019-07-11 stsp error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
7262 6fb7cd11 2019-08-22 stsp base_commit_id, branch_head_commit_id, repo,
7263 6fb7cd11 2019-08-22 stsp check_cancelled, NULL);
7264 818c7501 2019-07-11 stsp if (error)
7265 818c7501 2019-07-11 stsp goto done;
7266 818c7501 2019-07-11 stsp if (yca_id == NULL) {
7267 818c7501 2019-07-11 stsp error = got_error_msg(GOT_ERR_ANCESTRY,
7268 818c7501 2019-07-11 stsp "specified branch shares no common ancestry "
7269 818c7501 2019-07-11 stsp "with work tree's branch");
7270 818c7501 2019-07-11 stsp goto done;
7271 818c7501 2019-07-11 stsp }
7272 818c7501 2019-07-11 stsp
7273 a51a74b3 2019-07-27 stsp error = check_same_branch(base_commit_id, branch, yca_id, repo);
7274 a51a74b3 2019-07-27 stsp if (error) {
7275 a51a74b3 2019-07-27 stsp if (error->code != GOT_ERR_ANCESTRY)
7276 a51a74b3 2019-07-27 stsp goto done;
7277 a51a74b3 2019-07-27 stsp error = NULL;
7278 a51a74b3 2019-07-27 stsp } else {
7279 a51a74b3 2019-07-27 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH,
7280 a51a74b3 2019-07-27 stsp "specified branch resolves to a commit which "
7281 a51a74b3 2019-07-27 stsp "is already contained in work tree's branch");
7282 a51a74b3 2019-07-27 stsp goto done;
7283 a51a74b3 2019-07-27 stsp }
7284 818c7501 2019-07-11 stsp error = got_worktree_rebase_prepare(&new_base_branch,
7285 3e3a69f1 2019-07-25 stsp &tmp_branch, &fileindex, worktree, branch, repo);
7286 818c7501 2019-07-11 stsp if (error)
7287 818c7501 2019-07-11 stsp goto done;
7288 818c7501 2019-07-11 stsp }
7289 818c7501 2019-07-11 stsp
7290 ff0d2220 2019-07-11 stsp commit_id = branch_head_commit_id;
7291 818c7501 2019-07-11 stsp error = got_object_open_as_commit(&commit, repo, commit_id);
7292 818c7501 2019-07-11 stsp if (error)
7293 818c7501 2019-07-11 stsp goto done;
7294 818c7501 2019-07-11 stsp
7295 818c7501 2019-07-11 stsp parent_ids = got_object_commit_get_parent_ids(commit);
7296 818c7501 2019-07-11 stsp pid = SIMPLEQ_FIRST(parent_ids);
7297 fc66b545 2019-08-12 stsp if (pid == NULL) {
7298 fc66b545 2019-08-12 stsp if (!continue_rebase) {
7299 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
7300 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
7301 fc66b545 2019-08-12 stsp error = got_worktree_rebase_abort(worktree, fileindex,
7302 9627c110 2020-04-18 stsp repo, new_base_branch, update_progress, &upa);
7303 fc66b545 2019-08-12 stsp if (error)
7304 fc66b545 2019-08-12 stsp goto done;
7305 fc66b545 2019-08-12 stsp printf("Rebase of %s aborted\n",
7306 fc66b545 2019-08-12 stsp got_ref_get_name(branch));
7307 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
7308 9627c110 2020-04-18 stsp
7309 fc66b545 2019-08-12 stsp }
7310 fc66b545 2019-08-12 stsp error = got_error(GOT_ERR_EMPTY_REBASE);
7311 fc66b545 2019-08-12 stsp goto done;
7312 fc66b545 2019-08-12 stsp }
7313 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, commit_id, pid->id,
7314 8ca9bd68 2019-07-25 stsp yca_id, got_worktree_get_path_prefix(worktree),
7315 8ca9bd68 2019-07-25 stsp GOT_ERR_REBASE_PATH, repo);
7316 818c7501 2019-07-11 stsp got_object_commit_close(commit);
7317 818c7501 2019-07-11 stsp commit = NULL;
7318 818c7501 2019-07-11 stsp if (error)
7319 818c7501 2019-07-11 stsp goto done;
7320 64c6d990 2019-07-11 stsp
7321 818c7501 2019-07-11 stsp if (SIMPLEQ_EMPTY(&commits)) {
7322 38b0338b 2019-11-29 stsp if (continue_rebase) {
7323 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex,
7324 3e3a69f1 2019-07-25 stsp branch, new_base_branch, tmp_branch, repo);
7325 38b0338b 2019-11-29 stsp goto done;
7326 38b0338b 2019-11-29 stsp } else {
7327 38b0338b 2019-11-29 stsp /* Fast-forward the reference of the branch. */
7328 38b0338b 2019-11-29 stsp struct got_object_id *new_head_commit_id;
7329 38b0338b 2019-11-29 stsp char *id_str;
7330 38b0338b 2019-11-29 stsp error = got_ref_resolve(&new_head_commit_id, repo,
7331 38b0338b 2019-11-29 stsp new_base_branch);
7332 38b0338b 2019-11-29 stsp if (error)
7333 38b0338b 2019-11-29 stsp goto done;
7334 38b0338b 2019-11-29 stsp error = got_object_id_str(&id_str, new_head_commit_id);
7335 38b0338b 2019-11-29 stsp printf("Forwarding %s to commit %s\n",
7336 38b0338b 2019-11-29 stsp got_ref_get_name(branch), id_str);
7337 38b0338b 2019-11-29 stsp free(id_str);
7338 38b0338b 2019-11-29 stsp error = got_ref_change_ref(branch,
7339 38b0338b 2019-11-29 stsp new_head_commit_id);
7340 38b0338b 2019-11-29 stsp if (error)
7341 38b0338b 2019-11-29 stsp goto done;
7342 38b0338b 2019-11-29 stsp }
7343 818c7501 2019-07-11 stsp }
7344 818c7501 2019-07-11 stsp
7345 818c7501 2019-07-11 stsp pid = NULL;
7346 818c7501 2019-07-11 stsp SIMPLEQ_FOREACH(qid, &commits, entry) {
7347 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
7348 9627c110 2020-04-18 stsp
7349 818c7501 2019-07-11 stsp commit_id = qid->id;
7350 818c7501 2019-07-11 stsp parent_id = pid ? pid->id : yca_id;
7351 818c7501 2019-07-11 stsp pid = qid;
7352 818c7501 2019-07-11 stsp
7353 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
7354 01757395 2019-07-12 stsp error = got_worktree_rebase_merge_files(&merged_paths,
7355 3e3a69f1 2019-07-25 stsp worktree, fileindex, parent_id, commit_id, repo,
7356 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
7357 818c7501 2019-07-11 stsp if (error)
7358 818c7501 2019-07-11 stsp goto done;
7359 9627c110 2020-04-18 stsp
7360 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
7361 9627c110 2020-04-18 stsp if (upa.conflicts > 0)
7362 9627c110 2020-04-18 stsp rebase_status = GOT_STATUS_CONFLICT;
7363 818c7501 2019-07-11 stsp
7364 01757395 2019-07-12 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
7365 a0ea4fc0 2020-02-28 stsp error = show_rebase_merge_conflict(qid->id, repo);
7366 a0ea4fc0 2020-02-28 stsp if (error)
7367 a0ea4fc0 2020-02-28 stsp goto done;
7368 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
7369 818c7501 2019-07-11 stsp break;
7370 01757395 2019-07-12 stsp }
7371 818c7501 2019-07-11 stsp
7372 3e3a69f1 2019-07-25 stsp error = rebase_commit(&merged_paths, worktree, fileindex,
7373 3e3a69f1 2019-07-25 stsp tmp_branch, commit_id, repo);
7374 01757395 2019-07-12 stsp got_worktree_rebase_pathlist_free(&merged_paths);
7375 818c7501 2019-07-11 stsp if (error)
7376 818c7501 2019-07-11 stsp goto done;
7377 818c7501 2019-07-11 stsp }
7378 818c7501 2019-07-11 stsp
7379 818c7501 2019-07-11 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
7380 3e3a69f1 2019-07-25 stsp error = got_worktree_rebase_postpone(worktree, fileindex);
7381 818c7501 2019-07-11 stsp if (error)
7382 818c7501 2019-07-11 stsp goto done;
7383 818c7501 2019-07-11 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
7384 11495e04 2019-07-12 stsp "conflicts must be resolved before rebasing can continue");
7385 818c7501 2019-07-11 stsp } else
7386 3e3a69f1 2019-07-25 stsp error = rebase_complete(worktree, fileindex, branch,
7387 3e3a69f1 2019-07-25 stsp new_base_branch, tmp_branch, repo);
7388 818c7501 2019-07-11 stsp done:
7389 818c7501 2019-07-11 stsp got_object_id_queue_free(&commits);
7390 818c7501 2019-07-11 stsp free(branch_head_commit_id);
7391 818c7501 2019-07-11 stsp free(resume_commit_id);
7392 818c7501 2019-07-11 stsp free(yca_id);
7393 818c7501 2019-07-11 stsp if (commit)
7394 818c7501 2019-07-11 stsp got_object_commit_close(commit);
7395 818c7501 2019-07-11 stsp if (branch)
7396 818c7501 2019-07-11 stsp got_ref_close(branch);
7397 818c7501 2019-07-11 stsp if (new_base_branch)
7398 818c7501 2019-07-11 stsp got_ref_close(new_base_branch);
7399 818c7501 2019-07-11 stsp if (tmp_branch)
7400 818c7501 2019-07-11 stsp got_ref_close(tmp_branch);
7401 5ef14e63 2019-06-02 stsp if (worktree)
7402 5ef14e63 2019-06-02 stsp got_worktree_close(worktree);
7403 5ef14e63 2019-06-02 stsp if (repo)
7404 5ef14e63 2019-06-02 stsp got_repo_close(repo);
7405 5ef14e63 2019-06-02 stsp return error;
7406 0ebf8283 2019-07-24 stsp }
7407 0ebf8283 2019-07-24 stsp
7408 0ebf8283 2019-07-24 stsp __dead static void
7409 0ebf8283 2019-07-24 stsp usage_histedit(void)
7410 0ebf8283 2019-07-24 stsp {
7411 083957f4 2020-02-24 stsp fprintf(stderr, "usage: %s histedit [-a] [-c] [-F histedit-script] [-m]\n",
7412 0ebf8283 2019-07-24 stsp getprogname());
7413 0ebf8283 2019-07-24 stsp exit(1);
7414 0ebf8283 2019-07-24 stsp }
7415 0ebf8283 2019-07-24 stsp
7416 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_PICK 'p'
7417 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_EDIT 'e'
7418 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_FOLD 'f'
7419 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_DROP 'd'
7420 0ebf8283 2019-07-24 stsp #define GOT_HISTEDIT_MESG 'm'
7421 0ebf8283 2019-07-24 stsp
7422 0ebf8283 2019-07-24 stsp static struct got_histedit_cmd {
7423 0ebf8283 2019-07-24 stsp unsigned char code;
7424 0ebf8283 2019-07-24 stsp const char *name;
7425 0ebf8283 2019-07-24 stsp const char *desc;
7426 0ebf8283 2019-07-24 stsp } got_histedit_cmds[] = {
7427 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_PICK, "pick", "use commit" },
7428 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
7429 82997472 2020-01-29 stsp { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
7430 82997472 2020-01-29 stsp "be used" },
7431 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
7432 0ebf8283 2019-07-24 stsp { GOT_HISTEDIT_MESG, "mesg",
7433 0ebf8283 2019-07-24 stsp "single-line log message for commit above (open editor if empty)" },
7434 0ebf8283 2019-07-24 stsp };
7435 0ebf8283 2019-07-24 stsp
7436 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry {
7437 0ebf8283 2019-07-24 stsp TAILQ_ENTRY(got_histedit_list_entry) entry;
7438 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id;
7439 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
7440 0ebf8283 2019-07-24 stsp char *logmsg;
7441 0ebf8283 2019-07-24 stsp };
7442 0ebf8283 2019-07-24 stsp TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
7443 0ebf8283 2019-07-24 stsp
7444 0ebf8283 2019-07-24 stsp static const struct got_error *
7445 0ebf8283 2019-07-24 stsp histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
7446 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
7447 0ebf8283 2019-07-24 stsp {
7448 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7449 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *id_str = NULL;
7450 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
7451 8138f3e1 2019-08-11 stsp int n;
7452 0ebf8283 2019-07-24 stsp
7453 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, commit_id);
7454 0ebf8283 2019-07-24 stsp if (err)
7455 0ebf8283 2019-07-24 stsp goto done;
7456 0ebf8283 2019-07-24 stsp
7457 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 34, commit);
7458 0ebf8283 2019-07-24 stsp if (err)
7459 0ebf8283 2019-07-24 stsp goto done;
7460 0ebf8283 2019-07-24 stsp
7461 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, commit_id);
7462 0ebf8283 2019-07-24 stsp if (err)
7463 0ebf8283 2019-07-24 stsp goto done;
7464 0ebf8283 2019-07-24 stsp
7465 0ebf8283 2019-07-24 stsp n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
7466 0ebf8283 2019-07-24 stsp if (n < 0)
7467 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
7468 0ebf8283 2019-07-24 stsp done:
7469 0ebf8283 2019-07-24 stsp if (commit)
7470 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
7471 0ebf8283 2019-07-24 stsp free(id_str);
7472 0ebf8283 2019-07-24 stsp free(logmsg);
7473 0ebf8283 2019-07-24 stsp return err;
7474 0ebf8283 2019-07-24 stsp }
7475 0ebf8283 2019-07-24 stsp
7476 0ebf8283 2019-07-24 stsp static const struct got_error *
7477 083957f4 2020-02-24 stsp histedit_write_commit_list(struct got_object_id_queue *commits,
7478 083957f4 2020-02-24 stsp FILE *f, int edit_logmsg_only, struct got_repository *repo)
7479 0ebf8283 2019-07-24 stsp {
7480 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7481 0ebf8283 2019-07-24 stsp struct got_object_qid *qid;
7482 0ebf8283 2019-07-24 stsp
7483 0ebf8283 2019-07-24 stsp if (SIMPLEQ_EMPTY(commits))
7484 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
7485 0ebf8283 2019-07-24 stsp
7486 0ebf8283 2019-07-24 stsp SIMPLEQ_FOREACH(qid, commits, entry) {
7487 0ebf8283 2019-07-24 stsp err = histedit_write_commit(qid->id, got_histedit_cmds[0].name,
7488 0ebf8283 2019-07-24 stsp f, repo);
7489 0ebf8283 2019-07-24 stsp if (err)
7490 0ebf8283 2019-07-24 stsp break;
7491 083957f4 2020-02-24 stsp if (edit_logmsg_only) {
7492 083957f4 2020-02-24 stsp int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
7493 083957f4 2020-02-24 stsp if (n < 0) {
7494 083957f4 2020-02-24 stsp err = got_ferror(f, GOT_ERR_IO);
7495 083957f4 2020-02-24 stsp break;
7496 083957f4 2020-02-24 stsp }
7497 083957f4 2020-02-24 stsp }
7498 0ebf8283 2019-07-24 stsp }
7499 0ebf8283 2019-07-24 stsp
7500 0ebf8283 2019-07-24 stsp return err;
7501 0ebf8283 2019-07-24 stsp }
7502 0ebf8283 2019-07-24 stsp
7503 0ebf8283 2019-07-24 stsp static const struct got_error *
7504 514f2ffe 2020-01-29 stsp write_cmd_list(FILE *f, const char *branch_name,
7505 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits)
7506 0ebf8283 2019-07-24 stsp {
7507 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7508 0ebf8283 2019-07-24 stsp int n, i;
7509 514f2ffe 2020-01-29 stsp char *id_str;
7510 514f2ffe 2020-01-29 stsp struct got_object_qid *qid;
7511 514f2ffe 2020-01-29 stsp
7512 514f2ffe 2020-01-29 stsp qid = SIMPLEQ_FIRST(commits);
7513 514f2ffe 2020-01-29 stsp err = got_object_id_str(&id_str, qid->id);
7514 514f2ffe 2020-01-29 stsp if (err)
7515 514f2ffe 2020-01-29 stsp return err;
7516 514f2ffe 2020-01-29 stsp
7517 514f2ffe 2020-01-29 stsp n = fprintf(f,
7518 514f2ffe 2020-01-29 stsp "# Editing the history of branch '%s' starting at\n"
7519 514f2ffe 2020-01-29 stsp "# commit %s\n"
7520 514f2ffe 2020-01-29 stsp "# Commits will be processed in order from top to "
7521 514f2ffe 2020-01-29 stsp "bottom of this file.\n", branch_name, id_str);
7522 514f2ffe 2020-01-29 stsp if (n < 0) {
7523 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
7524 514f2ffe 2020-01-29 stsp goto done;
7525 514f2ffe 2020-01-29 stsp }
7526 0ebf8283 2019-07-24 stsp
7527 0ebf8283 2019-07-24 stsp n = fprintf(f, "# Available histedit commands:\n");
7528 514f2ffe 2020-01-29 stsp if (n < 0) {
7529 514f2ffe 2020-01-29 stsp err = got_ferror(f, GOT_ERR_IO);
7530 514f2ffe 2020-01-29 stsp goto done;
7531 514f2ffe 2020-01-29 stsp }
7532 0ebf8283 2019-07-24 stsp
7533 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
7534 0ebf8283 2019-07-24 stsp struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
7535 0ebf8283 2019-07-24 stsp n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
7536 0ebf8283 2019-07-24 stsp cmd->desc);
7537 0ebf8283 2019-07-24 stsp if (n < 0) {
7538 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
7539 0ebf8283 2019-07-24 stsp break;
7540 0ebf8283 2019-07-24 stsp }
7541 0ebf8283 2019-07-24 stsp }
7542 514f2ffe 2020-01-29 stsp done:
7543 514f2ffe 2020-01-29 stsp free(id_str);
7544 0ebf8283 2019-07-24 stsp return err;
7545 0ebf8283 2019-07-24 stsp }
7546 0ebf8283 2019-07-24 stsp
7547 0ebf8283 2019-07-24 stsp static const struct got_error *
7548 0ebf8283 2019-07-24 stsp histedit_syntax_error(int lineno)
7549 0ebf8283 2019-07-24 stsp {
7550 0ebf8283 2019-07-24 stsp static char msg[42];
7551 0ebf8283 2019-07-24 stsp int ret;
7552 0ebf8283 2019-07-24 stsp
7553 0ebf8283 2019-07-24 stsp ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
7554 0ebf8283 2019-07-24 stsp lineno);
7555 0ebf8283 2019-07-24 stsp if (ret == -1 || ret >= sizeof(msg))
7556 0ebf8283 2019-07-24 stsp return got_error(GOT_ERR_HISTEDIT_SYNTAX);
7557 0ebf8283 2019-07-24 stsp
7558 0ebf8283 2019-07-24 stsp return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
7559 0ebf8283 2019-07-24 stsp }
7560 0ebf8283 2019-07-24 stsp
7561 0ebf8283 2019-07-24 stsp static const struct got_error *
7562 0ebf8283 2019-07-24 stsp append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
7563 0ebf8283 2019-07-24 stsp char *logmsg, struct got_repository *repo)
7564 0ebf8283 2019-07-24 stsp {
7565 0ebf8283 2019-07-24 stsp const struct got_error *err;
7566 0ebf8283 2019-07-24 stsp struct got_commit_object *folded_commit = NULL;
7567 5943eee2 2019-08-13 stsp char *id_str, *folded_logmsg = NULL;
7568 0ebf8283 2019-07-24 stsp
7569 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
7570 0ebf8283 2019-07-24 stsp if (err)
7571 0ebf8283 2019-07-24 stsp return err;
7572 0ebf8283 2019-07-24 stsp
7573 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
7574 0ebf8283 2019-07-24 stsp if (err)
7575 0ebf8283 2019-07-24 stsp goto done;
7576 0ebf8283 2019-07-24 stsp
7577 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
7578 5943eee2 2019-08-13 stsp if (err)
7579 5943eee2 2019-08-13 stsp goto done;
7580 0ebf8283 2019-07-24 stsp if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
7581 0ebf8283 2019-07-24 stsp logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
7582 5943eee2 2019-08-13 stsp folded_logmsg) == -1) {
7583 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
7584 0ebf8283 2019-07-24 stsp }
7585 0ebf8283 2019-07-24 stsp done:
7586 0ebf8283 2019-07-24 stsp if (folded_commit)
7587 0ebf8283 2019-07-24 stsp got_object_commit_close(folded_commit);
7588 0ebf8283 2019-07-24 stsp free(id_str);
7589 5943eee2 2019-08-13 stsp free(folded_logmsg);
7590 0ebf8283 2019-07-24 stsp return err;
7591 0ebf8283 2019-07-24 stsp }
7592 0ebf8283 2019-07-24 stsp
7593 0ebf8283 2019-07-24 stsp static struct got_histedit_list_entry *
7594 0ebf8283 2019-07-24 stsp get_folded_commits(struct got_histedit_list_entry *hle)
7595 0ebf8283 2019-07-24 stsp {
7596 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *prev, *folded = NULL;
7597 0ebf8283 2019-07-24 stsp
7598 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(hle, got_histedit_list, entry);
7599 3f9de99f 2019-07-24 stsp while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
7600 3f9de99f 2019-07-24 stsp prev->cmd->code == GOT_HISTEDIT_DROP)) {
7601 3f9de99f 2019-07-24 stsp if (prev->cmd->code == GOT_HISTEDIT_FOLD)
7602 3f9de99f 2019-07-24 stsp folded = prev;
7603 0ebf8283 2019-07-24 stsp prev = TAILQ_PREV(prev, got_histedit_list, entry);
7604 0ebf8283 2019-07-24 stsp }
7605 0ebf8283 2019-07-24 stsp
7606 0ebf8283 2019-07-24 stsp return folded;
7607 0ebf8283 2019-07-24 stsp }
7608 0ebf8283 2019-07-24 stsp
7609 0ebf8283 2019-07-24 stsp static const struct got_error *
7610 0ebf8283 2019-07-24 stsp histedit_edit_logmsg(struct got_histedit_list_entry *hle,
7611 0ebf8283 2019-07-24 stsp struct got_repository *repo)
7612 0ebf8283 2019-07-24 stsp {
7613 5943eee2 2019-08-13 stsp char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
7614 0ebf8283 2019-07-24 stsp char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
7615 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7616 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
7617 0ebf8283 2019-07-24 stsp int fd;
7618 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *folded = NULL;
7619 0ebf8283 2019-07-24 stsp
7620 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
7621 0ebf8283 2019-07-24 stsp if (err)
7622 0ebf8283 2019-07-24 stsp return err;
7623 0ebf8283 2019-07-24 stsp
7624 0ebf8283 2019-07-24 stsp folded = get_folded_commits(hle);
7625 0ebf8283 2019-07-24 stsp if (folded) {
7626 0ebf8283 2019-07-24 stsp while (folded != hle) {
7627 3f9de99f 2019-07-24 stsp if (folded->cmd->code == GOT_HISTEDIT_DROP) {
7628 3f9de99f 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
7629 3f9de99f 2019-07-24 stsp continue;
7630 3f9de99f 2019-07-24 stsp }
7631 0ebf8283 2019-07-24 stsp err = append_folded_commit_msg(&new_msg, folded,
7632 0ebf8283 2019-07-24 stsp logmsg, repo);
7633 0ebf8283 2019-07-24 stsp if (err)
7634 0ebf8283 2019-07-24 stsp goto done;
7635 0ebf8283 2019-07-24 stsp free(logmsg);
7636 0ebf8283 2019-07-24 stsp logmsg = new_msg;
7637 0ebf8283 2019-07-24 stsp folded = TAILQ_NEXT(folded, entry);
7638 0ebf8283 2019-07-24 stsp }
7639 0ebf8283 2019-07-24 stsp }
7640 0ebf8283 2019-07-24 stsp
7641 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
7642 0ebf8283 2019-07-24 stsp if (err)
7643 0ebf8283 2019-07-24 stsp goto done;
7644 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&orig_logmsg, commit);
7645 5943eee2 2019-08-13 stsp if (err)
7646 5943eee2 2019-08-13 stsp goto done;
7647 0ebf8283 2019-07-24 stsp if (asprintf(&new_msg,
7648 0ebf8283 2019-07-24 stsp "%s\n# original log message of commit %s: %s",
7649 5943eee2 2019-08-13 stsp logmsg ? logmsg : "", id_str, orig_logmsg) == -1) {
7650 0ebf8283 2019-07-24 stsp err = got_error_from_errno("asprintf");
7651 0ebf8283 2019-07-24 stsp goto done;
7652 0ebf8283 2019-07-24 stsp }
7653 0ebf8283 2019-07-24 stsp free(logmsg);
7654 0ebf8283 2019-07-24 stsp logmsg = new_msg;
7655 0ebf8283 2019-07-24 stsp
7656 0ebf8283 2019-07-24 stsp err = got_object_id_str(&id_str, hle->commit_id);
7657 0ebf8283 2019-07-24 stsp if (err)
7658 0ebf8283 2019-07-24 stsp goto done;
7659 0ebf8283 2019-07-24 stsp
7660 bb63914a 2020-02-17 stsp err = got_opentemp_named_fd(&logmsg_path, &fd,
7661 bb63914a 2020-02-17 stsp GOT_TMPDIR_STR "/got-logmsg");
7662 0ebf8283 2019-07-24 stsp if (err)
7663 0ebf8283 2019-07-24 stsp goto done;
7664 0ebf8283 2019-07-24 stsp
7665 0ebf8283 2019-07-24 stsp dprintf(fd, logmsg);
7666 0ebf8283 2019-07-24 stsp close(fd);
7667 0ebf8283 2019-07-24 stsp
7668 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
7669 0ebf8283 2019-07-24 stsp if (err)
7670 0ebf8283 2019-07-24 stsp goto done;
7671 0ebf8283 2019-07-24 stsp
7672 0ebf8283 2019-07-24 stsp err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg);
7673 0ebf8283 2019-07-24 stsp if (err) {
7674 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
7675 0ebf8283 2019-07-24 stsp goto done;
7676 5943eee2 2019-08-13 stsp err = got_object_commit_get_logmsg(&hle->logmsg, commit);
7677 0ebf8283 2019-07-24 stsp }
7678 0ebf8283 2019-07-24 stsp done:
7679 0ebf8283 2019-07-24 stsp if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
7680 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", logmsg_path);
7681 0ebf8283 2019-07-24 stsp free(logmsg_path);
7682 0ebf8283 2019-07-24 stsp free(logmsg);
7683 5943eee2 2019-08-13 stsp free(orig_logmsg);
7684 0ebf8283 2019-07-24 stsp free(editor);
7685 0ebf8283 2019-07-24 stsp if (commit)
7686 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
7687 0ebf8283 2019-07-24 stsp return err;
7688 5ef14e63 2019-06-02 stsp }
7689 0ebf8283 2019-07-24 stsp
7690 0ebf8283 2019-07-24 stsp static const struct got_error *
7691 0ebf8283 2019-07-24 stsp histedit_parse_list(struct got_histedit_list *histedit_cmds,
7692 0ebf8283 2019-07-24 stsp FILE *f, struct got_repository *repo)
7693 0ebf8283 2019-07-24 stsp {
7694 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7695 0ebf8283 2019-07-24 stsp char *line = NULL, *p, *end;
7696 0ebf8283 2019-07-24 stsp size_t size;
7697 0ebf8283 2019-07-24 stsp ssize_t len;
7698 0ebf8283 2019-07-24 stsp int lineno = 0, i;
7699 0ebf8283 2019-07-24 stsp const struct got_histedit_cmd *cmd;
7700 0ebf8283 2019-07-24 stsp struct got_object_id *commit_id = NULL;
7701 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle = NULL;
7702 0ebf8283 2019-07-24 stsp
7703 0ebf8283 2019-07-24 stsp for (;;) {
7704 0ebf8283 2019-07-24 stsp len = getline(&line, &size, f);
7705 0ebf8283 2019-07-24 stsp if (len == -1) {
7706 0ebf8283 2019-07-24 stsp const struct got_error *getline_err;
7707 0ebf8283 2019-07-24 stsp if (feof(f))
7708 0ebf8283 2019-07-24 stsp break;
7709 0ebf8283 2019-07-24 stsp getline_err = got_error_from_errno("getline");
7710 0ebf8283 2019-07-24 stsp err = got_ferror(f, getline_err->code);
7711 0ebf8283 2019-07-24 stsp break;
7712 0ebf8283 2019-07-24 stsp }
7713 0ebf8283 2019-07-24 stsp lineno++;
7714 0ebf8283 2019-07-24 stsp p = line;
7715 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
7716 0ebf8283 2019-07-24 stsp p++;
7717 0ebf8283 2019-07-24 stsp if (p[0] == '#' || p[0] == '\0') {
7718 0ebf8283 2019-07-24 stsp free(line);
7719 0ebf8283 2019-07-24 stsp line = NULL;
7720 0ebf8283 2019-07-24 stsp continue;
7721 0ebf8283 2019-07-24 stsp }
7722 0ebf8283 2019-07-24 stsp cmd = NULL;
7723 0ebf8283 2019-07-24 stsp for (i = 0; i < nitems(got_histedit_cmds); i++) {
7724 0ebf8283 2019-07-24 stsp cmd = &got_histedit_cmds[i];
7725 0ebf8283 2019-07-24 stsp if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
7726 0ebf8283 2019-07-24 stsp isspace((unsigned char)p[strlen(cmd->name)])) {
7727 0ebf8283 2019-07-24 stsp p += strlen(cmd->name);
7728 0ebf8283 2019-07-24 stsp break;
7729 0ebf8283 2019-07-24 stsp }
7730 0ebf8283 2019-07-24 stsp if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
7731 0ebf8283 2019-07-24 stsp p++;
7732 0ebf8283 2019-07-24 stsp break;
7733 0ebf8283 2019-07-24 stsp }
7734 0ebf8283 2019-07-24 stsp }
7735 6c1844f6 2019-07-25 stsp if (i == nitems(got_histedit_cmds)) {
7736 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
7737 0ebf8283 2019-07-24 stsp break;
7738 0ebf8283 2019-07-24 stsp }
7739 0ebf8283 2019-07-24 stsp while (isspace((unsigned char)p[0]))
7740 0ebf8283 2019-07-24 stsp p++;
7741 0ebf8283 2019-07-24 stsp if (cmd->code == GOT_HISTEDIT_MESG) {
7742 0ebf8283 2019-07-24 stsp if (hle == NULL || hle->logmsg != NULL) {
7743 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CMD);
7744 0ebf8283 2019-07-24 stsp break;
7745 0ebf8283 2019-07-24 stsp }
7746 0ebf8283 2019-07-24 stsp if (p[0] == '\0') {
7747 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
7748 0ebf8283 2019-07-24 stsp if (err)
7749 0ebf8283 2019-07-24 stsp break;
7750 0ebf8283 2019-07-24 stsp } else {
7751 0ebf8283 2019-07-24 stsp hle->logmsg = strdup(p);
7752 0ebf8283 2019-07-24 stsp if (hle->logmsg == NULL) {
7753 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
7754 0ebf8283 2019-07-24 stsp break;
7755 0ebf8283 2019-07-24 stsp }
7756 0ebf8283 2019-07-24 stsp }
7757 0ebf8283 2019-07-24 stsp free(line);
7758 0ebf8283 2019-07-24 stsp line = NULL;
7759 0ebf8283 2019-07-24 stsp continue;
7760 0ebf8283 2019-07-24 stsp } else {
7761 0ebf8283 2019-07-24 stsp end = p;
7762 0ebf8283 2019-07-24 stsp while (end[0] && !isspace((unsigned char)end[0]))
7763 0ebf8283 2019-07-24 stsp end++;
7764 0ebf8283 2019-07-24 stsp *end = '\0';
7765 0ebf8283 2019-07-24 stsp
7766 0ebf8283 2019-07-24 stsp err = got_object_resolve_id_str(&commit_id, repo, p);
7767 0ebf8283 2019-07-24 stsp if (err) {
7768 0ebf8283 2019-07-24 stsp /* override error code */
7769 0ebf8283 2019-07-24 stsp err = histedit_syntax_error(lineno);
7770 0ebf8283 2019-07-24 stsp break;
7771 0ebf8283 2019-07-24 stsp }
7772 0ebf8283 2019-07-24 stsp }
7773 0ebf8283 2019-07-24 stsp hle = malloc(sizeof(*hle));
7774 0ebf8283 2019-07-24 stsp if (hle == NULL) {
7775 0ebf8283 2019-07-24 stsp err = got_error_from_errno("malloc");
7776 0ebf8283 2019-07-24 stsp break;
7777 0ebf8283 2019-07-24 stsp }
7778 0ebf8283 2019-07-24 stsp hle->cmd = cmd;
7779 0ebf8283 2019-07-24 stsp hle->commit_id = commit_id;
7780 0ebf8283 2019-07-24 stsp hle->logmsg = NULL;
7781 0ebf8283 2019-07-24 stsp commit_id = NULL;
7782 0ebf8283 2019-07-24 stsp free(line);
7783 0ebf8283 2019-07-24 stsp line = NULL;
7784 0ebf8283 2019-07-24 stsp TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
7785 0ebf8283 2019-07-24 stsp }
7786 0ebf8283 2019-07-24 stsp
7787 0ebf8283 2019-07-24 stsp free(line);
7788 0ebf8283 2019-07-24 stsp free(commit_id);
7789 0ebf8283 2019-07-24 stsp return err;
7790 0ebf8283 2019-07-24 stsp }
7791 0ebf8283 2019-07-24 stsp
7792 0ebf8283 2019-07-24 stsp static const struct got_error *
7793 bfce7f83 2019-07-27 stsp histedit_check_script(struct got_histedit_list *histedit_cmds,
7794 bfce7f83 2019-07-27 stsp struct got_object_id_queue *commits, struct got_repository *repo)
7795 bfce7f83 2019-07-27 stsp {
7796 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL;
7797 bfce7f83 2019-07-27 stsp struct got_object_qid *qid;
7798 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
7799 5b87815e 2020-03-05 stsp static char msg[92];
7800 bfce7f83 2019-07-27 stsp char *id_str;
7801 bfce7f83 2019-07-27 stsp
7802 bfce7f83 2019-07-27 stsp if (TAILQ_EMPTY(histedit_cmds))
7803 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
7804 bfce7f83 2019-07-27 stsp "histedit script contains no commands");
7805 a0de39f3 2019-08-09 stsp if (SIMPLEQ_EMPTY(commits))
7806 a0de39f3 2019-08-09 stsp return got_error(GOT_ERR_EMPTY_HISTEDIT);
7807 5b87815e 2020-03-05 stsp
7808 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
7809 5b87815e 2020-03-05 stsp struct got_histedit_list_entry *hle2;
7810 5b87815e 2020-03-05 stsp TAILQ_FOREACH(hle2, histedit_cmds, entry) {
7811 5b87815e 2020-03-05 stsp if (hle == hle2)
7812 5b87815e 2020-03-05 stsp continue;
7813 5b87815e 2020-03-05 stsp if (got_object_id_cmp(hle->commit_id,
7814 5b87815e 2020-03-05 stsp hle2->commit_id) != 0)
7815 5b87815e 2020-03-05 stsp continue;
7816 5b87815e 2020-03-05 stsp err = got_object_id_str(&id_str, hle->commit_id);
7817 5b87815e 2020-03-05 stsp if (err)
7818 5b87815e 2020-03-05 stsp return err;
7819 5b87815e 2020-03-05 stsp snprintf(msg, sizeof(msg), "commit %s is listed "
7820 5b87815e 2020-03-05 stsp "more than once in histedit script", id_str);
7821 5b87815e 2020-03-05 stsp free(id_str);
7822 5b87815e 2020-03-05 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
7823 5b87815e 2020-03-05 stsp }
7824 5b87815e 2020-03-05 stsp }
7825 bfce7f83 2019-07-27 stsp
7826 bfce7f83 2019-07-27 stsp SIMPLEQ_FOREACH(qid, commits, entry) {
7827 bfce7f83 2019-07-27 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
7828 bfce7f83 2019-07-27 stsp if (got_object_id_cmp(qid->id, hle->commit_id) == 0)
7829 bfce7f83 2019-07-27 stsp break;
7830 bfce7f83 2019-07-27 stsp }
7831 bfce7f83 2019-07-27 stsp if (hle == NULL) {
7832 bfce7f83 2019-07-27 stsp err = got_object_id_str(&id_str, qid->id);
7833 bfce7f83 2019-07-27 stsp if (err)
7834 bfce7f83 2019-07-27 stsp return err;
7835 bfce7f83 2019-07-27 stsp snprintf(msg, sizeof(msg),
7836 bfce7f83 2019-07-27 stsp "commit %s missing from histedit script", id_str);
7837 bfce7f83 2019-07-27 stsp free(id_str);
7838 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
7839 bfce7f83 2019-07-27 stsp }
7840 bfce7f83 2019-07-27 stsp }
7841 bfce7f83 2019-07-27 stsp
7842 0def28b1 2019-08-17 stsp hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
7843 0def28b1 2019-08-17 stsp if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
7844 bfce7f83 2019-07-27 stsp return got_error_msg(GOT_ERR_HISTEDIT_CMD,
7845 bfce7f83 2019-07-27 stsp "last commit in histedit script cannot be folded");
7846 bfce7f83 2019-07-27 stsp
7847 bfce7f83 2019-07-27 stsp return NULL;
7848 bfce7f83 2019-07-27 stsp }
7849 bfce7f83 2019-07-27 stsp
7850 bfce7f83 2019-07-27 stsp static const struct got_error *
7851 0ebf8283 2019-07-24 stsp histedit_run_editor(struct got_histedit_list *histedit_cmds,
7852 bfce7f83 2019-07-27 stsp const char *path, struct got_object_id_queue *commits,
7853 bfce7f83 2019-07-27 stsp struct got_repository *repo)
7854 0ebf8283 2019-07-24 stsp {
7855 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7856 0ebf8283 2019-07-24 stsp char *editor;
7857 0ebf8283 2019-07-24 stsp FILE *f = NULL;
7858 0ebf8283 2019-07-24 stsp
7859 0ebf8283 2019-07-24 stsp err = get_editor(&editor);
7860 0ebf8283 2019-07-24 stsp if (err)
7861 0ebf8283 2019-07-24 stsp return err;
7862 0ebf8283 2019-07-24 stsp
7863 0ebf8283 2019-07-24 stsp if (spawn_editor(editor, path) == -1) {
7864 0ebf8283 2019-07-24 stsp err = got_error_from_errno("failed spawning editor");
7865 0ebf8283 2019-07-24 stsp goto done;
7866 0ebf8283 2019-07-24 stsp }
7867 0ebf8283 2019-07-24 stsp
7868 0ebf8283 2019-07-24 stsp f = fopen(path, "r");
7869 0ebf8283 2019-07-24 stsp if (f == NULL) {
7870 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fopen");
7871 0ebf8283 2019-07-24 stsp goto done;
7872 0ebf8283 2019-07-24 stsp }
7873 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
7874 bfce7f83 2019-07-27 stsp if (err)
7875 bfce7f83 2019-07-27 stsp goto done;
7876 bfce7f83 2019-07-27 stsp
7877 bfce7f83 2019-07-27 stsp err = histedit_check_script(histedit_cmds, commits, repo);
7878 0ebf8283 2019-07-24 stsp done:
7879 0ebf8283 2019-07-24 stsp if (f && fclose(f) != 0 && err == NULL)
7880 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
7881 0ebf8283 2019-07-24 stsp free(editor);
7882 0ebf8283 2019-07-24 stsp return err;
7883 0ebf8283 2019-07-24 stsp }
7884 0ebf8283 2019-07-24 stsp
7885 0ebf8283 2019-07-24 stsp static const struct got_error *
7886 bfce7f83 2019-07-27 stsp histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
7887 514f2ffe 2020-01-29 stsp struct got_object_id_queue *, const char *, const char *,
7888 514f2ffe 2020-01-29 stsp struct got_repository *);
7889 0ebf8283 2019-07-24 stsp
7890 0ebf8283 2019-07-24 stsp static const struct got_error *
7891 0ebf8283 2019-07-24 stsp histedit_edit_script(struct got_histedit_list *histedit_cmds,
7892 514f2ffe 2020-01-29 stsp struct got_object_id_queue *commits, const char *branch_name,
7893 083957f4 2020-02-24 stsp int edit_logmsg_only, struct got_repository *repo)
7894 0ebf8283 2019-07-24 stsp {
7895 0ebf8283 2019-07-24 stsp const struct got_error *err;
7896 0ebf8283 2019-07-24 stsp FILE *f = NULL;
7897 0ebf8283 2019-07-24 stsp char *path = NULL;
7898 0ebf8283 2019-07-24 stsp
7899 0ebf8283 2019-07-24 stsp err = got_opentemp_named(&path, &f, "got-histedit");
7900 0ebf8283 2019-07-24 stsp if (err)
7901 0ebf8283 2019-07-24 stsp return err;
7902 0ebf8283 2019-07-24 stsp
7903 514f2ffe 2020-01-29 stsp err = write_cmd_list(f, branch_name, commits);
7904 0ebf8283 2019-07-24 stsp if (err)
7905 0ebf8283 2019-07-24 stsp goto done;
7906 0ebf8283 2019-07-24 stsp
7907 083957f4 2020-02-24 stsp err = histedit_write_commit_list(commits, f, edit_logmsg_only, repo);
7908 0ebf8283 2019-07-24 stsp if (err)
7909 0ebf8283 2019-07-24 stsp goto done;
7910 0ebf8283 2019-07-24 stsp
7911 083957f4 2020-02-24 stsp if (edit_logmsg_only) {
7912 083957f4 2020-02-24 stsp rewind(f);
7913 083957f4 2020-02-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
7914 083957f4 2020-02-24 stsp } else {
7915 083957f4 2020-02-24 stsp if (fclose(f) != 0) {
7916 083957f4 2020-02-24 stsp err = got_error_from_errno("fclose");
7917 0ebf8283 2019-07-24 stsp goto done;
7918 083957f4 2020-02-24 stsp }
7919 083957f4 2020-02-24 stsp f = NULL;
7920 083957f4 2020-02-24 stsp err = histedit_run_editor(histedit_cmds, path, commits, repo);
7921 083957f4 2020-02-24 stsp if (err) {
7922 083957f4 2020-02-24 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
7923 083957f4 2020-02-24 stsp err->code != GOT_ERR_HISTEDIT_CMD)
7924 083957f4 2020-02-24 stsp goto done;
7925 083957f4 2020-02-24 stsp err = histedit_edit_list_retry(histedit_cmds, err,
7926 083957f4 2020-02-24 stsp commits, path, branch_name, repo);
7927 083957f4 2020-02-24 stsp }
7928 0ebf8283 2019-07-24 stsp }
7929 0ebf8283 2019-07-24 stsp done:
7930 0ebf8283 2019-07-24 stsp if (f && fclose(f) != 0 && err == NULL)
7931 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
7932 0ebf8283 2019-07-24 stsp if (path && unlink(path) != 0 && err == NULL)
7933 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("unlink", path);
7934 0ebf8283 2019-07-24 stsp free(path);
7935 0ebf8283 2019-07-24 stsp return err;
7936 0ebf8283 2019-07-24 stsp }
7937 0ebf8283 2019-07-24 stsp
7938 0ebf8283 2019-07-24 stsp static const struct got_error *
7939 0ebf8283 2019-07-24 stsp histedit_save_list(struct got_histedit_list *histedit_cmds,
7940 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
7941 0ebf8283 2019-07-24 stsp {
7942 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7943 0ebf8283 2019-07-24 stsp char *path = NULL;
7944 0ebf8283 2019-07-24 stsp FILE *f = NULL;
7945 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
7946 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
7947 0ebf8283 2019-07-24 stsp
7948 c3022ba5 2019-07-27 stsp err = got_worktree_get_histedit_script_path(&path, worktree);
7949 0ebf8283 2019-07-24 stsp if (err)
7950 0ebf8283 2019-07-24 stsp return err;
7951 0ebf8283 2019-07-24 stsp
7952 0ebf8283 2019-07-24 stsp f = fopen(path, "w");
7953 0ebf8283 2019-07-24 stsp if (f == NULL) {
7954 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
7955 0ebf8283 2019-07-24 stsp goto done;
7956 0ebf8283 2019-07-24 stsp }
7957 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, histedit_cmds, entry) {
7958 0ebf8283 2019-07-24 stsp err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
7959 0ebf8283 2019-07-24 stsp repo);
7960 0ebf8283 2019-07-24 stsp if (err)
7961 0ebf8283 2019-07-24 stsp break;
7962 0ebf8283 2019-07-24 stsp
7963 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
7964 0ebf8283 2019-07-24 stsp int n = fprintf(f, "%c %s\n",
7965 0ebf8283 2019-07-24 stsp GOT_HISTEDIT_MESG, hle->logmsg);
7966 0ebf8283 2019-07-24 stsp if (n < 0) {
7967 0ebf8283 2019-07-24 stsp err = got_ferror(f, GOT_ERR_IO);
7968 0ebf8283 2019-07-24 stsp break;
7969 0ebf8283 2019-07-24 stsp }
7970 0ebf8283 2019-07-24 stsp }
7971 0ebf8283 2019-07-24 stsp }
7972 0ebf8283 2019-07-24 stsp done:
7973 0ebf8283 2019-07-24 stsp if (f && fclose(f) != 0 && err == NULL)
7974 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
7975 0ebf8283 2019-07-24 stsp free(path);
7976 0ebf8283 2019-07-24 stsp if (commit)
7977 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
7978 0ebf8283 2019-07-24 stsp return err;
7979 0ebf8283 2019-07-24 stsp }
7980 0ebf8283 2019-07-24 stsp
7981 bfce7f83 2019-07-27 stsp void
7982 bfce7f83 2019-07-27 stsp histedit_free_list(struct got_histedit_list *histedit_cmds)
7983 bfce7f83 2019-07-27 stsp {
7984 bfce7f83 2019-07-27 stsp struct got_histedit_list_entry *hle;
7985 bfce7f83 2019-07-27 stsp
7986 bfce7f83 2019-07-27 stsp while ((hle = TAILQ_FIRST(histedit_cmds))) {
7987 bfce7f83 2019-07-27 stsp TAILQ_REMOVE(histedit_cmds, hle, entry);
7988 bfce7f83 2019-07-27 stsp free(hle);
7989 bfce7f83 2019-07-27 stsp }
7990 bfce7f83 2019-07-27 stsp }
7991 bfce7f83 2019-07-27 stsp
7992 0ebf8283 2019-07-24 stsp static const struct got_error *
7993 0ebf8283 2019-07-24 stsp histedit_load_list(struct got_histedit_list *histedit_cmds,
7994 0ebf8283 2019-07-24 stsp const char *path, struct got_repository *repo)
7995 0ebf8283 2019-07-24 stsp {
7996 0ebf8283 2019-07-24 stsp const struct got_error *err = NULL;
7997 0ebf8283 2019-07-24 stsp FILE *f = NULL;
7998 0ebf8283 2019-07-24 stsp
7999 0ebf8283 2019-07-24 stsp f = fopen(path, "r");
8000 0ebf8283 2019-07-24 stsp if (f == NULL) {
8001 0ebf8283 2019-07-24 stsp err = got_error_from_errno2("fopen", path);
8002 0ebf8283 2019-07-24 stsp goto done;
8003 0ebf8283 2019-07-24 stsp }
8004 0ebf8283 2019-07-24 stsp
8005 0ebf8283 2019-07-24 stsp err = histedit_parse_list(histedit_cmds, f, repo);
8006 0ebf8283 2019-07-24 stsp done:
8007 0ebf8283 2019-07-24 stsp if (f && fclose(f) != 0 && err == NULL)
8008 0ebf8283 2019-07-24 stsp err = got_error_from_errno("fclose");
8009 0ebf8283 2019-07-24 stsp return err;
8010 0ebf8283 2019-07-24 stsp }
8011 0ebf8283 2019-07-24 stsp
8012 0ebf8283 2019-07-24 stsp static const struct got_error *
8013 0ebf8283 2019-07-24 stsp histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
8014 bfce7f83 2019-07-27 stsp const struct got_error *edit_err, struct got_object_id_queue *commits,
8015 514f2ffe 2020-01-29 stsp const char *path, const char *branch_name, struct got_repository *repo)
8016 0ebf8283 2019-07-24 stsp {
8017 bfce7f83 2019-07-27 stsp const struct got_error *err = NULL, *prev_err = edit_err;
8018 0ebf8283 2019-07-24 stsp int resp = ' ';
8019 0ebf8283 2019-07-24 stsp
8020 b006047e 2019-07-25 stsp while (resp != 'c' && resp != 'r' && resp != 'a') {
8021 0ebf8283 2019-07-24 stsp printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
8022 bfce7f83 2019-07-27 stsp "or (a)bort: ", getprogname(), prev_err->msg);
8023 0ebf8283 2019-07-24 stsp resp = getchar();
8024 a61a4414 2019-08-07 stsp if (resp == '\n')
8025 a61a4414 2019-08-07 stsp resp = getchar();
8026 426ebf2e 2019-07-25 stsp if (resp == 'c') {
8027 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
8028 bfce7f83 2019-07-27 stsp err = histedit_run_editor(histedit_cmds, path, commits,
8029 bfce7f83 2019-07-27 stsp repo);
8030 426ebf2e 2019-07-25 stsp if (err) {
8031 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
8032 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
8033 426ebf2e 2019-07-25 stsp break;
8034 bfce7f83 2019-07-27 stsp prev_err = err;
8035 426ebf2e 2019-07-25 stsp resp = ' ';
8036 426ebf2e 2019-07-25 stsp continue;
8037 426ebf2e 2019-07-25 stsp }
8038 bfce7f83 2019-07-27 stsp break;
8039 426ebf2e 2019-07-25 stsp } else if (resp == 'r') {
8040 bfce7f83 2019-07-27 stsp histedit_free_list(histedit_cmds);
8041 0ebf8283 2019-07-24 stsp err = histedit_edit_script(histedit_cmds,
8042 083957f4 2020-02-24 stsp commits, branch_name, 0, repo);
8043 426ebf2e 2019-07-25 stsp if (err) {
8044 bfce7f83 2019-07-27 stsp if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
8045 bfce7f83 2019-07-27 stsp err->code != GOT_ERR_HISTEDIT_CMD)
8046 426ebf2e 2019-07-25 stsp break;
8047 bfce7f83 2019-07-27 stsp prev_err = err;
8048 426ebf2e 2019-07-25 stsp resp = ' ';
8049 426ebf2e 2019-07-25 stsp continue;
8050 426ebf2e 2019-07-25 stsp }
8051 bfce7f83 2019-07-27 stsp break;
8052 426ebf2e 2019-07-25 stsp } else if (resp == 'a') {
8053 0ebf8283 2019-07-24 stsp err = got_error(GOT_ERR_HISTEDIT_CANCEL);
8054 0ebf8283 2019-07-24 stsp break;
8055 426ebf2e 2019-07-25 stsp } else
8056 0ebf8283 2019-07-24 stsp printf("invalid response '%c'\n", resp);
8057 0ebf8283 2019-07-24 stsp }
8058 0ebf8283 2019-07-24 stsp
8059 0ebf8283 2019-07-24 stsp return err;
8060 0ebf8283 2019-07-24 stsp }
8061 0ebf8283 2019-07-24 stsp
8062 0ebf8283 2019-07-24 stsp static const struct got_error *
8063 0ebf8283 2019-07-24 stsp histedit_complete(struct got_worktree *worktree,
8064 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex, struct got_reference *tmp_branch,
8065 3e3a69f1 2019-07-25 stsp struct got_reference *branch, struct got_repository *repo)
8066 0ebf8283 2019-07-24 stsp {
8067 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
8068 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
8069 3e3a69f1 2019-07-25 stsp return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
8070 3e3a69f1 2019-07-25 stsp branch, repo);
8071 0ebf8283 2019-07-24 stsp }
8072 0ebf8283 2019-07-24 stsp
8073 0ebf8283 2019-07-24 stsp static const struct got_error *
8074 0ebf8283 2019-07-24 stsp show_histedit_progress(struct got_commit_object *commit,
8075 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle, struct got_object_id *new_id)
8076 0ebf8283 2019-07-24 stsp {
8077 0ebf8283 2019-07-24 stsp const struct got_error *err;
8078 0ebf8283 2019-07-24 stsp char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
8079 0ebf8283 2019-07-24 stsp
8080 0ebf8283 2019-07-24 stsp err = got_object_id_str(&old_id_str, hle->commit_id);
8081 0ebf8283 2019-07-24 stsp if (err)
8082 0ebf8283 2019-07-24 stsp goto done;
8083 0ebf8283 2019-07-24 stsp
8084 0ebf8283 2019-07-24 stsp if (new_id) {
8085 0ebf8283 2019-07-24 stsp err = got_object_id_str(&new_id_str, new_id);
8086 0ebf8283 2019-07-24 stsp if (err)
8087 0ebf8283 2019-07-24 stsp goto done;
8088 0ebf8283 2019-07-24 stsp }
8089 0ebf8283 2019-07-24 stsp
8090 0ebf8283 2019-07-24 stsp old_id_str[12] = '\0';
8091 0ebf8283 2019-07-24 stsp if (new_id_str)
8092 0ebf8283 2019-07-24 stsp new_id_str[12] = '\0';
8093 0ebf8283 2019-07-24 stsp
8094 0ebf8283 2019-07-24 stsp if (hle->logmsg) {
8095 0ebf8283 2019-07-24 stsp logmsg = strdup(hle->logmsg);
8096 0ebf8283 2019-07-24 stsp if (logmsg == NULL) {
8097 0ebf8283 2019-07-24 stsp err = got_error_from_errno("strdup");
8098 0ebf8283 2019-07-24 stsp goto done;
8099 0ebf8283 2019-07-24 stsp }
8100 0ebf8283 2019-07-24 stsp trim_logmsg(logmsg, 42);
8101 0ebf8283 2019-07-24 stsp } else {
8102 0ebf8283 2019-07-24 stsp err = get_short_logmsg(&logmsg, 42, commit);
8103 0ebf8283 2019-07-24 stsp if (err)
8104 0ebf8283 2019-07-24 stsp goto done;
8105 0ebf8283 2019-07-24 stsp }
8106 0ebf8283 2019-07-24 stsp
8107 0ebf8283 2019-07-24 stsp switch (hle->cmd->code) {
8108 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_PICK:
8109 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_EDIT:
8110 0ebf8283 2019-07-24 stsp printf("%s -> %s: %s\n", old_id_str,
8111 0ebf8283 2019-07-24 stsp new_id_str ? new_id_str : "no-op change", logmsg);
8112 0ebf8283 2019-07-24 stsp break;
8113 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_DROP:
8114 0ebf8283 2019-07-24 stsp case GOT_HISTEDIT_FOLD:
8115 0ebf8283 2019-07-24 stsp printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
8116 0ebf8283 2019-07-24 stsp logmsg);
8117 0ebf8283 2019-07-24 stsp break;
8118 0ebf8283 2019-07-24 stsp default:
8119 0ebf8283 2019-07-24 stsp break;
8120 0ebf8283 2019-07-24 stsp }
8121 0ebf8283 2019-07-24 stsp done:
8122 0ebf8283 2019-07-24 stsp free(old_id_str);
8123 0ebf8283 2019-07-24 stsp free(new_id_str);
8124 0ebf8283 2019-07-24 stsp return err;
8125 0ebf8283 2019-07-24 stsp }
8126 0ebf8283 2019-07-24 stsp
8127 0ebf8283 2019-07-24 stsp static const struct got_error *
8128 0ebf8283 2019-07-24 stsp histedit_commit(struct got_pathlist_head *merged_paths,
8129 3e3a69f1 2019-07-25 stsp struct got_worktree *worktree, struct got_fileindex *fileindex,
8130 3e3a69f1 2019-07-25 stsp struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
8131 3e3a69f1 2019-07-25 stsp struct got_repository *repo)
8132 0ebf8283 2019-07-24 stsp {
8133 0ebf8283 2019-07-24 stsp const struct got_error *err;
8134 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
8135 0ebf8283 2019-07-24 stsp struct got_object_id *new_commit_id;
8136 0ebf8283 2019-07-24 stsp
8137 0ebf8283 2019-07-24 stsp if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
8138 0ebf8283 2019-07-24 stsp && hle->logmsg == NULL) {
8139 0ebf8283 2019-07-24 stsp err = histedit_edit_logmsg(hle, repo);
8140 0ebf8283 2019-07-24 stsp if (err)
8141 0ebf8283 2019-07-24 stsp return err;
8142 0ebf8283 2019-07-24 stsp }
8143 0ebf8283 2019-07-24 stsp
8144 0ebf8283 2019-07-24 stsp err = got_object_open_as_commit(&commit, repo, hle->commit_id);
8145 0ebf8283 2019-07-24 stsp if (err)
8146 0ebf8283 2019-07-24 stsp return err;
8147 0ebf8283 2019-07-24 stsp
8148 0ebf8283 2019-07-24 stsp err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
8149 3e3a69f1 2019-07-25 stsp worktree, fileindex, tmp_branch, commit, hle->commit_id,
8150 3e3a69f1 2019-07-25 stsp hle->logmsg, repo);
8151 0ebf8283 2019-07-24 stsp if (err) {
8152 0ebf8283 2019-07-24 stsp if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
8153 0ebf8283 2019-07-24 stsp goto done;
8154 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, NULL);
8155 0ebf8283 2019-07-24 stsp } else {
8156 0ebf8283 2019-07-24 stsp err = show_histedit_progress(commit, hle, new_commit_id);
8157 0ebf8283 2019-07-24 stsp free(new_commit_id);
8158 0ebf8283 2019-07-24 stsp }
8159 0ebf8283 2019-07-24 stsp done:
8160 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8161 0ebf8283 2019-07-24 stsp return err;
8162 0ebf8283 2019-07-24 stsp }
8163 0ebf8283 2019-07-24 stsp
8164 0ebf8283 2019-07-24 stsp static const struct got_error *
8165 0ebf8283 2019-07-24 stsp histedit_skip_commit(struct got_histedit_list_entry *hle,
8166 0ebf8283 2019-07-24 stsp struct got_worktree *worktree, struct got_repository *repo)
8167 0ebf8283 2019-07-24 stsp {
8168 0ebf8283 2019-07-24 stsp const struct got_error *error;
8169 0ebf8283 2019-07-24 stsp struct got_commit_object *commit;
8170 0ebf8283 2019-07-24 stsp
8171 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
8172 0ebf8283 2019-07-24 stsp repo);
8173 0ebf8283 2019-07-24 stsp if (error)
8174 0ebf8283 2019-07-24 stsp return error;
8175 0ebf8283 2019-07-24 stsp
8176 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo, hle->commit_id);
8177 0ebf8283 2019-07-24 stsp if (error)
8178 0ebf8283 2019-07-24 stsp return error;
8179 0ebf8283 2019-07-24 stsp
8180 0ebf8283 2019-07-24 stsp error = show_histedit_progress(commit, hle, NULL);
8181 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8182 0ebf8283 2019-07-24 stsp return error;
8183 ab20a43a 2020-01-29 stsp }
8184 ab20a43a 2020-01-29 stsp
8185 ab20a43a 2020-01-29 stsp static const struct got_error *
8186 ab20a43a 2020-01-29 stsp check_local_changes(void *arg, unsigned char status,
8187 ab20a43a 2020-01-29 stsp unsigned char staged_status, const char *path,
8188 ab20a43a 2020-01-29 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8189 ab20a43a 2020-01-29 stsp struct got_object_id *commit_id, int dirfd, const char *de_name)
8190 ab20a43a 2020-01-29 stsp {
8191 ab20a43a 2020-01-29 stsp int *have_local_changes = arg;
8192 ab20a43a 2020-01-29 stsp
8193 ab20a43a 2020-01-29 stsp switch (status) {
8194 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
8195 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
8196 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
8197 ab20a43a 2020-01-29 stsp case GOT_STATUS_CONFLICT:
8198 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
8199 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
8200 ab20a43a 2020-01-29 stsp default:
8201 ab20a43a 2020-01-29 stsp break;
8202 ab20a43a 2020-01-29 stsp }
8203 ab20a43a 2020-01-29 stsp
8204 ab20a43a 2020-01-29 stsp switch (staged_status) {
8205 ab20a43a 2020-01-29 stsp case GOT_STATUS_ADD:
8206 ab20a43a 2020-01-29 stsp case GOT_STATUS_DELETE:
8207 ab20a43a 2020-01-29 stsp case GOT_STATUS_MODIFY:
8208 ab20a43a 2020-01-29 stsp *have_local_changes = 1;
8209 ab20a43a 2020-01-29 stsp return got_error(GOT_ERR_CANCELLED);
8210 ab20a43a 2020-01-29 stsp default:
8211 ab20a43a 2020-01-29 stsp break;
8212 ab20a43a 2020-01-29 stsp }
8213 ab20a43a 2020-01-29 stsp
8214 ab20a43a 2020-01-29 stsp return NULL;
8215 0ebf8283 2019-07-24 stsp }
8216 0ebf8283 2019-07-24 stsp
8217 0ebf8283 2019-07-24 stsp static const struct got_error *
8218 0ebf8283 2019-07-24 stsp cmd_histedit(int argc, char *argv[])
8219 0ebf8283 2019-07-24 stsp {
8220 0ebf8283 2019-07-24 stsp const struct got_error *error = NULL;
8221 0ebf8283 2019-07-24 stsp struct got_worktree *worktree = NULL;
8222 3e3a69f1 2019-07-25 stsp struct got_fileindex *fileindex = NULL;
8223 0ebf8283 2019-07-24 stsp struct got_repository *repo = NULL;
8224 0ebf8283 2019-07-24 stsp char *cwd = NULL;
8225 0ebf8283 2019-07-24 stsp struct got_reference *branch = NULL;
8226 0ebf8283 2019-07-24 stsp struct got_reference *tmp_branch = NULL;
8227 0ebf8283 2019-07-24 stsp struct got_object_id *resume_commit_id = NULL;
8228 0ebf8283 2019-07-24 stsp struct got_object_id *base_commit_id = NULL;
8229 0ebf8283 2019-07-24 stsp struct got_object_id *head_commit_id = NULL;
8230 0ebf8283 2019-07-24 stsp struct got_commit_object *commit = NULL;
8231 9627c110 2020-04-18 stsp int ch, rebase_in_progress = 0;
8232 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8233 0ebf8283 2019-07-24 stsp int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
8234 083957f4 2020-02-24 stsp int edit_logmsg_only = 0;
8235 0ebf8283 2019-07-24 stsp const char *edit_script_path = NULL;
8236 0ebf8283 2019-07-24 stsp unsigned char rebase_status = GOT_STATUS_NO_CHANGE;
8237 0ebf8283 2019-07-24 stsp struct got_object_id_queue commits;
8238 0ebf8283 2019-07-24 stsp struct got_pathlist_head merged_paths;
8239 0ebf8283 2019-07-24 stsp const struct got_object_id_queue *parent_ids;
8240 0ebf8283 2019-07-24 stsp struct got_object_qid *pid;
8241 0ebf8283 2019-07-24 stsp struct got_histedit_list histedit_cmds;
8242 0ebf8283 2019-07-24 stsp struct got_histedit_list_entry *hle;
8243 0ebf8283 2019-07-24 stsp
8244 0ebf8283 2019-07-24 stsp SIMPLEQ_INIT(&commits);
8245 0ebf8283 2019-07-24 stsp TAILQ_INIT(&histedit_cmds);
8246 0ebf8283 2019-07-24 stsp TAILQ_INIT(&merged_paths);
8247 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8248 0ebf8283 2019-07-24 stsp
8249 083957f4 2020-02-24 stsp while ((ch = getopt(argc, argv, "acF:m")) != -1) {
8250 0ebf8283 2019-07-24 stsp switch (ch) {
8251 0ebf8283 2019-07-24 stsp case 'a':
8252 0ebf8283 2019-07-24 stsp abort_edit = 1;
8253 0ebf8283 2019-07-24 stsp break;
8254 0ebf8283 2019-07-24 stsp case 'c':
8255 0ebf8283 2019-07-24 stsp continue_edit = 1;
8256 0ebf8283 2019-07-24 stsp break;
8257 0ebf8283 2019-07-24 stsp case 'F':
8258 0ebf8283 2019-07-24 stsp edit_script_path = optarg;
8259 0ebf8283 2019-07-24 stsp break;
8260 083957f4 2020-02-24 stsp case 'm':
8261 083957f4 2020-02-24 stsp edit_logmsg_only = 1;
8262 083957f4 2020-02-24 stsp break;
8263 0ebf8283 2019-07-24 stsp default:
8264 0ebf8283 2019-07-24 stsp usage_histedit();
8265 0ebf8283 2019-07-24 stsp /* NOTREACHED */
8266 0ebf8283 2019-07-24 stsp }
8267 0ebf8283 2019-07-24 stsp }
8268 0ebf8283 2019-07-24 stsp
8269 0ebf8283 2019-07-24 stsp argc -= optind;
8270 0ebf8283 2019-07-24 stsp argv += optind;
8271 0ebf8283 2019-07-24 stsp
8272 0ebf8283 2019-07-24 stsp #ifndef PROFILE
8273 0ebf8283 2019-07-24 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8274 0ebf8283 2019-07-24 stsp "unveil", NULL) == -1)
8275 0ebf8283 2019-07-24 stsp err(1, "pledge");
8276 0ebf8283 2019-07-24 stsp #endif
8277 0ebf8283 2019-07-24 stsp if (abort_edit && continue_edit)
8278 083957f4 2020-02-24 stsp errx(1, "histedit's -a and -c options are mutually exclusive");
8279 083957f4 2020-02-24 stsp if (edit_script_path && edit_logmsg_only)
8280 083957f4 2020-02-24 stsp errx(1, "histedit's -F and -m options are mutually exclusive");
8281 083957f4 2020-02-24 stsp if (abort_edit && edit_logmsg_only)
8282 083957f4 2020-02-24 stsp errx(1, "histedit's -a and -m options are mutually exclusive");
8283 083957f4 2020-02-24 stsp if (continue_edit && edit_logmsg_only)
8284 083957f4 2020-02-24 stsp errx(1, "histedit's -c and -m options are mutually exclusive");
8285 0ebf8283 2019-07-24 stsp if (argc != 0)
8286 0ebf8283 2019-07-24 stsp usage_histedit();
8287 0ebf8283 2019-07-24 stsp
8288 0ebf8283 2019-07-24 stsp /*
8289 0ebf8283 2019-07-24 stsp * This command cannot apply unveil(2) in all cases because the
8290 0ebf8283 2019-07-24 stsp * user may choose to run an editor to edit the histedit script
8291 0ebf8283 2019-07-24 stsp * and to edit individual commit log messages.
8292 0ebf8283 2019-07-24 stsp * unveil(2) traverses exec(2); if an editor is used we have to
8293 0ebf8283 2019-07-24 stsp * apply unveil after edit script and log messages have been written.
8294 0ebf8283 2019-07-24 stsp * XXX TODO: Make use of unveil(2) where possible.
8295 0ebf8283 2019-07-24 stsp */
8296 0ebf8283 2019-07-24 stsp
8297 0ebf8283 2019-07-24 stsp cwd = getcwd(NULL, 0);
8298 0ebf8283 2019-07-24 stsp if (cwd == NULL) {
8299 0ebf8283 2019-07-24 stsp error = got_error_from_errno("getcwd");
8300 0ebf8283 2019-07-24 stsp goto done;
8301 0ebf8283 2019-07-24 stsp }
8302 0ebf8283 2019-07-24 stsp error = got_worktree_open(&worktree, cwd);
8303 fa51e947 2020-03-27 stsp if (error) {
8304 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8305 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "histedit", cwd);
8306 0ebf8283 2019-07-24 stsp goto done;
8307 fa51e947 2020-03-27 stsp }
8308 0ebf8283 2019-07-24 stsp
8309 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8310 c9956ddf 2019-09-08 stsp NULL);
8311 0ebf8283 2019-07-24 stsp if (error != NULL)
8312 0ebf8283 2019-07-24 stsp goto done;
8313 0ebf8283 2019-07-24 stsp
8314 0ebf8283 2019-07-24 stsp error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
8315 0ebf8283 2019-07-24 stsp if (error)
8316 0ebf8283 2019-07-24 stsp goto done;
8317 0ebf8283 2019-07-24 stsp if (rebase_in_progress) {
8318 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_REBASING);
8319 0ebf8283 2019-07-24 stsp goto done;
8320 0ebf8283 2019-07-24 stsp }
8321 0ebf8283 2019-07-24 stsp
8322 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
8323 0ebf8283 2019-07-24 stsp if (error)
8324 0ebf8283 2019-07-24 stsp goto done;
8325 0ebf8283 2019-07-24 stsp
8326 083957f4 2020-02-24 stsp if (edit_in_progress && edit_logmsg_only) {
8327 083957f4 2020-02-24 stsp error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
8328 083957f4 2020-02-24 stsp "histedit operation is in progress in this "
8329 083957f4 2020-02-24 stsp "work tree and must be continued or aborted "
8330 083957f4 2020-02-24 stsp "before the -m option can be used");
8331 083957f4 2020-02-24 stsp goto done;
8332 083957f4 2020-02-24 stsp }
8333 083957f4 2020-02-24 stsp
8334 0ebf8283 2019-07-24 stsp if (edit_in_progress && abort_edit) {
8335 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
8336 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
8337 3e3a69f1 2019-07-25 stsp worktree, repo);
8338 0ebf8283 2019-07-24 stsp if (error)
8339 0ebf8283 2019-07-24 stsp goto done;
8340 0ebf8283 2019-07-24 stsp printf("Switching work tree to %s\n",
8341 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
8342 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_abort(worktree, fileindex, repo,
8343 9627c110 2020-04-18 stsp branch, base_commit_id, update_progress, &upa);
8344 0ebf8283 2019-07-24 stsp if (error)
8345 0ebf8283 2019-07-24 stsp goto done;
8346 0ebf8283 2019-07-24 stsp printf("Histedit of %s aborted\n",
8347 0ebf8283 2019-07-24 stsp got_ref_get_symref_target(branch));
8348 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8349 0ebf8283 2019-07-24 stsp goto done; /* nothing else to do */
8350 0ebf8283 2019-07-24 stsp } else if (abort_edit) {
8351 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
8352 0ebf8283 2019-07-24 stsp goto done;
8353 0ebf8283 2019-07-24 stsp }
8354 0ebf8283 2019-07-24 stsp
8355 0ebf8283 2019-07-24 stsp if (continue_edit) {
8356 0ebf8283 2019-07-24 stsp char *path;
8357 0ebf8283 2019-07-24 stsp
8358 0ebf8283 2019-07-24 stsp if (!edit_in_progress) {
8359 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_NOT_HISTEDIT);
8360 0ebf8283 2019-07-24 stsp goto done;
8361 0ebf8283 2019-07-24 stsp }
8362 0ebf8283 2019-07-24 stsp
8363 c3022ba5 2019-07-27 stsp error = got_worktree_get_histedit_script_path(&path, worktree);
8364 0ebf8283 2019-07-24 stsp if (error)
8365 0ebf8283 2019-07-24 stsp goto done;
8366 0ebf8283 2019-07-24 stsp
8367 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds, path, repo);
8368 0ebf8283 2019-07-24 stsp free(path);
8369 0ebf8283 2019-07-24 stsp if (error)
8370 0ebf8283 2019-07-24 stsp goto done;
8371 0ebf8283 2019-07-24 stsp
8372 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_continue(&resume_commit_id,
8373 3e3a69f1 2019-07-25 stsp &tmp_branch, &branch, &base_commit_id, &fileindex,
8374 3e3a69f1 2019-07-25 stsp worktree, repo);
8375 0ebf8283 2019-07-24 stsp if (error)
8376 0ebf8283 2019-07-24 stsp goto done;
8377 0ebf8283 2019-07-24 stsp
8378 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
8379 0ebf8283 2019-07-24 stsp if (error)
8380 0ebf8283 2019-07-24 stsp goto done;
8381 0ebf8283 2019-07-24 stsp
8382 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
8383 0ebf8283 2019-07-24 stsp head_commit_id);
8384 0ebf8283 2019-07-24 stsp if (error)
8385 0ebf8283 2019-07-24 stsp goto done;
8386 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
8387 0ebf8283 2019-07-24 stsp pid = SIMPLEQ_FIRST(parent_ids);
8388 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
8389 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
8390 3aac7cf7 2019-07-25 stsp goto done;
8391 3aac7cf7 2019-07-25 stsp }
8392 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, head_commit_id, pid->id,
8393 8ca9bd68 2019-07-25 stsp base_commit_id, got_worktree_get_path_prefix(worktree),
8394 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
8395 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8396 0ebf8283 2019-07-24 stsp commit = NULL;
8397 0ebf8283 2019-07-24 stsp if (error)
8398 0ebf8283 2019-07-24 stsp goto done;
8399 0ebf8283 2019-07-24 stsp } else {
8400 0ebf8283 2019-07-24 stsp if (edit_in_progress) {
8401 0ebf8283 2019-07-24 stsp error = got_error(GOT_ERR_HISTEDIT_BUSY);
8402 0ebf8283 2019-07-24 stsp goto done;
8403 0ebf8283 2019-07-24 stsp }
8404 0ebf8283 2019-07-24 stsp
8405 0ebf8283 2019-07-24 stsp error = got_ref_open(&branch, repo,
8406 0ebf8283 2019-07-24 stsp got_worktree_get_head_ref_name(worktree), 0);
8407 0ebf8283 2019-07-24 stsp if (error != NULL)
8408 0ebf8283 2019-07-24 stsp goto done;
8409 0ebf8283 2019-07-24 stsp
8410 c7d20a3f 2019-07-30 stsp if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
8411 c7d20a3f 2019-07-30 stsp error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
8412 c7d20a3f 2019-07-30 stsp "will not edit commit history of a branch outside "
8413 c7d20a3f 2019-07-30 stsp "the \"refs/heads/\" reference namespace");
8414 c7d20a3f 2019-07-30 stsp goto done;
8415 c7d20a3f 2019-07-30 stsp }
8416 c7d20a3f 2019-07-30 stsp
8417 0ebf8283 2019-07-24 stsp error = got_ref_resolve(&head_commit_id, repo, branch);
8418 bfce7f83 2019-07-27 stsp got_ref_close(branch);
8419 bfce7f83 2019-07-27 stsp branch = NULL;
8420 0ebf8283 2019-07-24 stsp if (error)
8421 0ebf8283 2019-07-24 stsp goto done;
8422 0ebf8283 2019-07-24 stsp
8423 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
8424 0ebf8283 2019-07-24 stsp head_commit_id);
8425 0ebf8283 2019-07-24 stsp if (error)
8426 0ebf8283 2019-07-24 stsp goto done;
8427 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
8428 0ebf8283 2019-07-24 stsp pid = SIMPLEQ_FIRST(parent_ids);
8429 3aac7cf7 2019-07-25 stsp if (pid == NULL) {
8430 3aac7cf7 2019-07-25 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
8431 3aac7cf7 2019-07-25 stsp goto done;
8432 3aac7cf7 2019-07-25 stsp }
8433 8ca9bd68 2019-07-25 stsp error = collect_commits(&commits, head_commit_id, pid->id,
8434 8ca9bd68 2019-07-25 stsp got_worktree_get_base_commit_id(worktree),
8435 8ca9bd68 2019-07-25 stsp got_worktree_get_path_prefix(worktree),
8436 8ca9bd68 2019-07-25 stsp GOT_ERR_HISTEDIT_PATH, repo);
8437 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8438 0ebf8283 2019-07-24 stsp commit = NULL;
8439 0ebf8283 2019-07-24 stsp if (error)
8440 0ebf8283 2019-07-24 stsp goto done;
8441 0ebf8283 2019-07-24 stsp
8442 c5996fff 2020-01-29 stsp if (SIMPLEQ_EMPTY(&commits)) {
8443 c5996fff 2020-01-29 stsp error = got_error(GOT_ERR_EMPTY_HISTEDIT);
8444 c5996fff 2020-01-29 stsp goto done;
8445 c5996fff 2020-01-29 stsp }
8446 c5996fff 2020-01-29 stsp
8447 bfce7f83 2019-07-27 stsp error = got_worktree_histedit_prepare(&tmp_branch, &branch,
8448 bfce7f83 2019-07-27 stsp &base_commit_id, &fileindex, worktree, repo);
8449 bfce7f83 2019-07-27 stsp if (error)
8450 bfce7f83 2019-07-27 stsp goto done;
8451 bfce7f83 2019-07-27 stsp
8452 0ebf8283 2019-07-24 stsp if (edit_script_path) {
8453 0ebf8283 2019-07-24 stsp error = histedit_load_list(&histedit_cmds,
8454 0ebf8283 2019-07-24 stsp edit_script_path, repo);
8455 6ba2bea2 2019-07-27 stsp if (error) {
8456 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
8457 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
8458 9627c110 2020-04-18 stsp update_progress, &upa);
8459 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8460 0ebf8283 2019-07-24 stsp goto done;
8461 6ba2bea2 2019-07-27 stsp }
8462 0ebf8283 2019-07-24 stsp } else {
8463 514f2ffe 2020-01-29 stsp const char *branch_name;
8464 514f2ffe 2020-01-29 stsp branch_name = got_ref_get_symref_target(branch);
8465 514f2ffe 2020-01-29 stsp if (strncmp(branch_name, "refs/heads/", 11) == 0)
8466 514f2ffe 2020-01-29 stsp branch_name += 11;
8467 0ebf8283 2019-07-24 stsp error = histedit_edit_script(&histedit_cmds, &commits,
8468 083957f4 2020-02-24 stsp branch_name, edit_logmsg_only, repo);
8469 6ba2bea2 2019-07-27 stsp if (error) {
8470 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
8471 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
8472 9627c110 2020-04-18 stsp update_progress, &upa);
8473 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8474 0ebf8283 2019-07-24 stsp goto done;
8475 6ba2bea2 2019-07-27 stsp }
8476 0ebf8283 2019-07-24 stsp
8477 0ebf8283 2019-07-24 stsp }
8478 0ebf8283 2019-07-24 stsp
8479 0ebf8283 2019-07-24 stsp error = histedit_save_list(&histedit_cmds, worktree,
8480 0ebf8283 2019-07-24 stsp repo);
8481 6ba2bea2 2019-07-27 stsp if (error) {
8482 6ba2bea2 2019-07-27 stsp got_worktree_histedit_abort(worktree, fileindex,
8483 6ba2bea2 2019-07-27 stsp repo, branch, base_commit_id,
8484 9627c110 2020-04-18 stsp update_progress, &upa);
8485 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8486 0ebf8283 2019-07-24 stsp goto done;
8487 6ba2bea2 2019-07-27 stsp }
8488 0ebf8283 2019-07-24 stsp
8489 0ebf8283 2019-07-24 stsp }
8490 0ebf8283 2019-07-24 stsp
8491 4ec14e60 2019-08-28 hiltjo error = histedit_check_script(&histedit_cmds, &commits, repo);
8492 4ec14e60 2019-08-28 hiltjo if (error)
8493 0ebf8283 2019-07-24 stsp goto done;
8494 0ebf8283 2019-07-24 stsp
8495 0ebf8283 2019-07-24 stsp TAILQ_FOREACH(hle, &histedit_cmds, entry) {
8496 0ebf8283 2019-07-24 stsp if (resume_commit_id) {
8497 0ebf8283 2019-07-24 stsp if (got_object_id_cmp(hle->commit_id,
8498 0ebf8283 2019-07-24 stsp resume_commit_id) != 0)
8499 0ebf8283 2019-07-24 stsp continue;
8500 0ebf8283 2019-07-24 stsp
8501 0ebf8283 2019-07-24 stsp resume_commit_id = NULL;
8502 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP ||
8503 0ebf8283 2019-07-24 stsp hle->cmd->code == GOT_HISTEDIT_FOLD) {
8504 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree,
8505 0ebf8283 2019-07-24 stsp repo);
8506 ab20a43a 2020-01-29 stsp if (error)
8507 ab20a43a 2020-01-29 stsp goto done;
8508 0ebf8283 2019-07-24 stsp } else {
8509 ab20a43a 2020-01-29 stsp struct got_pathlist_head paths;
8510 ab20a43a 2020-01-29 stsp int have_changes = 0;
8511 ab20a43a 2020-01-29 stsp
8512 ab20a43a 2020-01-29 stsp TAILQ_INIT(&paths);
8513 ab20a43a 2020-01-29 stsp error = got_pathlist_append(&paths, "", NULL);
8514 ab20a43a 2020-01-29 stsp if (error)
8515 ab20a43a 2020-01-29 stsp goto done;
8516 ab20a43a 2020-01-29 stsp error = got_worktree_status(worktree, &paths,
8517 ab20a43a 2020-01-29 stsp repo, check_local_changes, &have_changes,
8518 ab20a43a 2020-01-29 stsp check_cancelled, NULL);
8519 ab20a43a 2020-01-29 stsp got_pathlist_free(&paths);
8520 ab20a43a 2020-01-29 stsp if (error) {
8521 ab20a43a 2020-01-29 stsp if (error->code != GOT_ERR_CANCELLED)
8522 ab20a43a 2020-01-29 stsp goto done;
8523 ab20a43a 2020-01-29 stsp if (sigint_received || sigpipe_received)
8524 ab20a43a 2020-01-29 stsp goto done;
8525 ab20a43a 2020-01-29 stsp }
8526 ab20a43a 2020-01-29 stsp if (have_changes) {
8527 ab20a43a 2020-01-29 stsp error = histedit_commit(NULL, worktree,
8528 ab20a43a 2020-01-29 stsp fileindex, tmp_branch, hle, repo);
8529 ab20a43a 2020-01-29 stsp if (error)
8530 ab20a43a 2020-01-29 stsp goto done;
8531 ab20a43a 2020-01-29 stsp } else {
8532 ab20a43a 2020-01-29 stsp error = got_object_open_as_commit(
8533 ab20a43a 2020-01-29 stsp &commit, repo, hle->commit_id);
8534 ab20a43a 2020-01-29 stsp if (error)
8535 ab20a43a 2020-01-29 stsp goto done;
8536 ab20a43a 2020-01-29 stsp error = show_histedit_progress(commit,
8537 ab20a43a 2020-01-29 stsp hle, NULL);
8538 ab20a43a 2020-01-29 stsp got_object_commit_close(commit);
8539 ab20a43a 2020-01-29 stsp commit = NULL;
8540 ab20a43a 2020-01-29 stsp if (error)
8541 ab20a43a 2020-01-29 stsp goto done;
8542 ab20a43a 2020-01-29 stsp }
8543 0ebf8283 2019-07-24 stsp }
8544 0ebf8283 2019-07-24 stsp continue;
8545 0ebf8283 2019-07-24 stsp }
8546 0ebf8283 2019-07-24 stsp
8547 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_DROP) {
8548 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
8549 0ebf8283 2019-07-24 stsp if (error)
8550 0ebf8283 2019-07-24 stsp goto done;
8551 0ebf8283 2019-07-24 stsp continue;
8552 0ebf8283 2019-07-24 stsp }
8553 0ebf8283 2019-07-24 stsp
8554 0ebf8283 2019-07-24 stsp error = got_object_open_as_commit(&commit, repo,
8555 0ebf8283 2019-07-24 stsp hle->commit_id);
8556 0ebf8283 2019-07-24 stsp if (error)
8557 0ebf8283 2019-07-24 stsp goto done;
8558 0ebf8283 2019-07-24 stsp parent_ids = got_object_commit_get_parent_ids(commit);
8559 0ebf8283 2019-07-24 stsp pid = SIMPLEQ_FIRST(parent_ids);
8560 0ebf8283 2019-07-24 stsp
8561 0ebf8283 2019-07-24 stsp error = got_worktree_histedit_merge_files(&merged_paths,
8562 3e3a69f1 2019-07-25 stsp worktree, fileindex, pid->id, hle->commit_id, repo,
8563 9627c110 2020-04-18 stsp update_progress, &upa, check_cancelled, NULL);
8564 0ebf8283 2019-07-24 stsp if (error)
8565 0ebf8283 2019-07-24 stsp goto done;
8566 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8567 0ebf8283 2019-07-24 stsp commit = NULL;
8568 0ebf8283 2019-07-24 stsp
8569 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8570 9627c110 2020-04-18 stsp if (upa.conflicts > 0)
8571 9627c110 2020-04-18 stsp rebase_status = GOT_STATUS_CONFLICT;
8572 9627c110 2020-04-18 stsp
8573 0ebf8283 2019-07-24 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
8574 a0ea4fc0 2020-02-28 stsp error = show_rebase_merge_conflict(hle->commit_id,
8575 a0ea4fc0 2020-02-28 stsp repo);
8576 a0ea4fc0 2020-02-28 stsp if (error)
8577 a0ea4fc0 2020-02-28 stsp goto done;
8578 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
8579 0ebf8283 2019-07-24 stsp break;
8580 0ebf8283 2019-07-24 stsp }
8581 0ebf8283 2019-07-24 stsp
8582 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
8583 0ebf8283 2019-07-24 stsp char *id_str;
8584 0ebf8283 2019-07-24 stsp error = got_object_id_str(&id_str, hle->commit_id);
8585 0ebf8283 2019-07-24 stsp if (error)
8586 0ebf8283 2019-07-24 stsp goto done;
8587 0ebf8283 2019-07-24 stsp printf("Stopping histedit for amending commit %s\n",
8588 0ebf8283 2019-07-24 stsp id_str);
8589 0ebf8283 2019-07-24 stsp free(id_str);
8590 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
8591 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree,
8592 3e3a69f1 2019-07-25 stsp fileindex);
8593 0ebf8283 2019-07-24 stsp goto done;
8594 0ebf8283 2019-07-24 stsp }
8595 0ebf8283 2019-07-24 stsp
8596 0ebf8283 2019-07-24 stsp if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
8597 0ebf8283 2019-07-24 stsp error = histedit_skip_commit(hle, worktree, repo);
8598 0ebf8283 2019-07-24 stsp if (error)
8599 0ebf8283 2019-07-24 stsp goto done;
8600 0ebf8283 2019-07-24 stsp continue;
8601 0ebf8283 2019-07-24 stsp }
8602 0ebf8283 2019-07-24 stsp
8603 3e3a69f1 2019-07-25 stsp error = histedit_commit(&merged_paths, worktree, fileindex,
8604 3e3a69f1 2019-07-25 stsp tmp_branch, hle, repo);
8605 0ebf8283 2019-07-24 stsp got_worktree_rebase_pathlist_free(&merged_paths);
8606 0ebf8283 2019-07-24 stsp if (error)
8607 0ebf8283 2019-07-24 stsp goto done;
8608 0ebf8283 2019-07-24 stsp }
8609 0ebf8283 2019-07-24 stsp
8610 0ebf8283 2019-07-24 stsp if (rebase_status == GOT_STATUS_CONFLICT) {
8611 3e3a69f1 2019-07-25 stsp error = got_worktree_histedit_postpone(worktree, fileindex);
8612 0ebf8283 2019-07-24 stsp if (error)
8613 0ebf8283 2019-07-24 stsp goto done;
8614 0ebf8283 2019-07-24 stsp error = got_error_msg(GOT_ERR_CONFLICTS,
8615 4cb8f8f3 2020-03-05 stsp "conflicts must be resolved before histedit can continue");
8616 0ebf8283 2019-07-24 stsp } else
8617 3e3a69f1 2019-07-25 stsp error = histedit_complete(worktree, fileindex, tmp_branch,
8618 3e3a69f1 2019-07-25 stsp branch, repo);
8619 0ebf8283 2019-07-24 stsp done:
8620 0ebf8283 2019-07-24 stsp got_object_id_queue_free(&commits);
8621 bfce7f83 2019-07-27 stsp histedit_free_list(&histedit_cmds);
8622 0ebf8283 2019-07-24 stsp free(head_commit_id);
8623 0ebf8283 2019-07-24 stsp free(base_commit_id);
8624 0ebf8283 2019-07-24 stsp free(resume_commit_id);
8625 0ebf8283 2019-07-24 stsp if (commit)
8626 0ebf8283 2019-07-24 stsp got_object_commit_close(commit);
8627 0ebf8283 2019-07-24 stsp if (branch)
8628 0ebf8283 2019-07-24 stsp got_ref_close(branch);
8629 0ebf8283 2019-07-24 stsp if (tmp_branch)
8630 0ebf8283 2019-07-24 stsp got_ref_close(tmp_branch);
8631 0ebf8283 2019-07-24 stsp if (worktree)
8632 0ebf8283 2019-07-24 stsp got_worktree_close(worktree);
8633 2822a352 2019-10-15 stsp if (repo)
8634 2822a352 2019-10-15 stsp got_repo_close(repo);
8635 2822a352 2019-10-15 stsp return error;
8636 2822a352 2019-10-15 stsp }
8637 2822a352 2019-10-15 stsp
8638 2822a352 2019-10-15 stsp __dead static void
8639 2822a352 2019-10-15 stsp usage_integrate(void)
8640 2822a352 2019-10-15 stsp {
8641 2822a352 2019-10-15 stsp fprintf(stderr, "usage: %s integrate branch\n", getprogname());
8642 2822a352 2019-10-15 stsp exit(1);
8643 2822a352 2019-10-15 stsp }
8644 2822a352 2019-10-15 stsp
8645 2822a352 2019-10-15 stsp static const struct got_error *
8646 2822a352 2019-10-15 stsp cmd_integrate(int argc, char *argv[])
8647 2822a352 2019-10-15 stsp {
8648 2822a352 2019-10-15 stsp const struct got_error *error = NULL;
8649 2822a352 2019-10-15 stsp struct got_repository *repo = NULL;
8650 2822a352 2019-10-15 stsp struct got_worktree *worktree = NULL;
8651 2822a352 2019-10-15 stsp char *cwd = NULL, *refname = NULL, *base_refname = NULL;
8652 2822a352 2019-10-15 stsp const char *branch_arg = NULL;
8653 2822a352 2019-10-15 stsp struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
8654 2822a352 2019-10-15 stsp struct got_fileindex *fileindex = NULL;
8655 2822a352 2019-10-15 stsp struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
8656 9627c110 2020-04-18 stsp int ch;
8657 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8658 2822a352 2019-10-15 stsp
8659 2822a352 2019-10-15 stsp while ((ch = getopt(argc, argv, "")) != -1) {
8660 2822a352 2019-10-15 stsp switch (ch) {
8661 2822a352 2019-10-15 stsp default:
8662 2822a352 2019-10-15 stsp usage_integrate();
8663 2822a352 2019-10-15 stsp /* NOTREACHED */
8664 2822a352 2019-10-15 stsp }
8665 2822a352 2019-10-15 stsp }
8666 2822a352 2019-10-15 stsp
8667 2822a352 2019-10-15 stsp argc -= optind;
8668 2822a352 2019-10-15 stsp argv += optind;
8669 2822a352 2019-10-15 stsp
8670 2822a352 2019-10-15 stsp if (argc != 1)
8671 2822a352 2019-10-15 stsp usage_integrate();
8672 2822a352 2019-10-15 stsp branch_arg = argv[0];
8673 2822a352 2019-10-15 stsp
8674 2822a352 2019-10-15 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8675 2822a352 2019-10-15 stsp "unveil", NULL) == -1)
8676 2822a352 2019-10-15 stsp err(1, "pledge");
8677 2822a352 2019-10-15 stsp
8678 2822a352 2019-10-15 stsp cwd = getcwd(NULL, 0);
8679 2822a352 2019-10-15 stsp if (cwd == NULL) {
8680 2822a352 2019-10-15 stsp error = got_error_from_errno("getcwd");
8681 2822a352 2019-10-15 stsp goto done;
8682 2822a352 2019-10-15 stsp }
8683 2822a352 2019-10-15 stsp
8684 2822a352 2019-10-15 stsp error = got_worktree_open(&worktree, cwd);
8685 fa51e947 2020-03-27 stsp if (error) {
8686 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8687 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "integrate",
8688 fa51e947 2020-03-27 stsp cwd);
8689 2822a352 2019-10-15 stsp goto done;
8690 fa51e947 2020-03-27 stsp }
8691 2822a352 2019-10-15 stsp
8692 2822a352 2019-10-15 stsp error = check_rebase_or_histedit_in_progress(worktree);
8693 2822a352 2019-10-15 stsp if (error)
8694 2822a352 2019-10-15 stsp goto done;
8695 2822a352 2019-10-15 stsp
8696 2822a352 2019-10-15 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8697 2822a352 2019-10-15 stsp NULL);
8698 2822a352 2019-10-15 stsp if (error != NULL)
8699 2822a352 2019-10-15 stsp goto done;
8700 2822a352 2019-10-15 stsp
8701 2822a352 2019-10-15 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8702 2822a352 2019-10-15 stsp got_worktree_get_root_path(worktree));
8703 2822a352 2019-10-15 stsp if (error)
8704 2822a352 2019-10-15 stsp goto done;
8705 2822a352 2019-10-15 stsp
8706 2822a352 2019-10-15 stsp if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
8707 2822a352 2019-10-15 stsp error = got_error_from_errno("asprintf");
8708 2822a352 2019-10-15 stsp goto done;
8709 2822a352 2019-10-15 stsp }
8710 2822a352 2019-10-15 stsp
8711 2822a352 2019-10-15 stsp error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
8712 2822a352 2019-10-15 stsp &base_branch_ref, worktree, refname, repo);
8713 2822a352 2019-10-15 stsp if (error)
8714 2822a352 2019-10-15 stsp goto done;
8715 2822a352 2019-10-15 stsp
8716 2822a352 2019-10-15 stsp refname = strdup(got_ref_get_name(branch_ref));
8717 2822a352 2019-10-15 stsp if (refname == NULL) {
8718 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
8719 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
8720 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
8721 2822a352 2019-10-15 stsp goto done;
8722 2822a352 2019-10-15 stsp }
8723 2822a352 2019-10-15 stsp base_refname = strdup(got_ref_get_name(base_branch_ref));
8724 2822a352 2019-10-15 stsp if (base_refname == NULL) {
8725 2822a352 2019-10-15 stsp error = got_error_from_errno("strdup");
8726 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
8727 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
8728 2822a352 2019-10-15 stsp goto done;
8729 2822a352 2019-10-15 stsp }
8730 2822a352 2019-10-15 stsp
8731 2822a352 2019-10-15 stsp error = got_ref_resolve(&commit_id, repo, branch_ref);
8732 2822a352 2019-10-15 stsp if (error)
8733 2822a352 2019-10-15 stsp goto done;
8734 2822a352 2019-10-15 stsp
8735 2822a352 2019-10-15 stsp error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
8736 2822a352 2019-10-15 stsp if (error)
8737 2822a352 2019-10-15 stsp goto done;
8738 2822a352 2019-10-15 stsp
8739 2822a352 2019-10-15 stsp if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
8740 2822a352 2019-10-15 stsp error = got_error_msg(GOT_ERR_SAME_BRANCH,
8741 2822a352 2019-10-15 stsp "specified branch has already been integrated");
8742 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
8743 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
8744 2822a352 2019-10-15 stsp goto done;
8745 2822a352 2019-10-15 stsp }
8746 2822a352 2019-10-15 stsp
8747 3aef623b 2019-10-15 stsp error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
8748 2822a352 2019-10-15 stsp if (error) {
8749 2822a352 2019-10-15 stsp if (error->code == GOT_ERR_ANCESTRY)
8750 2822a352 2019-10-15 stsp error = got_error(GOT_ERR_REBASE_REQUIRED);
8751 2822a352 2019-10-15 stsp got_worktree_integrate_abort(worktree, fileindex, repo,
8752 2822a352 2019-10-15 stsp branch_ref, base_branch_ref);
8753 2822a352 2019-10-15 stsp goto done;
8754 2822a352 2019-10-15 stsp }
8755 2822a352 2019-10-15 stsp
8756 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
8757 2822a352 2019-10-15 stsp error = got_worktree_integrate_continue(worktree, fileindex, repo,
8758 9627c110 2020-04-18 stsp branch_ref, base_branch_ref, update_progress, &upa,
8759 2822a352 2019-10-15 stsp check_cancelled, NULL);
8760 2822a352 2019-10-15 stsp if (error)
8761 2822a352 2019-10-15 stsp goto done;
8762 2822a352 2019-10-15 stsp
8763 2822a352 2019-10-15 stsp printf("Integrated %s into %s\n", refname, base_refname);
8764 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
8765 2822a352 2019-10-15 stsp done:
8766 715dc77e 2019-08-03 stsp if (repo)
8767 715dc77e 2019-08-03 stsp got_repo_close(repo);
8768 2822a352 2019-10-15 stsp if (worktree)
8769 2822a352 2019-10-15 stsp got_worktree_close(worktree);
8770 2822a352 2019-10-15 stsp free(cwd);
8771 2822a352 2019-10-15 stsp free(base_commit_id);
8772 2822a352 2019-10-15 stsp free(commit_id);
8773 2822a352 2019-10-15 stsp free(refname);
8774 2822a352 2019-10-15 stsp free(base_refname);
8775 715dc77e 2019-08-03 stsp return error;
8776 715dc77e 2019-08-03 stsp }
8777 715dc77e 2019-08-03 stsp
8778 715dc77e 2019-08-03 stsp __dead static void
8779 715dc77e 2019-08-03 stsp usage_stage(void)
8780 715dc77e 2019-08-03 stsp {
8781 f3055044 2019-08-07 stsp fprintf(stderr, "usage: %s stage [-l] | [-p] [-F response-script] "
8782 35213c7c 2020-07-23 stsp "[-S] [file-path ...]\n",
8783 715dc77e 2019-08-03 stsp getprogname());
8784 715dc77e 2019-08-03 stsp exit(1);
8785 715dc77e 2019-08-03 stsp }
8786 715dc77e 2019-08-03 stsp
8787 715dc77e 2019-08-03 stsp static const struct got_error *
8788 408b4ebc 2019-08-03 stsp print_stage(void *arg, unsigned char status, unsigned char staged_status,
8789 408b4ebc 2019-08-03 stsp const char *path, struct got_object_id *blob_id,
8790 12463d8b 2019-12-13 stsp struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
8791 12463d8b 2019-12-13 stsp int dirfd, const char *de_name)
8792 408b4ebc 2019-08-03 stsp {
8793 408b4ebc 2019-08-03 stsp const struct got_error *err = NULL;
8794 408b4ebc 2019-08-03 stsp char *id_str = NULL;
8795 408b4ebc 2019-08-03 stsp
8796 408b4ebc 2019-08-03 stsp if (staged_status != GOT_STATUS_ADD &&
8797 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_MODIFY &&
8798 408b4ebc 2019-08-03 stsp staged_status != GOT_STATUS_DELETE)
8799 408b4ebc 2019-08-03 stsp return NULL;
8800 408b4ebc 2019-08-03 stsp
8801 408b4ebc 2019-08-03 stsp if (staged_status == GOT_STATUS_ADD ||
8802 408b4ebc 2019-08-03 stsp staged_status == GOT_STATUS_MODIFY)
8803 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, staged_blob_id);
8804 408b4ebc 2019-08-03 stsp else
8805 408b4ebc 2019-08-03 stsp err = got_object_id_str(&id_str, blob_id);
8806 408b4ebc 2019-08-03 stsp if (err)
8807 408b4ebc 2019-08-03 stsp return err;
8808 408b4ebc 2019-08-03 stsp
8809 408b4ebc 2019-08-03 stsp printf("%s %c %s\n", id_str, staged_status, path);
8810 408b4ebc 2019-08-03 stsp free(id_str);
8811 dc424a06 2019-08-07 stsp return NULL;
8812 dc424a06 2019-08-07 stsp }
8813 2e1f37b0 2019-08-08 stsp
8814 dc424a06 2019-08-07 stsp static const struct got_error *
8815 715dc77e 2019-08-03 stsp cmd_stage(int argc, char *argv[])
8816 715dc77e 2019-08-03 stsp {
8817 715dc77e 2019-08-03 stsp const struct got_error *error = NULL;
8818 715dc77e 2019-08-03 stsp struct got_repository *repo = NULL;
8819 715dc77e 2019-08-03 stsp struct got_worktree *worktree = NULL;
8820 715dc77e 2019-08-03 stsp char *cwd = NULL;
8821 715dc77e 2019-08-03 stsp struct got_pathlist_head paths;
8822 715dc77e 2019-08-03 stsp struct got_pathlist_entry *pe;
8823 35213c7c 2020-07-23 stsp int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
8824 dc424a06 2019-08-07 stsp FILE *patch_script_file = NULL;
8825 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
8826 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
8827 715dc77e 2019-08-03 stsp
8828 715dc77e 2019-08-03 stsp TAILQ_INIT(&paths);
8829 715dc77e 2019-08-03 stsp
8830 35213c7c 2020-07-23 stsp while ((ch = getopt(argc, argv, "lpF:S")) != -1) {
8831 715dc77e 2019-08-03 stsp switch (ch) {
8832 408b4ebc 2019-08-03 stsp case 'l':
8833 408b4ebc 2019-08-03 stsp list_stage = 1;
8834 408b4ebc 2019-08-03 stsp break;
8835 dc424a06 2019-08-07 stsp case 'p':
8836 dc424a06 2019-08-07 stsp pflag = 1;
8837 dc424a06 2019-08-07 stsp break;
8838 dc424a06 2019-08-07 stsp case 'F':
8839 dc424a06 2019-08-07 stsp patch_script_path = optarg;
8840 dc424a06 2019-08-07 stsp break;
8841 35213c7c 2020-07-23 stsp case 'S':
8842 35213c7c 2020-07-23 stsp allow_bad_symlinks = 1;
8843 35213c7c 2020-07-23 stsp break;
8844 715dc77e 2019-08-03 stsp default:
8845 715dc77e 2019-08-03 stsp usage_stage();
8846 715dc77e 2019-08-03 stsp /* NOTREACHED */
8847 715dc77e 2019-08-03 stsp }
8848 715dc77e 2019-08-03 stsp }
8849 715dc77e 2019-08-03 stsp
8850 715dc77e 2019-08-03 stsp argc -= optind;
8851 715dc77e 2019-08-03 stsp argv += optind;
8852 715dc77e 2019-08-03 stsp
8853 715dc77e 2019-08-03 stsp #ifndef PROFILE
8854 715dc77e 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8855 715dc77e 2019-08-03 stsp "unveil", NULL) == -1)
8856 715dc77e 2019-08-03 stsp err(1, "pledge");
8857 715dc77e 2019-08-03 stsp #endif
8858 2db2652d 2019-08-07 stsp if (list_stage && (pflag || patch_script_path))
8859 2db2652d 2019-08-07 stsp errx(1, "-l option cannot be used with other options");
8860 dc424a06 2019-08-07 stsp if (patch_script_path && !pflag)
8861 dc424a06 2019-08-07 stsp errx(1, "-F option can only be used together with -p option");
8862 715dc77e 2019-08-03 stsp
8863 715dc77e 2019-08-03 stsp cwd = getcwd(NULL, 0);
8864 715dc77e 2019-08-03 stsp if (cwd == NULL) {
8865 715dc77e 2019-08-03 stsp error = got_error_from_errno("getcwd");
8866 715dc77e 2019-08-03 stsp goto done;
8867 715dc77e 2019-08-03 stsp }
8868 715dc77e 2019-08-03 stsp
8869 715dc77e 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
8870 fa51e947 2020-03-27 stsp if (error) {
8871 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8872 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "stage", cwd);
8873 715dc77e 2019-08-03 stsp goto done;
8874 fa51e947 2020-03-27 stsp }
8875 715dc77e 2019-08-03 stsp
8876 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8877 c9956ddf 2019-09-08 stsp NULL);
8878 715dc77e 2019-08-03 stsp if (error != NULL)
8879 715dc77e 2019-08-03 stsp goto done;
8880 715dc77e 2019-08-03 stsp
8881 dc424a06 2019-08-07 stsp if (patch_script_path) {
8882 dc424a06 2019-08-07 stsp patch_script_file = fopen(patch_script_path, "r");
8883 dc424a06 2019-08-07 stsp if (patch_script_file == NULL) {
8884 dc424a06 2019-08-07 stsp error = got_error_from_errno2("fopen",
8885 dc424a06 2019-08-07 stsp patch_script_path);
8886 dc424a06 2019-08-07 stsp goto done;
8887 dc424a06 2019-08-07 stsp }
8888 dc424a06 2019-08-07 stsp }
8889 9fd7cd22 2019-08-30 stsp error = apply_unveil(got_repo_get_path(repo), 0,
8890 715dc77e 2019-08-03 stsp got_worktree_get_root_path(worktree));
8891 715dc77e 2019-08-03 stsp if (error)
8892 715dc77e 2019-08-03 stsp goto done;
8893 715dc77e 2019-08-03 stsp
8894 6d022e97 2019-08-04 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
8895 6d022e97 2019-08-04 stsp if (error)
8896 6d022e97 2019-08-04 stsp goto done;
8897 715dc77e 2019-08-03 stsp
8898 6d022e97 2019-08-04 stsp if (list_stage)
8899 408b4ebc 2019-08-03 stsp error = got_worktree_status(worktree, &paths, repo,
8900 408b4ebc 2019-08-03 stsp print_stage, NULL, check_cancelled, NULL);
8901 2e1f37b0 2019-08-08 stsp else {
8902 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
8903 2e1f37b0 2019-08-08 stsp cpa.action = "stage";
8904 dc424a06 2019-08-07 stsp error = got_worktree_stage(worktree, &paths,
8905 dc424a06 2019-08-07 stsp pflag ? NULL : print_status, NULL,
8906 35213c7c 2020-07-23 stsp pflag ? choose_patch : NULL, &cpa,
8907 35213c7c 2020-07-23 stsp allow_bad_symlinks, repo);
8908 2e1f37b0 2019-08-08 stsp }
8909 ad493afc 2019-08-03 stsp done:
8910 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
8911 2e1f37b0 2019-08-08 stsp error == NULL)
8912 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
8913 ad493afc 2019-08-03 stsp if (repo)
8914 ad493afc 2019-08-03 stsp got_repo_close(repo);
8915 ad493afc 2019-08-03 stsp if (worktree)
8916 ad493afc 2019-08-03 stsp got_worktree_close(worktree);
8917 ad493afc 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
8918 ad493afc 2019-08-03 stsp free((char *)pe->path);
8919 ad493afc 2019-08-03 stsp got_pathlist_free(&paths);
8920 ad493afc 2019-08-03 stsp free(cwd);
8921 ad493afc 2019-08-03 stsp return error;
8922 ad493afc 2019-08-03 stsp }
8923 ad493afc 2019-08-03 stsp
8924 ad493afc 2019-08-03 stsp __dead static void
8925 ad493afc 2019-08-03 stsp usage_unstage(void)
8926 ad493afc 2019-08-03 stsp {
8927 2e1f37b0 2019-08-08 stsp fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
8928 2e1f37b0 2019-08-08 stsp "[file-path ...]\n",
8929 ad493afc 2019-08-03 stsp getprogname());
8930 ad493afc 2019-08-03 stsp exit(1);
8931 ad493afc 2019-08-03 stsp }
8932 ad493afc 2019-08-03 stsp
8933 ad493afc 2019-08-03 stsp
8934 ad493afc 2019-08-03 stsp static const struct got_error *
8935 ad493afc 2019-08-03 stsp cmd_unstage(int argc, char *argv[])
8936 ad493afc 2019-08-03 stsp {
8937 ad493afc 2019-08-03 stsp const struct got_error *error = NULL;
8938 ad493afc 2019-08-03 stsp struct got_repository *repo = NULL;
8939 ad493afc 2019-08-03 stsp struct got_worktree *worktree = NULL;
8940 ad493afc 2019-08-03 stsp char *cwd = NULL;
8941 ad493afc 2019-08-03 stsp struct got_pathlist_head paths;
8942 ad493afc 2019-08-03 stsp struct got_pathlist_entry *pe;
8943 9627c110 2020-04-18 stsp int ch, pflag = 0;
8944 9627c110 2020-04-18 stsp struct got_update_progress_arg upa;
8945 2e1f37b0 2019-08-08 stsp FILE *patch_script_file = NULL;
8946 2e1f37b0 2019-08-08 stsp const char *patch_script_path = NULL;
8947 2e1f37b0 2019-08-08 stsp struct choose_patch_arg cpa;
8948 ad493afc 2019-08-03 stsp
8949 ad493afc 2019-08-03 stsp TAILQ_INIT(&paths);
8950 ad493afc 2019-08-03 stsp
8951 2e1f37b0 2019-08-08 stsp while ((ch = getopt(argc, argv, "pF:")) != -1) {
8952 ad493afc 2019-08-03 stsp switch (ch) {
8953 2e1f37b0 2019-08-08 stsp case 'p':
8954 2e1f37b0 2019-08-08 stsp pflag = 1;
8955 2e1f37b0 2019-08-08 stsp break;
8956 2e1f37b0 2019-08-08 stsp case 'F':
8957 2e1f37b0 2019-08-08 stsp patch_script_path = optarg;
8958 2e1f37b0 2019-08-08 stsp break;
8959 ad493afc 2019-08-03 stsp default:
8960 ad493afc 2019-08-03 stsp usage_unstage();
8961 ad493afc 2019-08-03 stsp /* NOTREACHED */
8962 ad493afc 2019-08-03 stsp }
8963 ad493afc 2019-08-03 stsp }
8964 ad493afc 2019-08-03 stsp
8965 ad493afc 2019-08-03 stsp argc -= optind;
8966 ad493afc 2019-08-03 stsp argv += optind;
8967 ad493afc 2019-08-03 stsp
8968 ad493afc 2019-08-03 stsp #ifndef PROFILE
8969 ad493afc 2019-08-03 stsp if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8970 ad493afc 2019-08-03 stsp "unveil", NULL) == -1)
8971 ad493afc 2019-08-03 stsp err(1, "pledge");
8972 ad493afc 2019-08-03 stsp #endif
8973 2e1f37b0 2019-08-08 stsp if (patch_script_path && !pflag)
8974 2e1f37b0 2019-08-08 stsp errx(1, "-F option can only be used together with -p option");
8975 2e1f37b0 2019-08-08 stsp
8976 ad493afc 2019-08-03 stsp cwd = getcwd(NULL, 0);
8977 ad493afc 2019-08-03 stsp if (cwd == NULL) {
8978 ad493afc 2019-08-03 stsp error = got_error_from_errno("getcwd");
8979 ad493afc 2019-08-03 stsp goto done;
8980 ad493afc 2019-08-03 stsp }
8981 ad493afc 2019-08-03 stsp
8982 ad493afc 2019-08-03 stsp error = got_worktree_open(&worktree, cwd);
8983 fa51e947 2020-03-27 stsp if (error) {
8984 fa51e947 2020-03-27 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
8985 fa51e947 2020-03-27 stsp error = wrap_not_worktree_error(error, "unstage", cwd);
8986 ad493afc 2019-08-03 stsp goto done;
8987 fa51e947 2020-03-27 stsp }
8988 ad493afc 2019-08-03 stsp
8989 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8990 c9956ddf 2019-09-08 stsp NULL);
8991 ad493afc 2019-08-03 stsp if (error != NULL)
8992 ad493afc 2019-08-03 stsp goto done;
8993 ad493afc 2019-08-03 stsp
8994 2e1f37b0 2019-08-08 stsp if (patch_script_path) {
8995 2e1f37b0 2019-08-08 stsp patch_script_file = fopen(patch_script_path, "r");
8996 2e1f37b0 2019-08-08 stsp if (patch_script_file == NULL) {
8997 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fopen",
8998 2e1f37b0 2019-08-08 stsp patch_script_path);
8999 2e1f37b0 2019-08-08 stsp goto done;
9000 2e1f37b0 2019-08-08 stsp }
9001 2e1f37b0 2019-08-08 stsp }
9002 2e1f37b0 2019-08-08 stsp
9003 00f36e47 2019-09-06 stsp error = apply_unveil(got_repo_get_path(repo), 0,
9004 ad493afc 2019-08-03 stsp got_worktree_get_root_path(worktree));
9005 ad493afc 2019-08-03 stsp if (error)
9006 ad493afc 2019-08-03 stsp goto done;
9007 ad493afc 2019-08-03 stsp
9008 ad493afc 2019-08-03 stsp error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
9009 ad493afc 2019-08-03 stsp if (error)
9010 ad493afc 2019-08-03 stsp goto done;
9011 ad493afc 2019-08-03 stsp
9012 2e1f37b0 2019-08-08 stsp cpa.patch_script_file = patch_script_file;
9013 2e1f37b0 2019-08-08 stsp cpa.action = "unstage";
9014 9627c110 2020-04-18 stsp memset(&upa, 0, sizeof(upa));
9015 ad493afc 2019-08-03 stsp error = got_worktree_unstage(worktree, &paths, update_progress,
9016 9627c110 2020-04-18 stsp &upa, pflag ? choose_patch : NULL, &cpa, repo);
9017 9627c110 2020-04-18 stsp if (!error)
9018 9627c110 2020-04-18 stsp print_update_progress_stats(&upa);
9019 715dc77e 2019-08-03 stsp done:
9020 2e1f37b0 2019-08-08 stsp if (patch_script_file && fclose(patch_script_file) == EOF &&
9021 2e1f37b0 2019-08-08 stsp error == NULL)
9022 2e1f37b0 2019-08-08 stsp error = got_error_from_errno2("fclose", patch_script_path);
9023 0ebf8283 2019-07-24 stsp if (repo)
9024 0ebf8283 2019-07-24 stsp got_repo_close(repo);
9025 715dc77e 2019-08-03 stsp if (worktree)
9026 715dc77e 2019-08-03 stsp got_worktree_close(worktree);
9027 715dc77e 2019-08-03 stsp TAILQ_FOREACH(pe, &paths, entry)
9028 715dc77e 2019-08-03 stsp free((char *)pe->path);
9029 715dc77e 2019-08-03 stsp got_pathlist_free(&paths);
9030 715dc77e 2019-08-03 stsp free(cwd);
9031 01073a5d 2019-08-22 stsp return error;
9032 01073a5d 2019-08-22 stsp }
9033 01073a5d 2019-08-22 stsp
9034 01073a5d 2019-08-22 stsp __dead static void
9035 01073a5d 2019-08-22 stsp usage_cat(void)
9036 01073a5d 2019-08-22 stsp {
9037 896e9b6f 2019-08-26 stsp fprintf(stderr, "usage: %s cat [-r repository ] [ -c commit ] [ -P ] "
9038 896e9b6f 2019-08-26 stsp "arg1 [arg2 ...]\n", getprogname());
9039 01073a5d 2019-08-22 stsp exit(1);
9040 01073a5d 2019-08-22 stsp }
9041 01073a5d 2019-08-22 stsp
9042 01073a5d 2019-08-22 stsp static const struct got_error *
9043 01073a5d 2019-08-22 stsp cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
9044 01073a5d 2019-08-22 stsp {
9045 01073a5d 2019-08-22 stsp const struct got_error *err;
9046 01073a5d 2019-08-22 stsp struct got_blob_object *blob;
9047 01073a5d 2019-08-22 stsp
9048 01073a5d 2019-08-22 stsp err = got_object_open_as_blob(&blob, repo, id, 8192);
9049 01073a5d 2019-08-22 stsp if (err)
9050 01073a5d 2019-08-22 stsp return err;
9051 01073a5d 2019-08-22 stsp
9052 01073a5d 2019-08-22 stsp err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob);
9053 01073a5d 2019-08-22 stsp got_object_blob_close(blob);
9054 01073a5d 2019-08-22 stsp return err;
9055 01073a5d 2019-08-22 stsp }
9056 01073a5d 2019-08-22 stsp
9057 01073a5d 2019-08-22 stsp static const struct got_error *
9058 01073a5d 2019-08-22 stsp cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
9059 01073a5d 2019-08-22 stsp {
9060 01073a5d 2019-08-22 stsp const struct got_error *err;
9061 01073a5d 2019-08-22 stsp struct got_tree_object *tree;
9062 56e0773d 2019-11-28 stsp int nentries, i;
9063 01073a5d 2019-08-22 stsp
9064 01073a5d 2019-08-22 stsp err = got_object_open_as_tree(&tree, repo, id);
9065 01073a5d 2019-08-22 stsp if (err)
9066 01073a5d 2019-08-22 stsp return err;
9067 01073a5d 2019-08-22 stsp
9068 56e0773d 2019-11-28 stsp nentries = got_object_tree_get_nentries(tree);
9069 56e0773d 2019-11-28 stsp for (i = 0; i < nentries; i++) {
9070 56e0773d 2019-11-28 stsp struct got_tree_entry *te;
9071 01073a5d 2019-08-22 stsp char *id_str;
9072 01073a5d 2019-08-22 stsp if (sigint_received || sigpipe_received)
9073 01073a5d 2019-08-22 stsp break;
9074 56e0773d 2019-11-28 stsp te = got_object_tree_get_entry(tree, i);
9075 56e0773d 2019-11-28 stsp err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
9076 01073a5d 2019-08-22 stsp if (err)
9077 01073a5d 2019-08-22 stsp break;
9078 56e0773d 2019-11-28 stsp fprintf(outfile, "%s %.7o %s\n", id_str,
9079 56e0773d 2019-11-28 stsp got_tree_entry_get_mode(te),
9080 56e0773d 2019-11-28 stsp got_tree_entry_get_name(te));
9081 01073a5d 2019-08-22 stsp free(id_str);
9082 01073a5d 2019-08-22 stsp }
9083 01073a5d 2019-08-22 stsp
9084 01073a5d 2019-08-22 stsp got_object_tree_close(tree);
9085 01073a5d 2019-08-22 stsp return err;
9086 01073a5d 2019-08-22 stsp }
9087 01073a5d 2019-08-22 stsp
9088 01073a5d 2019-08-22 stsp static const struct got_error *
9089 01073a5d 2019-08-22 stsp cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
9090 01073a5d 2019-08-22 stsp {
9091 01073a5d 2019-08-22 stsp const struct got_error *err;
9092 01073a5d 2019-08-22 stsp struct got_commit_object *commit;
9093 01073a5d 2019-08-22 stsp const struct got_object_id_queue *parent_ids;
9094 01073a5d 2019-08-22 stsp struct got_object_qid *pid;
9095 01073a5d 2019-08-22 stsp char *id_str = NULL;
9096 24ea5512 2019-08-22 stsp const char *logmsg = NULL;
9097 01073a5d 2019-08-22 stsp
9098 01073a5d 2019-08-22 stsp err = got_object_open_as_commit(&commit, repo, id);
9099 01073a5d 2019-08-22 stsp if (err)
9100 01073a5d 2019-08-22 stsp return err;
9101 01073a5d 2019-08-22 stsp
9102 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
9103 01073a5d 2019-08-22 stsp if (err)
9104 01073a5d 2019-08-22 stsp goto done;
9105 01073a5d 2019-08-22 stsp
9106 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str);
9107 01073a5d 2019-08-22 stsp parent_ids = got_object_commit_get_parent_ids(commit);
9108 8aa93786 2019-08-22 stsp fprintf(outfile, "numparents %d\n",
9109 01073a5d 2019-08-22 stsp got_object_commit_get_nparents(commit));
9110 01073a5d 2019-08-22 stsp SIMPLEQ_FOREACH(pid, parent_ids, entry) {
9111 01073a5d 2019-08-22 stsp char *pid_str;
9112 01073a5d 2019-08-22 stsp err = got_object_id_str(&pid_str, pid->id);
9113 01073a5d 2019-08-22 stsp if (err)
9114 01073a5d 2019-08-22 stsp goto done;
9115 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str);
9116 01073a5d 2019-08-22 stsp free(pid_str);
9117 01073a5d 2019-08-22 stsp }
9118 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_AUTHOR,
9119 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
9120 01073a5d 2019-08-22 stsp got_object_commit_get_author_time(commit));
9121 01073a5d 2019-08-22 stsp
9122 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_COMMIT_LABEL_COMMITTER,
9123 8aa93786 2019-08-22 stsp got_object_commit_get_author(commit),
9124 01073a5d 2019-08-22 stsp got_object_commit_get_committer_time(commit));
9125 01073a5d 2019-08-22 stsp
9126 24ea5512 2019-08-22 stsp logmsg = got_object_commit_get_logmsg_raw(commit);
9127 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
9128 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", logmsg);
9129 01073a5d 2019-08-22 stsp done:
9130 01073a5d 2019-08-22 stsp free(id_str);
9131 01073a5d 2019-08-22 stsp got_object_commit_close(commit);
9132 01073a5d 2019-08-22 stsp return err;
9133 01073a5d 2019-08-22 stsp }
9134 01073a5d 2019-08-22 stsp
9135 01073a5d 2019-08-22 stsp static const struct got_error *
9136 01073a5d 2019-08-22 stsp cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
9137 01073a5d 2019-08-22 stsp {
9138 01073a5d 2019-08-22 stsp const struct got_error *err;
9139 01073a5d 2019-08-22 stsp struct got_tag_object *tag;
9140 01073a5d 2019-08-22 stsp char *id_str = NULL;
9141 01073a5d 2019-08-22 stsp const char *tagmsg = NULL;
9142 01073a5d 2019-08-22 stsp
9143 01073a5d 2019-08-22 stsp err = got_object_open_as_tag(&tag, repo, id);
9144 01073a5d 2019-08-22 stsp if (err)
9145 01073a5d 2019-08-22 stsp return err;
9146 01073a5d 2019-08-22 stsp
9147 01073a5d 2019-08-22 stsp err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
9148 01073a5d 2019-08-22 stsp if (err)
9149 01073a5d 2019-08-22 stsp goto done;
9150 01073a5d 2019-08-22 stsp
9151 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str);
9152 e15d5241 2019-08-22 stsp
9153 01073a5d 2019-08-22 stsp switch (got_object_tag_get_object_type(tag)) {
9154 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
9155 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
9156 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_BLOB);
9157 01073a5d 2019-08-22 stsp break;
9158 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
9159 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
9160 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TREE);
9161 01073a5d 2019-08-22 stsp break;
9162 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
9163 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
9164 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_COMMIT);
9165 01073a5d 2019-08-22 stsp break;
9166 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
9167 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
9168 8aa93786 2019-08-22 stsp GOT_OBJ_LABEL_TAG);
9169 01073a5d 2019-08-22 stsp break;
9170 01073a5d 2019-08-22 stsp default:
9171 01073a5d 2019-08-22 stsp break;
9172 01073a5d 2019-08-22 stsp }
9173 01073a5d 2019-08-22 stsp
9174 e15d5241 2019-08-22 stsp fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG,
9175 e15d5241 2019-08-22 stsp got_object_tag_get_name(tag));
9176 e15d5241 2019-08-22 stsp
9177 8aa93786 2019-08-22 stsp fprintf(outfile, "%s%s %lld +0000\n", GOT_TAG_LABEL_TAGGER,
9178 8aa93786 2019-08-22 stsp got_object_tag_get_tagger(tag),
9179 8aa93786 2019-08-22 stsp got_object_tag_get_tagger_time(tag));
9180 01073a5d 2019-08-22 stsp
9181 01073a5d 2019-08-22 stsp tagmsg = got_object_tag_get_message(tag);
9182 8aa93786 2019-08-22 stsp fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
9183 01073a5d 2019-08-22 stsp fprintf(outfile, "%s", tagmsg);
9184 01073a5d 2019-08-22 stsp done:
9185 01073a5d 2019-08-22 stsp free(id_str);
9186 01073a5d 2019-08-22 stsp got_object_tag_close(tag);
9187 01073a5d 2019-08-22 stsp return err;
9188 01073a5d 2019-08-22 stsp }
9189 01073a5d 2019-08-22 stsp
9190 01073a5d 2019-08-22 stsp static const struct got_error *
9191 01073a5d 2019-08-22 stsp cmd_cat(int argc, char *argv[])
9192 01073a5d 2019-08-22 stsp {
9193 01073a5d 2019-08-22 stsp const struct got_error *error;
9194 01073a5d 2019-08-22 stsp struct got_repository *repo = NULL;
9195 01073a5d 2019-08-22 stsp struct got_worktree *worktree = NULL;
9196 01073a5d 2019-08-22 stsp char *cwd = NULL, *repo_path = NULL, *label = NULL;
9197 896e9b6f 2019-08-26 stsp const char *commit_id_str = NULL;
9198 896e9b6f 2019-08-26 stsp struct got_object_id *id = NULL, *commit_id = NULL;
9199 896e9b6f 2019-08-26 stsp int ch, obj_type, i, force_path = 0;
9200 01073a5d 2019-08-22 stsp
9201 01073a5d 2019-08-22 stsp #ifndef PROFILE
9202 01073a5d 2019-08-22 stsp if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
9203 01073a5d 2019-08-22 stsp NULL) == -1)
9204 01073a5d 2019-08-22 stsp err(1, "pledge");
9205 01073a5d 2019-08-22 stsp #endif
9206 01073a5d 2019-08-22 stsp
9207 896e9b6f 2019-08-26 stsp while ((ch = getopt(argc, argv, "c:r:P")) != -1) {
9208 01073a5d 2019-08-22 stsp switch (ch) {
9209 896e9b6f 2019-08-26 stsp case 'c':
9210 896e9b6f 2019-08-26 stsp commit_id_str = optarg;
9211 896e9b6f 2019-08-26 stsp break;
9212 01073a5d 2019-08-22 stsp case 'r':
9213 01073a5d 2019-08-22 stsp repo_path = realpath(optarg, NULL);
9214 01073a5d 2019-08-22 stsp if (repo_path == NULL)
9215 9ba1d308 2019-10-21 stsp return got_error_from_errno2("realpath",
9216 9ba1d308 2019-10-21 stsp optarg);
9217 01073a5d 2019-08-22 stsp got_path_strip_trailing_slashes(repo_path);
9218 01073a5d 2019-08-22 stsp break;
9219 896e9b6f 2019-08-26 stsp case 'P':
9220 896e9b6f 2019-08-26 stsp force_path = 1;
9221 896e9b6f 2019-08-26 stsp break;
9222 01073a5d 2019-08-22 stsp default:
9223 01073a5d 2019-08-22 stsp usage_cat();
9224 01073a5d 2019-08-22 stsp /* NOTREACHED */
9225 01073a5d 2019-08-22 stsp }
9226 01073a5d 2019-08-22 stsp }
9227 01073a5d 2019-08-22 stsp
9228 01073a5d 2019-08-22 stsp argc -= optind;
9229 01073a5d 2019-08-22 stsp argv += optind;
9230 01073a5d 2019-08-22 stsp
9231 01073a5d 2019-08-22 stsp cwd = getcwd(NULL, 0);
9232 01073a5d 2019-08-22 stsp if (cwd == NULL) {
9233 01073a5d 2019-08-22 stsp error = got_error_from_errno("getcwd");
9234 01073a5d 2019-08-22 stsp goto done;
9235 01073a5d 2019-08-22 stsp }
9236 01073a5d 2019-08-22 stsp error = got_worktree_open(&worktree, cwd);
9237 01073a5d 2019-08-22 stsp if (error && error->code != GOT_ERR_NOT_WORKTREE)
9238 01073a5d 2019-08-22 stsp goto done;
9239 01073a5d 2019-08-22 stsp if (worktree) {
9240 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
9241 01073a5d 2019-08-22 stsp repo_path = strdup(
9242 01073a5d 2019-08-22 stsp got_worktree_get_repo_path(worktree));
9243 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
9244 01073a5d 2019-08-22 stsp error = got_error_from_errno("strdup");
9245 01073a5d 2019-08-22 stsp goto done;
9246 01073a5d 2019-08-22 stsp }
9247 01073a5d 2019-08-22 stsp }
9248 01073a5d 2019-08-22 stsp }
9249 01073a5d 2019-08-22 stsp
9250 01073a5d 2019-08-22 stsp if (repo_path == NULL) {
9251 01073a5d 2019-08-22 stsp repo_path = getcwd(NULL, 0);
9252 01073a5d 2019-08-22 stsp if (repo_path == NULL)
9253 01073a5d 2019-08-22 stsp return got_error_from_errno("getcwd");
9254 01073a5d 2019-08-22 stsp }
9255 01073a5d 2019-08-22 stsp
9256 c9956ddf 2019-09-08 stsp error = got_repo_open(&repo, repo_path, NULL);
9257 01073a5d 2019-08-22 stsp free(repo_path);
9258 01073a5d 2019-08-22 stsp if (error != NULL)
9259 01073a5d 2019-08-22 stsp goto done;
9260 01073a5d 2019-08-22 stsp
9261 01073a5d 2019-08-22 stsp error = apply_unveil(got_repo_get_path(repo), 1, NULL);
9262 896e9b6f 2019-08-26 stsp if (error)
9263 896e9b6f 2019-08-26 stsp goto done;
9264 896e9b6f 2019-08-26 stsp
9265 896e9b6f 2019-08-26 stsp if (commit_id_str == NULL)
9266 896e9b6f 2019-08-26 stsp commit_id_str = GOT_REF_HEAD;
9267 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&commit_id, NULL,
9268 71a27632 2020-01-15 stsp commit_id_str, GOT_OBJ_TYPE_COMMIT, 1, repo);
9269 01073a5d 2019-08-22 stsp if (error)
9270 01073a5d 2019-08-22 stsp goto done;
9271 01073a5d 2019-08-22 stsp
9272 01073a5d 2019-08-22 stsp for (i = 0; i < argc; i++) {
9273 896e9b6f 2019-08-26 stsp if (force_path) {
9274 896e9b6f 2019-08-26 stsp error = got_object_id_by_path(&id, repo, commit_id,
9275 896e9b6f 2019-08-26 stsp argv[i]);
9276 896e9b6f 2019-08-26 stsp if (error)
9277 896e9b6f 2019-08-26 stsp break;
9278 896e9b6f 2019-08-26 stsp } else {
9279 71a27632 2020-01-15 stsp error = got_repo_match_object_id(&id, &label, argv[i],
9280 896e9b6f 2019-08-26 stsp GOT_OBJ_TYPE_ANY, 0, repo);
9281 896e9b6f 2019-08-26 stsp if (error) {
9282 896e9b6f 2019-08-26 stsp if (error->code != GOT_ERR_BAD_OBJ_ID_STR &&
9283 896e9b6f 2019-08-26 stsp error->code != GOT_ERR_NOT_REF)
9284 896e9b6f 2019-08-26 stsp break;
9285 896e9b6f 2019-08-26 stsp error = got_object_id_by_path(&id, repo,
9286 896e9b6f 2019-08-26 stsp commit_id, argv[i]);
9287 896e9b6f 2019-08-26 stsp if (error)
9288 896e9b6f 2019-08-26 stsp break;
9289 896e9b6f 2019-08-26 stsp }
9290 896e9b6f 2019-08-26 stsp }
9291 01073a5d 2019-08-22 stsp
9292 01073a5d 2019-08-22 stsp error = got_object_get_type(&obj_type, repo, id);
9293 01073a5d 2019-08-22 stsp if (error)
9294 01073a5d 2019-08-22 stsp break;
9295 01073a5d 2019-08-22 stsp
9296 01073a5d 2019-08-22 stsp switch (obj_type) {
9297 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_BLOB:
9298 01073a5d 2019-08-22 stsp error = cat_blob(id, repo, stdout);
9299 01073a5d 2019-08-22 stsp break;
9300 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TREE:
9301 01073a5d 2019-08-22 stsp error = cat_tree(id, repo, stdout);
9302 01073a5d 2019-08-22 stsp break;
9303 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_COMMIT:
9304 01073a5d 2019-08-22 stsp error = cat_commit(id, repo, stdout);
9305 01073a5d 2019-08-22 stsp break;
9306 01073a5d 2019-08-22 stsp case GOT_OBJ_TYPE_TAG:
9307 01073a5d 2019-08-22 stsp error = cat_tag(id, repo, stdout);
9308 01073a5d 2019-08-22 stsp break;
9309 01073a5d 2019-08-22 stsp default:
9310 01073a5d 2019-08-22 stsp error = got_error(GOT_ERR_OBJ_TYPE);
9311 01073a5d 2019-08-22 stsp break;
9312 01073a5d 2019-08-22 stsp }
9313 01073a5d 2019-08-22 stsp if (error)
9314 01073a5d 2019-08-22 stsp break;
9315 01073a5d 2019-08-22 stsp free(label);
9316 01073a5d 2019-08-22 stsp label = NULL;
9317 01073a5d 2019-08-22 stsp free(id);
9318 01073a5d 2019-08-22 stsp id = NULL;
9319 01073a5d 2019-08-22 stsp }
9320 01073a5d 2019-08-22 stsp done:
9321 01073a5d 2019-08-22 stsp free(label);
9322 01073a5d 2019-08-22 stsp free(id);
9323 896e9b6f 2019-08-26 stsp free(commit_id);
9324 01073a5d 2019-08-22 stsp if (worktree)
9325 01073a5d 2019-08-22 stsp got_worktree_close(worktree);
9326 01073a5d 2019-08-22 stsp if (repo) {
9327 01073a5d 2019-08-22 stsp const struct got_error *repo_error;
9328 01073a5d 2019-08-22 stsp repo_error = got_repo_close(repo);
9329 01073a5d 2019-08-22 stsp if (error == NULL)
9330 01073a5d 2019-08-22 stsp error = repo_error;
9331 b2118c49 2020-07-28 stsp }
9332 b2118c49 2020-07-28 stsp return error;
9333 b2118c49 2020-07-28 stsp }
9334 b2118c49 2020-07-28 stsp
9335 b2118c49 2020-07-28 stsp __dead static void
9336 b2118c49 2020-07-28 stsp usage_info(void)
9337 b2118c49 2020-07-28 stsp {
9338 b2118c49 2020-07-28 stsp fprintf(stderr, "usage: %s info [path ...]\n",
9339 b2118c49 2020-07-28 stsp getprogname());
9340 b2118c49 2020-07-28 stsp exit(1);
9341 b2118c49 2020-07-28 stsp }
9342 b2118c49 2020-07-28 stsp
9343 b2118c49 2020-07-28 stsp static const struct got_error *
9344 b2118c49 2020-07-28 stsp print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
9345 b2118c49 2020-07-28 stsp struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
9346 b2118c49 2020-07-28 stsp struct got_object_id *commit_id)
9347 b2118c49 2020-07-28 stsp {
9348 b2118c49 2020-07-28 stsp const struct got_error *err = NULL;
9349 b2118c49 2020-07-28 stsp char *id_str = NULL;
9350 b2118c49 2020-07-28 stsp char datebuf[128];
9351 b2118c49 2020-07-28 stsp struct tm mytm, *tm;
9352 b2118c49 2020-07-28 stsp struct got_pathlist_head *paths = arg;
9353 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
9354 b2118c49 2020-07-28 stsp
9355 b2118c49 2020-07-28 stsp /*
9356 b2118c49 2020-07-28 stsp * Clear error indication from any of the path arguments which
9357 b2118c49 2020-07-28 stsp * would cause this file index entry to be displayed.
9358 b2118c49 2020-07-28 stsp */
9359 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, paths, entry) {
9360 b2118c49 2020-07-28 stsp if (got_path_cmp(path, pe->path, strlen(path),
9361 b2118c49 2020-07-28 stsp pe->path_len) == 0 ||
9362 b2118c49 2020-07-28 stsp got_path_is_child(path, pe->path, pe->path_len))
9363 b2118c49 2020-07-28 stsp pe->data = NULL; /* no error */
9364 b2118c49 2020-07-28 stsp }
9365 b2118c49 2020-07-28 stsp
9366 b2118c49 2020-07-28 stsp printf(GOT_COMMIT_SEP_STR);
9367 b2118c49 2020-07-28 stsp if (S_ISLNK(mode))
9368 b2118c49 2020-07-28 stsp printf("symlink: %s\n", path);
9369 b2118c49 2020-07-28 stsp else if (S_ISREG(mode)) {
9370 b2118c49 2020-07-28 stsp printf("file: %s\n", path);
9371 b2118c49 2020-07-28 stsp printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO));
9372 b2118c49 2020-07-28 stsp } else if (S_ISDIR(mode))
9373 b2118c49 2020-07-28 stsp printf("directory: %s\n", path);
9374 b2118c49 2020-07-28 stsp else
9375 b2118c49 2020-07-28 stsp printf("something: %s\n", path);
9376 b2118c49 2020-07-28 stsp
9377 b2118c49 2020-07-28 stsp tm = localtime_r(&mtime, &mytm);
9378 b2118c49 2020-07-28 stsp if (tm == NULL)
9379 b2118c49 2020-07-28 stsp return NULL;
9380 b2118c49 2020-07-28 stsp if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) >= sizeof(datebuf))
9381 b2118c49 2020-07-28 stsp return got_error(GOT_ERR_NO_SPACE);
9382 b2118c49 2020-07-28 stsp printf("timestamp: %s\n", datebuf);
9383 b2118c49 2020-07-28 stsp
9384 b2118c49 2020-07-28 stsp if (blob_id) {
9385 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, blob_id);
9386 b2118c49 2020-07-28 stsp if (err)
9387 b2118c49 2020-07-28 stsp return err;
9388 b2118c49 2020-07-28 stsp printf("based on blob: %s\n", id_str);
9389 b2118c49 2020-07-28 stsp free(id_str);
9390 b2118c49 2020-07-28 stsp }
9391 b2118c49 2020-07-28 stsp
9392 b2118c49 2020-07-28 stsp if (staged_blob_id) {
9393 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, staged_blob_id);
9394 b2118c49 2020-07-28 stsp if (err)
9395 b2118c49 2020-07-28 stsp return err;
9396 b2118c49 2020-07-28 stsp printf("based on staged blob: %s\n", id_str);
9397 b2118c49 2020-07-28 stsp free(id_str);
9398 b2118c49 2020-07-28 stsp }
9399 b2118c49 2020-07-28 stsp
9400 b2118c49 2020-07-28 stsp if (commit_id) {
9401 b2118c49 2020-07-28 stsp err = got_object_id_str(&id_str, commit_id);
9402 b2118c49 2020-07-28 stsp if (err)
9403 b2118c49 2020-07-28 stsp return err;
9404 b2118c49 2020-07-28 stsp printf("based on commit: %s\n", id_str);
9405 b2118c49 2020-07-28 stsp free(id_str);
9406 b2118c49 2020-07-28 stsp }
9407 b2118c49 2020-07-28 stsp
9408 b2118c49 2020-07-28 stsp return NULL;
9409 b2118c49 2020-07-28 stsp }
9410 b2118c49 2020-07-28 stsp
9411 b2118c49 2020-07-28 stsp static const struct got_error *
9412 b2118c49 2020-07-28 stsp cmd_info(int argc, char *argv[])
9413 b2118c49 2020-07-28 stsp {
9414 b2118c49 2020-07-28 stsp const struct got_error *error = NULL;
9415 b2118c49 2020-07-28 stsp struct got_worktree *worktree = NULL;
9416 b2118c49 2020-07-28 stsp char *cwd = NULL, *id_str = NULL;
9417 b2118c49 2020-07-28 stsp struct got_pathlist_head paths;
9418 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
9419 b2118c49 2020-07-28 stsp char *uuidstr = NULL;
9420 b2118c49 2020-07-28 stsp int ch, show_files = 0;
9421 b2118c49 2020-07-28 stsp
9422 b2118c49 2020-07-28 stsp TAILQ_INIT(&paths);
9423 b2118c49 2020-07-28 stsp
9424 b2118c49 2020-07-28 stsp while ((ch = getopt(argc, argv, "")) != -1) {
9425 b2118c49 2020-07-28 stsp switch (ch) {
9426 b2118c49 2020-07-28 stsp default:
9427 b2118c49 2020-07-28 stsp usage_info();
9428 b2118c49 2020-07-28 stsp /* NOTREACHED */
9429 b2118c49 2020-07-28 stsp }
9430 01073a5d 2019-08-22 stsp }
9431 b2118c49 2020-07-28 stsp
9432 b2118c49 2020-07-28 stsp argc -= optind;
9433 b2118c49 2020-07-28 stsp argv += optind;
9434 b2118c49 2020-07-28 stsp
9435 b2118c49 2020-07-28 stsp #ifndef PROFILE
9436 b2118c49 2020-07-28 stsp if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
9437 b2118c49 2020-07-28 stsp NULL) == -1)
9438 b2118c49 2020-07-28 stsp err(1, "pledge");
9439 b2118c49 2020-07-28 stsp #endif
9440 b2118c49 2020-07-28 stsp cwd = getcwd(NULL, 0);
9441 b2118c49 2020-07-28 stsp if (cwd == NULL) {
9442 b2118c49 2020-07-28 stsp error = got_error_from_errno("getcwd");
9443 b2118c49 2020-07-28 stsp goto done;
9444 b2118c49 2020-07-28 stsp }
9445 b2118c49 2020-07-28 stsp
9446 b2118c49 2020-07-28 stsp error = got_worktree_open(&worktree, cwd);
9447 b2118c49 2020-07-28 stsp if (error) {
9448 b2118c49 2020-07-28 stsp if (error->code == GOT_ERR_NOT_WORKTREE)
9449 b2118c49 2020-07-28 stsp error = wrap_not_worktree_error(error, "status", cwd);
9450 b2118c49 2020-07-28 stsp goto done;
9451 b2118c49 2020-07-28 stsp }
9452 b2118c49 2020-07-28 stsp
9453 b2118c49 2020-07-28 stsp error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree));
9454 b2118c49 2020-07-28 stsp if (error)
9455 b2118c49 2020-07-28 stsp goto done;
9456 b2118c49 2020-07-28 stsp
9457 b2118c49 2020-07-28 stsp if (argc >= 1) {
9458 b2118c49 2020-07-28 stsp error = get_worktree_paths_from_argv(&paths, argc, argv,
9459 b2118c49 2020-07-28 stsp worktree);
9460 b2118c49 2020-07-28 stsp if (error)
9461 b2118c49 2020-07-28 stsp goto done;
9462 b2118c49 2020-07-28 stsp show_files = 1;
9463 b2118c49 2020-07-28 stsp }
9464 b2118c49 2020-07-28 stsp
9465 b2118c49 2020-07-28 stsp error = got_object_id_str(&id_str,
9466 b2118c49 2020-07-28 stsp got_worktree_get_base_commit_id(worktree));
9467 b2118c49 2020-07-28 stsp if (error)
9468 b2118c49 2020-07-28 stsp goto done;
9469 b2118c49 2020-07-28 stsp
9470 b2118c49 2020-07-28 stsp error = got_worktree_get_uuid(&uuidstr, worktree);
9471 b2118c49 2020-07-28 stsp if (error)
9472 b2118c49 2020-07-28 stsp goto done;
9473 b2118c49 2020-07-28 stsp
9474 b2118c49 2020-07-28 stsp printf("work tree: %s\n", got_worktree_get_root_path(worktree));
9475 b2118c49 2020-07-28 stsp printf("work tree base commit: %s\n", id_str);
9476 b2118c49 2020-07-28 stsp printf("work tree path prefix: %s\n",
9477 b2118c49 2020-07-28 stsp got_worktree_get_path_prefix(worktree));
9478 b2118c49 2020-07-28 stsp printf("work tree branch reference: %s\n",
9479 b2118c49 2020-07-28 stsp got_worktree_get_head_ref_name(worktree));
9480 b2118c49 2020-07-28 stsp printf("work tree UUID: %s\n", uuidstr);
9481 b2118c49 2020-07-28 stsp printf("repository: %s\n", got_worktree_get_repo_path(worktree));
9482 b2118c49 2020-07-28 stsp
9483 b2118c49 2020-07-28 stsp if (show_files) {
9484 b2118c49 2020-07-28 stsp struct got_pathlist_entry *pe;
9485 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
9486 b2118c49 2020-07-28 stsp if (pe->path_len == 0)
9487 b2118c49 2020-07-28 stsp continue;
9488 b2118c49 2020-07-28 stsp /*
9489 b2118c49 2020-07-28 stsp * Assume this path will fail. This will be corrected
9490 b2118c49 2020-07-28 stsp * in print_path_info() in case the path does suceeed.
9491 b2118c49 2020-07-28 stsp */
9492 b2118c49 2020-07-28 stsp pe->data = (void *)got_error_path(pe->path,
9493 b2118c49 2020-07-28 stsp GOT_ERR_BAD_PATH);
9494 b2118c49 2020-07-28 stsp }
9495 b2118c49 2020-07-28 stsp error = got_worktree_path_info(worktree, &paths,
9496 b2118c49 2020-07-28 stsp print_path_info, &paths, check_cancelled, NULL);
9497 b2118c49 2020-07-28 stsp if (error)
9498 b2118c49 2020-07-28 stsp goto done;
9499 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry) {
9500 b2118c49 2020-07-28 stsp if (pe->data != NULL) {
9501 b2118c49 2020-07-28 stsp error = pe->data; /* bad path */
9502 b2118c49 2020-07-28 stsp break;
9503 b2118c49 2020-07-28 stsp }
9504 b2118c49 2020-07-28 stsp }
9505 b2118c49 2020-07-28 stsp }
9506 b2118c49 2020-07-28 stsp done:
9507 b2118c49 2020-07-28 stsp TAILQ_FOREACH(pe, &paths, entry)
9508 b2118c49 2020-07-28 stsp free((char *)pe->path);
9509 b2118c49 2020-07-28 stsp got_pathlist_free(&paths);
9510 b2118c49 2020-07-28 stsp free(cwd);
9511 b2118c49 2020-07-28 stsp free(id_str);
9512 b2118c49 2020-07-28 stsp free(uuidstr);
9513 0ebf8283 2019-07-24 stsp return error;
9514 0ebf8283 2019-07-24 stsp }