Blame


1 9f7d7167 2018-04-29 stsp /*
2 9f7d7167 2018-04-29 stsp * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
3 9f7d7167 2018-04-29 stsp *
4 9f7d7167 2018-04-29 stsp * Permission to use, copy, modify, and distribute this software for any
5 9f7d7167 2018-04-29 stsp * purpose with or without fee is hereby granted, provided that the above
6 9f7d7167 2018-04-29 stsp * copyright notice and this permission notice appear in all copies.
7 9f7d7167 2018-04-29 stsp *
8 9f7d7167 2018-04-29 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 9f7d7167 2018-04-29 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 9f7d7167 2018-04-29 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 9f7d7167 2018-04-29 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 9f7d7167 2018-04-29 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 9f7d7167 2018-04-29 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 9f7d7167 2018-04-29 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 9f7d7167 2018-04-29 stsp */
16 9f7d7167 2018-04-29 stsp
17 80ddbec8 2018-04-29 stsp #include <sys/queue.h>
18 80ddbec8 2018-04-29 stsp
19 9f7d7167 2018-04-29 stsp #include <curses.h>
20 9f7d7167 2018-04-29 stsp #include <panel.h>
21 9f7d7167 2018-04-29 stsp #include <locale.h>
22 9f7d7167 2018-04-29 stsp #include <stdlib.h>
23 9f7d7167 2018-04-29 stsp #include <getopt.h>
24 9f7d7167 2018-04-29 stsp #include <string.h>
25 9f7d7167 2018-04-29 stsp #include <err.h>
26 80ddbec8 2018-04-29 stsp #include <unistd.h>
27 9f7d7167 2018-04-29 stsp
28 9f7d7167 2018-04-29 stsp #include "got_error.h"
29 80ddbec8 2018-04-29 stsp #include "got_object.h"
30 80ddbec8 2018-04-29 stsp #include "got_reference.h"
31 80ddbec8 2018-04-29 stsp #include "got_repository.h"
32 80ddbec8 2018-04-29 stsp #include "got_diff.h"
33 9f7d7167 2018-04-29 stsp
34 9f7d7167 2018-04-29 stsp #ifndef nitems
35 9f7d7167 2018-04-29 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
36 9f7d7167 2018-04-29 stsp #endif
37 9f7d7167 2018-04-29 stsp
38 9f7d7167 2018-04-29 stsp enum tog_view_id {
39 9f7d7167 2018-04-29 stsp TOG_VIEW_LOG,
40 9f7d7167 2018-04-29 stsp TOG_VIEW_DIFF,
41 9f7d7167 2018-04-29 stsp TOG_VIEW_BLAME,
42 9f7d7167 2018-04-29 stsp };
43 9f7d7167 2018-04-29 stsp
44 9f7d7167 2018-04-29 stsp struct tog_cmd {
45 9f7d7167 2018-04-29 stsp const char *cmd_name;
46 9f7d7167 2018-04-29 stsp const struct got_error *(*cmd_main)(int, char *[]);
47 9f7d7167 2018-04-29 stsp void (*cmd_usage)(void);
48 9f7d7167 2018-04-29 stsp enum tog_view_id view;
49 9f7d7167 2018-04-29 stsp const char *cmd_descr;
50 9f7d7167 2018-04-29 stsp };
51 9f7d7167 2018-04-29 stsp
52 9f7d7167 2018-04-29 stsp __dead void usage(void);
53 9f7d7167 2018-04-29 stsp __dead void usage_log(void);
54 9f7d7167 2018-04-29 stsp __dead void usage_diff(void);
55 9f7d7167 2018-04-29 stsp __dead void usage_blame(void);
56 9f7d7167 2018-04-29 stsp
57 9f7d7167 2018-04-29 stsp const struct got_error* cmd_log(int, char *[]);
58 9f7d7167 2018-04-29 stsp const struct got_error* cmd_diff(int, char *[]);
59 9f7d7167 2018-04-29 stsp const struct got_error* cmd_blame(int, char *[]);
60 9f7d7167 2018-04-29 stsp
61 9f7d7167 2018-04-29 stsp struct tog_cmd tog_commands[] = {
62 9f7d7167 2018-04-29 stsp { "log", cmd_log, usage_log, TOG_VIEW_LOG,
63 9f7d7167 2018-04-29 stsp "show repository history" },
64 9f7d7167 2018-04-29 stsp { "diff", cmd_diff, usage_diff, TOG_VIEW_DIFF,
65 9f7d7167 2018-04-29 stsp "compare files and directories" },
66 9f7d7167 2018-04-29 stsp { "blame", cmd_blame, usage_blame, TOG_VIEW_BLAME,
67 9f7d7167 2018-04-29 stsp "show line-by-line file history" },
68 9f7d7167 2018-04-29 stsp };
69 9f7d7167 2018-04-29 stsp
70 9f7d7167 2018-04-29 stsp /* globals */
71 9f7d7167 2018-04-29 stsp WINDOW *tog_main_win;
72 9f7d7167 2018-04-29 stsp PANEL *tog_main_panel;
73 80ddbec8 2018-04-29 stsp static struct tog_log_view {
74 80ddbec8 2018-04-29 stsp WINDOW *window;
75 80ddbec8 2018-04-29 stsp PANEL *panel;
76 80ddbec8 2018-04-29 stsp } tog_log_view;
77 9f7d7167 2018-04-29 stsp
78 9f7d7167 2018-04-29 stsp __dead void
79 9f7d7167 2018-04-29 stsp usage_log(void)
80 9f7d7167 2018-04-29 stsp {
81 80ddbec8 2018-04-29 stsp endwin();
82 80ddbec8 2018-04-29 stsp fprintf(stderr, "usage: %s log [-c commit] [repository-path]\n",
83 9f7d7167 2018-04-29 stsp getprogname());
84 9f7d7167 2018-04-29 stsp exit(1);
85 80ddbec8 2018-04-29 stsp }
86 80ddbec8 2018-04-29 stsp
87 80ddbec8 2018-04-29 stsp static const struct got_error *
88 80ddbec8 2018-04-29 stsp draw_commit(struct got_commit_object *commit, struct got_object_id *id,
89 80ddbec8 2018-04-29 stsp struct got_repository *repo)
90 80ddbec8 2018-04-29 stsp {
91 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
92 80ddbec8 2018-04-29 stsp char *logmsg0 = NULL, *logmsg = NULL;
93 80ddbec8 2018-04-29 stsp char *newline;
94 80ddbec8 2018-04-29 stsp char *line = NULL;
95 80ddbec8 2018-04-29 stsp char *id_str;
96 80ddbec8 2018-04-29 stsp size_t len;
97 80ddbec8 2018-04-29 stsp
98 80ddbec8 2018-04-29 stsp err = got_object_id_str(&id_str, id);
99 80ddbec8 2018-04-29 stsp if (err)
100 80ddbec8 2018-04-29 stsp return err;
101 80ddbec8 2018-04-29 stsp logmsg0 = strdup(commit->logmsg);
102 80ddbec8 2018-04-29 stsp if (logmsg0 == NULL)
103 80ddbec8 2018-04-29 stsp return got_error_from_errno();
104 80ddbec8 2018-04-29 stsp logmsg = logmsg0;
105 80ddbec8 2018-04-29 stsp while (*logmsg == '\n')
106 80ddbec8 2018-04-29 stsp logmsg++;
107 80ddbec8 2018-04-29 stsp newline = strchr(logmsg, '\n');
108 80ddbec8 2018-04-29 stsp if (newline != NULL)
109 80ddbec8 2018-04-29 stsp *newline = '\0';
110 80ddbec8 2018-04-29 stsp
111 80ddbec8 2018-04-29 stsp if (asprintf(&line, "%.8s %.35s %s", id_str, commit->author,
112 80ddbec8 2018-04-29 stsp logmsg) == -1) {
113 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
114 80ddbec8 2018-04-29 stsp goto done;
115 80ddbec8 2018-04-29 stsp }
116 80ddbec8 2018-04-29 stsp
117 80ddbec8 2018-04-29 stsp waddstr(tog_log_view.window, line);
118 80ddbec8 2018-04-29 stsp len = strlen(line);
119 80ddbec8 2018-04-29 stsp while (len < COLS - 1) {
120 80ddbec8 2018-04-29 stsp waddch(tog_log_view.window, ' ');
121 80ddbec8 2018-04-29 stsp len++;
122 80ddbec8 2018-04-29 stsp }
123 80ddbec8 2018-04-29 stsp waddch(tog_log_view.window, '\n');
124 80ddbec8 2018-04-29 stsp done:
125 80ddbec8 2018-04-29 stsp free(logmsg0);
126 80ddbec8 2018-04-29 stsp free(line);
127 80ddbec8 2018-04-29 stsp return err;
128 80ddbec8 2018-04-29 stsp }
129 80ddbec8 2018-04-29 stsp struct commit_queue_entry {
130 80ddbec8 2018-04-29 stsp TAILQ_ENTRY(commit_queue_entry) entry;
131 80ddbec8 2018-04-29 stsp struct got_object_id *id;
132 80ddbec8 2018-04-29 stsp struct got_commit_object *commit;
133 80ddbec8 2018-04-29 stsp };
134 80ddbec8 2018-04-29 stsp
135 80ddbec8 2018-04-29 stsp static const struct got_error *
136 80ddbec8 2018-04-29 stsp draw_commits(struct got_object *root_obj, struct got_object_id *root_id,
137 80ddbec8 2018-04-29 stsp struct got_repository *repo, int selected)
138 80ddbec8 2018-04-29 stsp {
139 80ddbec8 2018-04-29 stsp const struct got_error *err;
140 80ddbec8 2018-04-29 stsp struct got_commit_object *root_commit;
141 80ddbec8 2018-04-29 stsp TAILQ_HEAD(, commit_queue_entry) commits;
142 80ddbec8 2018-04-29 stsp struct commit_queue_entry *entry;
143 80ddbec8 2018-04-29 stsp int ncommits = 0;
144 80ddbec8 2018-04-29 stsp
145 80ddbec8 2018-04-29 stsp TAILQ_INIT(&commits);
146 80ddbec8 2018-04-29 stsp
147 80ddbec8 2018-04-29 stsp err = got_object_commit_open(&root_commit, repo, root_obj);
148 80ddbec8 2018-04-29 stsp if (err)
149 80ddbec8 2018-04-29 stsp return err;
150 80ddbec8 2018-04-29 stsp
151 80ddbec8 2018-04-29 stsp entry = calloc(1, sizeof(*entry));
152 80ddbec8 2018-04-29 stsp if (entry == NULL)
153 80ddbec8 2018-04-29 stsp return got_error_from_errno();
154 80ddbec8 2018-04-29 stsp entry->id = got_object_id_dup(root_id);
155 80ddbec8 2018-04-29 stsp if (entry->id == NULL) {
156 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
157 80ddbec8 2018-04-29 stsp free(entry);
158 80ddbec8 2018-04-29 stsp return err;
159 80ddbec8 2018-04-29 stsp }
160 80ddbec8 2018-04-29 stsp entry->commit = root_commit;
161 80ddbec8 2018-04-29 stsp TAILQ_INSERT_HEAD(&commits, entry, entry);
162 80ddbec8 2018-04-29 stsp
163 80ddbec8 2018-04-29 stsp wclear(tog_log_view.window);
164 80ddbec8 2018-04-29 stsp
165 80ddbec8 2018-04-29 stsp while (!TAILQ_EMPTY(&commits) && ncommits < LINES) {
166 80ddbec8 2018-04-29 stsp struct got_parent_id *pid;
167 80ddbec8 2018-04-29 stsp struct got_object *obj;
168 80ddbec8 2018-04-29 stsp struct got_commit_object *pcommit;
169 80ddbec8 2018-04-29 stsp struct commit_queue_entry *pentry;
170 80ddbec8 2018-04-29 stsp
171 80ddbec8 2018-04-29 stsp entry = TAILQ_FIRST(&commits);
172 80ddbec8 2018-04-29 stsp
173 80ddbec8 2018-04-29 stsp if (ncommits == selected)
174 80ddbec8 2018-04-29 stsp wstandout(tog_log_view.window);
175 80ddbec8 2018-04-29 stsp err = draw_commit(entry->commit, entry->id, repo);
176 80ddbec8 2018-04-29 stsp if (ncommits == selected)
177 80ddbec8 2018-04-29 stsp wstandend(tog_log_view.window);
178 80ddbec8 2018-04-29 stsp if (err)
179 80ddbec8 2018-04-29 stsp break;
180 80ddbec8 2018-04-29 stsp ncommits++;
181 80ddbec8 2018-04-29 stsp
182 80ddbec8 2018-04-29 stsp if (entry->commit->nparents == 0)
183 80ddbec8 2018-04-29 stsp break;
184 80ddbec8 2018-04-29 stsp
185 80ddbec8 2018-04-29 stsp /* Follow the first parent (TODO: handle merge commits). */
186 80ddbec8 2018-04-29 stsp pid = SIMPLEQ_FIRST(&entry->commit->parent_ids);
187 80ddbec8 2018-04-29 stsp err = got_object_open(&obj, repo, pid->id);
188 80ddbec8 2018-04-29 stsp if (err)
189 80ddbec8 2018-04-29 stsp break;
190 80ddbec8 2018-04-29 stsp if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
191 80ddbec8 2018-04-29 stsp err = got_error(GOT_ERR_OBJ_TYPE);
192 80ddbec8 2018-04-29 stsp break;
193 80ddbec8 2018-04-29 stsp }
194 80ddbec8 2018-04-29 stsp
195 80ddbec8 2018-04-29 stsp err = got_object_commit_open(&pcommit, repo, obj);
196 80ddbec8 2018-04-29 stsp got_object_close(obj);
197 80ddbec8 2018-04-29 stsp if (err)
198 80ddbec8 2018-04-29 stsp break;
199 80ddbec8 2018-04-29 stsp
200 80ddbec8 2018-04-29 stsp pentry = calloc(1, sizeof(*pentry));
201 80ddbec8 2018-04-29 stsp if (pentry == NULL) {
202 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
203 80ddbec8 2018-04-29 stsp got_object_commit_close(pcommit);
204 80ddbec8 2018-04-29 stsp break;
205 80ddbec8 2018-04-29 stsp }
206 80ddbec8 2018-04-29 stsp pentry->id = got_object_id_dup(pid->id);
207 80ddbec8 2018-04-29 stsp if (pentry->id == NULL) {
208 80ddbec8 2018-04-29 stsp err = got_error_from_errno();
209 80ddbec8 2018-04-29 stsp got_object_commit_close(pcommit);
210 80ddbec8 2018-04-29 stsp break;
211 80ddbec8 2018-04-29 stsp }
212 80ddbec8 2018-04-29 stsp pentry->commit = pcommit;
213 80ddbec8 2018-04-29 stsp TAILQ_INSERT_TAIL(&commits, pentry, entry);
214 80ddbec8 2018-04-29 stsp
215 80ddbec8 2018-04-29 stsp TAILQ_REMOVE(&commits, entry, entry);
216 80ddbec8 2018-04-29 stsp got_object_commit_close(entry->commit);
217 80ddbec8 2018-04-29 stsp free(entry->id);
218 80ddbec8 2018-04-29 stsp free(entry);
219 80ddbec8 2018-04-29 stsp }
220 80ddbec8 2018-04-29 stsp
221 80ddbec8 2018-04-29 stsp while (!TAILQ_EMPTY(&commits)) {
222 80ddbec8 2018-04-29 stsp entry = TAILQ_FIRST(&commits);
223 80ddbec8 2018-04-29 stsp TAILQ_REMOVE(&commits, entry, entry);
224 80ddbec8 2018-04-29 stsp got_object_commit_close(entry->commit);
225 80ddbec8 2018-04-29 stsp free(entry->id);
226 80ddbec8 2018-04-29 stsp free(entry);
227 80ddbec8 2018-04-29 stsp }
228 80ddbec8 2018-04-29 stsp
229 80ddbec8 2018-04-29 stsp update_panels();
230 80ddbec8 2018-04-29 stsp doupdate();
231 80ddbec8 2018-04-29 stsp return err;
232 9f7d7167 2018-04-29 stsp }
233 9f7d7167 2018-04-29 stsp
234 80ddbec8 2018-04-29 stsp
235 80ddbec8 2018-04-29 stsp static const struct got_error *
236 80ddbec8 2018-04-29 stsp show_log_view(struct got_object_id *start_id, struct got_repository *repo)
237 80ddbec8 2018-04-29 stsp {
238 80ddbec8 2018-04-29 stsp const struct got_error *err = NULL;
239 80ddbec8 2018-04-29 stsp struct got_object *obj;
240 80ddbec8 2018-04-29 stsp int ch, done = 0, selected = 0;
241 80ddbec8 2018-04-29 stsp struct got_object_id *id = start_id;
242 80ddbec8 2018-04-29 stsp
243 80ddbec8 2018-04-29 stsp if (tog_log_view.window == NULL) {
244 80ddbec8 2018-04-29 stsp tog_log_view.window = newwin(0, 0, 0, 0);
245 80ddbec8 2018-04-29 stsp if (tog_log_view.window == NULL)
246 80ddbec8 2018-04-29 stsp return got_error_from_errno();
247 80ddbec8 2018-04-29 stsp }
248 80ddbec8 2018-04-29 stsp if (tog_log_view.panel == NULL) {
249 80ddbec8 2018-04-29 stsp tog_log_view.panel = new_panel(tog_log_view.window);
250 80ddbec8 2018-04-29 stsp if (tog_log_view.panel == NULL)
251 80ddbec8 2018-04-29 stsp return got_error_from_errno();
252 80ddbec8 2018-04-29 stsp }
253 80ddbec8 2018-04-29 stsp
254 80ddbec8 2018-04-29 stsp err = got_object_open(&obj, repo, id);
255 80ddbec8 2018-04-29 stsp if (err)
256 80ddbec8 2018-04-29 stsp return err;
257 80ddbec8 2018-04-29 stsp if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
258 80ddbec8 2018-04-29 stsp err = got_error(GOT_ERR_OBJ_TYPE);
259 80ddbec8 2018-04-29 stsp goto done;
260 80ddbec8 2018-04-29 stsp }
261 80ddbec8 2018-04-29 stsp
262 80ddbec8 2018-04-29 stsp do {
263 80ddbec8 2018-04-29 stsp err = draw_commits(obj, id, repo, selected);
264 80ddbec8 2018-04-29 stsp if (err)
265 80ddbec8 2018-04-29 stsp return err;
266 80ddbec8 2018-04-29 stsp
267 80ddbec8 2018-04-29 stsp nodelay(stdscr, FALSE);
268 80ddbec8 2018-04-29 stsp ch = wgetch(tog_log_view.window);
269 80ddbec8 2018-04-29 stsp switch (ch) {
270 80ddbec8 2018-04-29 stsp case 'q':
271 80ddbec8 2018-04-29 stsp done = 1;
272 80ddbec8 2018-04-29 stsp break;
273 80ddbec8 2018-04-29 stsp case 'k':
274 80ddbec8 2018-04-29 stsp case KEY_UP:
275 80ddbec8 2018-04-29 stsp if (selected > 0)
276 80ddbec8 2018-04-29 stsp selected--;
277 80ddbec8 2018-04-29 stsp break;
278 80ddbec8 2018-04-29 stsp case 'j':
279 80ddbec8 2018-04-29 stsp case KEY_DOWN:
280 80ddbec8 2018-04-29 stsp if (selected < LINES - 1)
281 80ddbec8 2018-04-29 stsp selected++;
282 80ddbec8 2018-04-29 stsp break;
283 80ddbec8 2018-04-29 stsp default:
284 80ddbec8 2018-04-29 stsp break;
285 80ddbec8 2018-04-29 stsp }
286 80ddbec8 2018-04-29 stsp nodelay(stdscr, TRUE);
287 80ddbec8 2018-04-29 stsp } while (!done);
288 80ddbec8 2018-04-29 stsp done:
289 80ddbec8 2018-04-29 stsp got_object_close(obj);
290 80ddbec8 2018-04-29 stsp return err;
291 80ddbec8 2018-04-29 stsp }
292 80ddbec8 2018-04-29 stsp
293 9f7d7167 2018-04-29 stsp const struct got_error *
294 9f7d7167 2018-04-29 stsp cmd_log(int argc, char *argv[])
295 9f7d7167 2018-04-29 stsp {
296 80ddbec8 2018-04-29 stsp const struct got_error *error;
297 80ddbec8 2018-04-29 stsp struct got_repository *repo;
298 80ddbec8 2018-04-29 stsp struct got_object_id *id = NULL;
299 80ddbec8 2018-04-29 stsp char *repo_path = NULL;
300 80ddbec8 2018-04-29 stsp char *start_commit = NULL;
301 80ddbec8 2018-04-29 stsp int ch;
302 80ddbec8 2018-04-29 stsp
303 80ddbec8 2018-04-29 stsp #ifndef PROFILE
304 80ddbec8 2018-04-29 stsp if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
305 80ddbec8 2018-04-29 stsp err(1, "pledge");
306 80ddbec8 2018-04-29 stsp #endif
307 80ddbec8 2018-04-29 stsp
308 80ddbec8 2018-04-29 stsp while ((ch = getopt(argc, argv, "c:")) != -1) {
309 80ddbec8 2018-04-29 stsp switch (ch) {
310 80ddbec8 2018-04-29 stsp case 'c':
311 80ddbec8 2018-04-29 stsp start_commit = optarg;
312 80ddbec8 2018-04-29 stsp break;
313 80ddbec8 2018-04-29 stsp default:
314 80ddbec8 2018-04-29 stsp usage();
315 80ddbec8 2018-04-29 stsp /* NOTREACHED */
316 80ddbec8 2018-04-29 stsp }
317 80ddbec8 2018-04-29 stsp }
318 80ddbec8 2018-04-29 stsp
319 80ddbec8 2018-04-29 stsp argc -= optind;
320 80ddbec8 2018-04-29 stsp argv += optind;
321 80ddbec8 2018-04-29 stsp
322 80ddbec8 2018-04-29 stsp if (argc == 0) {
323 80ddbec8 2018-04-29 stsp repo_path = getcwd(NULL, 0);
324 80ddbec8 2018-04-29 stsp if (repo_path == NULL)
325 80ddbec8 2018-04-29 stsp return got_error_from_errno();
326 80ddbec8 2018-04-29 stsp } else if (argc == 1) {
327 80ddbec8 2018-04-29 stsp repo_path = realpath(argv[0], NULL);
328 80ddbec8 2018-04-29 stsp if (repo_path == NULL)
329 80ddbec8 2018-04-29 stsp return got_error_from_errno();
330 80ddbec8 2018-04-29 stsp } else
331 80ddbec8 2018-04-29 stsp usage_log();
332 80ddbec8 2018-04-29 stsp
333 80ddbec8 2018-04-29 stsp error = got_repo_open(&repo, repo_path);
334 80ddbec8 2018-04-29 stsp free(repo_path);
335 80ddbec8 2018-04-29 stsp if (error != NULL)
336 80ddbec8 2018-04-29 stsp return error;
337 80ddbec8 2018-04-29 stsp
338 80ddbec8 2018-04-29 stsp if (start_commit == NULL) {
339 80ddbec8 2018-04-29 stsp struct got_reference *head_ref;
340 80ddbec8 2018-04-29 stsp error = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
341 80ddbec8 2018-04-29 stsp if (error != NULL)
342 80ddbec8 2018-04-29 stsp return error;
343 80ddbec8 2018-04-29 stsp error = got_ref_resolve(&id, repo, head_ref);
344 80ddbec8 2018-04-29 stsp got_ref_close(head_ref);
345 80ddbec8 2018-04-29 stsp if (error != NULL)
346 80ddbec8 2018-04-29 stsp return error;
347 80ddbec8 2018-04-29 stsp } else {
348 80ddbec8 2018-04-29 stsp struct got_object *obj;
349 80ddbec8 2018-04-29 stsp error = got_object_open_by_id_str(&obj, repo, start_commit);
350 80ddbec8 2018-04-29 stsp if (error == NULL) {
351 80ddbec8 2018-04-29 stsp id = got_object_get_id(obj);
352 80ddbec8 2018-04-29 stsp if (id == NULL)
353 80ddbec8 2018-04-29 stsp error = got_error_from_errno();
354 80ddbec8 2018-04-29 stsp }
355 80ddbec8 2018-04-29 stsp }
356 80ddbec8 2018-04-29 stsp if (error != NULL)
357 80ddbec8 2018-04-29 stsp return error;
358 80ddbec8 2018-04-29 stsp error = show_log_view(id, repo);
359 80ddbec8 2018-04-29 stsp free(id);
360 80ddbec8 2018-04-29 stsp got_repo_close(repo);
361 80ddbec8 2018-04-29 stsp return error;
362 9f7d7167 2018-04-29 stsp }
363 9f7d7167 2018-04-29 stsp
364 9f7d7167 2018-04-29 stsp __dead void
365 9f7d7167 2018-04-29 stsp usage_diff(void)
366 9f7d7167 2018-04-29 stsp {
367 80ddbec8 2018-04-29 stsp endwin();
368 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s diff [repository-path] object1 object2\n",
369 9f7d7167 2018-04-29 stsp getprogname());
370 9f7d7167 2018-04-29 stsp exit(1);
371 9f7d7167 2018-04-29 stsp }
372 9f7d7167 2018-04-29 stsp
373 9f7d7167 2018-04-29 stsp const struct got_error *
374 9f7d7167 2018-04-29 stsp cmd_diff(int argc, char *argv[])
375 9f7d7167 2018-04-29 stsp {
376 9f7d7167 2018-04-29 stsp return got_error(GOT_ERR_NOT_IMPL);
377 9f7d7167 2018-04-29 stsp }
378 9f7d7167 2018-04-29 stsp
379 9f7d7167 2018-04-29 stsp __dead void
380 9f7d7167 2018-04-29 stsp usage_blame(void)
381 9f7d7167 2018-04-29 stsp {
382 80ddbec8 2018-04-29 stsp endwin();
383 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s blame [repository-path] blob-object\n",
384 9f7d7167 2018-04-29 stsp getprogname());
385 9f7d7167 2018-04-29 stsp exit(1);
386 9f7d7167 2018-04-29 stsp }
387 9f7d7167 2018-04-29 stsp
388 9f7d7167 2018-04-29 stsp const struct got_error *
389 9f7d7167 2018-04-29 stsp cmd_blame(int argc, char *argv[])
390 9f7d7167 2018-04-29 stsp {
391 9f7d7167 2018-04-29 stsp return got_error(GOT_ERR_NOT_IMPL);
392 9f7d7167 2018-04-29 stsp }
393 9f7d7167 2018-04-29 stsp
394 9f7d7167 2018-04-29 stsp static const struct got_error *
395 9f7d7167 2018-04-29 stsp init_curses(void)
396 9f7d7167 2018-04-29 stsp {
397 9f7d7167 2018-04-29 stsp initscr();
398 9f7d7167 2018-04-29 stsp cbreak();
399 9f7d7167 2018-04-29 stsp noecho();
400 9f7d7167 2018-04-29 stsp nonl();
401 9f7d7167 2018-04-29 stsp intrflush(stdscr, FALSE);
402 9f7d7167 2018-04-29 stsp keypad(stdscr, TRUE);
403 9f7d7167 2018-04-29 stsp
404 9f7d7167 2018-04-29 stsp tog_main_win = newwin(0, 0, 0, 0);
405 9f7d7167 2018-04-29 stsp if (tog_main_win == NULL)
406 9f7d7167 2018-04-29 stsp return got_error_from_errno();
407 9f7d7167 2018-04-29 stsp tog_main_panel = new_panel(tog_main_win);
408 9f7d7167 2018-04-29 stsp if (tog_main_panel == NULL)
409 9f7d7167 2018-04-29 stsp return got_error_from_errno();
410 9f7d7167 2018-04-29 stsp
411 9f7d7167 2018-04-29 stsp return NULL;
412 9f7d7167 2018-04-29 stsp }
413 9f7d7167 2018-04-29 stsp
414 9f7d7167 2018-04-29 stsp __dead void
415 9f7d7167 2018-04-29 stsp usage(void)
416 9f7d7167 2018-04-29 stsp {
417 9f7d7167 2018-04-29 stsp int i;
418 9f7d7167 2018-04-29 stsp
419 9f7d7167 2018-04-29 stsp fprintf(stderr, "usage: %s [-h] command [arg ...]\n\n"
420 9f7d7167 2018-04-29 stsp "Available commands:\n", getprogname());
421 9f7d7167 2018-04-29 stsp for (i = 0; i < nitems(tog_commands); i++) {
422 9f7d7167 2018-04-29 stsp struct tog_cmd *cmd = &tog_commands[i];
423 9f7d7167 2018-04-29 stsp fprintf(stderr, " %s: %s\n", cmd->cmd_name, cmd->cmd_descr);
424 9f7d7167 2018-04-29 stsp }
425 9f7d7167 2018-04-29 stsp exit(1);
426 9f7d7167 2018-04-29 stsp }
427 9f7d7167 2018-04-29 stsp
428 9f7d7167 2018-04-29 stsp int
429 9f7d7167 2018-04-29 stsp main(int argc, char *argv[])
430 9f7d7167 2018-04-29 stsp {
431 9f7d7167 2018-04-29 stsp const struct got_error *error = NULL;
432 9f7d7167 2018-04-29 stsp struct tog_cmd *cmd = NULL;
433 9f7d7167 2018-04-29 stsp int ch, hflag = 0;
434 9f7d7167 2018-04-29 stsp
435 9f7d7167 2018-04-29 stsp setlocale(LC_ALL, "");
436 9f7d7167 2018-04-29 stsp
437 9f7d7167 2018-04-29 stsp while ((ch = getopt(argc, argv, "h")) != -1) {
438 9f7d7167 2018-04-29 stsp switch (ch) {
439 9f7d7167 2018-04-29 stsp case 'h':
440 9f7d7167 2018-04-29 stsp hflag = 1;
441 9f7d7167 2018-04-29 stsp break;
442 9f7d7167 2018-04-29 stsp default:
443 9f7d7167 2018-04-29 stsp usage();
444 9f7d7167 2018-04-29 stsp /* NOTREACHED */
445 9f7d7167 2018-04-29 stsp }
446 9f7d7167 2018-04-29 stsp }
447 9f7d7167 2018-04-29 stsp
448 9f7d7167 2018-04-29 stsp argc -= optind;
449 9f7d7167 2018-04-29 stsp argv += optind;
450 9f7d7167 2018-04-29 stsp optind = 0;
451 9f7d7167 2018-04-29 stsp
452 9f7d7167 2018-04-29 stsp if (argc == 0)
453 9f7d7167 2018-04-29 stsp cmd = &tog_commands[0];
454 9f7d7167 2018-04-29 stsp else {
455 9f7d7167 2018-04-29 stsp int i;
456 9f7d7167 2018-04-29 stsp
457 9f7d7167 2018-04-29 stsp for (i = 0; i < nitems(tog_commands); i++) {
458 9f7d7167 2018-04-29 stsp if (strncmp(tog_commands[i].cmd_name, argv[0],
459 9f7d7167 2018-04-29 stsp strlen(argv[0])) == 0) {
460 9f7d7167 2018-04-29 stsp cmd = &tog_commands[i];
461 9f7d7167 2018-04-29 stsp if (hflag)
462 9f7d7167 2018-04-29 stsp tog_commands[i].cmd_usage();
463 9f7d7167 2018-04-29 stsp break;
464 9f7d7167 2018-04-29 stsp }
465 9f7d7167 2018-04-29 stsp }
466 9f7d7167 2018-04-29 stsp if (cmd == NULL) {
467 9f7d7167 2018-04-29 stsp fprintf(stderr, "%s: unknown command '%s'\n",
468 9f7d7167 2018-04-29 stsp getprogname(), argv[0]);
469 9f7d7167 2018-04-29 stsp return 1;
470 9f7d7167 2018-04-29 stsp }
471 9f7d7167 2018-04-29 stsp }
472 9f7d7167 2018-04-29 stsp
473 9f7d7167 2018-04-29 stsp error = init_curses();
474 9f7d7167 2018-04-29 stsp if (error) {
475 80ddbec8 2018-04-29 stsp fprintf(stderr, "cannot initialize ncurses: %s\n", error->msg);
476 9f7d7167 2018-04-29 stsp return 1;
477 9f7d7167 2018-04-29 stsp }
478 9f7d7167 2018-04-29 stsp
479 9f7d7167 2018-04-29 stsp error = cmd->cmd_main(argc, argv);
480 9f7d7167 2018-04-29 stsp if (error)
481 9f7d7167 2018-04-29 stsp goto done;
482 9f7d7167 2018-04-29 stsp done:
483 9f7d7167 2018-04-29 stsp endwin();
484 9f7d7167 2018-04-29 stsp if (error)
485 9f7d7167 2018-04-29 stsp fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
486 9f7d7167 2018-04-29 stsp return 0;
487 9f7d7167 2018-04-29 stsp }