Commit d9ecaf8c by Vicent Marti

Merge remote-tracking branch 'gnprice/revwalk' into development

parents 22744837 2e233285
general
showindex
diff
rev-list
*.dSYM
#include <stdio.h>
#include <string.h>
#include <git2.h>
static void check_error(int error_code, const char *action)
{
if (!error_code)
return;
const git_error *error = giterr_last();
fprintf(stderr, "Error %d %s: %s\n", -error_code, action,
(error && error->message) ? error->message : "???");
exit(1);
}
static int push_commit(git_revwalk *walk, git_object *obj, int hide)
{
if (hide)
return git_revwalk_hide(walk, git_object_id(obj));
else
return git_revwalk_push(walk, git_object_id(obj));
}
static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide)
{
int error;
git_object *obj;
if ((error = git_revparse_single(&obj, repo, spec)))
return error;
return push_commit(walk, obj, hide);
}
static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide)
{
git_object *left, *right;
int threedots;
int error = 0;
if ((error = git_revparse_rangelike(&left, &right, &threedots, repo, range)))
return error;
if (threedots) {
/* TODO: support "<commit>...<commit>" */
return GIT_EINVALIDSPEC;
}
if ((error = push_commit(walk, left, !hide)))
goto out;
error = push_commit(walk, right, hide);
out:
git_object_free(left);
git_object_free(right);
return error;
}
static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, const char *const *opts)
{
int hide, i, error;
unsigned int sorting = GIT_SORT_NONE;
hide = 0;
for (i = 0; i < nopts; i++) {
if (!strcmp(opts[i], "--topo-order")) {
sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting);
} else if (!strcmp(opts[i], "--date-order")) {
sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting);
} else if (!strcmp(opts[i], "--reverse")) {
sorting = (sorting & ~GIT_SORT_REVERSE)
| ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting);
} else if (!strcmp(opts[i], "--not")) {
hide = !hide;
} else if (opts[i][0] == '^') {
if ((error = push_spec(repo, walk, opts[i] + 1, !hide)))
return error;
} else if (strstr(opts[i], "..")) {
if ((error = push_range(repo, walk, opts[i], hide)))
return error;
} else {
if ((error = push_spec(repo, walk, opts[i], hide)))
return error;
}
}
return 0;
}
int main (int argc, char **argv)
{
int error;
git_repository *repo;
git_revwalk *walk;
git_oid oid;
char buf[41];
error = git_repository_open_ext(&repo, ".", 0, NULL);
check_error(error, "opening repository");
error = git_revwalk_new(&walk, repo);
check_error(error, "allocating revwalk");
error = revwalk_parseopts(repo, walk, argc-1, argv+1);
check_error(error, "parsing options");
while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid);
buf[40] = '\0';
printf("%s\n", buf);
}
return 0;
}
#!/bin/bash
THIS_FILE="$(readlink -f "$0")"
ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")"
PROGRAM="$ROOT"/examples/rev-list
LIBDIR="$ROOT"/build
REPO="$ROOT"/tests-clar/resources/testrepo.git
cd "$REPO"
run () {
LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@"
}
diff -u - <(run --date-order a4a7dce) <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
out="$(run --topo-order a4a7dce)"
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(echo "$out") <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
c47800c7266a2be04c571c04d5a6614691ea99bd
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(run --date-order --reverse a4a7dce) <<EOF
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
c47800c7266a2be04c571c04d5a6614691ea99bd
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
out=$(run --topo-order --reverse a4a7dce)
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
c47800c7266a2be04c571c04d5a6614691ea99bd
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
diff -u - <(echo "$out") <<EOF
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
c47800c7266a2be04c571c04d5a6614691ea99bd
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
out="$(run --date-order --topo-order --reverse --reverse a4a7dce)"
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(echo "$out") <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
c47800c7266a2be04c571c04d5a6614691ea99bd
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(run ^9fd738e~2 9fd738e) <<EOF
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
EOF
diff -u - <(run --not 9fd738e..9fd738e~2) <<EOF
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
EOF
......@@ -32,6 +32,19 @@ GIT_BEGIN_DECL
*/
GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec);
/**
* Parse a string with the form of a revision range, as accepted by
* `git rev-list`, `git diff`, and others.
*
* @param left (output) the left-hand commit
* @param right (output) the right-hand commit
* @param threedots (output) 0 if the endpoints are separated by two dots, 1 if by three
* @param repo the repository to find the commits in
* @param rangelike the rangelike string to be parsed
* @return 0 on success, or any error `git_revparse_single` can return
*/
GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike);
/** @} */
GIT_END_DECL
#endif
......@@ -92,7 +92,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
*
* The given commit will be used as one of the roots
* when starting the revision walk. At least one commit
* must be pushed the repository before a walk can
* must be pushed onto the walker before a walk can
* be started.
*
* @param walk the walker being used for the traversal.
......@@ -217,6 +217,21 @@ GIT_EXTERN(int) git_revwalk_next(git_oid *out, git_revwalk *walk);
GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
/**
* Push and hide the respective endpoints of the given range.
*
* The range should be of the form
* <commit>..<commit>
* where each <commit> is in the form accepted by 'git_revparse_single'.
* The left-hand commit will be hidden and the right-hand commit pushed.
*
* @param walk the walker being used for the traversal
* @param range the range
* @return 0 or an error code
*
*/
GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range);
/**
* Free a revision walker previously allocated.
*
* @param walk traversal handle to close. If NULL nothing occurs.
......
......@@ -867,3 +867,28 @@ cleanup:
git_buf_free(&buf);
return error;
}
int git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike)
{
int error = 0;
const char *p, *q;
char *revspec;
p = strstr(rangelike, "..");
if (!p) {
giterr_set(GITERR_INVALID, "Malformed range (or rangelike syntax): %s", rangelike);
return GIT_EINVALIDSPEC;
} else if (p[2] == '.') {
*threedots = 1;
q = p + 3;
} else {
*threedots = 0;
q = p + 2;
}
revspec = git__substrdup(rangelike, p - rangelike);
error = (git_revparse_single(left, repo, revspec)
|| git_revparse_single(right, repo, q));
git__free(revspec);
return error;
}
......@@ -11,6 +11,7 @@
#include "pool.h"
#include "revwalk.h"
#include "git2/revparse.h"
#include "merge.h"
#include <regex.h>
......@@ -228,6 +229,30 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
return push_ref(walk, refname, 0);
}
int git_revwalk_push_range(git_revwalk *walk, const char *range)
{
git_object *left, *right;
int threedots;
int error = 0;
if ((error = git_revparse_rangelike(&left, &right, &threedots, walk->repo, range)))
return error;
if (threedots) {
/* TODO: support "<commit>...<commit>" */
giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk");
return GIT_EINVALIDSPEC;
}
if ((error = push_commit(walk, git_object_id(left), 1)))
goto out;
error = push_commit(walk, git_object_id(right), 0);
out:
git_object_free(left);
git_object_free(right);
return error;
}
int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
{
assert(walk && refname);
......
......@@ -32,6 +32,33 @@ static void test_object(const char *spec, const char *expected_oid)
test_object_inrepo(spec, expected_oid, g_repo);
}
static void test_rangelike(const char *rangelike,
const char *expected_left,
const char *expected_right,
int expected_threedots)
{
char objstr[64] = {0};
git_object *left, *right;
int threedots;
int error;
error = git_revparse_rangelike(&left, &right, &threedots, g_repo, rangelike);
if (expected_left != NULL) {
cl_assert_equal_i(0, error);
cl_assert_equal_i(threedots, expected_threedots);
git_oid_fmt(objstr, git_object_id(left));
cl_assert_equal_s(objstr, expected_left);
git_oid_fmt(objstr, git_object_id(right));
cl_assert_equal_s(objstr, expected_right);
} else
cl_assert(error != 0);
git_object_free(left);
git_object_free(right);
}
void test_refs_revparse__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
......@@ -596,3 +623,19 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void)
git_object_free(target);
cl_git_sandbox_cleanup();
}
void test_refs_revparse__range(void)
{
test_rangelike("be3563a^1..be3563a",
"9fd738e8f7967c078dceed8190330fc8648ee56a",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
0);
test_rangelike("be3563a^1...be3563a",
"9fd738e8f7967c078dceed8190330fc8648ee56a",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644",
1);
test_rangelike("be3563a^1.be3563a", NULL, NULL, 0);
}
#include "clar_libgit2.h"
/*
$ git log --oneline --graph --decorate
* a4a7dce (HEAD, br2) Merge branch 'master' into br2
* a4a7dce [0] Merge branch 'master' into br2
|\
| * 9fd738e (master) a fourth commit
| * 4a202b3 a third commit
* | c47800c branch commit one
| * 9fd738e [1] a fourth commit
| * 4a202b3 [2] a third commit
* | c47800c [3] branch commit one
|/
* 5b5b025 another commit
* 8496071 testing
* 5b5b025 [5] another commit
* 8496071 [4] testing
*/
static const char *commit_head = "a4a7dce85cf63874e984719f4fdd239f5145052f";
......@@ -39,6 +38,10 @@ static const int commit_sorting_time_reverse[][6] = {
{4, 5, 2, 1, 3, 0}
};
static const int commit_sorting_segment[][6] = {
{1, 2, -1, -1, -1, -1}
};
#define commit_count 6
static const int result_bytes = 24;
......@@ -57,22 +60,17 @@ static int get_commit_index(git_oid *raw_oid)
return -1;
}
static int test_walk(git_revwalk *walk, const git_oid *root,
int flags, const int possible_results[][6], int results_count)
static int test_walk_only(git_revwalk *walk,
const int possible_results[][commit_count], int results_count)
{
git_oid oid;
int i;
int result_array[commit_count];
git_revwalk_sorting(walk, flags);
git_revwalk_push(walk, root);
for (i = 0; i < commit_count; ++i)
result_array[i] = -1;
i = 0;
while (git_revwalk_next(&oid, walk) == 0) {
result_array[i++] = get_commit_index(&oid);
/*{
......@@ -91,6 +89,15 @@ static int test_walk(git_revwalk *walk, const git_oid *root,
return GIT_ERROR;
}
static int test_walk(git_revwalk *walk, const git_oid *root,
int flags, const int possible_results[][6], int results_count)
{
git_revwalk_sorting(walk, flags);
git_revwalk_push(walk, root);
return test_walk_only(walk, possible_results, results_count);
}
static git_repository *_repo;
static git_revwalk *_walk;
......@@ -189,3 +196,11 @@ void test_revwalk_basic__disallow_non_commit(void)
cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"));
cl_git_fail(git_revwalk_push(_walk, &oid));
}
void test_revwalk_basic__push_range(void)
{
git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0);
cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e"));
cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment