rev-list.c 3.71 KB
Newer Older
1
/*
2 3
 * libgit2 "rev-list" example - shows how to transform a rev-spec into a list
 * of commit ids
4
 *
5 6 7 8 9 10 11 12 13
 * Written by the libgit2 contributors
 *
 * To the extent possible under law, the author(s) have dedicated all copyright
 * and related and neighboring rights to this software to the public domain
 * worldwide. This software is distributed without any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication along
 * with this software. If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
14
 */
Greg Price committed
15

16
#include "common.h"
Greg Price committed
17

18 19 20 21
#include <assert.h>

static int revwalk_parse_options(git_sort_t *sort, struct args_info *args);
static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args);
22

23
int lg2_rev_list(git_repository *repo, int argc, char **argv)
Greg Price committed
24
{
25
	struct args_info args = ARGS_INFO_INIT;
26 27
	git_revwalk *walk;
	git_oid oid;
28
	git_sort_t sort;
29
	char buf[GIT_OID_HEXSZ+1];
30

31 32
	check_lg2(revwalk_parse_options(&sort, &args), "parsing options", NULL);

33
	check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL);
34 35
	git_revwalk_sorting(walk, sort);
	check_lg2(revwalk_parse_revs(repo, walk, &args), "parsing revs", NULL);
36 37 38

	while (!git_revwalk_next(&oid, walk)) {
		git_oid_fmt(buf, &oid);
39
		buf[GIT_OID_HEXSZ] = '\0';
40 41 42
		printf("%s\n", buf);
	}

43
	git_revwalk_free(walk);
44
	return 0;
Greg Price committed
45 46
}

Ben Straub committed
47
static int push_commit(git_revwalk *walk, const git_oid *oid, int hide)
Greg Price committed
48 49
{
	if (hide)
50
		return git_revwalk_hide(walk, oid);
Greg Price committed
51
	else
52
		return git_revwalk_push(walk, oid);
Greg Price committed
53 54 55 56 57
}

static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide)
{
	int error;
58
	git_object *obj;
Greg Price committed
59

Ben Straub committed
60
	if ((error = git_revparse_single(&obj, repo, spec)) < 0)
Greg Price committed
61
		return error;
Vicent Marti committed
62

63 64 65
	error = push_commit(walk, git_object_id(obj), hide);
	git_object_free(obj);
	return error;
Greg Price committed
66 67 68 69
}

static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide)
{
Vicent Marti committed
70
	git_revspec revspec;
Greg Price committed
71 72
	int error = 0;

Vicent Marti committed
73
	if ((error = git_revparse(&revspec, repo, range)))
Greg Price committed
74
		return error;
Vicent Marti committed
75 76

	if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
Greg Price committed
77 78 79 80
		/* TODO: support "<commit>...<commit>" */
		return GIT_EINVALIDSPEC;
	}

Vicent Marti committed
81
	if ((error = push_commit(walk, git_object_id(revspec.from), !hide)))
Greg Price committed
82 83
		goto out;

Vicent Marti committed
84 85 86 87 88
	error = push_commit(walk, git_object_id(revspec.to), hide);

out:
	git_object_free(revspec.from);
	git_object_free(revspec.to);
Greg Price committed
89 90 91
	return error;
}

92 93 94 95 96 97 98
static void print_usage(void)
{
	fprintf(stderr, "rev-list [--git-dir=dir] [--topo-order|--date-order] [--reverse] <revspec>\n");
	exit(-1);
}

static int revwalk_parse_options(git_sort_t *sort, struct args_info *args)
Greg Price committed
99
{
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	assert(sort && args);
	*sort = GIT_SORT_NONE;

	if (args->argc < 1)
		print_usage();

	for (args->pos = 1; args->pos < args->argc; ++args->pos) {
		const char *curr = args->argv[args->pos];

		if (!strcmp(curr, "--topo-order")) {
			*sort |= GIT_SORT_TOPOLOGICAL;
		} else if (!strcmp(curr, "--date-order")) {
			*sort |= GIT_SORT_TIME;
		} else if (!strcmp(curr, "--reverse")) {
			*sort |= (*sort & ~GIT_SORT_REVERSE) ^ GIT_SORT_REVERSE;
		} else {
			break;
		}
	}
	return 0;
}

static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args)
{
	int hide, error;
	git_oid oid;
Greg Price committed
126 127

	hide = 0;
128 129 130 131
	for (; args->pos < args->argc; ++args->pos) {
		const char *curr = args->argv[args->pos];

		if (!strcmp(curr, "--not")) {
Greg Price committed
132
			hide = !hide;
133 134
		} else if (curr[0] == '^') {
			if ((error = push_spec(repo, walk, curr + 1, !hide)))
Greg Price committed
135
				return error;
136 137
		} else if (strstr(curr, "..")) {
			if ((error = push_range(repo, walk, curr, hide)))
Greg Price committed
138 139
				return error;
		} else {
140 141 142 143 144 145
			if (push_spec(repo, walk, curr, hide) == 0)
				continue;

			if ((error = git_oid_fromstr(&oid, curr)))
				return error;
			if ((error = push_commit(walk, &oid, hide)))
Greg Price committed
146 147 148 149 150 151 152
				return error;
		}
	}

	return 0;
}