summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/log.c208
1 files changed, 146 insertions, 62 deletions
diff --git a/examples/log.c b/examples/log.c
index 83e5cbcc0..5603d743d 100644
--- a/examples/log.c
+++ b/examples/log.c
@@ -3,21 +3,15 @@
#include <stdlib.h>
#include <string.h>
-static void check(int error, const char *message)
+static void check(int error, const char *message, const char *arg)
{
- if (error) {
+ if (!error)
+ return;
+ if (arg)
+ fprintf(stderr, "%s '%s' (%d)\n", message, arg, error);
+ else
fprintf(stderr, "%s (%d)\n", message, error);
- exit(1);
- }
-}
-
-static int check_str_param(const char *arg, const char *pat, const char **val)
-{
- size_t len = strlen(pat);
- if (strncmp(arg, pat, len))
- return 0;
- *val = (const char *)(arg + len);
- return 1;
+ exit(1);
}
static void usage(const char *message, const char *arg)
@@ -30,75 +24,165 @@ static void usage(const char *message, const char *arg)
exit(1);
}
-int main(int argc, char *argv[])
-{
- int i, j, last_nonoption, force_files = -1;
- char *a;
- const char *dir = ".";
+struct log_state {
git_repository *repo;
+ const char *repodir;
git_revwalk *walker;
- git_revspec revs;
+ int hide;
+ int sorting;
+};
- git_threads_init();
+static void set_sorting(struct log_state *s, unsigned int sort_mode)
+{
+ if (!s->repo) {
+ if (!s->repodir) s->repodir = ".";
+ check(git_repository_open_ext(&s->repo, s->repodir, 0, NULL),
+ "Could not open repository", s->repodir);
+ }
- for (i = 1, last_nonoption = 1; i < argc; ++i) {
- a = argv[i];
+ if (!s->walker)
+ check(git_revwalk_new(&s->walker, s->repo),
+ "Could not create revision walker", NULL);
+
+ if (sort_mode == GIT_SORT_REVERSE)
+ s->sorting = s->sorting ^ GIT_SORT_REVERSE;
+ else
+ s->sorting = sort_mode | (s->sorting & GIT_SORT_REVERSE);
+
+ git_revwalk_sorting(s->walker, s->sorting);
+}
+
+static void push_rev(struct log_state *s, git_object *obj, int hide)
+{
+ hide = s->hide ^ hide;
+
+ if (!s->walker)
+ check(git_revwalk_new(&s->walker, s->repo),
+ "Could not create revision walker", NULL);
+
+ if (!obj)
+ check(git_revwalk_push_head(s->walker),
+ "Could not find repository HEAD", NULL);
+ else if (hide)
+ check(git_revwalk_hide(s->walker, git_object_id(obj)),
+ "Reference does not refer to a commit", NULL);
+ else
+ check(git_revwalk_push(s->walker, git_object_id(obj)),
+ "Reference does not refer to a commit", NULL);
+
+ git_object_free(obj);
+}
- if (a[0] != '-' || force_files > 0) {
- /* condense args not prefixed with '-' to start of argv */
- if (last_nonoption != i)
- argv[last_nonoption] = a;
- last_nonoption++;
+static int add_revision(struct log_state *s, const char *revstr)
+{
+ git_revspec revs;
+ int hide = 0;
+
+ if (!s->repo) {
+ if (!s->repodir) s->repodir = ".";
+ check(git_repository_open_ext(&s->repo, s->repodir, 0, NULL),
+ "Could not open repository", s->repodir);
+ }
+
+ if (!revstr)
+ push_rev(s, NULL, hide);
+ else if (*revstr == '^') {
+ revs.flags = GIT_REVPARSE_SINGLE;
+ hide = !hide;
+ if (!git_revparse_single(&revs.from, s->repo, revstr + 1))
+ return -1;
+ } else
+ if (!git_revparse(&revs, s->repo, revstr))
+ return -1;
+
+ if ((revs.flags & GIT_REVPARSE_SINGLE) != 0)
+ push_rev(s, revs.from, hide);
+ else {
+ push_rev(s, revs.to, hide);
+
+ if ((revs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
+ git_oid base;
+ check(git_merge_base(&base, s->repo,
+ git_object_id(revs.from), git_object_id(revs.to)),
+ "Could not find merge base", revstr);
+ check(git_object_lookup(&revs.to, s->repo, &base, GIT_OBJ_COMMIT),
+ "Could not find merge base commit", NULL);
+
+ push_rev(s, revs.to, hide);
}
- else if (!strcmp(a, "--"))
- force_files = last_nonoption; /* copy all args as filenames */
- else if (!check_str_param(a, "--git-dir=", &dir))
- usage("Unknown argument", a);
+
+ push_rev(s, revs.from, !hide);
}
- check(git_repository_open_ext(&repo, dir, 0, NULL),
- "Could not open repository");
- check(git_revwalk_new(&walker, repo),
- "Could not create revision walker");
+ return 0;
+}
+
+struct log_options {
+ int show_diff;
+ int skip;
+ int min_parents, max_parents;
+ git_time_t before;
+ git_time_t after;
+ char *author;
+ char *committer;
- if (force_files < 0)
- force_files = last_nonoption;
+};
- for (i = 1; i < force_files; ) {
- printf("option '%s'\n", argv[i]);
+int main(int argc, char *argv[])
+{
+ int i, count = 0;
+ char *a;
+ struct log_state s;
+ git_strarray paths;
+ git_oid oid;
+ git_commit *commit;
+ char buf[GIT_OID_HEXSZ + 1];
- if (!git_revparse(&revs, repo, argv[i])) {
- char str[GIT_OID_HEXSZ+1];
+ git_threads_init();
- if (revs.from) {
- git_oid_tostr(str, sizeof(str), git_object_id(revs.from));
- printf("revwalk from %s\n", str);
- }
- if (revs.to) {
- git_oid_tostr(str, sizeof(str), git_object_id(revs.to));
- printf("revwalk to %s\n", str);
- }
+ memset(&s, 0, sizeof(s));
- /* push / hide / merge-base in revwalker */
+ for (i = 1; i < argc; ++i) {
+ a = argv[i];
+ if (a[0] != '-') {
+ if (!add_revision(&s, a))
+ ++count;
+ else /* try failed revision parse as filename */
+ break;
+ } else if (!strcmp(a, "--")) {
++i;
- } else {
- /* shift array down */
- for (a = argv[i], j = i + 1; j < force_files; ++j)
- argv[j - 1] = argv[j];
- argv[--force_files] = a;
+ break;
}
+ else if (!strcmp(a, "--date-order"))
+ set_sorting(&s, GIT_SORT_TIME);
+ else if (!strcmp(a, "--topo-order"))
+ set_sorting(&s, GIT_SORT_TOPOLOGICAL);
+ else if (!strcmp(a, "--reverse"))
+ set_sorting(&s, GIT_SORT_REVERSE);
+ else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
+ s.repodir = a + strlen("--git-dir=");
+ else
+ usage("Unsupported argument", a);
}
- if (i == 1) {
- /* no revs pushed so push HEAD */
- printf("revwalk HEAD\n");
- }
+ if (!count)
+ add_revision(&s, NULL);
+
+ paths.strings = &argv[i];
+ paths.count = argc - i;
- for (i = force_files; i < last_nonoption; ++i)
- printf("file %s\n", argv[i]);
+ while (!git_revwalk_next(&oid, s.walker)) {
+ check(git_commit_lookup(&commit, s.repo, &oid),
+ "Failed to look up commit", NULL);
+ git_commit_free(commit);
+
+ git_oid_tostr(buf, sizeof(buf), &oid);
+ printf("%s\n", buf);
+ }
- git_repository_free(repo);
+ git_revwalk_free(s.walker);
+ git_repository_free(s.repo);
git_threads_shutdown();
return 0;