From: Klemens Nanni Subject: got: log: -g grep-pattern To: gameoftrees@openbsd.org Date: Fri, 29 Nov 2019 22:11:01 +0100 Here's a preliminary diff to allow filtering commits based on their log message; this is the pendant to `git log --grep='. There's an XXX in there regarding error handling, it can probably be improved, but `got log -g grep-pattern' already does work as expected. ----------------------------------------------- commit c94f0a879a9d8e997c639ba430576f543cbff415 (master) from: Klemens Nanni date: Fri Nov 29 21:00:51 2019 UTC log: Implement -g grep-pattern match_logmsg() is copied from tog's match_commit(). diff c48aed8c5e0fe5a2ebc85da3f009d43d33a94b52 73783f31cff2eaeeb35545c41971122991e7836e blob - 9c0c3772a7c0a876c6e1fc5ae868fe928503cb90 blob + 17d45a37ff693946c3aac03a5b28ae3ee83ec22c --- got/got.1 +++ got/got.1 @@ -314,7 +314,7 @@ in a pattern. .It Cm st Short alias for .Cm status . -.It Cm log Oo Fl c Ar commit Oc Oo Fl C Ar number Oc Oo Fl f Oc Oo Fl l Ar N Oc Oo Fl p Oc Oo Fl r Ar repository-path Oc Op Ar path +.It Cm log Oo Fl c Ar commit Oc Oo Fl C Ar number Oc Oo Fl f Oc Oo Fl l Ar N Oc Oo Fl p Oc Oo Fl g Ar grep-pattern Oc Oo Fl r Ar repository-path Oc Op Ar path Display history of a repository. If a .Ar path @@ -354,6 +354,12 @@ Display the patch of modifications made in each commit If a .Ar path is specified, only show the patch of modifications at or within this path. +.It Fl g Ar grep-pattern +If specified, show only commits which log message matches the extended +regular expression +.Ar grep-pattern . +Regular expression syntax is documented in +.Xr re_format 7 . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current blob - 9f403407a6f1173c7f605a66f2f04a512323bd71 blob + 6cbe56eb5f53391ae34b78190739a260cd059e91 --- got/got.c +++ got/got.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "got_version.h" #include "got_error.h" @@ -1589,6 +1590,32 @@ get_datestr(time_t *time, char *datebuf) return s; } +static const struct got_error * +match_logmsg(int *have_match, struct got_object_id *id, + struct got_commit_object *commit, regex_t *regex) +{ + const struct got_error *err = NULL; + regmatch_t regmatch; + char *id_str = NULL, *logmsg = NULL; + + *have_match = 0; + + err = got_object_id_str(&id_str, id); + if (err) + return err; + + err = got_object_commit_get_logmsg(&logmsg, commit); + if (err) + goto done; + + if (regexec(regex, logmsg, 1, ®match, 0) == 0) + *have_match = 1; +done: + free(id_str); + free(logmsg); + return err; +} + #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n" static const struct got_error * @@ -1705,12 +1732,19 @@ print_commit(struct got_commit_object *commit, struct static const struct got_error * print_commits(struct got_object_id *root_id, struct got_repository *repo, - char *path, int show_patch, int diff_context, int limit, + char *path, int show_patch, char *grep_pattern, int diff_context, int limit, int first_parent_traversal, struct got_reflist_head *refs) { const struct got_error *err; struct got_commit_graph *graph; + regex_t regex; + int have_match; + if (grep_pattern && + regcomp(®ex, grep_pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) + /* XXX handle error? how? */ + errx(1, "regcomp"); + err = got_commit_graph_open(&graph, root_id, path, first_parent_traversal, repo); if (err) @@ -1747,6 +1781,19 @@ print_commits(struct got_object_id *root_id, struct go err = got_object_open_as_commit(&commit, repo, id); if (err) break; + + if (grep_pattern) { + err = match_logmsg(&have_match, id, commit, ®ex); + if (err) { + got_object_commit_close(commit); + break; + } + if (have_match == 0) { + got_object_commit_close(commit); + continue; + } + } + err = print_commit(commit, id, repo, path, show_patch, diff_context, refs); got_object_commit_close(commit); @@ -1754,6 +1801,8 @@ print_commits(struct got_object_id *root_id, struct go break; } done: + if (grep_pattern) + regfree(®ex); got_commit_graph_close(graph); return err; } @@ -1762,7 +1811,7 @@ __dead static void usage_log(void) { fprintf(stderr, "usage: %s log [-c commit] [-C number] [-f] [ -l N ] [-p] " - "[-r repository-path] [path]\n", getprogname()); + "[-g grep-pattern] [-r repository-path] [path]\n", getprogname()); exit(1); } @@ -1791,7 +1840,7 @@ cmd_log(int argc, char *argv[]) struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL; - char *start_commit = NULL; + char *start_commit = NULL, *grep_pattern = NULL; int diff_context = 3, ch; int show_patch = 0, limit = 0, first_parent_traversal = 0; const char *errstr; @@ -1808,7 +1857,7 @@ cmd_log(int argc, char *argv[]) limit = get_default_log_limit(); - while ((ch = getopt(argc, argv, "b:pc:C:l:fr:")) != -1) { + while ((ch = getopt(argc, argv, "b:pc:C:l:fr:g:")) != -1) { switch (ch) { case 'p': show_patch = 1; @@ -1837,6 +1886,9 @@ cmd_log(int argc, char *argv[]) optarg); got_path_strip_trailing_slashes(repo_path); break; + case 'g': + grep_pattern = optarg; + break; default: usage_log(); /* NOTREACHED */ @@ -1982,7 +2034,7 @@ cmd_log(int argc, char *argv[]) if (error) goto done; - error = print_commits(id, repo, path, show_patch, + error = print_commits(id, repo, path, show_patch, grep_pattern, diff_context, limit, first_parent_traversal, &refs); done: free(path);