Commit c0e529f3 by Vicent Marti

Merge branch 'arrbee/examples-log' into development

parents bf3ee3cf 406dd556
......@@ -3,7 +3,7 @@
CC = gcc
CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers
LFLAGS = -L../build -lgit2 -lz
APPS = general showindex diff rev-list cat-file status
APPS = general showindex diff rev-list cat-file status log rev-parse
all: $(APPS)
......
This diff is collapsed. Click to expand it.
#include <stdio.h>
#include <git2.h>
#include <stdlib.h>
#include <string.h>
static void check(int error, const char *message, const char *arg)
{
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 void usage(const char *message, const char *arg)
{
if (message && arg)
fprintf(stderr, "%s: %s\n", message, arg);
else if (message)
fprintf(stderr, "%s\n", message);
fprintf(stderr, "usage: rev-parse [ --option ] <args>...\n");
exit(1);
}
struct parse_state {
git_repository *repo;
const char *repodir;
int not;
};
static int parse_revision(struct parse_state *ps, const char *revstr)
{
git_revspec rs;
char str[GIT_OID_HEXSZ + 1];
if (!ps->repo) {
if (!ps->repodir)
ps->repodir = ".";
check(git_repository_open_ext(&ps->repo, ps->repodir, 0, NULL),
"Could not open repository from", ps->repodir);
}
check(git_revparse(&rs, ps->repo, revstr), "Could not parse", revstr);
if ((rs.flags & GIT_REVPARSE_SINGLE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
printf("%s\n", str);
git_object_free(rs.from);
}
else if ((rs.flags & GIT_REVPARSE_RANGE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.to));
printf("%s\n", str);
git_object_free(rs.to);
if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
git_oid base;
check(git_merge_base(&base, ps->repo,
git_object_id(rs.from), git_object_id(rs.to)),
"Could not find merge base", revstr);
git_oid_tostr(str, sizeof(str), &base);
printf("%s\n", str);
}
git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
printf("^%s\n", str);
git_object_free(rs.from);
}
else {
check(0, "Invalid results from git_revparse", revstr);
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
char *a;
struct parse_state ps;
git_threads_init();
memset(&ps, 0, sizeof(ps));
for (i = 1; i < argc; ++i) {
a = argv[i];
if (a[0] != '-') {
if (parse_revision(&ps, a) != 0)
break;
} else if (!strcmp(a, "--not"))
ps.not = !ps.not;
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
ps.repodir = a + strlen("--git-dir=");
else
usage("Cannot handle argument", a);
}
git_repository_free(ps.repo);
git_threads_shutdown();
return 0;
}
......@@ -56,5 +56,6 @@
#include "git2/message.h"
#include "git2/pack.h"
#include "git2/stash.h"
#include "git2/pathspec.h"
#endif
......@@ -130,6 +130,14 @@ GIT_EXTERN(const git_signature *) git_commit_committer(const git_commit *commit)
GIT_EXTERN(const git_signature *) git_commit_author(const git_commit *commit);
/**
* Get the full raw text of the commit header.
*
* @param commit a previously loaded commit
* @return the header text of the commit
*/
GIT_EXTERN(const char *) git_commit_raw_header(const git_commit *commit);
/**
* Get the tree pointed to by a commit.
*
* @param tree_out pointer where to store the tree object
......
......@@ -798,6 +798,14 @@ GIT_EXTERN(size_t) git_diff_num_deltas_of_type(
git_delta_t type);
/**
* Check if deltas are sorted case sensitively or insensitively.
*
* @param diff Diff list to check
* @return 0 if case sensitive, 1 if case is ignored
*/
GIT_EXTERN(int) git_diff_is_sorted_icase(const git_diff_list *diff);
/**
* Return the diff delta and patch for an entry in the diff list.
*
* The `git_diff_patch` is a newly created object contains the text diffs
......
......@@ -138,6 +138,14 @@ typedef enum {
GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2),
} git_index_add_option_t;
/**
* Match any index stage.
*
* Some index APIs take a stage to match; pass this value to match
* any entry matching the path regardless of stage.
*/
#define GIT_INDEX_STAGE_ANY -1
/** @name Index File Functions
*
* These functions work on the index file itself.
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_git_pathspec_h__
#define INCLUDE_git_pathspec_h__
#include "common.h"
#include "types.h"
#include "strarray.h"
#include "diff.h"
/**
* Compiled pathspec
*/
typedef struct git_pathspec git_pathspec;
/**
* List of filenames matching a pathspec
*/
typedef struct git_pathspec_match_list git_pathspec_match_list;
/**
* Options controlling how pathspec match should be executed
*
* - GIT_PATHSPEC_IGNORE_CASE forces match to ignore case; otherwise
* match will use native case sensitivity of platform filesystem
* - GIT_PATHSPEC_USE_CASE forces case sensitive match; otherwise
* match will use native case sensitivity of platform filesystem
* - GIT_PATHSPEC_NO_GLOB disables glob patterns and just uses simple
* string comparison for matching
* - GIT_PATHSPEC_NO_MATCH_ERROR means the match functions return error
* code GIT_ENOTFOUND if no matches are found; otherwise no matches is
* still success (return 0) but `git_pathspec_match_list_entrycount`
* will indicate 0 matches.
* - GIT_PATHSPEC_FIND_FAILURES means that the `git_pathspec_match_list`
* should track which patterns matched which files so that at the end of
* the match we can identify patterns that did not match any files.
* - GIT_PATHSPEC_FAILURES_ONLY means that the `git_pathspec_match_list`
* does not need to keep the actual matching filenames. Use this to
* just test if there were any matches at all or in combination with
* GIT_PATHSPEC_FIND_FAILURES to validate a pathspec.
*/
typedef enum {
GIT_PATHSPEC_DEFAULT = 0,
GIT_PATHSPEC_IGNORE_CASE = (1u << 0),
GIT_PATHSPEC_USE_CASE = (1u << 1),
GIT_PATHSPEC_NO_GLOB = (1u << 2),
GIT_PATHSPEC_NO_MATCH_ERROR = (1u << 3),
GIT_PATHSPEC_FIND_FAILURES = (1u << 4),
GIT_PATHSPEC_FAILURES_ONLY = (1u << 5),
} git_pathspec_flag_t;
/**
* Compile a pathspec
*
* @param out Output of the compiled pathspec
* @param pathspec A git_strarray of the paths to match
* @return 0 on success, <0 on failure
*/
GIT_EXTERN(int) git_pathspec_new(
git_pathspec **out, const git_strarray *pathspec);
/**
* Free a pathspec
*
* @param ps The compiled pathspec
*/
GIT_EXTERN(void) git_pathspec_free(git_pathspec *ps);
/**
* Try to match a path against a pathspec
*
* Unlike most of the other pathspec matching functions, this will not
* fall back on the native case-sensitivity for your platform. You must
* explicitly pass flags to control case sensitivity or else this will
* fall back on being case sensitive.
*
* @param ps The compiled pathspec
* @param flags Combination of git_pathspec_flag_t options to control match
* @param path The pathname to attempt to match
* @return 1 is path matches spec, 0 if it does not
*/
GIT_EXTERN(int) git_pathspec_matches_path(
const git_pathspec *ps, uint32_t flags, const char *path);
/**
* Match a pathspec against the working directory of a repository.
*
* This matches the pathspec against the current files in the working
* directory of the repository. It is an error to invoke this on a bare
* repo. This handles git ignores (i.e. ignored files will not be
* considered to match the `pathspec` unless the file is tracked in the
* index).
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param repo The repository in which to match; bare repo is an error
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag was given
*/
GIT_EXTERN(int) git_pathspec_match_workdir(
git_pathspec_match_list **out,
git_repository *repo,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against entries in an index.
*
* This matches the pathspec against the files in the repository index.
*
* NOTE: At the moment, the case sensitivity of this match is controlled
* by the current case-sensitivity of the index object itself and the
* USE_CASE and IGNORE_CASE flags will have no effect. This behavior will
* be corrected in a future release.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param index The index to match against
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_index(
git_pathspec_match_list **out,
git_index *index,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against files in a tree.
*
* This matches the pathspec against the files in the given tree.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param tree The root-level tree to match against
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_tree(
git_pathspec_match_list **out,
git_tree *tree,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against files in a diff list.
*
* This matches the pathspec against the files in the given diff list.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param diff A generated diff list
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_diff(
git_pathspec_match_list **out,
git_diff_list *diff,
uint32_t flags,
git_pathspec *ps);
/**
* Free memory associates with a git_pathspec_match_list
*
* @param m The git_pathspec_match_list to be freed
*/
GIT_EXTERN(void) git_pathspec_match_list_free(git_pathspec_match_list *m);
/**
* Get the number of items in a match list.
*
* @param m The git_pathspec_match_list object
* @return Number of items in match list
*/
GIT_EXTERN(size_t) git_pathspec_match_list_entrycount(
const git_pathspec_match_list *m);
/**
* Get a matching filename by position.
*
* This routine cannot be used if the match list was generated by
* `git_pathspec_match_diff`. If so, it will always return NULL.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the list
* @return The filename of the match
*/
GIT_EXTERN(const char *) git_pathspec_match_list_entry(
const git_pathspec_match_list *m, size_t pos);
/**
* Get a matching diff delta by position.
*
* This routine can only be used if the match list was generated by
* `git_pathspec_match_diff`. Otherwise it will always return NULL.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the list
* @return The filename of the match
*/
GIT_EXTERN(const git_diff_delta *) git_pathspec_match_list_diff_entry(
const git_pathspec_match_list *m, size_t pos);
/**
* Get the number of pathspec items that did not match.
*
* This will be zero unless you passed GIT_PATHSPEC_FIND_FAILURES when
* generating the git_pathspec_match_list.
*
* @param m The git_pathspec_match_list object
* @return Number of items in original pathspec that had no matches
*/
GIT_EXTERN(size_t) git_pathspec_match_list_failed_entrycount(
const git_pathspec_match_list *m);
/**
* Get an original pathspec string that had no matches.
*
* This will be return NULL for positions out of range.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the failed items
* @return The pathspec pattern that didn't match anything
*/
GIT_EXTERN(const char *) git_pathspec_match_list_failed_entry(
const git_pathspec_match_list *m, size_t pos);
#endif
......@@ -30,6 +30,9 @@
#define git_array_init(a) \
do { (a).size = (a).asize = 0; (a).ptr = NULL; } while (0)
#define git_array_init_to_size(a, desired) \
do { (a).size = 0; (a).asize = desired; (a).ptr = git__calloc(desired, sizeof(*(a).ptr)); } while (0)
#define git_array_clear(a) \
do { git__free((a).ptr); git_array_init(a); } while (0)
......@@ -63,4 +66,6 @@ GIT_INLINE(void *) git_array_grow(git_array_generic_t *a, size_t item_size)
#define git_array_size(a) (a).size
#define git_array_valid_index(a, i) ((i) < (a).size)
#endif
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_bitvec_h__
#define INCLUDE_bitvec_h__
#include "util.h"
/*
* This is a silly little fixed length bit vector type that will store
* vectors of 64 bits or less directly in the structure and allocate
* memory for vectors longer than 64 bits. You can use the two versions
* transparently through the API and avoid heap allocation completely when
* using a short bit vector as a result.
*/
typedef struct {
size_t length;
union {
uint64_t *words;
uint64_t bits;
} u;
} git_bitvec;
GIT_INLINE(int) git_bitvec_init(git_bitvec *bv, size_t capacity)
{
memset(bv, 0x0, sizeof(*bv));
if (capacity >= 64) {
bv->length = (capacity / 64) + 1;
bv->u.words = git__calloc(bv->length, sizeof(uint64_t));
if (!bv->u.words)
return -1;
}
return 0;
}
#define GIT_BITVEC_MASK(BIT) ((uint64_t)1 << (BIT % 64))
#define GIT_BITVEC_WORD(BV, BIT) (BV->length ? &BV->u.words[BIT / 64] : &BV->u.bits)
GIT_INLINE(void) git_bitvec_set(git_bitvec *bv, size_t bit, bool on)
{
uint64_t *word = GIT_BITVEC_WORD(bv, bit);
uint64_t mask = GIT_BITVEC_MASK(bit);
if (on)
*word |= mask;
else
*word &= ~mask;
}
GIT_INLINE(bool) git_bitvec_get(git_bitvec *bv, size_t bit)
{
uint64_t *word = GIT_BITVEC_WORD(bv, bit);
return (*word & GIT_BITVEC_MASK(bit)) != 0;
}
GIT_INLINE(void) git_bitvec_clear(git_bitvec *bv)
{
if (!bv->length)
bv->u.bits = 0;
else
memset(bv->u.words, 0x0, bv->length * sizeof(uint64_t));
}
GIT_INLINE(void) git_bitvec_free(git_bitvec *bv)
{
if (bv->length)
git__free(bv->u.words);
}
#endif
......@@ -246,10 +246,10 @@ static int checkout_action_wd_only(
bool remove = false;
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
if (!git_pathspec_match_path(
if (!git_pathspec__match(
pathspec, wd->path,
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
git_iterator_ignore_case(workdir), NULL))
git_iterator_ignore_case(workdir), NULL, NULL))
return 0;
/* check if item is tracked in the index but not in the checkout diff */
......@@ -607,7 +607,7 @@ static int checkout_get_actions(
uint32_t *actions = NULL;
if (data->opts.paths.count > 0 &&
git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
return -1;
if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
......@@ -659,7 +659,7 @@ static int checkout_get_actions(
goto fail;
}
git_pathspec_free(&pathspec);
git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool);
return 0;
......@@ -670,7 +670,7 @@ fail:
*actions_ptr = NULL;
git__free(actions);
git_pathspec_free(&pathspec);
git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool);
return error;
......
......@@ -19,30 +19,19 @@
#include <stdarg.h>
static void clear_parents(git_commit *commit)
{
size_t i;
for (i = 0; i < commit->parent_ids.length; ++i) {
git_oid *parent = git_vector_get(&commit->parent_ids, i);
git__free(parent);
}
git_vector_clear(&commit->parent_ids);
}
void git_commit__free(void *_commit)
{
git_commit *commit = _commit;
clear_parents(commit);
git_vector_free(&commit->parent_ids);
git_array_clear(commit->parent_ids);
git_signature_free(commit->author);
git_signature_free(commit->committer);
git__free(commit->raw_header);
git__free(commit->message);
git__free(commit->message_encoding);
git__free(commit);
}
......@@ -171,12 +160,34 @@ int git_commit_create(
int git_commit__parse(void *_commit, git_odb_object *odb_obj)
{
git_commit *commit = _commit;
const char *buffer = git_odb_object_data(odb_obj);
const char *buffer_end = buffer + git_odb_object_size(odb_obj);
const char *buffer_start = git_odb_object_data(odb_obj), *buffer;
const char *buffer_end = buffer_start + git_odb_object_size(odb_obj);
git_oid parent_id;
size_t parent_count = 0, header_len;
if (git_vector_init(&commit->parent_ids, 4, NULL) < 0)
return -1;
/* find end-of-header (counting parents as we go) */
for (buffer = buffer_start; buffer < buffer_end; ++buffer) {
if (!strncmp("\n\n", buffer, 2)) {
++buffer;
break;
}
if (!strncmp("\nparent ", buffer, strlen("\nparent ")))
++parent_count;
}
header_len = buffer - buffer_start;
commit->raw_header = git__strndup(buffer_start, header_len);
GITERR_CHECK_ALLOC(commit->raw_header);
/* point "buffer" to header data */
buffer = commit->raw_header;
buffer_end = commit->raw_header + header_len;
if (parent_count < 1)
parent_count = 1;
git_array_init_to_size(commit->parent_ids, parent_count);
GITERR_CHECK_ARRAY(commit->parent_ids);
if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
goto bad_buffer;
......@@ -186,13 +197,10 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
*/
while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
git_oid *new_id = git__malloc(sizeof(git_oid));
git_oid *new_id = git_array_alloc(commit->parent_ids);
GITERR_CHECK_ALLOC(new_id);
git_oid_cpy(new_id, &parent_id);
if (git_vector_insert(&commit->parent_ids, new_id) < 0)
return -1;
}
commit->author = git__malloc(sizeof(git_signature));
......@@ -208,8 +216,8 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
return -1;
/* Parse add'l header entries until blank line found */
while (buffer < buffer_end && *buffer != '\n') {
/* Parse add'l header entries */
while (buffer < buffer_end) {
const char *eoln = buffer;
while (eoln < buffer_end && *eoln != '\n')
++eoln;
......@@ -223,15 +231,18 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
if (eoln < buffer_end && *eoln == '\n')
++eoln;
buffer = eoln;
}
/* buffer is now at the end of the header, double-check and move forward into the message */
if (buffer < buffer_end && *buffer == '\n')
buffer++;
/* point "buffer" to data after header */
buffer = git_odb_object_data(odb_obj);
buffer_end = buffer + git_odb_object_size(odb_obj);
buffer += header_len;
if (*buffer == '\n')
++buffer;
/* parse commit message */
/* extract commit message */
if (buffer <= buffer_end) {
commit->message = git__strndup(buffer, buffer_end - buffer);
GITERR_CHECK_ALLOC(commit->message);
......@@ -255,9 +266,10 @@ GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
GIT_COMMIT_GETTER(const char *, message, commit->message)
GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header)
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)commit->parent_ids.length)
GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids))
GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id);
int git_commit_tree(git_tree **tree_out, const git_commit *commit)
......@@ -271,7 +283,7 @@ const git_oid *git_commit_parent_id(
{
assert(commit);
return git_vector_get(&commit->parent_ids, n);
return git_array_get(commit->parent_ids, n);
}
int git_commit_parent(
......
......@@ -10,14 +10,14 @@
#include "git2/commit.h"
#include "tree.h"
#include "repository.h"
#include "vector.h"
#include "array.h"
#include <time.h>
struct git_commit {
git_object object;
git_vector parent_ids;
git_array_t(git_oid) parent_ids;
git_oid tree_id;
git_signature *author;
......@@ -25,6 +25,7 @@ struct git_commit {
char *message_encoding;
char *message;
char *raw_header;
};
void git_commit__free(void *commit);
......
......@@ -81,11 +81,11 @@ static int diff_delta__from_one(
DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
return 0;
if (!git_pathspec_match_path(
if (!git_pathspec__match(
&diff->pathspec, entry->path,
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
&matched_pathspec))
&matched_pathspec, NULL))
return 0;
delta = diff_delta__alloc(diff, status, entry->path);
......@@ -247,6 +247,11 @@ GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
return str;
}
const char *git_diff_delta__path(const git_diff_delta *delta)
{
return diff_delta__path(delta);
}
int git_diff_delta__cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
......@@ -387,7 +392,7 @@ static int diff_list_apply_options(
DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase);
/* initialize pathspec from options */
if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0)
if (git_pathspec__vinit(&diff->pathspec, &opts->pathspec, pool) < 0)
return -1;
}
......@@ -473,7 +478,7 @@ static void diff_list_free(git_diff_list *diff)
}
git_vector_free(&diff->deltas);
git_pathspec_free(&diff->pathspec);
git_pathspec__vfree(&diff->pathspec);
git_pool_clear(&diff->pool);
git__memzero(diff, sizeof(*diff));
......@@ -634,11 +639,11 @@ static int maybe_modified(
bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
const char *matched_pathspec;
if (!git_pathspec_match_path(
if (!git_pathspec__match(
&diff->pathspec, oitem->path,
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
&matched_pathspec))
&matched_pathspec, NULL))
return 0;
memset(&noid, 0, sizeof(noid));
......@@ -1235,6 +1240,11 @@ size_t git_diff_num_deltas_of_type(git_diff_list *diff, git_delta_t type)
return count;
}
int git_diff_is_sorted_icase(const git_diff_list *diff)
{
return (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0;
}
int git_diff__paired_foreach(
git_diff_list *head2idx,
git_diff_list *idx2wd,
......
......@@ -76,6 +76,8 @@ extern void git_diff_list_addref(git_diff_list *diff);
extern int git_diff_delta__cmp(const void *a, const void *b);
extern int git_diff_delta__casecmp(const void *a, const void *b);
extern const char *git_diff_delta__path(const git_diff_delta *delta);
extern bool git_diff_delta__should_skip(
const git_diff_options *opts, const git_diff_delta *delta);
......
......@@ -101,8 +101,6 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
static bool is_index_extended(git_index *index);
static int write_index(git_index *index, git_filebuf *file);
static int index_find(size_t *at_pos, git_index *index, const char *path, int stage);
static void index_entry_free(git_index_entry *entry);
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
......@@ -114,7 +112,7 @@ static int index_srch(const void *key, const void *array_member)
ret = strcmp(srch_key->path, entry->path);
if (ret == 0)
if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY)
ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
return ret;
......@@ -128,7 +126,7 @@ static int index_isrch(const void *key, const void *array_member)
ret = strcasecmp(srch_key->path, entry->path);
if (ret == 0)
if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY)
ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
return ret;
......@@ -562,7 +560,7 @@ const git_index_entry *git_index_get_bypath(
git_vector_sort(&index->entries);
if (index_find(&pos, index, path, stage) < 0) {
if (git_index__find(&pos, index, path, stage) < 0) {
giterr_set(GITERR_INDEX, "Index does not contain %s", path);
return NULL;
}
......@@ -719,7 +717,8 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
entry->flags |= GIT_IDXENTRY_NAMEMASK;
/* look if an entry with this path already exists */
if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
if (!git_index__find(
&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
existing = (git_index_entry **)&index->entries.contents[position];
/* update filemode to existing values if stat is not trusted */
......@@ -831,7 +830,7 @@ int git_index_remove(git_index *index, const char *path, int stage)
git_vector_sort(&index->entries);
if (index_find(&position, index, path, stage) < 0) {
if (git_index__find(&position, index, path, stage) < 0) {
giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d",
path, stage);
return GIT_ENOTFOUND;
......@@ -887,7 +886,8 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
return error;
}
static int index_find(size_t *at_pos, git_index *index, const char *path, int stage)
int git_index__find(
size_t *at_pos, git_index *index, const char *path, int stage)
{
struct entry_srch_key srch_key;
......@@ -896,7 +896,8 @@ static int index_find(size_t *at_pos, git_index *index, const char *path, int st
srch_key.path = path;
srch_key.stage = stage;
return git_vector_bsearch2(at_pos, &index->entries, index->entries_search, &srch_key);
return git_vector_bsearch2(
at_pos, &index->entries, index->entries_search, &srch_key);
}
int git_index_find(size_t *at_pos, git_index *index, const char *path)
......@@ -2053,7 +2054,7 @@ int git_index_add_all(
git_iterator *wditer = NULL;
const git_index_entry *wd = NULL;
git_index_entry *entry;
git_pathspec_context ps;
git_pathspec ps;
const char *match;
size_t existing;
bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
......@@ -2074,7 +2075,7 @@ int git_index_add_all(
if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0)
return -1;
if ((error = git_pathspec_context_init(&ps, paths)) < 0)
if ((error = git_pathspec__init(&ps, paths)) < 0)
return error;
/* optionally check that pathspec doesn't mention any ignored files */
......@@ -2091,14 +2092,14 @@ int git_index_add_all(
while (!(error = git_iterator_advance(&wd, wditer))) {
/* check if path actually matches */
if (!git_pathspec_match_path(
&ps.pathspec, wd->path, no_fnmatch, ignorecase, &match))
if (!git_pathspec__match(
&ps.pathspec, wd->path, no_fnmatch, ignorecase, &match, NULL))
continue;
/* skip ignored items that are not already in the index */
if ((flags & GIT_INDEX_ADD_FORCE) == 0 &&
git_iterator_current_is_ignored(wditer) &&
index_find(&existing, index, wd->path, 0) < 0)
git_index__find(&existing, index, wd->path, 0) < 0)
continue;
/* issue notification callback if requested */
......@@ -2148,7 +2149,7 @@ int git_index_add_all(
cleanup:
git_iterator_free(wditer);
git_pathspec_context_free(&ps);
git_pathspec__clear(&ps);
return error;
}
......@@ -2168,13 +2169,13 @@ static int index_apply_to_all(
{
int error = 0;
size_t i;
git_pathspec_context ps;
git_pathspec ps;
const char *match;
git_buf path = GIT_BUF_INIT;
assert(index);
if ((error = git_pathspec_context_init(&ps, paths)) < 0)
if ((error = git_pathspec__init(&ps, paths)) < 0)
return error;
git_vector_sort(&index->entries);
......@@ -2183,8 +2184,9 @@ static int index_apply_to_all(
git_index_entry *entry = git_vector_get(&index->entries, i);
/* check if path actually matches */
if (!git_pathspec_match_path(
&ps.pathspec, entry->path, false, index->ignore_case, &match))
if (!git_pathspec__match(
&ps.pathspec, entry->path, false, index->ignore_case,
&match, NULL))
continue;
/* issue notification callback if requested */
......@@ -2231,7 +2233,7 @@ static int index_apply_to_all(
}
git_buf_free(&path);
git_pathspec_context_free(&ps);
git_pathspec__clear(&ps);
return error;
}
......
......@@ -47,13 +47,17 @@ struct git_index_conflict_iterator {
size_t cur;
};
extern void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st);
extern void git_index_entry__init_from_stat(
git_index_entry *entry, struct stat *st);
extern size_t git_index__prefix_position(git_index *index, const char *path);
extern int git_index_entry__cmp(const void *a, const void *b);
extern int git_index_entry__cmp_icase(const void *a, const void *b);
extern int git_index__find(
size_t *at_pos, git_index *index, const char *path, int stage);
extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
#endif
......@@ -8,9 +8,35 @@
#define INCLUDE_pathspec_h__
#include "common.h"
#include <git2/pathspec.h>
#include "buffer.h"
#include "vector.h"
#include "pool.h"
#include "array.h"
/* public compiled pathspec */
struct git_pathspec {
git_refcount rc;
char *prefix;
git_vector pathspec;
git_pool pool;
};
enum {
PATHSPEC_DATATYPE_STRINGS = 0,
PATHSPEC_DATATYPE_DIFF = 1,
};
typedef git_array_t(char *) git_pathspec_string_array_t;
/* public interface to pathspec matching */
struct git_pathspec_match_list {
git_pathspec *pathspec;
git_array_t(void *) matches;
git_pathspec_string_array_t failures;
git_pool pool;
int datatype;
};
/* what is the common non-wildcard prefix for all items in the pathspec */
extern char *git_pathspec_prefix(const git_strarray *pathspec);
......@@ -19,36 +45,31 @@ extern char *git_pathspec_prefix(const git_strarray *pathspec);
extern bool git_pathspec_is_empty(const git_strarray *pathspec);
/* build a vector of fnmatch patterns to evaluate efficiently */
extern int git_pathspec_init(
extern int git_pathspec__vinit(
git_vector *vspec, const git_strarray *strspec, git_pool *strpool);
/* free data from the pathspec vector */
extern void git_pathspec_free(git_vector *vspec);
extern void git_pathspec__vfree(git_vector *vspec);
#define GIT_PATHSPEC_NOMATCH ((size_t)-1)
/*
* Match a path against the vectorized pathspec.
* The matched pathspec is passed back into the `matched_pathspec` parameter,
* unless it is passed as NULL by the caller.
*/
extern bool git_pathspec_match_path(
git_vector *vspec,
extern bool git_pathspec__match(
const git_vector *vspec,
const char *path,
bool disable_fnmatch,
bool casefold,
const char **matched_pathspec);
const char **matched_pathspec,
size_t *matched_at);
/* easy pathspec setup */
typedef struct {
char *prefix;
git_vector pathspec;
git_pool pool;
} git_pathspec_context;
extern int git_pathspec_context_init(
git_pathspec_context *ctxt, const git_strarray *paths);
extern int git_pathspec__init(git_pathspec *ps, const git_strarray *paths);
extern void git_pathspec_context_free(
git_pathspec_context *ctxt);
extern void git_pathspec__clear(git_pathspec *ps);
#endif
#include "clar_libgit2.h"
#include "bitvec.h"
#if 0
static void print_bitvec(git_bitvec *bv)
{
int b;
if (!bv->length) {
for (b = 63; b >= 0; --b)
fprintf(stderr, "%d", (bv->u.bits & (1ul << b)) ? 1 : 0);
} else {
for (b = bv->length * 8; b >= 0; --b)
fprintf(stderr, "%d", (bv->u.ptr[b >> 3] & (b & 0x0ff)) ? 1 : 0);
}
fprintf(stderr, "\n");
}
#endif
static void set_some_bits(git_bitvec *bv, size_t length)
{
size_t i;
for (i = 0; i < length; ++i) {
if (i % 3 == 0 || i % 7 == 0)
git_bitvec_set(bv, i, true);
}
}
static void check_some_bits(git_bitvec *bv, size_t length)
{
size_t i;
for (i = 0; i < length; ++i)
cl_assert_equal_b(i % 3 == 0 || i % 7 == 0, git_bitvec_get(bv, i));
}
void test_core_bitvec__0(void)
{
git_bitvec bv;
cl_git_pass(git_bitvec_init(&bv, 32));
set_some_bits(&bv, 16);
check_some_bits(&bv, 16);
git_bitvec_clear(&bv);
set_some_bits(&bv, 32);
check_some_bits(&bv, 32);
git_bitvec_clear(&bv);
set_some_bits(&bv, 64);
check_some_bits(&bv, 64);
git_bitvec_free(&bv);
cl_git_pass(git_bitvec_init(&bv, 128));
set_some_bits(&bv, 32);
check_some_bits(&bv, 32);
set_some_bits(&bv, 128);
check_some_bits(&bv, 128);
git_bitvec_free(&bv);
cl_git_pass(git_bitvec_init(&bv, 4000));
set_some_bits(&bv, 4000);
check_some_bits(&bv, 4000);
git_bitvec_free(&bv);
}
#include "clar_libgit2.h"
#include "diff_helpers.h"
static git_repository *g_repo = NULL;
void test_diff_pathspec__initialize(void)
{
g_repo = cl_git_sandbox_init("status");
}
void test_diff_pathspec__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_diff_pathspec__0(void)
{
const char *a_commit = "26a125ee"; /* the current HEAD */
const char *b_commit = "0017bd4a"; /* the start */
git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit);
git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit);
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff_list *diff = NULL;
git_strarray paths = { NULL, 1 };
char *path;
git_pathspec *ps;
git_pathspec_match_list *matches;
cl_assert(a);
cl_assert(b);
path = "*_file";
paths.strings = &path;
cl_git_pass(git_pathspec_new(&ps, &paths));
cl_git_pass(git_pathspec_match_tree(&matches, a, GIT_PATHSPEC_DEFAULT, ps));
cl_assert_equal_i(7, git_pathspec_match_list_entrycount(matches));
cl_assert_equal_s("current_file", git_pathspec_match_list_entry(matches,0));
cl_assert(git_pathspec_match_list_diff_entry(matches,0) == NULL);
git_pathspec_match_list_free(matches);
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, NULL, a, &opts));
cl_git_pass(git_pathspec_match_diff(
&matches, diff, GIT_PATHSPEC_DEFAULT, ps));
cl_assert_equal_i(7, git_pathspec_match_list_entrycount(matches));
cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
cl_assert_equal_s("current_file",
git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
cl_assert_equal_i(GIT_DELTA_ADDED,
git_pathspec_match_list_diff_entry(matches,0)->status);
git_pathspec_match_list_free(matches);
git_diff_list_free(diff);
diff = NULL;
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
cl_git_pass(git_pathspec_match_diff(
&matches, diff, GIT_PATHSPEC_DEFAULT, ps));
cl_assert_equal_i(3, git_pathspec_match_list_entrycount(matches));
cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
cl_assert_equal_s("subdir/current_file",
git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
cl_assert_equal_i(GIT_DELTA_DELETED,
git_pathspec_match_list_diff_entry(matches,0)->status);
git_pathspec_match_list_free(matches);
git_diff_list_free(diff);
diff = NULL;
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts));
cl_git_pass(git_pathspec_match_diff(
&matches, diff, GIT_PATHSPEC_DEFAULT, ps));
cl_assert_equal_i(4, git_pathspec_match_list_entrycount(matches));
cl_assert(git_pathspec_match_list_diff_entry(matches, 0) != NULL);
cl_assert(git_pathspec_match_list_entry(matches, 0) == NULL);
cl_assert_equal_s("modified_file",
git_pathspec_match_list_diff_entry(matches,0)->new_file.path);
cl_assert_equal_i(GIT_DELTA_MODIFIED,
git_pathspec_match_list_diff_entry(matches,0)->status);
git_pathspec_match_list_free(matches);
git_diff_list_free(diff);
diff = NULL;
git_tree_free(a);
git_tree_free(b);
}
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