From: Martin Pieuchot Subject: Re: tog(1) log by default++ To: gameoftrees@openbsd.org Date: Sat, 29 Feb 2020 12:21:54 +0100 On 28/02/20(Fri) 21:09, Stefan Sperling wrote: > On Fri, Feb 28, 2020 at 07:42:50PM +0100, Stefan Sperling wrote: > > Either way, it means that this feature request looks small on the > > surface but actually creates a lot of work for me. > > See? You made me do it :-P Thank you so much :o) > > This diff resolves the specified path upfront. Which is also hacky > but at least this is not racy and has good error reporting. > > I don't think we should have hidden usages so this should be > documented in plain sight (within the man page and tog -h). I love being the lazy guy! > Does this still work as expected? > Please fetch latest commits before applying this diff. I does! Thanks \o/ > diff a2f4a3591f215ab55f58ef4ee630b960af87a4d5 /home/stsp/src/got > blob - bda2731240200f40602cfea8febe058252a6059f > file + tog/tog.1 > --- tog/tog.1 > +++ tog/tog.1 > @@ -21,9 +21,13 @@ > .Nd Git repository browser > .Sh SYNOPSIS > .Nm > -.Ar command > +.Op Ar command > .Op Fl h > .Op Ar arg ... > +.Pp > +.Nm > +.Ar path > +.El > .Sh DESCRIPTION > .Nm > is an interactive read-only browser for Git repositories. > @@ -37,6 +41,8 @@ supports several types of views which display reposito > Displays commits in the repository's history. > This view is displayed initially if no > .Ar command > +is specified, or if just a > +.Ar path > is specified. > .It Diff view > Displays changes made in a particular commit. > blob - c91d11d969cc44a6e226b70fc4c3a355600a9218 > file + tog/tog.c > --- tog/tog.c > +++ tog/tog.c > @@ -26,6 +26,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -5333,34 +5334,133 @@ list_commands(void) > __dead static void > usage(int hflag) > { > - fprintf(stderr, "usage: %s [-h] [-V | --version] [command] [arg ...]\n", > - getprogname()); > - if (hflag) > + fprintf(stderr, "usage: %s [-h] [-V | --version] [command] " > + "[arg ...]\n", getprogname()); > + if (hflag) { > + fprintf(stderr, "lazy usage: %s path\n", getprogname()); > list_commands(); > + } > exit(1); > } > > static char ** > -make_argv(const char *arg0, const char *arg1) > +make_argv(int argc, ...) > { > + va_list ap; > char **argv; > - int argc = (arg1 == NULL ? 1 : 2); > + int i; > > + va_start(ap, argc); > + > argv = calloc(argc, sizeof(char *)); > if (argv == NULL) > err(1, "calloc"); > - argv[0] = strdup(arg0); > - if (argv[0] == NULL) > - err(1, "strdup"); > - if (arg1) { > - argv[1] = strdup(arg1); > - if (argv[1] == NULL) > + for (i = 0; i < argc; i++) { > + argv[i] = strdup(va_arg(ap, char *)); > + if (argv[i] == NULL) > err(1, "strdup"); > } > > + va_end(ap); > return argv; > } > > +/* > + * Try to convert 'tog path' into a 'tog log path' command. > + * The user could simply have mistyped the command rather than knowingly > + * provided a path. So check whether argv[0] can in fact be resolved > + * to a path in the HEAD commit and print a special error if not. > + * This hack is for mpi@ <3 > + */ > +const struct got_error * > +tog_log_with_path(int argc, char *argv[]) > +{ > + const struct got_error *error = NULL; > + struct tog_cmd *cmd = NULL; > + struct got_repository *repo = NULL; > + struct got_worktree *worktree = NULL; > + struct got_object_id *commit_id = NULL, *id = NULL; > + char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; > + char *commit_id_str = NULL, **cmd_argv = NULL; > + > + cwd = getcwd(NULL, 0); > + if (cwd == NULL) > + return got_error_from_errno("getcwd"); > + > + error = got_worktree_open(&worktree, cwd); > + if (error && error->code != GOT_ERR_NOT_WORKTREE) > + goto done; > + > + if (worktree) > + repo_path = strdup(got_worktree_get_repo_path(worktree)); > + else > + repo_path = strdup(cwd); > + if (repo_path == NULL) { > + error = got_error_from_errno("strdup"); > + goto done; > + } > + > + error = got_repo_open(&repo, repo_path, NULL); > + if (error != NULL) > + goto done; > + > + error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, > + repo, worktree); > + if (error) > + goto done; > + > + error = got_repo_match_object_id(&commit_id, NULL, worktree ? > + got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, > + GOT_OBJ_TYPE_COMMIT, 1, repo); > + if (error) > + goto done; > + > + if (worktree) { > + got_worktree_close(worktree); > + worktree = NULL; > + } > + > + error = got_object_id_by_path(&id, repo, commit_id, in_repo_path); > + if (error) { > + if (error->code != GOT_ERR_NO_TREE_ENTRY) > + goto done; > + fprintf(stderr, "%s: '%s' is no known command or path\n", > + getprogname(), argv[0]); > + usage(1); > + /* not reached */ > + } > + > + got_repo_close(repo); > + repo = NULL; > + > + error = got_object_id_str(&commit_id_str, commit_id); > + if (error) > + goto done; > + > + cmd = &tog_commands[0]; /* log */ > + argc = 4; > + cmd_argv = make_argv(argc, cmd->name, "-c", commit_id_str, argv[0]); > + error = cmd->cmd_main(argc, cmd_argv); > +done: > + if (repo) > + got_repo_close(repo); > + if (worktree) > + got_worktree_close(worktree); > + free(id); > + free(commit_id_str); > + free(commit_id); > + free(cwd); > + free(repo_path); > + free(in_repo_path); > + if (cmd_argv) { > + int i; > + for (i = 0; i < argc; i++) > + free(cmd_argv[i]); > + free(cmd_argv); > + } > + return error; > +} > + > int > main(int argc, char *argv[]) > { > @@ -5404,8 +5504,8 @@ main(int argc, char *argv[]) > usage(hflag); > /* Build an argument vector which runs a default command. */ > cmd = &tog_commands[0]; > - cmd_argv = make_argv(cmd->name, NULL); > argc = 1; > + cmd_argv = make_argv(argc, cmd->name); > } else { > int i; > > @@ -5417,19 +5517,19 @@ main(int argc, char *argv[]) > break; > } > } > - > - if (cmd == NULL) { > - fprintf(stderr, "%s: unknown command '%s'\n", > - getprogname(), argv[0]); > - list_commands(); > - return 1; > - } > } > > - if (hflag) > - cmd->cmd_usage(); > - else > - error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); > + if (cmd == NULL) { > + if (argc != 1) > + usage(0); > + /* No command specified; try log with a path */ > + error = tog_log_with_path(argc, argv); > + } else { > + if (hflag) > + cmd->cmd_usage(); > + else > + error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); > + } > > endwin(); > if (cmd_argv) {