Commit 155aca2d by Carlos Martín Nieto

revwalk: introduce pushing and hiding by glob

git_revwalk_{push,hide}_glob() lets you push the OIDs of references
that match the specified glob. This is the basics for what git.git
does with the rev-list options --branches, --tags, --remotes and
--glob.
parent 8f7be6ca
...@@ -101,6 +101,20 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); ...@@ -101,6 +101,20 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
*/ */
GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid); GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid);
/**
* Push matching references
*
* The OIDs pinted to by the references that match the given glob
* pattern will be pushed to the revision walker.
*
* A leading 'refs/' is implied it not present as well as a trailing
* '/ *' if the glob lacks '?', '*' or '['.
*
* @param walk the walker being used for the traversal
* @param glob the glob pattern references should match
* @return GIT_SUCCESS or an error code
*/
GIT_EXTERN(int) git_revwalk_push_glob(git_revwalk *walk, const char *glob);
/** /**
* Mark a commit (and its ancestors) uninteresting for the output. * Mark a commit (and its ancestors) uninteresting for the output.
...@@ -118,6 +132,22 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid); ...@@ -118,6 +132,22 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid);
GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid); GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid);
/** /**
* Hide matching references.
*
* The OIDs pinted to by the references that match the given glob
* pattern and their ancestors will be hidden from the output on the
* revision walk.
*
* A leading 'refs/' is implied it not present as well as a trailing
* '/ *' if the glob lacks '?', '*' or '['.
*
* @param walk the walker being used for the traversal
* @param glob the glob pattern references should match
* @return GIT_SUCCESS or an error code
*/
GIT_EXTERN(int) git_revwalk_hide_glob(git_revwalk *walk, const char *glob);
/**
* Get the next commit from the revision walk. * Get the next commit from the revision walk.
* *
* The initial call to this method is *not* blocking when * The initial call to this method is *not* blocking when
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "git2/revwalk.h" #include "git2/revwalk.h"
#include <regex.h>
typedef struct commit_object { typedef struct commit_object {
git_oid oid; git_oid oid;
uint32_t time; uint32_t time;
...@@ -298,12 +300,97 @@ int git_revwalk_push(git_revwalk *walk, const git_oid *oid) ...@@ -298,12 +300,97 @@ int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
return push_commit(walk, oid, 0); return push_commit(walk, oid, 0);
} }
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid) int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
{ {
assert(walk && oid); assert(walk && oid);
return push_commit(walk, oid, 1); return push_commit(walk, oid, 1);
} }
struct push_cb_data {
git_revwalk *walk;
const char *glob;
int hide;
};
static int push_glob_cb(const char *refname, void *data_)
{
struct push_cb_data *data = (struct push_cb_data *)data_;
if (!git__fnmatch(data->glob, refname, 0)) {
git_reference *ref, *resolved;
int error;
error = git_reference_lookup(&ref, data->walk->repo, refname);
if (error < GIT_SUCCESS)
return error;
error = git_reference_resolve(&resolved, ref);
git_reference_free(ref);
if (error < GIT_SUCCESS)
return error;
error = push_commit(data->walk, git_reference_oid(resolved), data->hide);
git_reference_free(resolved);
return error;
}
return GIT_SUCCESS;
}
static int push_glob(git_revwalk *walk, const char *glob, int hide)
{
git_buf buf = GIT_BUF_INIT;
struct push_cb_data data;
int error;
regex_t preg;
assert(walk && glob);
/* refs/ is implied if not given in the glob */
if (strncmp(glob, GIT_REFS_DIR, strlen(GIT_REFS_DIR))) {
git_buf_printf(&buf, GIT_REFS_DIR "%s", glob);
} else {
git_buf_puts(&buf, glob);
}
/* If no '?', '*' or '[' exist, we append '/ *' to the glob */
memset(&preg, 0x0, sizeof(regex_t));
if (regcomp(&preg, "[?*[]", REG_EXTENDED)) {
error = git__throw(GIT_EOSERR, "Regex failed to compile");
goto cleanup;
}
if (regexec(&preg, glob, 0, NULL, 0))
git_buf_puts(&buf, "/*");
if (git_buf_oom(&buf)) {
error = GIT_ENOMEM;
goto cleanup;
}
data.walk = walk;
data.glob = git_buf_cstr(&buf);
data.hide = hide;
error = git_reference_foreach(walk->repo, GIT_REF_LISTALL, push_glob_cb, &data);
cleanup:
regfree(&preg);
git_buf_free(&buf);
return error;
}
int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
{
assert(walk && glob);
return push_glob(walk, glob, 0);
}
int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
{
assert(walk && glob);
return push_glob(walk, glob, 1);
}
static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit) static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit)
{ {
return git_pqueue_insert(&walk->iterator_time, commit); return git_pqueue_insert(&walk->iterator_time, commit);
......
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