Merge pull request #2381 from ecoffey/example_log_author_filter Add support for --author flag in example log implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
diff --git a/PROJECTS.md b/PROJECTS.md
index 9472fb4..d172144 100644
--- a/PROJECTS.md
+++ b/PROJECTS.md
@@ -39,12 +39,6 @@ These are good small projects to get started with libgit2.
the data is available, you would just need to add the code into the
`print_commit()` routine (along with a way of passing the option
into that function).
- * For `examples/log.c`, implement any one of `--author=<...>`,
- `--committer=<...>`, or `--grep=<...>` but just use simple string
- match with `strstr()` instead of full regular expression
- matching. (I.e. I'm suggesting implementing this as if
- `--fixed-strings` was always turned on, because it will be a simpler
- project.)
* As an extension to the matching idea for `examples/log.c`, add the
`-i` option to use `strcasestr()` for matches.
* For `examples/log.c`, implement the `--first-parent` option now that
diff --git a/examples/log.c b/examples/log.c
index 471c5ff..d5f75a2 100644
--- a/examples/log.c
+++ b/examples/log.c
@@ -54,8 +54,9 @@ struct log_options {
int min_parents, max_parents;
git_time_t before;
git_time_t after;
- char *author;
- char *committer;
+ const char *author;
+ const char *committer;
+ const char *grep;
};
/** utility functions that parse options and help with log output */
@@ -65,6 +66,9 @@ static void print_time(const git_time *intime, const char *prefix);
static void print_commit(git_commit *commit);
static int match_with_parent(git_commit *commit, int i, git_diff_options *);
+/** utility functions for filtering */
+static int signature_matches(const git_signature *sig, const char *filter);
+static int log_message_matches(const git_commit *commit, const char *filter);
int main(int argc, char *argv[])
{
@@ -128,6 +132,15 @@ int main(int argc, char *argv[])
continue;
}
+ if (!signature_matches(git_commit_author(commit), opt.author))
+ continue;
+
+ if (!signature_matches(git_commit_committer(commit), opt.committer))
+ continue;
+
+ if (!log_message_matches(commit, opt.grep))
+ continue;
+
if (count++ < opt.skip)
continue;
if (opt.limit != -1 && printed++ >= opt.limit) {
@@ -172,6 +185,32 @@ int main(int argc, char *argv[])
return 0;
}
+/** Determine if the given git_signature does not contain the filter text. */
+static int signature_matches(const git_signature *sig, const char *filter) {
+ if (filter == NULL)
+ return 1;
+
+ if (sig != NULL &&
+ (strstr(sig->name, filter) != NULL ||
+ strstr(sig->email, filter) != NULL))
+ return 1;
+
+ return 0;
+}
+
+static int log_message_matches(const git_commit *commit, const char *filter) {
+ const char *message = NULL;
+
+ if (filter == NULL)
+ return 1;
+
+ if ((message = git_commit_message(commit)) != NULL &&
+ strstr(message, filter) != NULL)
+ return 1;
+
+ return 0;
+}
+
/** Push object (for hide or show) onto revwalker. */
static void push_rev(struct log_state *s, git_object *obj, int hide)
{
@@ -401,6 +440,12 @@ static int parse_options(
set_sorting(s, GIT_SORT_TOPOLOGICAL);
else if (!strcmp(a, "--reverse"))
set_sorting(s, GIT_SORT_REVERSE);
+ else if (match_str_arg(&opt->author, &args, "--author"))
+ /** Found valid --author */;
+ else if (match_str_arg(&opt->committer, &args, "--committer"))
+ /** Found valid --committer */;
+ else if (match_str_arg(&opt->grep, &args, "--grep"))
+ /** Found valid --grep */;
else if (match_str_arg(&s->repodir, &args, "--git-dir"))
/** Found git-dir. */;
else if (match_int_arg(&opt->skip, &args, "--skip", 0))