Commit 28fd7206 by Vicent Marti

Merge pull request #2108 from libgit2/rb/threadsafe-index-iterator

Make index iterator thread safe
parents 2bed3553 83038272
...@@ -305,6 +305,11 @@ ELSE () ...@@ -305,6 +305,11 @@ ELSE ()
ENDIF () ENDIF ()
IF (APPLE) # Apple deprecated OpenSSL IF (APPLE) # Apple deprecated OpenSSL
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
# With clang, disable some annoying extra warnings
IF (NOT CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-const-variable -Wno-unused-function")
ENDIF()
ENDIF () ENDIF ()
IF (PROFILE) IF (PROFILE)
SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}")
......
...@@ -77,7 +77,12 @@ typedef struct git_index_entry { ...@@ -77,7 +77,12 @@ typedef struct git_index_entry {
#define GIT_IDXENTRY_VALID (0x8000) #define GIT_IDXENTRY_VALID (0x8000)
#define GIT_IDXENTRY_STAGESHIFT 12 #define GIT_IDXENTRY_STAGESHIFT 12
#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) #define GIT_IDXENTRY_STAGE(E) \
(((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT)
#define GIT_IDXENTRY_STAGE_SET(E,S) do { \
(E)->flags = ((E)->flags & ~GIT_IDXENTRY_STAGEMASK) | \
(((S) & 0x03) << GIT_IDXENTRY_STAGESHIFT); } while (0)
/** /**
* Bitmasks for on-disk fields of `git_index_entry`'s `flags_extended` * Bitmasks for on-disk fields of `git_index_entry`'s `flags_extended`
...@@ -327,12 +332,14 @@ GIT_EXTERN(size_t) git_index_entrycount(const git_index *index); ...@@ -327,12 +332,14 @@ GIT_EXTERN(size_t) git_index_entrycount(const git_index *index);
/** /**
* Clear the contents (all the entries) of an index object. * Clear the contents (all the entries) of an index object.
* This clears the index object in memory; changes must be manually *
* written to disk for them to take effect. * This clears the index object in memory; changes must be explicitly
* written to disk for them to take effect persistently.
* *
* @param index an existing index object * @param index an existing index object
* @return 0 on success, error code < 0 on failure
*/ */
GIT_EXTERN(void) git_index_clear(git_index *index); GIT_EXTERN(int) git_index_clear(git_index *index);
/** /**
* Get a pointer to one of the entries in the index * Get a pointer to one of the entries in the index
...@@ -568,8 +575,7 @@ GIT_EXTERN(int) git_index_update_all( ...@@ -568,8 +575,7 @@ GIT_EXTERN(int) git_index_update_all(
* @param at_pos the address to which the position of the index entry is written (optional) * @param at_pos the address to which the position of the index entry is written (optional)
* @param index an existing index object * @param index an existing index object
* @param path path to search * @param path path to search
* @return a zero-based position in the index if found; * @return a zero-based position in the index if found; GIT_ENOTFOUND otherwise
* GIT_ENOTFOUND otherwise
*/ */
GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path); GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path);
...@@ -613,6 +619,7 @@ GIT_EXTERN(int) git_index_conflict_add( ...@@ -613,6 +619,7 @@ GIT_EXTERN(int) git_index_conflict_add(
* @param their_out Pointer to store the their entry * @param their_out Pointer to store the their entry
* @param index an existing index object * @param index an existing index object
* @param path path to search * @param path path to search
* @return 0 or an error code
*/ */
GIT_EXTERN(int) git_index_conflict_get( GIT_EXTERN(int) git_index_conflict_get(
const git_index_entry **ancestor_out, const git_index_entry **ancestor_out,
...@@ -625,16 +632,18 @@ GIT_EXTERN(int) git_index_conflict_get( ...@@ -625,16 +632,18 @@ GIT_EXTERN(int) git_index_conflict_get(
* Removes the index entries that represent a conflict of a single file. * Removes the index entries that represent a conflict of a single file.
* *
* @param index an existing index object * @param index an existing index object
* @param path to search * @param path path to remove conflicts for
* @return 0 or an error code
*/ */
GIT_EXTERN(int) git_index_conflict_remove(git_index *index, const char *path); GIT_EXTERN(int) git_index_conflict_remove(git_index *index, const char *path);
/** /**
* Remove all conflicts in the index (entries with a stage greater than 0.) * Remove all conflicts in the index (entries with a stage greater than 0).
* *
* @param index an existing index object * @param index an existing index object
* @return 0 or an error code
*/ */
GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index); GIT_EXTERN(int) git_index_conflict_cleanup(git_index *index);
/** /**
* Determine if the index contains entries representing file conflicts. * Determine if the index contains entries representing file conflicts.
...@@ -644,9 +653,12 @@ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index); ...@@ -644,9 +653,12 @@ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index);
GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); GIT_EXTERN(int) git_index_has_conflicts(const git_index *index);
/** /**
* Create an iterator for the conflicts in the index. You may not modify the * Create an iterator for the conflicts in the index.
* index while iterating, the results are undefined. *
* The index must not be modified while iterating; the results are undefined.
* *
* @param iterator_out The newly created conflict iterator
* @param index The index to scan
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_index_conflict_iterator_new( GIT_EXTERN(int) git_index_conflict_iterator_new(
......
/*
* 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_sys_git_diff_h__
#define INCLUDE_sys_git_diff_h__
#include "git2/common.h"
#include "git2/types.h"
#include "git2/oid.h"
/**
* @file git2/sys/diff.h
* @brief Low-level Git diff utilities
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Diff print callback that writes to a git_buf.
*
* This function is provided not for you to call it directly, but instead
* so you can use it as a function pointer to the `git_diff_print` or
* `git_patch_print` APIs. When using those APIs, you specify a callback
* to actually handle the diff and/or patch data.
*
* Use this callback to easily write that data to a `git_buf` buffer. You
* must pass a `git_buf *` value as the payload to the `git_diff_print`
* and/or `git_patch_print` function. The data will be appended to the
* buffer (after any existing content).
*/
GIT_EXTERN(int) git_diff_print_callback__to_buf(
const git_diff_delta *delta,
const git_diff_hunk *hunk,
const git_diff_line *line,
void *payload); /*< payload must be a `git_buf *` */
/**
* Diff print callback that writes to stdio FILE handle.
*
* This function is provided not for you to call it directly, but instead
* so you can use it as a function pointer to the `git_diff_print` or
* `git_patch_print` APIs. When using those APIs, you specify a callback
* to actually handle the diff and/or patch data.
*
* Use this callback to easily write that data to a stdio FILE handle. You
* must pass a `FILE *` value (such as `stdout` or `stderr` or the return
* value from `fopen()`) as the payload to the `git_diff_print`
* and/or `git_patch_print` function. If you pass NULL, this will write
* data to `stdout`.
*/
GIT_EXTERN(int) git_diff_print_callback__to_file_handle(
const git_diff_delta *delta,
const git_diff_hunk *hunk,
const git_diff_line *line,
void *payload); /*< payload must be a `FILE *` */
/** @} */
GIT_END_DECL
#endif
...@@ -8,38 +8,6 @@ ...@@ -8,38 +8,6 @@
#define INCLUDE_attr_h__ #define INCLUDE_attr_h__
#include "attr_file.h" #include "attr_file.h"
#include "attrcache.h"
#define GIT_ATTR_CONFIG "core.attributesfile"
#define GIT_IGNORE_CONFIG "core.excludesfile"
typedef int (*git_attr_file_parser)(
git_repository *, void *, const char *, git_attr_file *);
extern int git_attr_cache__insert_macro(
git_repository *repo, git_attr_rule *macro);
extern git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name);
extern int git_attr_cache__push_file(
git_repository *repo,
const char *base,
const char *filename,
git_attr_file_source source,
git_attr_file_parser parse,
void *parsedata, /* passed through to parse function */
git_vector *stack);
extern int git_attr_cache__internal_file(
git_repository *repo,
const char *key,
git_attr_file **file_ptr);
/* returns true if path is in cache */
extern bool git_attr_cache__is_cached(
git_repository *repo, git_attr_file_source source, const char *path);
extern int git_attr_cache__decide_sources(
uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs);
#endif #endif
...@@ -35,6 +35,14 @@ ...@@ -35,6 +35,14 @@
(GIT_ATTR_FNMATCH_ALLOWSPACE | \ (GIT_ATTR_FNMATCH_ALLOWSPACE | \
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO) GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
typedef enum {
GIT_ATTR_FILE__IN_MEMORY = 0,
GIT_ATTR_FILE__FROM_FILE = 1,
GIT_ATTR_FILE__FROM_INDEX = 2,
GIT_ATTR_FILE_NUM_SOURCES = 3
} git_attr_file_source;
extern const char *git_attr__true; extern const char *git_attr__true;
extern const char *git_attr__false; extern const char *git_attr__false;
extern const char *git_attr__unset; extern const char *git_attr__unset;
...@@ -63,17 +71,32 @@ typedef struct { ...@@ -63,17 +71,32 @@ typedef struct {
const char *value; const char *value;
} git_attr_assignment; } git_attr_assignment;
typedef struct git_attr_file_entry git_attr_file_entry;
typedef struct { typedef struct {
char *key; /* cache "source#path" this was loaded from */ git_refcount rc;
git_vector rules; /* vector of <rule*> or <fnmatch*> */ git_mutex lock;
git_pool *pool; git_attr_file_entry *entry;
bool pool_is_allocated; git_attr_file_source source;
git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool pool;
union { union {
git_oid oid; git_oid oid;
git_futils_filestamp stamp; git_futils_filestamp stamp;
} cache_data; } cache_data;
} git_attr_file; } git_attr_file;
struct git_attr_file_entry {
git_attr_file *file[GIT_ATTR_FILE_NUM_SOURCES];
const char *path; /* points into fullpath */
char fullpath[GIT_FLEX_ARRAY];
};
typedef int (*git_attr_file_parser)(
git_repository *repo,
git_attr_file *file,
const char *data);
typedef struct { typedef struct {
git_buf full; git_buf full;
char *path; char *path;
...@@ -81,29 +104,37 @@ typedef struct { ...@@ -81,29 +104,37 @@ typedef struct {
int is_dir; int is_dir;
} git_attr_path; } git_attr_path;
typedef enum {
GIT_ATTR_FILE_FROM_FILE = 0,
GIT_ATTR_FILE_FROM_INDEX = 1
} git_attr_file_source;
/* /*
* git_attr_file API * git_attr_file API
*/ */
extern int git_attr_file__new( int git_attr_file__new(
git_attr_file **attrs_ptr, git_attr_file_source src, const char *path, git_pool *pool); git_attr_file **out,
git_attr_file_entry *entry,
git_attr_file_source source);
void git_attr_file__free(git_attr_file *file);
int git_attr_file__load(
git_attr_file **out,
git_repository *repo,
git_attr_file_entry *ce,
git_attr_file_source source,
git_attr_file_parser parser);
extern int git_attr_file__new_and_load( int git_attr_file__load_standalone(
git_attr_file **attrs_ptr, const char *path); git_attr_file **out, const char *path);
extern void git_attr_file__free(git_attr_file *file); int git_attr_file__out_of_date(
git_repository *repo, git_attr_file *file);
extern void git_attr_file__clear_rules(git_attr_file *file); int git_attr_file__parse_buffer(
git_repository *repo, git_attr_file *attrs, const char *data);
extern int git_attr_file__parse_buffer( int git_attr_file__clear_rules(
git_repository *repo, void *parsedata, const char *buf, git_attr_file *file); git_attr_file *file, bool need_lock);
extern int git_attr_file__lookup_one( int git_attr_file__lookup_one(
git_attr_file *file, git_attr_file *file,
const git_attr_path *path, const git_attr_path *path,
const char *attr, const char *attr,
...@@ -114,7 +145,7 @@ extern int git_attr_file__lookup_one( ...@@ -114,7 +145,7 @@ extern int git_attr_file__lookup_one(
git_vector_rforeach(&(file)->rules, (iter), (rule)) \ git_vector_rforeach(&(file)->rules, (iter), (rule)) \
if (git_attr_rule__match((rule), (path))) if (git_attr_rule__match((rule), (path)))
extern uint32_t git_attr_file__name_hash(const char *name); uint32_t git_attr_file__name_hash(const char *name);
/* /*
......
This diff is collapsed. Click to expand it.
...@@ -7,18 +7,50 @@ ...@@ -7,18 +7,50 @@
#ifndef INCLUDE_attrcache_h__ #ifndef INCLUDE_attrcache_h__
#define INCLUDE_attrcache_h__ #define INCLUDE_attrcache_h__
#include "pool.h" #include "attr_file.h"
#include "strmap.h" #include "strmap.h"
#define GIT_ATTR_CONFIG "core.attributesfile"
#define GIT_IGNORE_CONFIG "core.excludesfile"
typedef struct { typedef struct {
int initialized;
git_pool pool;
git_strmap *files; /* hash path to git_attr_file of rules */
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
char *cfg_attr_file; /* cached value of core.attributesfile */ char *cfg_attr_file; /* cached value of core.attributesfile */
char *cfg_excl_file; /* cached value of core.excludesfile */ char *cfg_excl_file; /* cached value of core.excludesfile */
git_strmap *files; /* hash path to git_attr_cache_entry records */
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
git_mutex lock;
git_pool pool;
} git_attr_cache; } git_attr_cache;
extern int git_attr_cache__init(git_repository *repo); extern int git_attr_cache__do_init(git_repository *repo);
#define git_attr_cache__init(REPO) \
(git_repository_attr_cache(REPO) ? 0 : git_attr_cache__do_init(REPO))
/* get file - loading and reload as needed */
extern int git_attr_cache__get(
git_attr_file **file,
git_repository *repo,
git_attr_file_source source,
const char *base,
const char *filename,
git_attr_file_parser parser);
extern bool git_attr_cache__is_cached(
git_repository *repo,
git_attr_file_source source,
const char *path);
extern int git_attr_cache__alloc_file_entry(
git_attr_file_entry **out,
const char *base,
const char *path,
git_pool *pool);
extern int git_attr_cache__insert_macro(
git_repository *repo, git_attr_rule *macro);
extern git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name);
#endif #endif
...@@ -277,19 +277,23 @@ static int checkout_action_wd_only( ...@@ -277,19 +277,23 @@ static int checkout_action_wd_only(
/* check if item is tracked in the index but not in the checkout diff */ /* check if item is tracked in the index but not in the checkout diff */
if (data->index != NULL) { if (data->index != NULL) {
size_t pos;
error = git_index__find_pos(
&pos, data->index, wd->path, 0, GIT_INDEX_STAGE_ANY);
if (wd->mode != GIT_FILEMODE_TREE) { if (wd->mode != GIT_FILEMODE_TREE) {
if (!(error = git_index_find(NULL, data->index, wd->path))) { if (!error) { /* found by git_index__find_pos call */
notify = GIT_CHECKOUT_NOTIFY_DIRTY; notify = GIT_CHECKOUT_NOTIFY_DIRTY;
remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0); remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
} else if (error != GIT_ENOTFOUND) } else if (error != GIT_ENOTFOUND)
return error; return error;
else else
giterr_clear(); error = 0; /* git_index__find_pos does not set error msg */
} else { } else {
/* for tree entries, we have to see if there are any index /* for tree entries, we have to see if there are any index
* entries that are contained inside that tree * entries that are contained inside that tree
*/ */
size_t pos = git_index__prefix_position(data->index, wd->path);
const git_index_entry *e = git_index_get_byindex(data->index, pos); const git_index_entry *e = git_index_get_byindex(data->index, pos);
if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) { if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
...@@ -653,10 +657,13 @@ static int checkout_conflictdata_cmp(const void *a, const void *b) ...@@ -653,10 +657,13 @@ static int checkout_conflictdata_cmp(const void *a, const void *b)
return diff; return diff;
} }
int checkout_conflictdata_empty(const git_vector *conflicts, size_t idx) int checkout_conflictdata_empty(
const git_vector *conflicts, size_t idx, void *payload)
{ {
checkout_conflictdata *conflict; checkout_conflictdata *conflict;
GIT_UNUSED(payload);
if ((conflict = git_vector_get(conflicts, idx)) == NULL) if ((conflict = git_vector_get(conflicts, idx)) == NULL)
return -1; return -1;
...@@ -954,7 +961,8 @@ static int checkout_conflicts_coalesce_renames( ...@@ -954,7 +961,8 @@ static int checkout_conflicts_coalesce_renames(
ancestor_conflict->one_to_two = 1; ancestor_conflict->one_to_two = 1;
} }
git_vector_remove_matching(&data->conflicts, checkout_conflictdata_empty); git_vector_remove_matching(
&data->conflicts, checkout_conflictdata_empty, NULL);
done: done:
return error; return error;
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
# include <unistd.h> # include <unistd.h>
# ifdef GIT_THREADS # ifdef GIT_THREADS
# include <pthread.h> # include <pthread.h>
# include <sched.h>
# endif # endif
#define GIT_STDLIB_CALL #define GIT_STDLIB_CALL
......
...@@ -180,11 +180,15 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) ...@@ -180,11 +180,15 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
b->level = level; b->level = level;
b->values = git_strmap_alloc(); if ((res = git_strmap_alloc(&b->values)) < 0)
GITERR_CHECK_ALLOC(b->values); return res;
git_array_init(b->readers); git_array_init(b->readers);
reader = git_array_alloc(b->readers); reader = git_array_alloc(b->readers);
if (!reader) {
git_strmap_free(b->values);
return -1;
}
memset(reader, 0, sizeof(struct reader)); memset(reader, 0, sizeof(struct reader));
reader->file_path = git__strdup(b->file_path); reader->file_path = git__strdup(b->file_path);
...@@ -205,6 +209,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) ...@@ -205,6 +209,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
reader = git_array_get(b->readers, 0); reader = git_array_get(b->readers, 0);
git_buf_free(&reader->buffer); git_buf_free(&reader->buffer);
return res; return res;
} }
...@@ -218,8 +223,10 @@ static int config_refresh(git_config_backend *cfg) ...@@ -218,8 +223,10 @@ static int config_refresh(git_config_backend *cfg)
for (i = 0; i < git_array_size(b->readers); i++) { for (i = 0; i < git_array_size(b->readers); i++) {
reader = git_array_get(b->readers, i); reader = git_array_get(b->readers, i);
res = git_futils_readbuffer_updated( res = git_futils_readbuffer_updated(
&reader->buffer, reader->file_path, &reader->file_mtime, &reader->file_size, &updated); &reader->buffer, reader->file_path,
&reader->file_mtime, &reader->file_size, &updated);
if (res < 0) if (res < 0)
return (res == GIT_ENOTFOUND) ? 0 : res; return (res == GIT_ENOTFOUND) ? 0 : res;
...@@ -233,10 +240,9 @@ static int config_refresh(git_config_backend *cfg) ...@@ -233,10 +240,9 @@ static int config_refresh(git_config_backend *cfg)
/* need to reload - store old values and prep for reload */ /* need to reload - store old values and prep for reload */
old_values = b->values; old_values = b->values;
b->values = git_strmap_alloc(); if ((res = git_strmap_alloc(&b->values)) < 0) {
GITERR_CHECK_ALLOC(b->values); b->values = old_values;
} else if ((res = config_parse(b, reader, b->level, 0)) < 0) {
if ((res = config_parse(b, reader, b->level, 0)) < 0) {
free_vars(b->values); free_vars(b->values);
b->values = old_values; b->values = old_values;
} else { } else {
......
...@@ -318,6 +318,31 @@ static const char *diff_mnemonic_prefix( ...@@ -318,6 +318,31 @@ static const char *diff_mnemonic_prefix(
return pfx; return pfx;
} }
static void diff_set_ignore_case(git_diff *diff, bool ignore_case)
{
if (!ignore_case) {
diff->opts.flags &= ~GIT_DIFF_IGNORE_CASE;
diff->strcomp = git__strcmp;
diff->strncomp = git__strncmp;
diff->pfxcomp = git__prefixcmp;
diff->entrycomp = git_index_entry_cmp;
git_vector_set_cmp(&diff->deltas, git_diff_delta__cmp);
} else {
diff->opts.flags |= GIT_DIFF_IGNORE_CASE;
diff->strcomp = git__strcasecmp;
diff->strncomp = git__strncasecmp;
diff->pfxcomp = git__prefixcmp_icase;
diff->entrycomp = git_index_entry_icmp;
git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);
}
git_vector_sort(&diff->deltas);
}
static git_diff *diff_list_alloc( static git_diff *diff_list_alloc(
git_repository *repo, git_repository *repo,
git_iterator *old_iter, git_iterator *old_iter,
...@@ -344,24 +369,10 @@ static git_diff *diff_list_alloc( ...@@ -344,24 +369,10 @@ static git_diff *diff_list_alloc(
/* Use case-insensitive compare if either iterator has /* Use case-insensitive compare if either iterator has
* the ignore_case bit set */ * the ignore_case bit set */
if (!git_iterator_ignore_case(old_iter) && diff_set_ignore_case(
!git_iterator_ignore_case(new_iter)) { diff,
diff->opts.flags &= ~GIT_DIFF_IGNORE_CASE; git_iterator_ignore_case(old_iter) ||
git_iterator_ignore_case(new_iter));
diff->strcomp = git__strcmp;
diff->strncomp = git__strncmp;
diff->pfxcomp = git__prefixcmp;
diff->entrycomp = git_index_entry__cmp;
} else {
diff->opts.flags |= GIT_DIFF_IGNORE_CASE;
diff->strcomp = git__strcasecmp;
diff->strncomp = git__strncasecmp;
diff->pfxcomp = git__prefixcmp_icase;
diff->entrycomp = git_index_entry__cmp_icase;
git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);
}
return diff; return diff;
} }
...@@ -1183,39 +1194,25 @@ int git_diff_tree_to_index( ...@@ -1183,39 +1194,25 @@ int git_diff_tree_to_index(
const git_diff_options *opts) const git_diff_options *opts)
{ {
int error = 0; int error = 0;
bool reset_index_ignore_case = false; bool index_ignore_case = false;
assert(diff && repo); assert(diff && repo);
if (!index && (error = diff_load_index(&index, repo)) < 0) if (!index && (error = diff_load_index(&index, repo)) < 0)
return error; return error;
if (index->ignore_case) { index_ignore_case = index->ignore_case;
git_index__set_ignore_case(index, false);
reset_index_ignore_case = true;
}
DIFF_FROM_ITERATORS( DIFF_FROM_ITERATORS(
git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), git_iterator_for_tree(
git_iterator_for_index(&b, index, 0, pfx, pfx) &a, old_tree, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx),
git_iterator_for_index(
&b, index, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx)
); );
if (reset_index_ignore_case) { /* if index is in case-insensitive order, re-sort deltas to match */
git_index__set_ignore_case(index, true); if (!error && index_ignore_case)
diff_set_ignore_case(*diff, true);
if (!error) {
git_diff *d = *diff;
d->opts.flags |= GIT_DIFF_IGNORE_CASE;
d->strcomp = git__strcasecmp;
d->strncomp = git__strncasecmp;
d->pfxcomp = git__prefixcmp_icase;
d->entrycomp = git_index_entry__cmp_icase;
git_vector_set_cmp(&d->deltas, git_diff_delta__casecmp);
git_vector_sort(&d->deltas);
}
}
return error; return error;
} }
......
...@@ -66,7 +66,7 @@ git_diff_driver_registry *git_diff_driver_registry_new() ...@@ -66,7 +66,7 @@ git_diff_driver_registry *git_diff_driver_registry_new()
if (!reg) if (!reg)
return NULL; return NULL;
if ((reg->drivers = git_strmap_alloc()) == NULL) { if (git_strmap_alloc(&reg->drivers) < 0) {
git_diff_driver_registry_free(reg); git_diff_driver_registry_free(reg);
return NULL; return NULL;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "diff.h" #include "diff.h"
#include "diff_patch.h" #include "diff_patch.h"
#include "fileops.h" #include "fileops.h"
#include "git2/sys/diff.h"
typedef struct { typedef struct {
git_diff *diff; git_diff *diff;
...@@ -435,7 +436,7 @@ int git_patch_print( ...@@ -435,7 +436,7 @@ int git_patch_print(
return error; return error;
} }
static int diff_print_to_buffer_cb( int git_diff_print_callback__to_buf(
const git_diff_delta *delta, const git_diff_delta *delta,
const git_diff_hunk *hunk, const git_diff_hunk *hunk,
const git_diff_line *line, const git_diff_line *line,
...@@ -444,6 +445,11 @@ static int diff_print_to_buffer_cb( ...@@ -444,6 +445,11 @@ static int diff_print_to_buffer_cb(
git_buf *output = payload; git_buf *output = payload;
GIT_UNUSED(delta); GIT_UNUSED(hunk); GIT_UNUSED(delta); GIT_UNUSED(hunk);
if (!output) {
giterr_set(GITERR_INVALID, "Buffer pointer must be provided");
return -1;
}
if (line->origin == GIT_DIFF_LINE_ADDITION || if (line->origin == GIT_DIFF_LINE_ADDITION ||
line->origin == GIT_DIFF_LINE_DELETION || line->origin == GIT_DIFF_LINE_DELETION ||
line->origin == GIT_DIFF_LINE_CONTEXT) line->origin == GIT_DIFF_LINE_CONTEXT)
...@@ -452,10 +458,28 @@ static int diff_print_to_buffer_cb( ...@@ -452,10 +458,28 @@ static int diff_print_to_buffer_cb(
return git_buf_put(output, line->content, line->content_len); return git_buf_put(output, line->content, line->content_len);
} }
int git_diff_print_callback__to_file_handle(
const git_diff_delta *delta,
const git_diff_hunk *hunk,
const git_diff_line *line,
void *payload)
{
FILE *fp = payload ? payload : stdout;
GIT_UNUSED(delta); GIT_UNUSED(hunk);
if (line->origin == GIT_DIFF_LINE_CONTEXT ||
line->origin == GIT_DIFF_LINE_ADDITION ||
line->origin == GIT_DIFF_LINE_DELETION)
fputc(line->origin, fp);
fwrite(line->content, 1, line->content_len, fp);
return 0;
}
/* print a git_patch to a git_buf */ /* print a git_patch to a git_buf */
int git_patch_to_buf( int git_patch_to_buf(
git_buf *out, git_buf *out,
git_patch *patch) git_patch *patch)
{ {
return git_patch_print(patch, diff_print_to_buffer_cb, out); return git_patch_print(patch, git_diff_print_callback__to_buf, out);
} }
...@@ -132,6 +132,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) ...@@ -132,6 +132,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
if (read_size != (ssize_t)len) { if (read_size != (ssize_t)len) {
giterr_set(GITERR_OS, "Failed to read descriptor"); giterr_set(GITERR_OS, "Failed to read descriptor");
git_buf_free(buf);
return -1; return -1;
} }
...@@ -804,10 +805,8 @@ int git_futils_filestamp_check( ...@@ -804,10 +805,8 @@ int git_futils_filestamp_check(
if (stamp == NULL) if (stamp == NULL)
return 1; return 1;
if (p_stat(path, &st) < 0) { if (p_stat(path, &st) < 0)
giterr_set(GITERR_OS, "Could not stat '%s'", path);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
}
if (stamp->mtime == (git_time_t)st.st_mtime && if (stamp->mtime == (git_time_t)st.st_mtime &&
stamp->size == (git_off_t)st.st_size && stamp->size == (git_off_t)st.st_size &&
...@@ -831,3 +830,16 @@ void git_futils_filestamp_set( ...@@ -831,3 +830,16 @@ void git_futils_filestamp_set(
else else
memset(target, 0, sizeof(*target)); memset(target, 0, sizeof(*target));
} }
void git_futils_filestamp_set_from_stat(
git_futils_filestamp *stamp, struct stat *st)
{
if (st) {
stamp->mtime = (git_time_t)st->st_mtime;
stamp->size = (git_off_t)st->st_size;
stamp->ino = (unsigned int)st->st_ino;
} else {
memset(stamp, 0, sizeof(*stamp));
}
}
...@@ -292,13 +292,14 @@ typedef struct { ...@@ -292,13 +292,14 @@ typedef struct {
* Compare stat information for file with reference info. * Compare stat information for file with reference info.
* *
* This function updates the file stamp to current data for the given path * This function updates the file stamp to current data for the given path
* and returns 0 if the file is up-to-date relative to the prior setting or * and returns 0 if the file is up-to-date relative to the prior setting,
* 1 if the file has been changed. (This also may return GIT_ENOTFOUND if * 1 if the file has been changed, or GIT_ENOTFOUND if the file doesn't
* the file doesn't exist.) * exist. This will not call giterr_set, so you must set the error if you
* plan to return an error.
* *
* @param stamp File stamp to be checked * @param stamp File stamp to be checked
* @param path Path to stat and check if changed * @param path Path to stat and check if changed
* @return 0 if up-to-date, 1 if out-of-date, <0 on error * @return 0 if up-to-date, 1 if out-of-date, GIT_ENOTFOUND if cannot stat
*/ */
extern int git_futils_filestamp_check( extern int git_futils_filestamp_check(
git_futils_filestamp *stamp, const char *path); git_futils_filestamp *stamp, const char *path);
...@@ -316,4 +317,10 @@ extern int git_futils_filestamp_check( ...@@ -316,4 +317,10 @@ extern int git_futils_filestamp_check(
extern void git_futils_filestamp_set( extern void git_futils_filestamp_set(
git_futils_filestamp *tgt, const git_futils_filestamp *src); git_futils_filestamp *tgt, const git_futils_filestamp *src);
/**
* Set file stamp data from stat structure
*/
extern void git_futils_filestamp_set_from_stat(
git_futils_filestamp *stamp, struct stat *st);
#endif /* INCLUDE_fileops_h__ */ #endif /* INCLUDE_fileops_h__ */
...@@ -16,8 +16,9 @@ git_mutex git__mwindow_mutex; ...@@ -16,8 +16,9 @@ git_mutex git__mwindow_mutex;
#define MAX_SHUTDOWN_CB 8 #define MAX_SHUTDOWN_CB 8
git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
git_atomic git__n_shutdown_callbacks; static git_atomic git__n_shutdown_callbacks;
static git_atomic git__n_inits;
void git__on_shutdown(git_global_shutdown_fn callback) void git__on_shutdown(git_global_shutdown_fn callback)
{ {
...@@ -74,7 +75,6 @@ static void git__shutdown(void) ...@@ -74,7 +75,6 @@ static void git__shutdown(void)
static DWORD _tls_index; static DWORD _tls_index;
static DWORD _mutex = 0; static DWORD _mutex = 0;
static DWORD _n_inits = 0;
static int synchronized_threads_init() static int synchronized_threads_init()
{ {
...@@ -101,7 +101,7 @@ int git_threads_init(void) ...@@ -101,7 +101,7 @@ int git_threads_init(void)
while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); } while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
/* Only do work on a 0 -> 1 transition of the refcount */ /* Only do work on a 0 -> 1 transition of the refcount */
if (1 == ++_n_inits) if (1 == git_atomic_inc(&git__n_inits))
error = synchronized_threads_init(); error = synchronized_threads_init();
/* Exit the lock */ /* Exit the lock */
...@@ -124,7 +124,7 @@ void git_threads_shutdown(void) ...@@ -124,7 +124,7 @@ void git_threads_shutdown(void)
while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); } while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
/* Only do work on a 1 -> 0 transition of the refcount */ /* Only do work on a 1 -> 0 transition of the refcount */
if (0 == --_n_inits) if (0 == git_atomic_dec(&git__n_inits))
synchronized_threads_shutdown(); synchronized_threads_shutdown();
/* Exit the lock */ /* Exit the lock */
...@@ -135,7 +135,7 @@ git_global_st *git__global_state(void) ...@@ -135,7 +135,7 @@ git_global_st *git__global_state(void)
{ {
void *ptr; void *ptr;
assert(_n_inits); assert(git_atomic_get(&git__n_inits) > 0);
if ((ptr = TlsGetValue(_tls_index)) != NULL) if ((ptr = TlsGetValue(_tls_index)) != NULL)
return ptr; return ptr;
...@@ -153,7 +153,6 @@ git_global_st *git__global_state(void) ...@@ -153,7 +153,6 @@ git_global_st *git__global_state(void)
static pthread_key_t _tls_key; static pthread_key_t _tls_key;
static pthread_once_t _once_init = PTHREAD_ONCE_INIT; static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
static git_atomic git__n_inits;
int init_error = 0; int init_error = 0;
static void cb__free_status(void *st) static void cb__free_status(void *st)
...@@ -204,7 +203,7 @@ git_global_st *git__global_state(void) ...@@ -204,7 +203,7 @@ git_global_st *git__global_state(void)
{ {
void *ptr; void *ptr;
assert(git__n_inits.val); assert(git_atomic_get(&git__n_inits) > 0);
if ((ptr = pthread_getspecific(_tls_key)) != NULL) if ((ptr = pthread_getspecific(_tls_key)) != NULL)
return ptr; return ptr;
...@@ -224,14 +223,15 @@ static git_global_st __state; ...@@ -224,14 +223,15 @@ static git_global_st __state;
int git_threads_init(void) int git_threads_init(void)
{ {
/* noop */ git_atomic_inc(&git__n_inits);
return 0; return 0;
} }
void git_threads_shutdown(void) void git_threads_shutdown(void)
{ {
/* Shut down any subsystems that have global state */ /* Shut down any subsystems that have global state */
git__shutdown(); if (0 == git_atomic_dec(&git__n_inits))
git__shutdown();
} }
git_global_st *git__global_state(void) git_global_st *git__global_state(void)
......
...@@ -21,12 +21,15 @@ struct git_index { ...@@ -21,12 +21,15 @@ struct git_index {
git_refcount rc; git_refcount rc;
char *index_file_path; char *index_file_path;
git_futils_filestamp stamp; git_futils_filestamp stamp;
git_vector entries; git_vector entries;
unsigned int on_disk:1; git_mutex lock; /* lock held while entries is being changed */
git_vector deleted; /* deleted entries if readers > 0 */
git_atomic readers; /* number of active iterators */
unsigned int on_disk:1;
unsigned int ignore_case:1; unsigned int ignore_case:1;
unsigned int distrust_filemode:1; unsigned int distrust_filemode:1;
unsigned int no_symlinks:1; unsigned int no_symlinks:1;
...@@ -50,12 +53,21 @@ struct git_index_conflict_iterator { ...@@ -50,12 +53,21 @@ struct git_index_conflict_iterator {
extern void git_index_entry__init_from_stat( extern void git_index_entry__init_from_stat(
git_index_entry *entry, struct stat *st, bool trust_mode); git_index_entry *entry, struct stat *st, bool trust_mode);
extern size_t git_index__prefix_position(git_index *index, const char *path); /* Index entry comparison functions for array sorting */
extern int git_index_entry_cmp(const void *a, const void *b);
extern int git_index_entry_icmp(const void *a, const void *b);
extern int git_index_entry__cmp(const void *a, const void *b); /* Index entry search functions for search using a search spec */
extern int git_index_entry__cmp_icase(const void *a, const void *b); extern int git_index_entry_srch(const void *a, const void *b);
extern int git_index_entry_isrch(const void *a, const void *b);
extern int git_index__find( /* Search index for `path`, returning GIT_ENOTFOUND if it does not exist
* (but not setting an error message).
*
* `at_pos` is set to the position where it is or would be inserted.
* Pass `path_len` as strlen of path or 0 to call strlen internally.
*/
extern int git_index__find_pos(
size_t *at_pos, git_index *index, const char *path, size_t path_len, int stage); size_t *at_pos, git_index *index, const char *path, size_t path_len, int stage);
extern void git_index__set_ignore_case(git_index *index, bool ignore_case); extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
...@@ -69,4 +81,16 @@ GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index) ...@@ -69,4 +81,16 @@ GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index)
extern int git_index__changed_relative_to(git_index *index, const git_futils_filestamp *fs); extern int git_index__changed_relative_to(git_index *index, const git_futils_filestamp *fs);
/* Copy the current entries vector *and* increment the index refcount.
* Call `git_index__release_snapshot` when done.
*/
extern int git_index_snapshot_new(git_vector *snap, git_index *index);
extern void git_index_snapshot_release(git_vector *snap, git_index *index);
/* Allow searching in a snapshot; entries must already be sorted! */
extern int git_index_snapshot_find(
size_t *at_pos, git_vector *snap, git_vector_cmp entry_srch,
const char *path, size_t path_len, int stage);
#endif #endif
...@@ -644,6 +644,8 @@ typedef struct { ...@@ -644,6 +644,8 @@ typedef struct {
git_iterator base; git_iterator base;
git_iterator_callbacks cb; git_iterator_callbacks cb;
git_index *index; git_index *index;
git_vector entries;
git_vector_cmp entry_srch;
size_t current; size_t current;
/* when not in autoexpand mode, use these to represent "tree" state */ /* when not in autoexpand mode, use these to represent "tree" state */
git_buf partial; git_buf partial;
...@@ -654,10 +656,10 @@ typedef struct { ...@@ -654,10 +656,10 @@ typedef struct {
static const git_index_entry *index_iterator__index_entry(index_iterator *ii) static const git_index_entry *index_iterator__index_entry(index_iterator *ii)
{ {
const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); const git_index_entry *ie = git_vector_get(&ii->entries, ii->current);
if (ie != NULL && iterator__past_end(ii, ie->path)) { if (ie != NULL && iterator__past_end(ii, ie->path)) {
ii->current = git_index_entrycount(ii->index); ii->current = git_vector_length(&ii->entries);
ie = NULL; ie = NULL;
} }
...@@ -726,7 +728,7 @@ static int index_iterator__current( ...@@ -726,7 +728,7 @@ static int index_iterator__current(
const git_index_entry **entry, git_iterator *self) const git_index_entry **entry, git_iterator *self)
{ {
index_iterator *ii = (index_iterator *)self; index_iterator *ii = (index_iterator *)self;
const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); const git_index_entry *ie = git_vector_get(&ii->entries, ii->current);
if (ie != NULL && index_iterator__at_tree(ii)) { if (ie != NULL && index_iterator__at_tree(ii)) {
ii->tree_entry.path = ii->partial.ptr; ii->tree_entry.path = ii->partial.ptr;
...@@ -744,14 +746,14 @@ static int index_iterator__current( ...@@ -744,14 +746,14 @@ static int index_iterator__current(
static int index_iterator__at_end(git_iterator *self) static int index_iterator__at_end(git_iterator *self)
{ {
index_iterator *ii = (index_iterator *)self; index_iterator *ii = (index_iterator *)self;
return (ii->current >= git_index_entrycount(ii->index)); return (ii->current >= git_vector_length(&ii->entries));
} }
static int index_iterator__advance( static int index_iterator__advance(
const git_index_entry **entry, git_iterator *self) const git_index_entry **entry, git_iterator *self)
{ {
index_iterator *ii = (index_iterator *)self; index_iterator *ii = (index_iterator *)self;
size_t entrycount = git_index_entrycount(ii->index); size_t entrycount = git_vector_length(&ii->entries);
const git_index_entry *ie; const git_index_entry *ie;
if (!iterator__has_been_accessed(ii)) if (!iterator__has_been_accessed(ii))
...@@ -766,7 +768,7 @@ static int index_iterator__advance( ...@@ -766,7 +768,7 @@ static int index_iterator__advance(
while (ii->current < entrycount) { while (ii->current < entrycount) {
ii->current++; ii->current++;
if (!(ie = git_index_get_byindex(ii->index, ii->current)) || if (!(ie = git_vector_get(&ii->entries, ii->current)) ||
ii->base.prefixcomp(ie->path, ii->partial.ptr) != 0) ii->base.prefixcomp(ie->path, ii->partial.ptr) != 0)
break; break;
} }
...@@ -789,7 +791,7 @@ static int index_iterator__advance_into( ...@@ -789,7 +791,7 @@ static int index_iterator__advance_into(
const git_index_entry **entry, git_iterator *self) const git_index_entry **entry, git_iterator *self)
{ {
index_iterator *ii = (index_iterator *)self; index_iterator *ii = (index_iterator *)self;
const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); const git_index_entry *ie = git_vector_get(&ii->entries, ii->current);
if (ie != NULL && index_iterator__at_tree(ii)) { if (ie != NULL && index_iterator__at_tree(ii)) {
if (ii->restore_terminator) if (ii->restore_terminator)
...@@ -815,8 +817,11 @@ static int index_iterator__reset( ...@@ -815,8 +817,11 @@ static int index_iterator__reset(
if (iterator__reset_range(self, start, end) < 0) if (iterator__reset_range(self, start, end) < 0)
return -1; return -1;
ii->current = ii->base.start ? ii->current = 0;
git_index__prefix_position(ii->index, ii->base.start) : 0;
if (ii->base.start)
git_index_snapshot_find(
&ii->current, &ii->entries, ii->entry_srch, ii->base.start, 0, 0);
if ((ie = index_iterator__skip_conflicts(ii)) == NULL) if ((ie = index_iterator__skip_conflicts(ii)) == NULL)
return 0; return 0;
...@@ -841,9 +846,8 @@ static int index_iterator__reset( ...@@ -841,9 +846,8 @@ static int index_iterator__reset(
static void index_iterator__free(git_iterator *self) static void index_iterator__free(git_iterator *self)
{ {
index_iterator *ii = (index_iterator *)self; index_iterator *ii = (index_iterator *)self;
git_index_free(ii->index); git_index_snapshot_release(&ii->entries, ii->index);
ii->index = NULL; ii->index = NULL;
git_buf_free(&ii->partial); git_buf_free(&ii->partial);
} }
...@@ -854,18 +858,29 @@ int git_iterator_for_index( ...@@ -854,18 +858,29 @@ int git_iterator_for_index(
const char *start, const char *start,
const char *end) const char *end)
{ {
int error = 0;
index_iterator *ii = git__calloc(1, sizeof(index_iterator)); index_iterator *ii = git__calloc(1, sizeof(index_iterator));
GITERR_CHECK_ALLOC(ii); GITERR_CHECK_ALLOC(ii);
if ((error = git_index_snapshot_new(&ii->entries, index)) < 0) {
git__free(ii);
return error;
}
ii->index = index;
ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index));
if (index->ignore_case) { if ((error = iterator__update_ignore_case((git_iterator *)ii, flags)) < 0) {
ii->base.flags |= GIT_ITERATOR_IGNORE_CASE; git_iterator_free((git_iterator *)ii);
ii->base.prefixcomp = git__prefixcmp_icase; return error;
} }
ii->index = index; ii->entry_srch = iterator__ignore_case(ii) ?
GIT_REFCOUNT_INC(index); git_index_entry_isrch : git_index_entry_srch;
git_vector_set_cmp(&ii->entries, iterator__ignore_case(ii) ?
git_index_entry_icmp : git_index_entry_cmp);
git_vector_sort(&ii->entries);
git_buf_init(&ii->partial, 0); git_buf_init(&ii->partial, 0);
ii->tree_entry.mode = GIT_FILEMODE_TREE; ii->tree_entry.mode = GIT_FILEMODE_TREE;
...@@ -873,7 +888,6 @@ int git_iterator_for_index( ...@@ -873,7 +888,6 @@ int git_iterator_for_index(
index_iterator__reset((git_iterator *)ii, NULL, NULL); index_iterator__reset((git_iterator *)ii, NULL, NULL);
*iter = (git_iterator *)ii; *iter = (git_iterator *)ii;
return 0; return 0;
} }
......
...@@ -995,10 +995,12 @@ static void merge_diff_list_coalesce_renames( ...@@ -995,10 +995,12 @@ static void merge_diff_list_coalesce_renames(
} }
} }
static int merge_diff_empty(const git_vector *conflicts, size_t idx) static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p)
{ {
git_merge_diff *conflict = conflicts->contents[idx]; git_merge_diff *conflict = conflicts->contents[idx];
GIT_UNUSED(p);
return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) &&
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) &&
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry));
...@@ -1079,7 +1081,7 @@ int git_merge_diff_list__find_renames( ...@@ -1079,7 +1081,7 @@ int git_merge_diff_list__find_renames(
merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts);
/* And remove any entries that were merged and are now empty. */ /* And remove any entries that were merged and are now empty. */
git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty); git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL);
done: done:
if (cache != NULL) { if (cache != NULL) {
...@@ -1228,7 +1230,7 @@ done: ...@@ -1228,7 +1230,7 @@ done:
return error; return error;
} }
GIT_INLINE(int) index_entry_dup( GIT_INLINE(int) index_entry_dup_pool(
git_index_entry *out, git_index_entry *out,
git_pool *pool, git_pool *pool,
const git_index_entry *src) const git_index_entry *src)
...@@ -1274,9 +1276,9 @@ static git_merge_diff *merge_diff_from_index_entries( ...@@ -1274,9 +1276,9 @@ static git_merge_diff *merge_diff_from_index_entries(
if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL) if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL)
return NULL; return NULL;
if (index_entry_dup(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 ||
index_entry_dup(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 ||
index_entry_dup(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0)
return NULL; return NULL;
conflict->our_status = merge_delta_type_from_index_entries( conflict->our_status = merge_delta_type_from_index_entries(
...@@ -1316,7 +1318,7 @@ static int merge_diff_list_insert_unmodified( ...@@ -1316,7 +1318,7 @@ static int merge_diff_list_insert_unmodified(
entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry));
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
if ((error = index_entry_dup(entry, &diff_list->pool, tree_items[0])) >= 0) if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0)
error = git_vector_insert(&diff_list->staged, entry); error = git_vector_insert(&diff_list->staged, entry);
return error; return error;
...@@ -1330,7 +1332,7 @@ int git_merge_diff_list__find_differences( ...@@ -1330,7 +1332,7 @@ int git_merge_diff_list__find_differences(
{ {
git_iterator *iterators[3] = {0}; git_iterator *iterators[3] = {0};
const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
git_vector_cmp entry_compare = git_index_entry__cmp; git_vector_cmp entry_compare = git_index_entry_cmp;
struct merge_diff_df_data df_data = {0}; struct merge_diff_df_data df_data = {0};
int cur_item_modified; int cur_item_modified;
size_t i, j; size_t i, j;
......
...@@ -445,7 +445,7 @@ static int pathspec_match_from_iterator( ...@@ -445,7 +445,7 @@ static int pathspec_match_from_iterator(
/* check if path is ignored and untracked */ /* check if path is ignored and untracked */
if (index != NULL && if (index != NULL &&
git_iterator_current_is_ignored(iter) && git_iterator_current_is_ignored(iter) &&
git_index__find(NULL, index, entry->path, 0, GIT_INDEX_STAGE_ANY) < 0) git_index__find_pos(NULL, index, entry->path, 0, GIT_INDEX_STAGE_ANY) < 0)
continue; continue;
/* mark the matched pattern as used */ /* mark the matched pattern as used */
......
...@@ -108,7 +108,7 @@ struct git_repository { ...@@ -108,7 +108,7 @@ struct git_repository {
git_submodule_cache *_submodules; git_submodule_cache *_submodules;
git_cache objects; git_cache objects;
git_attr_cache attrcache; git_attr_cache *attrcache;
git_diff_driver_registry *diff_drivers; git_diff_driver_registry *diff_drivers;
char *path_repository; char *path_repository;
...@@ -123,7 +123,7 @@ struct git_repository { ...@@ -123,7 +123,7 @@ struct git_repository {
GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
{ {
return &repo->attrcache; return repo->attrcache;
} }
int git_repository_head_tree(git_tree **tree, git_repository *repo); int git_repository_head_tree(git_tree **tree, git_repository *repo);
......
...@@ -20,7 +20,7 @@ int git_sortedcache_new( ...@@ -20,7 +20,7 @@ int git_sortedcache_new(
if (git_pool_init(&sc->pool, 1, 0) < 0 || if (git_pool_init(&sc->pool, 1, 0) < 0 ||
git_vector_init(&sc->items, 4, item_cmp) < 0 || git_vector_init(&sc->items, 4, item_cmp) < 0 ||
(sc->map = git_strmap_alloc()) == NULL) git_strmap_alloc(&sc->map) < 0)
goto fail; goto fail;
if (git_rwlock_init(&sc->lock)) { if (git_rwlock_init(&sc->lock)) {
...@@ -39,8 +39,7 @@ int git_sortedcache_new( ...@@ -39,8 +39,7 @@ int git_sortedcache_new(
return 0; return 0;
fail: fail:
if (sc->map) git_strmap_free(sc->map);
git_strmap_free(sc->map);
git_vector_free(&sc->items); git_vector_free(&sc->items);
git_pool_clear(&sc->pool); git_pool_clear(&sc->pool);
git__free(sc); git__free(sc);
...@@ -233,9 +232,8 @@ unlock: ...@@ -233,9 +232,8 @@ unlock:
void git_sortedcache_updated(git_sortedcache *sc) void git_sortedcache_updated(git_sortedcache *sc)
{ {
/* update filestamp to latest value */ /* update filestamp to latest value */
if (git_futils_filestamp_check(&sc->stamp, sc->path) < 0) git_futils_filestamp_check(&sc->stamp, sc->path);
giterr_clear();
} }
/* release all items in sorted cache */ /* release all items in sorted cache */
......
...@@ -22,7 +22,9 @@ typedef khiter_t git_strmap_iter; ...@@ -22,7 +22,9 @@ typedef khiter_t git_strmap_iter;
#define GIT__USE_STRMAP \ #define GIT__USE_STRMAP \
__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) __KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal)
#define git_strmap_alloc() kh_init(str) #define git_strmap_alloc(hp) \
((*(hp) = kh_init(str)) == NULL) ? giterr_set_oom(), -1 : 0
#define git_strmap_free(h) kh_destroy(str, h), h = NULL #define git_strmap_free(h) kh_destroy(str, h), h = NULL
#define git_strmap_clear(h) kh_clear(str, h) #define git_strmap_clear(h) kh_clear(str, h)
......
...@@ -1638,8 +1638,7 @@ static int submodule_cache_alloc( ...@@ -1638,8 +1638,7 @@ static int submodule_cache_alloc(
return -1; return -1;
} }
cache->submodules = git_strmap_alloc(); if (git_strmap_alloc(&cache->submodules) < 0) {
if (!cache->submodules) {
submodule_cache_free(cache); submodule_cache_free(cache);
return -1; return -1;
} }
...@@ -1694,8 +1693,6 @@ static int submodule_cache_refresh(git_submodule_cache *cache, int refresh) ...@@ -1694,8 +1693,6 @@ static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
update_gitmod = (wd != NULL) ? update_gitmod = (wd != NULL) ?
git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr) : git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr) :
(cache->gitmodules_stamp.mtime != 0); (cache->gitmodules_stamp.mtime != 0);
if (update_gitmod < 0)
giterr_clear();
} }
/* clear submodule flags that are to be refreshed */ /* clear submodule flags that are to be refreshed */
......
...@@ -47,6 +47,12 @@ typedef git_atomic git_atomic_ssize; ...@@ -47,6 +47,12 @@ typedef git_atomic git_atomic_ssize;
#define git_thread_exit(status) pthread_exit(status) #define git_thread_exit(status) pthread_exit(status)
#define git_thread_join(id, status) pthread_join(id, status) #define git_thread_join(id, status) pthread_join(id, status)
#if defined(GIT_WIN32)
#define git_thread_yield() Sleep(0)
#else
#define git_thread_yield() sched_yield()
#endif
/* Pthreads Mutex */ /* Pthreads Mutex */
#define git_mutex pthread_mutex_t #define git_mutex pthread_mutex_t
#define git_mutex_init(a) pthread_mutex_init(a, NULL) #define git_mutex_init(a) pthread_mutex_init(a, NULL)
...@@ -176,6 +182,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) ...@@ -176,6 +182,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
#define git_thread_kill(thread) (void)0 #define git_thread_kill(thread) (void)0
#define git_thread_exit(status) (void)0 #define git_thread_exit(status) (void)0
#define git_thread_join(id, status) (void)0 #define git_thread_join(id, status) (void)0
#define git_thread_yield() (void)0
/* Pthreads Mutex */ /* Pthreads Mutex */
#define git_mutex unsigned int #define git_mutex unsigned int
......
...@@ -7,23 +7,16 @@ ...@@ -7,23 +7,16 @@
#include "tree-cache.h" #include "tree-cache.h"
static git_tree_cache *find_child(const git_tree_cache *tree, const char *path) static git_tree_cache *find_child(
const git_tree_cache *tree, const char *path, const char *end)
{ {
size_t i, dirlen; size_t i, dirlen = end ? (size_t)(end - path) : strlen(path);
const char *end;
end = strchr(path, '/');
if (end == NULL) {
end = strrchr(path, '\0');
}
dirlen = end - path;
for (i = 0; i < tree->children_count; ++i) { for (i = 0; i < tree->children_count; ++i) {
const char *childname = tree->children[i]->name; git_tree_cache *child = tree->children[i];
if (strlen(childname) == dirlen && !memcmp(path, childname, dirlen)) if (child->namelen == dirlen && !memcmp(path, child->name, dirlen))
return tree->children[i]; return child;
} }
return NULL; return NULL;
...@@ -44,7 +37,7 @@ void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path) ...@@ -44,7 +37,7 @@ void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path)
if (end == NULL) /* End of path */ if (end == NULL) /* End of path */
break; break;
tree = find_child(tree, ptr); tree = find_child(tree, ptr, end);
if (tree == NULL) /* We don't have that tree */ if (tree == NULL) /* We don't have that tree */
return; return;
...@@ -64,10 +57,9 @@ const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char ...@@ -64,10 +57,9 @@ const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char
while (1) { while (1) {
end = strchr(ptr, '/'); end = strchr(ptr, '/');
tree = find_child(tree, ptr); tree = find_child(tree, ptr, end);
if (tree == NULL) { /* Can't find it */ if (tree == NULL) /* Can't find it */
return NULL; return NULL;
}
if (end == NULL || *end + 1 == '\0') if (end == NULL || *end + 1 == '\0')
return tree; return tree;
...@@ -100,6 +92,7 @@ static int read_tree_internal(git_tree_cache **out, ...@@ -100,6 +92,7 @@ static int read_tree_internal(git_tree_cache **out,
tree->parent = parent; tree->parent = parent;
/* NUL-terminated tree name */ /* NUL-terminated tree name */
tree->namelen = name_len;
memcpy(tree->name, name_start, name_len); memcpy(tree->name, name_start, name_len);
tree->name[name_len] = '\0'; tree->name[name_len] = '\0';
......
...@@ -18,6 +18,7 @@ struct git_tree_cache { ...@@ -18,6 +18,7 @@ struct git_tree_cache {
ssize_t entries; ssize_t entries;
git_oid oid; git_oid oid;
size_t namelen;
char name[GIT_FLEX_ARRAY]; char name[GIT_FLEX_ARRAY];
}; };
......
...@@ -542,10 +542,12 @@ int git__bsearch_r( ...@@ -542,10 +542,12 @@ int git__bsearch_r(
*/ */
int git__strcmp_cb(const void *a, const void *b) int git__strcmp_cb(const void *a, const void *b)
{ {
const char *stra = (const char *)a; return strcmp((const char *)a, (const char *)b);
const char *strb = (const char *)b; }
return strcmp(stra, strb); int git__strcasecmp_cb(const void *a, const void *b)
{
return strcasecmp((const char *)a, (const char *)b);
} }
int git__parse_bool(int *out, const char *value) int git__parse_bool(int *out, const char *value)
......
...@@ -196,6 +196,7 @@ extern int git__bsearch_r( ...@@ -196,6 +196,7 @@ extern int git__bsearch_r(
size_t *position); size_t *position);
extern int git__strcmp_cb(const void *a, const void *b); extern int git__strcmp_cb(const void *a, const void *b);
extern int git__strcasecmp_cb(const void *a, const void *b);
extern int git__strcmp(const char *a, const char *b); extern int git__strcmp(const char *a, const char *b);
extern int git__strcasecmp(const char *a, const char *b); extern int git__strcasecmp(const char *a, const char *b);
......
...@@ -177,7 +177,8 @@ void git_vector_sort(git_vector *v) ...@@ -177,7 +177,8 @@ void git_vector_sort(git_vector *v)
if (git_vector_is_sorted(v) || !v->_cmp) if (git_vector_is_sorted(v) || !v->_cmp)
return; return;
git__tsort(v->contents, v->length, v->_cmp); if (v->length > 1)
git__tsort(v->contents, v->length, v->_cmp);
git_vector_set_sorted(v, 1); git_vector_set_sorted(v, 1);
} }
...@@ -276,14 +277,16 @@ void git_vector_uniq(git_vector *v, void (*git_free_cb)(void *)) ...@@ -276,14 +277,16 @@ void git_vector_uniq(git_vector *v, void (*git_free_cb)(void *))
} }
void git_vector_remove_matching( void git_vector_remove_matching(
git_vector *v, int (*match)(const git_vector *v, size_t idx)) git_vector *v,
int (*match)(const git_vector *v, size_t idx, void *payload),
void *payload)
{ {
size_t i, j; size_t i, j;
for (i = 0, j = 0; j < v->length; ++j) { for (i = 0, j = 0; j < v->length; ++j) {
v->contents[i] = v->contents[j]; v->contents[i] = v->contents[j];
if (!match(v, i)) if (!match(v, i, payload))
i++; i++;
} }
...@@ -339,3 +342,18 @@ int git_vector_set(void **old, git_vector *v, size_t position, void *value) ...@@ -339,3 +342,18 @@ int git_vector_set(void **old, git_vector *v, size_t position, void *value)
return 0; return 0;
} }
int git_vector_verify_sorted(const git_vector *v)
{
size_t i;
if (!git_vector_is_sorted(v))
return -1;
for (i = 1; i < v->length; ++i) {
if (v->_cmp(v->contents[i - 1], v->contents[i]) > 0)
return -1;
}
return 0;
}
...@@ -85,8 +85,11 @@ int git_vector_insert_sorted(git_vector *v, void *element, ...@@ -85,8 +85,11 @@ int git_vector_insert_sorted(git_vector *v, void *element,
int git_vector_remove(git_vector *v, size_t idx); int git_vector_remove(git_vector *v, size_t idx);
void git_vector_pop(git_vector *v); void git_vector_pop(git_vector *v);
void git_vector_uniq(git_vector *v, void (*git_free_cb)(void *)); void git_vector_uniq(git_vector *v, void (*git_free_cb)(void *));
void git_vector_remove_matching( void git_vector_remove_matching(
git_vector *v, int (*match)(const git_vector *v, size_t idx)); git_vector *v,
int (*match)(const git_vector *v, size_t idx, void *payload),
void *payload);
int git_vector_resize_to(git_vector *v, size_t new_length); int git_vector_resize_to(git_vector *v, size_t new_length);
int git_vector_set(void **old, git_vector *v, size_t position, void *value); int git_vector_set(void **old, git_vector *v, size_t position, void *value);
...@@ -108,4 +111,7 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) ...@@ -108,4 +111,7 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
} }
} }
/* Just use this in tests, not for realz. returns -1 if not sorted */
int git_vector_verify_sorted(const git_vector *v);
#endif #endif
...@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void) ...@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void)
git_attr_assignment *assign; git_attr_assignment *assign;
git_attr_rule *rule; git_attr_rule *rule;
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
rule = get_rule(0); rule = get_rule(0);
...@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void) ...@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
/* let's do a thorough check of this rule, then just verify /* let's do a thorough check of this rule, then just verify
...@@ -121,9 +121,9 @@ void test_attr_file__assign_variants(void) ...@@ -121,9 +121,9 @@ void test_attr_file__assign_variants(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr2")));
cl_assert_equal_s(cl_fixture("attr/attr2"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr2"), file->entry->path);
cl_assert(file->rules.length == 11); cl_assert(file->rules.length == 11);
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL); check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
...@@ -187,8 +187,8 @@ void test_attr_file__check_attr_examples(void) ...@@ -187,8 +187,8 @@ void test_attr_file__check_attr_examples(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
cl_assert_equal_s(cl_fixture("attr/attr3"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr3"), file->entry->path);
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
rule = get_rule(0); rule = get_rule(0);
......
...@@ -9,8 +9,8 @@ void test_attr_lookup__simple(void) ...@@ -9,8 +9,8 @@ void test_attr_lookup__simple(void)
git_attr_path path; git_attr_path path;
const char *value = NULL; const char *value = NULL;
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL)); cl_git_pass(git_attr_path__init(&path, "test", NULL));
...@@ -129,8 +129,8 @@ void test_attr_lookup__match_variants(void) ...@@ -129,8 +129,8 @@ void test_attr_lookup__match_variants(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2); cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL)); cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
...@@ -190,7 +190,7 @@ void test_attr_lookup__assign_variants(void) ...@@ -190,7 +190,7 @@ void test_attr_lookup__assign_variants(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr2")));
cl_assert(file->rules.length == 11); cl_assert(file->rules.length == 11);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
...@@ -225,7 +225,7 @@ void test_attr_lookup__check_attr_examples(void) ...@@ -225,7 +225,7 @@ void test_attr_lookup__check_attr_examples(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3"))); cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
...@@ -250,9 +250,9 @@ void test_attr_lookup__from_buffer(void) ...@@ -250,9 +250,9 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, 0, NULL, NULL)); cl_git_pass(git_attr_file__new(&file, NULL, 0));
cl_git_pass(git_attr_file__parse_buffer(NULL, NULL, "a* foo\nabc bar\n* baz", file)); cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz"));
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
......
...@@ -68,9 +68,12 @@ void test_attr_repo__get_one(void) ...@@ -68,9 +68,12 @@ void test_attr_repo__get_one(void)
attr_check_expected(scan->expected, scan->expected_str, scan->attr, value); attr_check_expected(scan->expected, scan->expected_str, scan->attr, value);
} }
cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes")); cl_assert(git_attr_cache__is_cached(
cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes")); g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes"));
cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes")); cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes"));
} }
void test_attr_repo__get_many(void) void test_attr_repo__get_many(void)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Use this wrapper around all `git_` library calls that return error codes! * Use this wrapper around all `git_` library calls that return error codes!
*/ */
#define cl_git_pass(expr) cl_git_pass_(expr, __FILE__, __LINE__) #define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__)
#define cl_git_pass_(expr, file, line) do { \ #define cl_git_pass_(expr, file, line) do { \
int _lg2_error; \ int _lg2_error; \
......
...@@ -3,12 +3,22 @@ ...@@ -3,12 +3,22 @@
GIT__USE_STRMAP; GIT__USE_STRMAP;
git_strmap *g_table;
void test_core_strmap__initialize(void)
{
cl_git_pass(git_strmap_alloc(&g_table));
cl_assert(g_table != NULL);
}
void test_core_strmap__cleanup(void)
{
git_strmap_free(g_table);
}
void test_core_strmap__0(void) void test_core_strmap__0(void)
{ {
git_strmap *table = git_strmap_alloc(); cl_assert(git_strmap_num_entries(g_table) == 0);
cl_assert(table != NULL);
cl_assert(git_strmap_num_entries(table) == 0);
git_strmap_free(table);
} }
static void insert_strings(git_strmap *table, int count) static void insert_strings(git_strmap *table, int count)
...@@ -37,21 +47,17 @@ void test_core_strmap__1(void) ...@@ -37,21 +47,17 @@ void test_core_strmap__1(void)
{ {
int i; int i;
char *str; char *str;
git_strmap *table = git_strmap_alloc();
cl_assert(table != NULL);
insert_strings(table, 20); insert_strings(g_table, 20);
cl_assert(git_strmap_exists(table, "aaaaaaaaa")); cl_assert(git_strmap_exists(g_table, "aaaaaaaaa"));
cl_assert(git_strmap_exists(table, "ggggggggg")); cl_assert(git_strmap_exists(g_table, "ggggggggg"));
cl_assert(!git_strmap_exists(table, "aaaaaaaab")); cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
cl_assert(!git_strmap_exists(table, "abcdefghi")); cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
i = 0; i = 0;
git_strmap_foreach_value(table, str, { i++; free(str); }); git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 20); cl_assert(i == 20);
git_strmap_free(table);
} }
void test_core_strmap__2(void) void test_core_strmap__2(void)
...@@ -59,44 +65,36 @@ void test_core_strmap__2(void) ...@@ -59,44 +65,36 @@ void test_core_strmap__2(void)
khiter_t pos; khiter_t pos;
int i; int i;
char *str; char *str;
git_strmap *table = git_strmap_alloc();
cl_assert(table != NULL);
insert_strings(table, 20); insert_strings(g_table, 20);
cl_assert(git_strmap_exists(table, "aaaaaaaaa")); cl_assert(git_strmap_exists(g_table, "aaaaaaaaa"));
cl_assert(git_strmap_exists(table, "ggggggggg")); cl_assert(git_strmap_exists(g_table, "ggggggggg"));
cl_assert(!git_strmap_exists(table, "aaaaaaaab")); cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
cl_assert(!git_strmap_exists(table, "abcdefghi")); cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
cl_assert(git_strmap_exists(table, "bbbbbbbbb")); cl_assert(git_strmap_exists(g_table, "bbbbbbbbb"));
pos = git_strmap_lookup_index(table, "bbbbbbbbb"); pos = git_strmap_lookup_index(g_table, "bbbbbbbbb");
cl_assert(git_strmap_valid_index(table, pos)); cl_assert(git_strmap_valid_index(g_table, pos));
cl_assert_equal_s(git_strmap_value_at(table, pos), "bbbbbbbbb"); cl_assert_equal_s(git_strmap_value_at(g_table, pos), "bbbbbbbbb");
free(git_strmap_value_at(table, pos)); free(git_strmap_value_at(g_table, pos));
git_strmap_delete_at(table, pos); git_strmap_delete_at(g_table, pos);
cl_assert(!git_strmap_exists(table, "bbbbbbbbb")); cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb"));
i = 0; i = 0;
git_strmap_foreach_value(table, str, { i++; free(str); }); git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 19); cl_assert(i == 19);
git_strmap_free(table);
} }
void test_core_strmap__3(void) void test_core_strmap__3(void)
{ {
int i; int i;
char *str; char *str;
git_strmap *table = git_strmap_alloc();
cl_assert(table != NULL);
insert_strings(table, 10000); insert_strings(g_table, 10000);
i = 0; i = 0;
git_strmap_foreach_value(table, str, { i++; free(str); }); git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 10000); cl_assert(i == 10000);
git_strmap_free(table);
} }
...@@ -190,8 +190,9 @@ void test_core_vector__5(void) ...@@ -190,8 +190,9 @@ void test_core_vector__5(void)
git_vector_free(&x); git_vector_free(&x);
} }
static int remove_ones(const git_vector *v, size_t idx) static int remove_ones(const git_vector *v, size_t idx, void *p)
{ {
GIT_UNUSED(p);
return (git_vector_get(v, idx) == (void *)0x001); return (git_vector_get(v, idx) == (void *)0x001);
} }
...@@ -206,7 +207,7 @@ void test_core_vector__remove_matching(void) ...@@ -206,7 +207,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 1); cl_assert(x.length == 1);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0); cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
...@@ -214,7 +215,7 @@ void test_core_vector__remove_matching(void) ...@@ -214,7 +215,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 3); cl_assert(x.length == 3);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0); cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x002);
...@@ -223,7 +224,7 @@ void test_core_vector__remove_matching(void) ...@@ -223,7 +224,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4); cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2); cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) { git_vector_foreach(&x, i, compare) {
...@@ -238,7 +239,7 @@ void test_core_vector__remove_matching(void) ...@@ -238,7 +239,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4); cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2); cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) { git_vector_foreach(&x, i, compare) {
...@@ -253,7 +254,7 @@ void test_core_vector__remove_matching(void) ...@@ -253,7 +254,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4); cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2); cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) { git_vector_foreach(&x, i, compare) {
...@@ -268,7 +269,7 @@ void test_core_vector__remove_matching(void) ...@@ -268,7 +269,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x003); git_vector_insert(&x, (void*) 0x003);
cl_assert(x.length == 4); cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones); git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 4); cl_assert(x.length == 4);
git_vector_free(&x); git_vector_free(&x);
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "diff_helpers.h" #include "diff_helpers.h"
#include "git2/sys/diff.h"
git_tree *resolve_commit_oid_to_tree( git_tree *resolve_commit_oid_to_tree(
git_repository *repo, git_repository *repo,
...@@ -215,32 +216,16 @@ abort: ...@@ -215,32 +216,16 @@ abort:
return GIT_EUSER; return GIT_EUSER;
} }
static int diff_print_cb(
const git_diff_delta *delta,
const git_diff_hunk *hunk,
const git_diff_line *line,
void *payload)
{
FILE *fp = payload;
GIT_UNUSED(delta); GIT_UNUSED(hunk);
if (line->origin == GIT_DIFF_LINE_CONTEXT ||
line->origin == GIT_DIFF_LINE_ADDITION ||
line->origin == GIT_DIFF_LINE_DELETION)
fputc(line->origin, fp);
fwrite(line->content, 1, line->content_len, fp);
return 0;
}
void diff_print(FILE *fp, git_diff *diff) void diff_print(FILE *fp, git_diff *diff)
{ {
cl_git_pass(git_diff_print( cl_git_pass(
diff, GIT_DIFF_FORMAT_PATCH, diff_print_cb, fp ? fp : stderr)); git_diff_print(diff, GIT_DIFF_FORMAT_PATCH,
git_diff_print_callback__to_file_handle, fp ? fp : stderr));
} }
void diff_print_raw(FILE *fp, git_diff *diff) void diff_print_raw(FILE *fp, git_diff *diff)
{ {
cl_git_pass(git_diff_print( cl_git_pass(
diff, GIT_DIFF_FORMAT_RAW, diff_print_cb, fp ? fp : stderr)); git_diff_print(diff, GIT_DIFF_FORMAT_RAW,
git_diff_print_callback__to_file_handle, fp ? fp : stderr));
} }
...@@ -355,6 +355,7 @@ static void index_iterator_test( ...@@ -355,6 +355,7 @@ static void index_iterator_test(
const char *sandbox, const char *sandbox,
const char *start, const char *start,
const char *end, const char *end,
git_iterator_flag_t flags,
int expected_count, int expected_count,
const char **expected_names, const char **expected_names,
const char **expected_oids) const char **expected_oids)
...@@ -362,11 +363,13 @@ static void index_iterator_test( ...@@ -362,11 +363,13 @@ static void index_iterator_test(
git_index *index; git_index *index;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int error, count = 0; int error, count = 0, caps;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); caps = git_index_caps(index);
cl_git_pass(git_iterator_for_index(&i, index, flags, start, end));
while (!(error = git_iterator_advance(&entry, i))) { while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry); cl_assert(entry);
...@@ -388,6 +391,8 @@ static void index_iterator_test( ...@@ -388,6 +391,8 @@ static void index_iterator_test(
cl_assert_equal_i(expected_count, count); cl_assert_equal_i(expected_count, count);
git_iterator_free(i); git_iterator_free(i);
cl_assert(caps == git_index_caps(index));
git_index_free(index); git_index_free(index);
} }
...@@ -446,7 +451,8 @@ static const char *expected_index_oids_0[] = { ...@@ -446,7 +451,8 @@ static const char *expected_index_oids_0[] = {
void test_diff_iterator__index_0(void) void test_diff_iterator__index_0(void)
{ {
index_iterator_test( index_iterator_test(
"attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0); "attr", NULL, NULL, 0, ARRAY_SIZE(expected_index_0),
expected_index_0, expected_index_oids_0);
} }
static const char *expected_index_range[] = { static const char *expected_index_range[] = {
...@@ -466,25 +472,26 @@ static const char *expected_index_oids_range[] = { ...@@ -466,25 +472,26 @@ static const char *expected_index_oids_range[] = {
void test_diff_iterator__index_range(void) void test_diff_iterator__index_range(void)
{ {
index_iterator_test( index_iterator_test(
"attr", "root", "root", 4, expected_index_range, expected_index_oids_range); "attr", "root", "root", 0, ARRAY_SIZE(expected_index_range),
expected_index_range, expected_index_oids_range);
} }
void test_diff_iterator__index_range_empty_0(void) void test_diff_iterator__index_range_empty_0(void)
{ {
index_iterator_test( index_iterator_test(
"attr", "empty", "empty", 0, NULL, NULL); "attr", "empty", "empty", 0, 0, NULL, NULL);
} }
void test_diff_iterator__index_range_empty_1(void) void test_diff_iterator__index_range_empty_1(void)
{ {
index_iterator_test( index_iterator_test(
"attr", "z_empty_after", NULL, 0, NULL, NULL); "attr", "z_empty_after", NULL, 0, 0, NULL, NULL);
} }
void test_diff_iterator__index_range_empty_2(void) void test_diff_iterator__index_range_empty_2(void)
{ {
index_iterator_test( index_iterator_test(
"attr", NULL, ".aaa_empty_before", 0, NULL, NULL); "attr", NULL, ".aaa_empty_before", 0, 0, NULL, NULL);
} }
static const char *expected_index_1[] = { static const char *expected_index_1[] = {
...@@ -522,9 +529,45 @@ static const char* expected_index_oids_1[] = { ...@@ -522,9 +529,45 @@ static const char* expected_index_oids_1[] = {
void test_diff_iterator__index_1(void) void test_diff_iterator__index_1(void)
{ {
index_iterator_test( index_iterator_test(
"status", NULL, NULL, 13, expected_index_1, expected_index_oids_1); "status", NULL, NULL, 0, ARRAY_SIZE(expected_index_1),
expected_index_1, expected_index_oids_1);
} }
static const char *expected_index_cs[] = {
"B", "D", "F", "H", "J", "L/1", "L/B", "L/D", "L/a", "L/c",
"a", "c", "e", "g", "i", "k/1", "k/B", "k/D", "k/a", "k/c",
};
static const char *expected_index_ci[] = {
"a", "B", "c", "D", "e", "F", "g", "H", "i", "J",
"k/1", "k/a", "k/B", "k/c", "k/D", "L/1", "L/a", "L/B", "L/c", "L/D",
};
void test_diff_iterator__index_case_folding(void)
{
git_buf path = GIT_BUF_INIT;
int fs_is_ci = 0;
cl_git_pass(git_buf_joinpath(&path, cl_fixture("icase"), ".gitted/CoNfIg"));
fs_is_ci = git_path_exists(path.ptr);
git_buf_free(&path);
index_iterator_test(
"icase", NULL, NULL, 0, ARRAY_SIZE(expected_index_cs),
fs_is_ci ? expected_index_ci : expected_index_cs, NULL);
cl_git_sandbox_cleanup();
index_iterator_test(
"icase", NULL, NULL, GIT_ITERATOR_IGNORE_CASE,
ARRAY_SIZE(expected_index_ci), expected_index_ci, NULL);
cl_git_sandbox_cleanup();
index_iterator_test(
"icase", NULL, NULL, GIT_ITERATOR_DONT_IGNORE_CASE,
ARRAY_SIZE(expected_index_cs), expected_index_cs, NULL);
}
/* -- WORKDIR ITERATOR TESTS -- */ /* -- WORKDIR ITERATOR TESTS -- */
......
...@@ -544,36 +544,22 @@ void test_index_tests__corrupted_extension(void) ...@@ -544,36 +544,22 @@ void test_index_tests__corrupted_extension(void)
cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR); cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR);
} }
static void assert_index_is_sorted(git_index *index)
{
git_vector *entries = &index->entries;
size_t i;
cl_assert(git_vector_is_sorted(entries));
for (i = 1; i < git_vector_length(entries); ++i) {
git_index_entry *prev = git_vector_get(entries, i - 1);
git_index_entry *curr = git_vector_get(entries, i);
cl_assert(index->entries._cmp(prev, curr) <= 0);
}
}
void test_index_tests__reload_while_ignoring_case(void) void test_index_tests__reload_while_ignoring_case(void)
{ {
git_index *index; git_index *index;
unsigned int caps; unsigned int caps;
cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
assert_index_is_sorted(index); cl_git_pass(git_vector_verify_sorted(&index->entries));
caps = git_index_caps(index); caps = git_index_caps(index);
cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEXCAP_IGNORE_CASE)); cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEXCAP_IGNORE_CASE));
cl_git_pass(git_index_read(index, true)); cl_git_pass(git_index_read(index, true));
assert_index_is_sorted(index); cl_git_pass(git_vector_verify_sorted(&index->entries));
cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE)); cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE));
cl_git_pass(git_index_read(index, true)); cl_git_pass(git_index_read(index, true));
assert_index_is_sorted(index); cl_git_pass(git_vector_verify_sorted(&index->entries));
git_index_free(index); git_index_free(index);
} }
...@@ -54,8 +54,10 @@ void test_status_ignore__0(void) ...@@ -54,8 +54,10 @@ void test_status_ignore__0(void)
} }
/* confirm that ignore files were cached */ /* confirm that ignore files were cached */
cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude")); cl_assert(git_attr_cache__is_cached(
cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore")); g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
} }
......
#include "clar_libgit2.h"
#include "thread_helpers.h"
static git_repository *_repo;
static git_tree *_a, *_b;
static git_atomic _counts[4];
static int _check_counts;
#define THREADS 20
void test_threads_diff__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static void setup_trees(void)
{
git_index *idx;
_repo = cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */
/* avoid competing to load initial index */
cl_git_pass(git_repository_index(&idx, _repo));
git_index_free(idx);
cl_git_pass(git_revparse_single(
(git_object **)&_a, _repo, "0017bd4ab1^{tree}"));
cl_git_pass(git_revparse_single(
(git_object **)&_b, _repo, "26a125ee1b^{tree}"));
memset(_counts, 0, sizeof(_counts));
}
static void free_trees(void)
{
git_tree_free(_a); _a = NULL;
git_tree_free(_b); _b = NULL;
if (_check_counts) {
cl_assert_equal_i(288, git_atomic_get(&_counts[0]));
cl_assert_equal_i(112, git_atomic_get(&_counts[1]));
cl_assert_equal_i( 80, git_atomic_get(&_counts[2]));
cl_assert_equal_i( 96, git_atomic_get(&_counts[3]));
}
}
static void *run_index_diffs(void *arg)
{
int thread = *(int *)arg;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff *diff = NULL;
size_t i;
int exp[4] = { 0, 0, 0, 0 };
switch (thread & 0x03) {
case 0: /* diff index to workdir */;
cl_git_pass(git_diff_index_to_workdir(&diff, _repo, NULL, &opts));
break;
case 1: /* diff tree 'a' to index */;
cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, NULL, &opts));
break;
case 2: /* diff tree 'b' to index */;
cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, NULL, &opts));
break;
case 3: /* diff index to workdir (explicit index) */;
{
git_index *idx;
cl_git_pass(git_repository_index(&idx, _repo));
cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
git_index_free(idx);
break;
}
}
/* keep some diff stats to make sure results are as expected */
i = git_diff_num_deltas(diff);
git_atomic_add(&_counts[0], (int32_t)i);
exp[0] = (int)i;
while (i > 0) {
switch (git_diff_get_delta(diff, --i)->status) {
case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break;
case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&_counts[2]); break;
case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&_counts[3]); break;
default: break;
}
}
switch (thread & 0x03) {
case 0: case 3:
cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]);
cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]);
break;
case 1:
cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]);
cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]);
break;
case 2:
cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]);
cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]);
break;
}
git_diff_free(diff);
giterr_clear();
return arg;
}
void test_threads_diff__concurrent_diffs(void)
{
_repo = cl_git_sandbox_init("status");
_check_counts = 1;
run_in_parallel(
5, 32, run_index_diffs, setup_trees, free_trees);
}
static void *run_index_diffs_with_modifier(void *arg)
{
int thread = *(int *)arg;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff *diff = NULL;
git_index *idx = NULL;
cl_git_pass(git_repository_index(&idx, _repo));
/* have first thread altering the index as we go */
if (thread == 0) {
int i;
for (i = 0; i < 300; ++i) {
switch (i & 0x03) {
case 0: (void)git_index_add_bypath(idx, "new_file"); break;
case 1: (void)git_index_remove_bypath(idx, "modified_file"); break;
case 2: (void)git_index_remove_bypath(idx, "new_file"); break;
case 3: (void)git_index_add_bypath(idx, "modified_file"); break;
}
git_thread_yield();
}
goto done;
}
/* only use explicit index in this test to prevent reloading */
switch (thread & 0x03) {
case 0: /* diff index to workdir */;
cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
break;
case 1: /* diff tree 'a' to index */;
cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, idx, &opts));
break;
case 2: /* diff tree 'b' to index */;
cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, idx, &opts));
break;
case 3: /* diff index to workdir reversed */;
opts.flags |= GIT_DIFF_REVERSE;
cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
break;
}
/* results will be unpredictable with index modifier thread running */
git_diff_free(diff);
done:
git_index_free(idx);
giterr_clear();
return arg;
}
void test_threads_diff__with_concurrent_index_modified(void)
{
_repo = cl_git_sandbox_init("status");
_check_counts = 0;
run_in_parallel(
5, 16, run_index_diffs_with_modifier, setup_trees, free_trees);
}
#include "clar_libgit2.h"
#include "thread_helpers.h"
#include "iterator.h"
static git_repository *_repo;
void test_threads_iterator__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static void *run_workdir_iterator(void *arg)
{
int error = 0;
git_iterator *iter;
const git_index_entry *entry = NULL;
cl_git_pass(git_iterator_for_workdir(
&iter, _repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
while (!error) {
if (entry && entry->mode == GIT_FILEMODE_TREE) {
error = git_iterator_advance_into(&entry, iter);
if (error == GIT_ENOTFOUND)
error = git_iterator_advance(&entry, iter);
} else {
error = git_iterator_advance(&entry, iter);
}
if (!error)
(void)git_iterator_current_is_ignored(iter);
}
cl_assert_equal_i(GIT_ITEROVER, error);
git_iterator_free(iter);
giterr_clear();
return arg;
}
void test_threads_iterator__workdir(void)
{
_repo = cl_git_sandbox_init("status");
run_in_parallel(
1, 20, run_workdir_iterator, NULL, NULL);
}
...@@ -37,6 +37,7 @@ static void *iterate_refs(void *arg) ...@@ -37,6 +37,7 @@ static void *iterate_refs(void *arg)
git_reference_iterator_free(i); git_reference_iterator_free(i);
giterr_clear();
return arg; return arg;
} }
...@@ -115,6 +116,7 @@ static void *create_refs(void *arg) ...@@ -115,6 +116,7 @@ static void *create_refs(void *arg)
for (i = 0; i < 10; ++i) for (i = 0; i < 10; ++i)
git_reference_free(ref[i]); git_reference_free(ref[i]);
giterr_clear();
return arg; return arg;
} }
...@@ -141,6 +143,7 @@ static void *delete_refs(void *arg) ...@@ -141,6 +143,7 @@ static void *delete_refs(void *arg)
} }
} }
giterr_clear();
return arg; return arg;
} }
......
#include "clar_libgit2.h"
#include "thread_helpers.h"
void run_in_parallel(
int repeats,
int threads,
void *(*func)(void *),
void (*before_test)(void),
void (*after_test)(void))
{
int r, t, *id = git__calloc(threads, sizeof(int));
#ifdef GIT_THREADS
git_thread *th = git__calloc(threads, sizeof(git_thread));
cl_assert(th != NULL);
#else
void *th = NULL;
#endif
cl_assert(id != NULL);
for (r = 0; r < repeats; ++r) {
if (before_test) before_test();
for (t = 0; t < threads; ++t) {
id[t] = t;
#ifdef GIT_THREADS
cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t]));
#else
cl_assert(func(&id[t]) == &id[t]);
#endif
}
#ifdef GIT_THREADS
for (t = 0; t < threads; ++t)
cl_git_pass(git_thread_join(th[t], NULL));
memset(th, 0, threads * sizeof(git_thread));
#endif
if (after_test) after_test();
}
git__free(id);
git__free(th);
}
#include "thread-utils.h"
void run_in_parallel(
int repeats,
int threads,
void *(*func)(void *),
void (*before_test)(void),
void (*after_test)(void));
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