Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Martí <tanoku@gmail.com>2012-05-06 01:22:06 +0400
committerVicent Martí <tanoku@gmail.com>2012-05-06 01:22:06 +0400
commit4ef14af93517b3842bc0dfa24147cf10dd029582 (patch)
tree88f90fa8c9d903f072a2b1c647c51a9899e520c7
parentf95e8cc07c85034f737872455fce2895186be19d (diff)
parent282283acc65bab9de231a2b3dc489eb171d5f1cf (diff)
Merge pull request #664 from arrbee/attrs-from-indexdevelopment-merge
Support git attrs from index (and bare repo)
-rw-r--r--AUTHORS1
-rw-r--r--include/git2/attr.h166
-rw-r--r--src/attr.c287
-rw-r--r--src/attr.h26
-rw-r--r--src/attr_file.c90
-rw-r--r--src/attr_file.h21
-rw-r--r--src/config_file.c1
-rw-r--r--src/crlf.c3
-rw-r--r--src/diff.c12
-rw-r--r--src/diff_output.c2
-rw-r--r--src/ignore.c71
-rw-r--r--src/ignore.h5
-rw-r--r--src/object.c41
-rw-r--r--src/odb.c12
-rw-r--r--src/odb.h2
-rw-r--r--src/odb_loose.c8
-rw-r--r--src/odb_pack.c6
-rw-r--r--src/pack.c25
-rw-r--r--src/repository.c20
-rw-r--r--src/repository.h4
-rw-r--r--src/status.c44
-rw-r--r--src/strmap.h28
-rw-r--r--tests-clar/attr/file.c25
-rw-r--r--tests-clar/attr/flags.c108
-rw-r--r--tests-clar/attr/lookup.c22
-rw-r--r--tests-clar/attr/repo.c39
-rw-r--r--tests-clar/diff/tree.c68
-rw-r--r--tests-clar/resources/attr_index/.gitted/HEAD1
-rw-r--r--tests-clar/resources/attr_index/.gitted/config6
-rw-r--r--tests-clar/resources/attr_index/.gitted/description1
-rw-r--r--tests-clar/resources/attr_index/.gitted/indexbin0 -> 520 bytes
-rw-r--r--tests-clar/resources/attr_index/.gitted/info/exclude6
-rw-r--r--tests-clar/resources/attr_index/.gitted/info/refs1
-rw-r--r--tests-clar/resources/attr_index/.gitted/logs/HEAD4
-rw-r--r--tests-clar/resources/attr_index/.gitted/logs/refs/heads/master4
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/38/12cfef36615db1788d4e63f90028007e17a3483
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/59/d942b8be2784bc96db9b22202c10815c9a077b1
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/cd/f17ea3fe625ef812f4dce7f423f4f299287505bin0 -> 61 bytes
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/f7/2502ddd01412bb20796ff812af56fd53b82b52bin0 -> 149 bytes
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/info/packs2
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.idxbin0 -> 1492 bytes
-rw-r--r--tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.packbin0 -> 1106 bytes
-rw-r--r--tests-clar/resources/attr_index/.gitted/packed-refs2
-rw-r--r--tests-clar/resources/attr_index/.gitted/refs/heads/master1
-rw-r--r--tests-clar/resources/attr_index/README.md1
-rw-r--r--tests-clar/resources/attr_index/README.txt1
-rw-r--r--tests-clar/resources/attr_index/gitattributes4
-rw-r--r--tests-clar/resources/attr_index/sub/sub/.gitattributes3
-rw-r--r--tests-clar/resources/attr_index/sub/sub/README.md1
-rw-r--r--tests-clar/resources/attr_index/sub/sub/README.txt1
-rw-r--r--tests-clar/status/ignore.c4
51 files changed, 867 insertions, 317 deletions
diff --git a/AUTHORS b/AUTHORS
index 954f25964..03904ff55 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -43,6 +43,7 @@ Ramsay Jones
Robert G. Jakabosky
Romain Geissler
Romain Muller
+Russell Belfer
Sakari Jokinen
Sam
Sarath Lakshman
diff --git a/include/git2/attr.h b/include/git2/attr.h
index 81d1e517b..6a05496dc 100644
--- a/include/git2/attr.h
+++ b/include/git2/attr.h
@@ -19,42 +19,186 @@
*/
GIT_BEGIN_DECL
+/**
+ * GIT_ATTR_TRUE checks if an attribute is set on. In core git
+ * parlance, this the value for "Set" attributes.
+ *
+ * For example, if the attribute file contains:
+ *
+ * *.c foo
+ *
+ * Then for file `xyz.c` looking up attribute "foo" gives a value for
+ * which `GIT_ATTR_TRUE(value)` is true.
+ */
#define GIT_ATTR_TRUE(attr) ((attr) == git_attr__true)
+
+/**
+ * GIT_ATTR_FALSE checks if an attribute is set off. In core git
+ * parlance, this is the value for attributes that are "Unset" (not to
+ * be confused with values that a "Unspecified").
+ *
+ * For example, if the attribute file contains:
+ *
+ * *.h -foo
+ *
+ * Then for file `zyx.h` looking up attribute "foo" gives a value for
+ * which `GIT_ATTR_FALSE(value)` is true.
+ */
#define GIT_ATTR_FALSE(attr) ((attr) == git_attr__false)
-#define GIT_ATTR_UNSPECIFIED(attr) ((attr) == NULL)
+
+/**
+ * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This
+ * may be due to the attribute not being mentioned at all or because
+ * the attribute was explicitly set unspecified via the `!` operator.
+ *
+ * For example, if the attribute file contains:
+ *
+ * *.c foo
+ * *.h -foo
+ * onefile.c !foo
+ *
+ * Then for `onefile.c` looking up attribute "foo" yields a value with
+ * `GIT_ATTR_UNSPECIFIED(value)` of true. Also, looking up "foo" on
+ * file `onefile.rb` or looking up "bar" on any file will all give
+ * `GIT_ATTR_UNSPECIFIED(value)` of true.
+ */
+#define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_attr__unset)
+
+/**
+ * GIT_ATTR_SET_TO_VALUE checks if an attribute is set to a value (as
+ * opposied to TRUE, FALSE or UNSPECIFIED). This would be the case if
+ * for a file with something like:
+ *
+ * *.txt eol=lf
+ *
+ * Given this, looking up "eol" for `onefile.txt` will give back the
+ * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
+ */
+#define GIT_ATTR_SET_TO_VALUE(attr) \
+ ((attr) && (attr) != git_attr__unset && \
+ (attr) != git_attr__true && (attr) != git_attr__false)
GIT_EXTERN(const char *) git_attr__true;
GIT_EXTERN(const char *) git_attr__false;
+GIT_EXTERN(const char *) git_attr__unset;
+
+/**
+ * Check attribute flags: Reading values from index and working directory.
+ *
+ * When checking attributes, it is possible to check attribute files
+ * in both the working directory (if there is one) and the index (if
+ * there is one). You can explicitly choose where to check and in
+ * which order using the following flags.
+ *
+ * Core git usually checks the working directory then the index,
+ * except during a checkout when it checks the index first. It will
+ * use index only for creating archives or for a bare repo (if an
+ * index has been specified for the bare repo).
+ */
+#define GIT_ATTR_CHECK_FILE_THEN_INDEX 0
+#define GIT_ATTR_CHECK_INDEX_THEN_FILE 1
+#define GIT_ATTR_CHECK_INDEX_ONLY 2
+/**
+ * Check attribute flags: Using the system attributes file.
+ *
+ * Normally, attribute checks include looking in the /etc (or system
+ * equivalent) directory for a `gitattributes` file. Passing this
+ * flag will cause attribute checks to ignore that file.
+ */
+#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
/**
- * Lookup attribute for path returning string caller must free
+ * Look up the value of one git attribute for path.
+ *
+ * @param repo The repository containing the path.
+ * @param flags A combination of GIT_ATTR_CHECK... flags.
+ * @param path The path to check for attributes. Relative paths are
+ * interpreted relative to the repo root. The file does
+ * not have to exist, but if it does not, then it will be
+ * treated as a plain file (not a directory).
+ * @param name The name of the attribute to look up.
+ * @param value Output of the value of the attribute. Use the GIT_ATTR_...
+ * macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just
+ * use the string value for attributes set to a value. You
+ * should NOT modify or free this value.
*/
GIT_EXTERN(int) git_attr_get(
- git_repository *repo, const char *path, const char *name,
+ git_repository *repo,
+ uint32_t flags,
+ const char *path,
+ const char *name,
const char **value);
/**
- * Lookup list of attributes for path, populating array of strings
+ * Look up a list of git attributes for path.
+ *
+ * Use this if you have a known list of attributes that you want to
+ * look up in a single call. This is somewhat more efficient than
+ * calling `git_attr_get()` multiple times.
+ *
+ * For example, you might write:
+ *
+ * const char *attrs[] = { "crlf", "diff", "foo" };
+ * const char **values[3];
+ * git_attr_get_many(repo, 0, "my/fun/file.c", 3, attrs, values);
+ *
+ * Then you could loop through the 3 values to get the settings for
+ * the three attributes you asked about.
+ *
+ * @param repo The repository containing the path.
+ * @param flags A combination of GIT_ATTR_CHECK... flags.
+ * @param path The path inside the repo to check attributes. This
+ * does not have to exist, but if it does not, then
+ * it will be treated as a plain file (i.e. not a directory).
+ * @param num_attr The number of attributes being looked up
+ * @param names An array of num_attr strings containing attribute names.
+ * @param values An array of num_attr entries that will have string
+ * pointers written into it for the values of the attributes.
+ * You should not modify or free the values that are written
+ * into this array (although of course, you should free the
+ * array itself if you allocated it).
*/
GIT_EXTERN(int) git_attr_get_many(
- git_repository *repo, const char *path,
- size_t num_attr, const char **names,
+ git_repository *repo,
+ uint32_t flags,
+ const char *path,
+ size_t num_attr,
+ const char **names,
const char **values);
/**
- * Perform an operation on each attribute of a path.
+ * Loop over all the git attributes for a path.
+ *
+ * @param repo The repository containing the path.
+ * @param flags A combination of GIT_ATTR_CHECK... flags.
+ * @param path The path inside the repo to check attributes. This
+ * does not have to exist, but if it does not, then
+ * it will be treated as a plain file (i.e. not a directory).
+ * @param callback The function that will be invoked on each attribute
+ * and attribute value. The name parameter will be the name
+ * of the attribute and the value will be the value it is
+ * set to, including possibly NULL if the attribute is
+ * explicitly set to UNSPECIFIED using the ! sign. This
+ * will be invoked only once per attribute name, even if
+ * there are multiple rules for a given file. The highest
+ * priority rule will be used.
+ * @param payload Passed on as extra parameter to callback function.
*/
GIT_EXTERN(int) git_attr_foreach(
- git_repository *repo, const char *path,
+ git_repository *repo,
+ uint32_t flags,
+ const char *path,
int (*callback)(const char *name, const char *value, void *payload),
void *payload);
/**
* Flush the gitattributes cache.
*
- * Call this if you have reason to believe that the attributes files
- * on disk no longer match the cached contents of memory.
+ * Call this if you have reason to believe that the attributes files on
+ * disk no longer match the cached contents of memory. This will cause
+ * the attributes files to be reloaded the next time that an attribute
+ * access function is called.
*/
GIT_EXTERN(void) git_attr_cache_flush(
git_repository *repo);
@@ -62,7 +206,7 @@ GIT_EXTERN(void) git_attr_cache_flush(
/**
* Add a macro definition.
*
- * Macros will automatically be loaded from the top level .gitattributes
+ * Macros will automatically be loaded from the top level `.gitattributes`
* file of the repository (plus the build-in "binary" macro). This
* function allows you to add others. For example, to add the default
* macro, you would call:
diff --git a/src/attr.c b/src/attr.c
index 120d12737..b7ac6355d 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -6,12 +6,18 @@
GIT__USE_STRMAP;
static int collect_attr_files(
- git_repository *repo, const char *path, git_vector *files);
+ git_repository *repo,
+ uint32_t flags,
+ const char *path,
+ git_vector *files);
int git_attr_get(
- git_repository *repo, const char *pathname,
- const char *name, const char **value)
+ git_repository *repo,
+ uint32_t flags,
+ const char *pathname,
+ const char *name,
+ const char **value)
{
int error;
git_attr_path path;
@@ -26,7 +32,7 @@ int git_attr_get(
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
return -1;
- if ((error = collect_attr_files(repo, pathname, &files)) < 0)
+ if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
goto cleanup;
attr.name = name;
@@ -58,8 +64,12 @@ typedef struct {
} attr_get_many_info;
int git_attr_get_many(
- git_repository *repo, const char *pathname,
- size_t num_attr, const char **names, const char **values)
+ git_repository *repo,
+ uint32_t flags,
+ const char *pathname,
+ size_t num_attr,
+ const char **names,
+ const char **values)
{
int error;
git_attr_path path;
@@ -75,7 +85,7 @@ int git_attr_get_many(
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
return -1;
- if ((error = collect_attr_files(repo, pathname, &files)) < 0)
+ if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
goto cleanup;
info = git__calloc(num_attr, sizeof(attr_get_many_info));
@@ -119,7 +129,9 @@ cleanup:
int git_attr_foreach(
- git_repository *repo, const char *pathname,
+ git_repository *repo,
+ uint32_t flags,
+ const char *pathname,
int (*callback)(const char *name, const char *value, void *payload),
void *payload)
{
@@ -135,7 +147,7 @@ int git_attr_foreach(
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
return -1;
- if ((error = collect_attr_files(repo, pathname, &files)) < 0)
+ if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
goto cleanup;
seen = git_strmap_alloc();
@@ -203,113 +215,231 @@ int git_attr_add_macro(
return error;
}
-bool git_attr_cache__is_cached(git_repository *repo, const char *path)
+bool git_attr_cache__is_cached(
+ git_repository *repo, git_attr_file_source source, const char *path)
{
- const char *cache_key = path;
+ git_buf cache_key = GIT_BUF_INIT;
git_strmap *files = git_repository_attr_cache(repo)->files;
+ const char *workdir = git_repository_workdir(repo);
+ bool rval;
+
+ if (workdir && git__prefixcmp(path, workdir) == 0)
+ path += strlen(workdir);
+ if (git_buf_printf(&cache_key, "%d#%s", (int)source, path) < 0)
+ return false;
+
+ rval = git_strmap_exists(files, git_buf_cstr(&cache_key));
+
+ git_buf_free(&cache_key);
+
+ return rval;
+}
+
+static int load_attr_file(const char *filename, const char **data)
+{
+ int error;
+ git_buf content = GIT_BUF_INIT;
+
+ error = git_futils_readbuffer(&content, filename);
+ *data = error ? NULL : git_buf_detach(&content);
+
+ return error;
+}
- if (repo && git__prefixcmp(cache_key, git_repository_workdir(repo)) == 0)
- cache_key += strlen(git_repository_workdir(repo));
+static int load_attr_blob_from_index(
+ git_repository *repo, const char *filename, git_blob **blob)
+{
+ int error;
+ git_index *index;
+ git_index_entry *entry;
+
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
+ (error = git_index_find(index, filename)) < 0)
+ return error;
- return git_strmap_exists(files, cache_key);
+ entry = git_index_get(index, error);
+
+ return git_blob_lookup(blob, repo, &entry->oid);
}
-int git_attr_cache__lookup_or_create_file(
+int git_attr_cache__internal_file(
git_repository *repo,
- const char *key,
const char *filename,
- int (*loader)(git_repository *, const char *, git_attr_file *),
- git_attr_file **file_ptr)
+ git_attr_file **file)
{
- int error;
+ int error = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_attr_file *file = NULL;
- khiter_t pos;
-
- pos = git_strmap_lookup_index(cache->files, key);
- if (git_strmap_valid_index(cache->files, pos)) {
- *file_ptr = git_strmap_value_at(cache->files, pos);
- return 0;
- }
+ khiter_t cache_pos = git_strmap_lookup_index(cache->files, filename);
- if (loader && git_path_exists(filename) == false) {
- *file_ptr = NULL;
+ if (git_strmap_valid_index(cache->files, cache_pos)) {
+ *file = git_strmap_value_at(cache->files, cache_pos);
return 0;
}
- if (git_attr_file__new(&file, &cache->pool) < 0)
+ if (git_attr_file__new(file, 0, filename, &cache->pool) < 0)
return -1;
- if (loader)
- error = loader(repo, filename, file);
- else
- error = git_attr_file__set_path(repo, key, file);
-
- if (!error) {
- git_strmap_insert(cache->files, file->path, file, error);
- if (error > 0)
- error = 0;
- }
-
- if (error < 0) {
- git_attr_file__free(file);
- file = NULL;
- }
+ git_strmap_insert(cache->files, (*file)->key + 2, *file, error);
+ if (error > 0)
+ error = 0;
- *file_ptr = file;
return error;
}
-/* add git_attr_file to vector of files, loading if needed */
int git_attr_cache__push_file(
git_repository *repo,
- git_vector *stack,
- const char *base,
- const char *filename,
- int (*loader)(git_repository *, const char *, git_attr_file *))
+ const char *base,
+ const char *filename,
+ git_attr_file_source source,
+ git_attr_file_parser parse,
+ git_vector *stack)
{
- int error;
+ int error = 0;
git_buf path = GIT_BUF_INIT;
+ const char *workdir = git_repository_workdir(repo);
+ const char *relfile, *content = NULL;
+ git_attr_cache *cache = git_repository_attr_cache(repo);
git_attr_file *file = NULL;
- const char *cache_key;
+ git_blob *blob = NULL;
- if (base != NULL) {
+ assert(filename && stack);
+
+ /* join base and path as needed */
+ if (base != NULL && git_path_root(filename) < 0) {
if (git_buf_joinpath(&path, base, filename) < 0)
return -1;
filename = path.ptr;
}
- /* either get attr_file from cache or read from disk */
- cache_key = filename;
- if (repo && git__prefixcmp(cache_key, git_repository_workdir(repo)) == 0)
- cache_key += strlen(git_repository_workdir(repo));
+ relfile = filename;
+ if (workdir && git__prefixcmp(relfile, workdir) == 0)
+ relfile += strlen(workdir);
+
+ /* check cache */
+ if (cache && cache->files) {
+ git_buf cache_key = GIT_BUF_INIT;
+ khiter_t cache_pos;
+
+ if (git_buf_printf(&cache_key, "%d#%s", (int)source, relfile) < 0)
+ return -1;
+
+ cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr);
+
+ git_buf_free(&cache_key);
+
+ if (git_strmap_valid_index(cache->files, cache_pos)) {
+ file = git_strmap_value_at(cache->files, cache_pos);
+ goto finish;
+ }
+ }
+
+ /* if not in cache, load data, parse, and cache */
+
+ if (source == GIT_ATTR_FILE_FROM_FILE)
+ error = load_attr_file(filename, &content);
+ else
+ error = load_attr_blob_from_index(repo, relfile, &blob);
+
+ if (error) {
+ /* not finding a file is not an error for this function */
+ if (error == GIT_ENOTFOUND) {
+ giterr_clear();
+ error = 0;
+ }
+ goto finish;
+ }
+
+ if (blob)
+ content = git_blob_rawcontent(blob);
- error = git_attr_cache__lookup_or_create_file(
- repo, cache_key, filename, loader, &file);
+ if ((error = git_attr_file__new(&file, source, relfile, &cache->pool)) < 0)
+ goto finish;
+ if (parse && (error = parse(repo, content, file)) < 0)
+ goto finish;
+
+ git_strmap_insert(cache->files, file->key, file, error);
+ if (error > 0)
+ error = 0;
+
+finish:
+ /* push file onto vector if we found one*/
if (!error && file != NULL)
error = git_vector_insert(stack, file);
+ if (error != 0)
+ git_attr_file__free(file);
+
+ if (blob)
+ git_blob_free(blob);
+ else
+ git__free((void *)content);
+
git_buf_free(&path);
+
return error;
}
-#define push_attrs(R,S,B,F) \
- git_attr_cache__push_file((R),(S),(B),(F),git_attr_file__from_file)
+#define push_attr_file(R,S,B,F) \
+ git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,git_attr_file__parse_buffer,(S))
typedef struct {
git_repository *repo;
+ uint32_t flags;
+ const char *workdir;
+ git_index *index;
git_vector *files;
} attr_walk_up_info;
+int git_attr_cache__decide_sources(
+ uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs)
+{
+ int count = 0;
+
+ switch (flags & 0x03) {
+ case GIT_ATTR_CHECK_FILE_THEN_INDEX:
+ if (has_wd)
+ srcs[count++] = GIT_ATTR_FILE_FROM_FILE;
+ if (has_index)
+ srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
+ break;
+ case GIT_ATTR_CHECK_INDEX_THEN_FILE:
+ if (has_index)
+ srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
+ if (has_wd)
+ srcs[count++] = GIT_ATTR_FILE_FROM_FILE;
+ break;
+ case GIT_ATTR_CHECK_INDEX_ONLY:
+ if (has_index)
+ srcs[count++] = GIT_ATTR_FILE_FROM_INDEX;
+ break;
+ }
+
+ return count;
+}
+
static int push_one_attr(void *ref, git_buf *path)
{
+ int error = 0, n_src, i;
attr_walk_up_info *info = (attr_walk_up_info *)ref;
- return push_attrs(info->repo, info->files, path->ptr, GIT_ATTR_FILE);
+ git_attr_file_source src[2];
+
+ n_src = git_attr_cache__decide_sources(
+ info->flags, info->workdir != NULL, info->index != NULL, src);
+
+ for (i = 0; !error && i < n_src; ++i)
+ error = git_attr_cache__push_file(
+ info->repo, path->ptr, GIT_ATTR_FILE, src[i],
+ git_attr_file__parse_buffer, info->files);
+
+ return error;
}
static int collect_attr_files(
- git_repository *repo, const char *path, git_vector *files)
+ git_repository *repo,
+ uint32_t flags,
+ const char *path,
+ git_vector *files)
{
int error;
git_buf dir = GIT_BUF_INIT;
@@ -320,7 +450,11 @@ static int collect_attr_files(
git_vector_init(files, 4, NULL) < 0)
return -1;
- error = git_path_find_dir(&dir, path, workdir);
+ /* given a unrooted path in a non-bare repo, resolve it */
+ if (workdir && git_path_root(path) < 0)
+ error = git_path_find_dir(&dir, path, workdir);
+ else
+ error = git_buf_sets(&dir, path);
if (error < 0)
goto cleanup;
@@ -331,29 +465,36 @@ static int collect_attr_files(
* - $GIT_PREFIX/etc/gitattributes
*/
- error = push_attrs(
+ error = push_attr_file(
repo, files, git_repository_path(repo), GIT_ATTR_FILE_INREPO);
if (error < 0)
goto cleanup;
- info.repo = repo;
+ info.repo = repo;
+ info.flags = flags;
+ info.workdir = workdir;
+ if (git_repository_index__weakptr(&info.index, repo) < 0)
+ giterr_clear(); /* no error even if there is no index */
info.files = files;
+
error = git_path_walk_up(&dir, workdir, push_one_attr, &info);
if (error < 0)
goto cleanup;
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
- error = push_attrs(
+ error = push_attr_file(
repo, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file);
if (error < 0)
goto cleanup;
}
- error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
- if (!error)
- error = push_attrs(repo, files, NULL, dir.ptr);
- else if (error == GIT_ENOTFOUND)
- error = 0;
+ if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
+ error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
+ if (!error)
+ error = push_attr_file(repo, files, NULL, dir.ptr);
+ else if (error == GIT_ENOTFOUND)
+ error = 0;
+ }
cleanup:
if (error < 0)
diff --git a/src/attr.h b/src/attr.h
index 43caf1b81..a35b1160f 100644
--- a/src/attr.h
+++ b/src/attr.h
@@ -22,6 +22,9 @@ typedef struct {
const char *cfg_excl_file; /* cached value of core.excludesfile */
} git_attr_cache;
+typedef int (*git_attr_file_parser)(
+ git_repository *, const char *, git_attr_file *);
+
extern int git_attr_cache__init(git_repository *repo);
extern int git_attr_cache__insert_macro(
@@ -30,21 +33,24 @@ extern int git_attr_cache__insert_macro(
extern git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name);
-extern int git_attr_cache__lookup_or_create_file(
+extern int git_attr_cache__push_file(
git_repository *repo,
- const char *key,
+ const char *base,
const char *filename,
- int (*loader)(git_repository *, const char *, git_attr_file *),
- git_attr_file **file_ptr);
+ git_attr_file_source source,
+ git_attr_file_parser parse,
+ git_vector *stack);
-extern int git_attr_cache__push_file(
+extern int git_attr_cache__internal_file(
git_repository *repo,
- git_vector *stack,
- const char *base,
- const char *filename,
- int (*loader)(git_repository *, const char *, git_attr_file *));
+ 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, const char *path);
+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
diff --git a/src/attr_file.c b/src/attr_file.c
index 25c21b1fd..ab320a6c4 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -1,15 +1,22 @@
#include "common.h"
#include "repository.h"
#include "filebuf.h"
+#include "git2/blob.h"
+#include "git2/tree.h"
#include <ctype.h>
const char *git_attr__true = "[internal]__TRUE__";
const char *git_attr__false = "[internal]__FALSE__";
+const char *git_attr__unset = "[internal]__UNSET__";
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
static void git_attr_rule__clear(git_attr_rule *rule);
-int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool)
+int git_attr_file__new(
+ git_attr_file **attrs_ptr,
+ git_attr_file_source from,
+ const char *path,
+ git_pool *pool)
{
git_attr_file *attrs = NULL;
@@ -25,6 +32,18 @@ int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool)
attrs->pool_is_allocated = true;
}
+ if (path) {
+ size_t len = strlen(path);
+
+ attrs->key = git_pool_malloc(attrs->pool, len + 3);
+ GITERR_CHECK_ALLOC(attrs->key);
+
+ attrs->key[0] = '0' + from;
+ attrs->key[1] = '#';
+ memcpy(&attrs->key[2], path, len);
+ attrs->key[len + 2] = '\0';
+ }
+
if (git_vector_init(&attrs->rules, 4, NULL) < 0)
goto fail;
@@ -37,31 +56,7 @@ fail:
return -1;
}
-int git_attr_file__set_path(
- git_repository *repo, const char *path, git_attr_file *file)
-{
- if (file->path != NULL) {
- git__free(file->path);
- file->path = NULL;
- }
-
- if (repo == NULL)
- file->path = git__strdup(path);
- else {
- const char *workdir = git_repository_workdir(repo);
-
- if (workdir && git__prefixcmp(path, workdir) == 0)
- file->path = git__strdup(path + strlen(workdir));
- else
- file->path = git__strdup(path);
- }
-
- GITERR_CHECK_ALLOC(file->path);
-
- return 0;
-}
-
-int git_attr_file__from_buffer(
+int git_attr_file__parse_buffer(
git_repository *repo, const char *buffer, git_attr_file *attrs)
{
int error = 0;
@@ -73,10 +68,10 @@ int git_attr_file__from_buffer(
scan = buffer;
- if (attrs->path && git__suffixcmp(attrs->path, GIT_ATTR_FILE) == 0) {
- context = git__strndup(attrs->path,
- strlen(attrs->path) - strlen(GIT_ATTR_FILE));
- GITERR_CHECK_ALLOC(context);
+ /* if subdir file path, convert context for file paths */
+ if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) {
+ context = attrs->key + 2;
+ context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0';
}
while (!error && *scan) {
@@ -112,28 +107,34 @@ int git_attr_file__from_buffer(
}
git_attr_rule__free(rule);
- git__free(context);
+
+ /* restore file path used for context */
+ if (context)
+ context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
return error;
}
-int git_attr_file__from_file(
- git_repository *repo, const char *path, git_attr_file *file)
+int git_attr_file__new_and_load(
+ git_attr_file **attrs_ptr,
+ const char *path)
{
int error;
- git_buf fbuf = GIT_BUF_INIT;
+ git_buf content = GIT_BUF_INIT;
- assert(path && file);
+ if ((error = git_attr_file__new(attrs_ptr, 0, path, NULL)) < 0)
+ return error;
- if (file->path == NULL && git_attr_file__set_path(repo, path, file) < 0)
- return -1;
-
- if (git_futils_readbuffer(&fbuf, path) < 0)
- return -1;
+ if (!(error = git_futils_readbuffer(&content, path)))
+ error = git_attr_file__parse_buffer(
+ NULL, git_buf_cstr(&content), *attrs_ptr);
- error = git_attr_file__from_buffer(repo, fbuf.ptr, file);
+ git_buf_free(&content);
- git_buf_free(&fbuf);
+ if (error) {
+ git_attr_file__free(*attrs_ptr);
+ *attrs_ptr = NULL;
+ }
return error;
}
@@ -151,9 +152,6 @@ void git_attr_file__free(git_attr_file *file)
git_vector_free(&file->rules);
- git__free(file->path);
- file->path = NULL;
-
if (file->pool_is_allocated) {
git_pool_clear(file->pool);
git__free(file->pool);
@@ -504,7 +502,7 @@ int git_attr_assignment__parse(
assign->value = git_attr__false;
scan++;
} else if (*scan == '!') {
- assign->value = NULL; /* explicit unspecified state */
+ assign->value = git_attr__unset; /* explicit unspecified state */
scan++;
} else if (*scan == '#') /* comment rest of line */
break;
diff --git a/src/attr_file.h b/src/attr_file.h
index 10851bc49..ec488c4dc 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -48,7 +48,7 @@ typedef struct {
} git_attr_assignment;
typedef struct {
- char *path; /* cache the path this was loaded from */
+ char *key; /* cache "source#path" this was loaded from */
git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool *pool;
bool pool_is_allocated;
@@ -61,20 +61,25 @@ typedef struct {
int is_dir;
} 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
*/
-extern int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool);
+extern int git_attr_file__new(
+ git_attr_file **attrs_ptr, git_attr_file_source src, const char *path, git_pool *pool);
+
+extern int git_attr_file__new_and_load(
+ git_attr_file **attrs_ptr, const char *path);
+
extern void git_attr_file__free(git_attr_file *file);
-extern int git_attr_file__from_buffer(
+extern int git_attr_file__parse_buffer(
git_repository *repo, const char *buf, git_attr_file *file);
-extern int git_attr_file__from_file(
- git_repository *repo, const char *path, git_attr_file *file);
-
-extern int git_attr_file__set_path(
- git_repository *repo, const char *path, git_attr_file *file);
extern int git_attr_file__lookup_one(
git_attr_file *file,
diff --git a/src/config_file.c b/src/config_file.c
index ed5caf980..746d9655c 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -265,6 +265,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
cvar_free(old_var);
if (config_write(b, key, NULL, value) < 0) {
+ git_strmap_delete(b->values, var->key);
cvar_free(var);
return -1;
}
diff --git a/src/crlf.c b/src/crlf.c
index b495d2de0..5d09a1f40 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -82,7 +82,8 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con
const char *attr_vals[NUM_CONV_ATTRS];
int error;
- error = git_attr_get_many(repo, path, NUM_CONV_ATTRS, attr_names, attr_vals);
+ error = git_attr_get_many(
+ repo, 0, path, NUM_CONV_ATTRS, attr_names, attr_vals);
if (error == GIT_ENOTFOUND) {
ca->crlf_action = GIT_CRLF_GUESS;
diff --git a/src/diff.c b/src/diff.c
index b845f9e8c..524cc9f59 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -506,7 +506,7 @@ static int diff_from_iterators(
git_diff_list **diff_ptr)
{
const git_index_entry *oitem, *nitem;
- char *ignore_prefix = NULL;
+ git_buf ignore_prefix = GIT_BUF_INIT;
git_diff_list *diff = git_diff_list_alloc(repo, opts);
if (!diff)
goto fail;
@@ -536,8 +536,8 @@ static int diff_from_iterators(
git_delta_t delta_type = GIT_DELTA_ADDED;
/* contained in ignored parent directory, so this can be skipped. */
- if (ignore_prefix != NULL &&
- git__prefixcmp(nitem->path, ignore_prefix) == 0)
+ if (git_buf_len(&ignore_prefix) &&
+ git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
{
if (git_iterator_advance(new_iter, &nitem) < 0)
goto fail;
@@ -555,7 +555,7 @@ static int diff_from_iterators(
(oitem && git__prefixcmp(oitem->path, nitem->path) == 0))
{
if (is_ignored)
- ignore_prefix = nitem->path;
+ git_buf_sets(&ignore_prefix, nitem->path);
if (git_iterator_advance_into_directory(new_iter, &nitem) < 0)
goto fail;
@@ -589,12 +589,16 @@ static int diff_from_iterators(
git_iterator_free(old_iter);
git_iterator_free(new_iter);
+ git_buf_free(&ignore_prefix);
+
*diff_ptr = diff;
return 0;
fail:
git_iterator_free(old_iter);
git_iterator_free(new_iter);
+ git_buf_free(&ignore_prefix);
+
git_diff_list_free(diff);
*diff_ptr = NULL;
return -1;
diff --git a/src/diff_output.c b/src/diff_output.c
index ca28fd01e..c380db996 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -103,7 +103,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file)
{
const char *value;
- if (git_attr_get(repo, file->path, "diff", &value) < 0)
+ if (git_attr_get(repo, 0, file->path, "diff", &value) < 0)
return -1;
if (GIT_ATTR_FALSE(value))
diff --git a/src/ignore.c b/src/ignore.c
index 20b96c602..fc6194bb5 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -5,29 +5,22 @@
#define GIT_IGNORE_FILE_INREPO "info/exclude"
#define GIT_IGNORE_FILE ".gitignore"
-static int load_ignore_file(
- git_repository *repo, const char *path, git_attr_file *ignores)
+static int parse_ignore_file(
+ git_repository *repo, const char *buffer, git_attr_file *ignores)
{
- int error;
- git_buf fbuf = GIT_BUF_INIT;
+ int error = 0;
git_attr_fnmatch *match = NULL;
const char *scan = NULL;
char *context = NULL;
- if (ignores->path == NULL) {
- if (git_attr_file__set_path(repo, path, ignores) < 0)
- return -1;
- }
+ GIT_UNUSED(repo);
- if (git__suffixcmp(ignores->path, GIT_IGNORE_FILE) == 0) {
- context = git__strndup(ignores->path,
- strlen(ignores->path) - strlen(GIT_IGNORE_FILE));
- GITERR_CHECK_ALLOC(context);
+ if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
+ context = ignores->key + 2;
+ context[strlen(context) - strlen(GIT_IGNORE_FILE)] = '\0';
}
- error = git_futils_readbuffer(&fbuf, path);
-
- scan = fbuf.ptr;
+ scan = buffer;
while (!error && *scan) {
if (!match) {
@@ -54,23 +47,27 @@ static int load_ignore_file(
}
}
- git_buf_free(&fbuf);
git__free(match);
- git__free(context);
+ /* restore file path used for context */
+ if (context)
+ context[strlen(context)] = '.'; /* first char of GIT_IGNORE_FILE */
return error;
}
-#define push_ignore(R,S,B,F) \
- git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file)
+#define push_ignore_file(R,S,B,F) \
+ git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,parse_ignore_file,(S))
static int push_one_ignore(void *ref, git_buf *path)
{
git_ignores *ign = (git_ignores *)ref;
- return push_ignore(ign->repo, &ign->ign_path, path->ptr, GIT_IGNORE_FILE);
+ return push_ignore_file(ign->repo, &ign->ign_path, path->ptr, GIT_IGNORE_FILE);
}
-int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ignores)
+int git_ignore__for_path(
+ git_repository *repo,
+ const char *path,
+ git_ignores *ignores)
{
int error = 0;
const char *workdir = git_repository_workdir(repo);
@@ -86,30 +83,37 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ig
(error = git_attr_cache__init(repo)) < 0)
goto cleanup;
- /* translate path into directory within workdir */
- if ((error = git_path_find_dir(&ignores->dir, path, workdir)) < 0)
+ /* given a unrooted path in a non-bare repo, resolve it */
+ if (workdir && git_path_root(path) < 0)
+ error = git_path_find_dir(&ignores->dir, path, workdir);
+ else
+ error = git_buf_sets(&ignores->dir, path);
+ if (error < 0)
goto cleanup;
/* set up internals */
- error = git_attr_cache__lookup_or_create_file(
- repo, GIT_IGNORE_INTERNAL, NULL, NULL, &ignores->ign_internal);
+ error = git_attr_cache__internal_file(
+ repo, GIT_IGNORE_INTERNAL, &ignores->ign_internal);
if (error < 0)
goto cleanup;
/* load .gitignore up the path */
- error = git_path_walk_up(&ignores->dir, workdir, push_one_ignore, ignores);
- if (error < 0)
- goto cleanup;
+ if (workdir != NULL) {
+ error = git_path_walk_up(
+ &ignores->dir, workdir, push_one_ignore, ignores);
+ if (error < 0)
+ goto cleanup;
+ }
/* load .git/info/exclude */
- error = push_ignore(repo, &ignores->ign_global,
+ error = push_ignore_file(repo, &ignores->ign_global,
git_repository_path(repo), GIT_IGNORE_FILE_INREPO);
if (error < 0)
goto cleanup;
/* load core.excludesfile */
if (git_repository_attr_cache(repo)->cfg_excl_file != NULL)
- error = push_ignore(repo, &ignores->ign_global, NULL,
+ error = push_ignore_file(repo, &ignores->ign_global, NULL,
git_repository_attr_cache(repo)->cfg_excl_file);
cleanup:
@@ -124,7 +128,7 @@ int git_ignore__push_dir(git_ignores *ign, const char *dir)
if (git_buf_joinpath(&ign->dir, ign->dir.ptr, dir) < 0)
return -1;
else
- return push_ignore(
+ return push_ignore_file(
ign->repo, &ign->ign_path, ign->dir.ptr, GIT_IGNORE_FILE);
}
@@ -132,7 +136,7 @@ int git_ignore__pop_dir(git_ignores *ign)
{
if (ign->ign_path.length > 0) {
git_attr_file *file = git_vector_last(&ign->ign_path);
- if (git__suffixcmp(ign->dir.ptr, file->path) == 0)
+ if (git__suffixcmp(ign->dir.ptr, file->key + 2) == 0)
git_vector_pop(&ign->ign_path);
git_buf_rtruncate_at_char(&ign->dir, '/');
}
@@ -163,7 +167,8 @@ static bool ignore_lookup_in_rules(
return false;
}
-int git_ignore__lookup(git_ignores *ignores, const char *pathname, int *ignored)
+int git_ignore__lookup(
+ git_ignores *ignores, const char *pathname, int *ignored)
{
unsigned int i;
git_attr_file *file;
diff --git a/src/ignore.h b/src/ignore.h
index 49f72bf25..809d2edbd 100644
--- a/src/ignore.h
+++ b/src/ignore.h
@@ -25,13 +25,14 @@ typedef struct {
git_vector ign_global;
} git_ignores;
-extern int git_ignore__for_path(
- git_repository *repo, const char *path, git_ignores *ign);
+extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
extern int git_ignore__push_dir(git_ignores *ign, const char *dir);
+
extern int git_ignore__pop_dir(git_ignores *ign);
extern void git_ignore__free(git_ignores *ign);
+
extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored);
#endif
diff --git a/src/object.c b/src/object.c
index 8e8eac4e3..e02bd69ba 100644
--- a/src/object.c
+++ b/src/object.c
@@ -146,7 +146,7 @@ int git_object_lookup_prefix(
}
if (error < 0)
- return -1;
+ return error;
if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
git_odb_object_free(odb_obj);
@@ -292,3 +292,42 @@ size_t git_object__size(git_otype type)
return git_objects_table[type].size;
}
+int git_object__resolve_to_type(git_object **obj, git_otype type)
+{
+ int error = 0;
+ git_object *scan, *next;
+
+ if (type == GIT_OBJ_ANY)
+ return 0;
+
+ scan = *obj;
+
+ while (!error && scan && git_object_type(scan) != type) {
+
+ switch (git_object_type(scan)) {
+ case GIT_OBJ_COMMIT:
+ {
+ git_tree *tree = NULL;
+ error = git_commit_tree(&tree, (git_commit *)scan);
+ next = (git_object *)tree;
+ break;
+ }
+
+ case GIT_OBJ_TAG:
+ error = git_tag_target(&next, (git_tag *)scan);
+ break;
+
+ default:
+ giterr_set(GITERR_REFERENCE, "Object does not resolve to type");
+ error = -1;
+ next = NULL;
+ break;
+ }
+
+ git_object_free(scan);
+ scan = next;
+ }
+
+ *obj = scan;
+ return error;
+}
diff --git a/src/odb.c b/src/odb.c
index 2538b8a77..934b317ed 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -589,7 +589,7 @@ int git_odb_read_prefix(
}
if (found == 0)
- return git_odb__error_notfound("no match for prefix");
+ return git_odb__error_notfound("no match for prefix", short_id);
if (found > 1)
return git_odb__error_ambiguous("multiple matches for prefix");
@@ -684,9 +684,15 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi
return error;
}
-int git_odb__error_notfound(const char *message)
+int git_odb__error_notfound(const char *message, const git_oid *oid)
{
- giterr_set(GITERR_ODB, "Object not found - %s", message);
+ if (oid != NULL) {
+ char oid_str[GIT_OID_HEXSZ + 1];
+ git_oid_tostr(oid_str, sizeof(oid_str), oid);
+ giterr_set(GITERR_ODB, "Object not found - %s (%s)", message, oid_str);
+ } else
+ giterr_set(GITERR_ODB, "Object not found - %s", message);
+
return GIT_ENOTFOUND;
}
diff --git a/src/odb.h b/src/odb.h
index 4c425c007..263e4c30b 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -70,7 +70,7 @@ int git_odb__hashlink(git_oid *out, const char *path);
/*
* Generate a GIT_ENOTFOUND error for the ODB.
*/
-int git_odb__error_notfound(const char *message);
+int git_odb__error_notfound(const char *message, const git_oid *oid);
/*
* Generate a GIT_EAMBIGUOUS error for the ODB.
diff --git a/src/odb_loose.c b/src/odb_loose.c
index d028deca5..989b03ab2 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -528,7 +528,7 @@ static int locate_object_short_oid(
/* Check that directory exists */
if (git_path_isdir(object_location->ptr) == false)
- return git_odb__error_notfound("failed to locate from short oid");
+ return git_odb__error_notfound("no matching loose object for prefix", short_oid);
state.dir_len = git_buf_len(object_location);
state.short_oid_len = len;
@@ -541,7 +541,7 @@ static int locate_object_short_oid(
return error;
if (!state.found)
- return git_odb__error_notfound("failed to locate from short oid");
+ return git_odb__error_notfound("no matching loose object for prefix", short_oid);
/* Convert obtained hex formatted oid to raw */
error = git_oid_fromstr(res_oid, (char *)state.res_oid);
@@ -590,7 +590,7 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_
raw.type = GIT_OBJ_BAD;
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
- error = git_odb__error_notfound("in loose backend");
+ error = git_odb__error_notfound("no matching loose object", oid);
else if ((error = read_header_loose(&raw, &object_path)) == 0) {
*len_p = raw.len;
*type_p = raw.type;
@@ -610,7 +610,7 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p
assert(backend && oid);
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
- error = git_odb__error_notfound("in loose backend");
+ error = git_odb__error_notfound("no matching loose object", oid);
else if ((error = read_loose(&raw, &object_path)) == 0) {
*buffer_p = raw.data;
*len_p = raw.len;
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 242200b4a..458f288d9 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -242,7 +242,7 @@ static int packfile_refresh_all(struct pack_backend *backend)
return 0;
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
- return git_odb__error_notfound("failed to refresh packfiles");
+ return git_odb__error_notfound("failed to refresh packfiles", NULL);
if (st.st_mtime != backend->pack_folder_mtime) {
git_buf path = GIT_BUF_INIT;
@@ -288,7 +288,7 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
}
}
- return git_odb__error_notfound("failed to find pack entry");
+ return git_odb__error_notfound("failed to find pack entry", oid);
}
static int pack_entry_find_prefix(
@@ -330,7 +330,7 @@ static int pack_entry_find_prefix(
}
if (!found)
- return git_odb__error_notfound("failed to find pack entry");
+ return git_odb__error_notfound("no matching pack entry for prefix", short_oid);
else if (found > 1)
return git_odb__error_ambiguous("found multiple pack entries");
else
diff --git a/src/pack.c b/src/pack.c
index 8d71138a2..4a6bc6ae8 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -375,6 +375,18 @@ int git_packfile_unpack(
return error;
}
+static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size)
+{
+ GIT_UNUSED(opaq);
+ return git__calloc(count, size);
+}
+
+static void use_git_free(void *opaq, void *ptr)
+{
+ GIT_UNUSED(opaq);
+ git__free(ptr);
+}
+
int packfile_unpack_compressed(
git_rawobj *obj,
struct git_pack_file *p,
@@ -393,6 +405,8 @@ int packfile_unpack_compressed(
memset(&stream, 0, sizeof(stream));
stream.next_out = buffer;
stream.avail_out = (uInt)size + 1;
+ stream.zalloc = use_git_alloc;
+ stream.zfree = use_git_free;
st = inflateInit(&stream);
if (st != Z_OK) {
@@ -541,7 +555,7 @@ static int packfile_open(struct git_pack_file *p)
assert(p->index_map.data);
if (!p->index_map.data && pack_index_open(p) < 0)
- return git_odb__error_notfound("failed to open packfile");
+ return git_odb__error_notfound("failed to open packfile", NULL);
/* TODO: open with noatime */
p->mwf.fd = git_futils_open_ro(p->pack_name);
@@ -615,7 +629,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
path_len -= strlen(".idx");
if (path_len < 1) {
git__free(p);
- return git_odb__error_notfound("invalid packfile path");
+ return git_odb__error_notfound("invalid packfile path", NULL);
}
memcpy(p->pack_name, path, path_len);
@@ -627,7 +641,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
strcpy(p->pack_name + path_len, ".pack");
if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) {
git__free(p);
- return git_odb__error_notfound("packfile not found");
+ return git_odb__error_notfound("packfile not found", NULL);
}
/* ok, it looks sane as far as we can check without
@@ -733,9 +747,8 @@ static int pack_entry_find_offset(
if (pos < (int)p->num_objects) {
current = index + pos * stride;
- if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) {
+ if (!git_oid_ncmp(short_oid, (const git_oid *)current, len))
found = 1;
- }
}
}
@@ -749,7 +762,7 @@ static int pack_entry_find_offset(
}
if (!found)
- return git_odb__error_notfound("failed to find offset for pack entry");
+ return git_odb__error_notfound("failed to find offset for pack entry", short_oid);
if (found > 1)
return git_odb__error_ambiguous("found multiple offsets for pack entry");
*offset_out = nth_packed_object_offset(p, pos);
diff --git a/src/repository.c b/src/repository.c
index cfabee420..d4de38104 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -862,3 +862,23 @@ int git_repository_is_bare(git_repository *repo)
assert(repo);
return repo->is_bare;
}
+
+int git_repository_head_tree(git_tree **tree, git_repository *repo)
+{
+ git_oid head_oid;
+ git_object *obj = NULL;
+
+ if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) {
+ /* cannot resolve HEAD - probably brand new repo */
+ giterr_clear();
+ *tree = NULL;
+ return 0;
+ }
+
+ if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0 ||
+ git_object__resolve_to_type(&obj, GIT_OBJ_TREE) < 0)
+ return -1;
+
+ *tree = (git_tree *)obj;
+ return 0;
+}
diff --git a/src/repository.h b/src/repository.h
index 1ffac58f1..91c69a655 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -98,6 +98,8 @@ struct git_repository {
* export */
void git_object__free(void *object);
+int git_object__resolve_to_type(git_object **obj, git_otype type);
+
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
@@ -106,6 +108,8 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
return &repo->attrcache;
}
+int git_repository_head_tree(git_tree **tree, git_repository *repo);
+
/*
* Weak pointers to repository internals.
*
diff --git a/src/status.c b/src/status.c
index 356cbeb98..ff8535c66 100644
--- a/src/status.c
+++ b/src/status.c
@@ -18,41 +18,6 @@
#include "git2/diff.h"
#include "diff.h"
-static int resolve_head_to_tree(git_tree **tree, git_repository *repo)
-{
- git_oid head_oid;
- git_object *obj = NULL;
-
- if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) {
- /* cannot resolve HEAD - probably brand new repo */
- giterr_clear();
- *tree = NULL;
- return 0;
- }
-
- if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0)
- goto fail;
-
- switch (git_object_type(obj)) {
- case GIT_OBJ_TREE:
- *tree = (git_tree *)obj;
- break;
- case GIT_OBJ_COMMIT:
- if (git_commit_tree(tree, (git_commit *)obj) < 0)
- goto fail;
- git_object_free(obj);
- break;
- default:
- goto fail;
- }
-
- return 0;
-
-fail:
- git_object_free(obj);
- return -1;
-}
-
static unsigned int index_delta2status(git_delta_t index_status)
{
unsigned int st = GIT_STATUS_CURRENT;
@@ -120,11 +85,8 @@ int git_status_foreach_ext(
assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR);
- switch (resolve_head_to_tree(&head, repo)) {
- case 0: break;
- case GIT_ENOTFOUND: return 0;
- default: return -1;
- }
+ if ((err = git_repository_head_tree(&head, repo)) < 0)
+ return err;
memset(&diffopt, 0, sizeof(diffopt));
memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
@@ -405,7 +367,7 @@ int git_status_file(
status_entry_update_from_index(e, index);
/* Try to find file in HEAD */
- if ((error = resolve_head_to_tree(&tree, repo)) < 0)
+ if ((error = git_repository_head_tree(&tree, repo)) < 0)
goto cleanup;
if (tree != NULL) {
diff --git a/src/strmap.h b/src/strmap.h
index 55fbd7c6e..da5ca0dba 100644
--- a/src/strmap.h
+++ b/src/strmap.h
@@ -36,18 +36,28 @@ typedef khash_t(str) git_strmap;
#define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v
#define git_strmap_delete_at(h, idx) kh_del(str, h, idx)
-#define git_strmap_insert(h, key, val, err) do { \
- khiter_t __pos = kh_put(str, h, key, &err); \
- if (err >= 0) kh_val(h, __pos) = val; \
- } while (0)
-
-#define git_strmap_insert2(h, key, val, old, err) do { \
- khiter_t __pos = kh_put(str, h, key, &err); \
- if (err >= 0) { \
- old = (err == 0) ? kh_val(h, __pos) : NULL; \
+#define git_strmap_insert(h, key, val, rval) do { \
+ khiter_t __pos = kh_put(str, h, key, &rval); \
+ if (rval >= 0) { \
+ if (rval == 0) kh_key(h, __pos) = key; \
kh_val(h, __pos) = val; \
} } while (0)
+#define git_strmap_insert2(h, key, val, oldv, rval) do { \
+ khiter_t __pos = kh_put(str, h, key, &rval); \
+ if (rval >= 0) { \
+ if (rval == 0) { \
+ oldv = kh_val(h, __pos); \
+ kh_key(h, __pos) = key; \
+ } else { oldv = NULL; } \
+ kh_val(h, __pos) = val; \
+ } } while (0)
+
+#define git_strmap_delete(h, key) do { \
+ khiter_t __pos = git_strmap_lookup_index(h, key); \
+ if (git_strmap_valid_index(h, __pos)) \
+ git_strmap_delete_at(h, __pos); } while (0)
+
#define git_strmap_foreach kh_foreach
#define git_strmap_foreach_value kh_foreach_value
diff --git a/tests-clar/attr/file.c b/tests-clar/attr/file.c
index 4e1010230..d19708838 100644
--- a/tests-clar/attr/file.c
+++ b/tests-clar/attr/file.c
@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void)
git_attr_assignment *assign;
git_attr_rule *rule;
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
+
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
cl_assert(file->rules.length == 1);
rule = get_rule(0);
@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
+
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
cl_assert(file->rules.length == 10);
/* let's do a thorough check of this rule, then just verify
@@ -123,9 +123,9 @@ void test_attr_file__assign_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
- cl_assert_equal_s(cl_fixture("attr/attr2"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
+
+ cl_assert_equal_s(cl_fixture("attr/attr2"), file->key + 2);
cl_assert(file->rules.length == 11);
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
@@ -189,9 +189,8 @@ void test_attr_file__check_attr_examples(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
- cl_assert_equal_s(cl_fixture("attr/attr3"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
+ cl_assert_equal_s(cl_fixture("attr/attr3"), file->key + 2);
cl_assert(file->rules.length == 3);
rule = get_rule(0);
@@ -214,7 +213,7 @@ void test_attr_file__check_attr_examples(void)
cl_assert(rule->assigns.length == 1);
assign = get_assign(rule, 0);
cl_assert_equal_s("myAttr", assign->name);
- cl_assert(assign->value == NULL);
+ cl_assert(GIT_ATTR_UNSPECIFIED(assign->value));
rule = get_rule(2);
cl_assert_equal_s("README", rule->match.pattern);
diff --git a/tests-clar/attr/flags.c b/tests-clar/attr/flags.c
new file mode 100644
index 000000000..5081de8b2
--- /dev/null
+++ b/tests-clar/attr/flags.c
@@ -0,0 +1,108 @@
+#include "clar_libgit2.h"
+#include "git2/attr.h"
+
+void test_attr_flags__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_attr_flags__bare(void)
+{
+ git_repository *repo = cl_git_sandbox_init("testrepo.git");
+ const char *value;
+
+ cl_assert(git_repository_is_bare(repo));
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff", &value));
+ cl_assert(GIT_ATTR_UNSPECIFIED(value));
+}
+
+void test_attr_flags__index_vs_workdir(void)
+{
+ git_repository *repo = cl_git_sandbox_init("attr_index");
+ const char *value;
+
+ cl_assert(!git_repository_is_bare(repo));
+
+ /* wd then index */
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "README.md", "bar", &value));
+ cl_assert(GIT_ATTR_FALSE(value));
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "README.md", "blargh", &value));
+ cl_assert_equal_s(value, "goop");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "README.txt", "foo", &value));
+ cl_assert(GIT_ATTR_FALSE(value));
+
+ /* index then wd */
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "README.md", "bar", &value));
+ cl_assert(GIT_ATTR_TRUE(value));
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "README.md", "blargh", &value));
+ cl_assert_equal_s(value, "garble");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "README.txt", "foo", &value));
+ cl_assert(GIT_ATTR_TRUE(value));
+}
+
+void test_attr_flags__subdir(void)
+{
+ git_repository *repo = cl_git_sandbox_init("attr_index");
+ const char *value;
+
+ /* wd then index */
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "sub/sub/README.md", "bar", &value));
+ cl_assert_equal_s(value, "1234");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "sub/sub/README.txt", "another", &value));
+ cl_assert_equal_s(value, "one");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "sub/sub/README.txt", "again", &value));
+ cl_assert(GIT_ATTR_TRUE(value));
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
+ "sub/sub/README.txt", "beep", &value));
+ cl_assert_equal_s(value, "10");
+
+ /* index then wd */
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "sub/sub/README.md", "bar", &value));
+ cl_assert_equal_s(value, "1337");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "sub/sub/README.txt", "another", &value));
+ cl_assert_equal_s(value, "one");
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "sub/sub/README.txt", "again", &value));
+ cl_assert(GIT_ATTR_TRUE(value));
+
+ cl_git_pass(git_attr_get(
+ repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+ "sub/sub/README.txt", "beep", &value));
+ cl_assert_equal_s(value, "5");
+}
+
diff --git a/tests-clar/attr/lookup.c b/tests-clar/attr/lookup.c
index 81a4a55d3..b2a6aac64 100644
--- a/tests-clar/attr/lookup.c
+++ b/tests-clar/attr/lookup.c
@@ -9,9 +9,8 @@ void test_attr_lookup__simple(void)
git_attr_path path;
const char *value = NULL;
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL));
@@ -130,9 +129,8 @@ void test_attr_lookup__match_variants(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->path);
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
@@ -192,8 +190,7 @@ void test_attr_lookup__assign_variants(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
cl_assert(file->rules.length == 11);
run_test_cases(file, cases, 0);
@@ -228,8 +225,7 @@ void test_attr_lookup__check_attr_examples(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
+ cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0);
@@ -254,8 +250,10 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new(&file, NULL));
- cl_git_pass(git_attr_file__from_buffer(NULL, "a* foo\nabc bar\n* baz", file));
+ cl_git_pass(git_attr_file__new(&file, 0, NULL, NULL));
+
+ cl_git_pass(git_attr_file__parse_buffer(NULL, "a* foo\nabc bar\n* baz", file));
+
cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0);
diff --git a/tests-clar/attr/repo.c b/tests-clar/attr/repo.c
index 7423c3045..006a49081 100644
--- a/tests-clar/attr/repo.c
+++ b/tests-clar/attr/repo.c
@@ -64,13 +64,13 @@ void test_attr_repo__get_one(void)
for (scan = test_cases; scan->path != NULL; scan++) {
const char *value;
- cl_git_pass(git_attr_get(g_repo, scan->path, scan->attr, &value));
+ cl_git_pass(git_attr_get(g_repo, 0, scan->path, scan->attr, &value));
attr_check_expected(scan->expected, scan->expected_str, value);
}
- cl_assert(git_attr_cache__is_cached(g_repo, ".git/info/attributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, ".gitattributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, "sub/.gitattributes"));
+ cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes"));
+ cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes"));
+ cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes"));
}
void test_attr_repo__get_many(void)
@@ -78,21 +78,21 @@ void test_attr_repo__get_many(void)
const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
const char *values[4];
- cl_git_pass(git_attr_get_many(g_repo, "root_test1", 4, names, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "root_test1", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
- cl_git_pass(git_attr_get_many(g_repo, "root_test2", 4, names, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "root_test2", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_FALSE(values[1]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
- cl_git_pass(git_attr_get_many(g_repo, "sub/subdir_test1", 4, names, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "sub/subdir_test1", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1]));
@@ -118,16 +118,17 @@ void test_attr_repo__foreach(void)
int count;
count = 0;
- cl_git_pass(git_attr_foreach(g_repo, "root_test1", &count_attrs, &count));
+ cl_git_pass(git_attr_foreach(
+ g_repo, 0, "root_test1", &count_attrs, &count));
cl_assert(count == 2);
count = 0;
- cl_git_pass(git_attr_foreach(g_repo, "sub/subdir_test1",
+ cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test1",
&count_attrs, &count));
cl_assert(count == 4); /* repoattr, rootattr, subattr, negattr */
count = 0;
- cl_git_pass(git_attr_foreach(g_repo, "sub/subdir_test2.txt",
+ cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test2.txt",
&count_attrs, &count));
cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */
}
@@ -136,19 +137,19 @@ void test_attr_repo__manpage_example(void)
{
const char *value;
- cl_git_pass(git_attr_get(g_repo, "sub/abc", "foo", &value));
+ cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "foo", &value));
cl_assert(GIT_ATTR_TRUE(value));
- cl_git_pass(git_attr_get(g_repo, "sub/abc", "bar", &value));
+ cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "bar", &value));
cl_assert(GIT_ATTR_UNSPECIFIED(value));
- cl_git_pass(git_attr_get(g_repo, "sub/abc", "baz", &value));
+ cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "baz", &value));
cl_assert(GIT_ATTR_FALSE(value));
- cl_git_pass(git_attr_get(g_repo, "sub/abc", "merge", &value));
+ cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "merge", &value));
cl_assert_equal_s("filfre", value);
- cl_git_pass(git_attr_get(g_repo, "sub/abc", "frotz", &value));
+ cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "frotz", &value));
cl_assert(GIT_ATTR_UNSPECIFIED(value));
}
@@ -159,7 +160,7 @@ void test_attr_repo__macros(void)
const char *names3[3] = { "macro2", "multi2", "multi3" };
const char *values[5];
- cl_git_pass(git_attr_get_many(g_repo, "binfile", 5, names, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "binfile", 5, names, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1]));
@@ -167,7 +168,7 @@ void test_attr_repo__macros(void)
cl_assert(GIT_ATTR_FALSE(values[3]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[4]));
- cl_git_pass(git_attr_get_many(g_repo, "macro_test", 5, names2, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 5, names2, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1]));
@@ -175,7 +176,7 @@ void test_attr_repo__macros(void)
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
cl_assert_equal_s("77", values[4]);
- cl_git_pass(git_attr_get_many(g_repo, "macro_test", 3, names3, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 3, names3, values));
cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_FALSE(values[1]));
@@ -188,7 +189,7 @@ void test_attr_repo__bad_macros(void)
"firstmacro", "secondmacro", "thirdmacro" };
const char *values[6];
- cl_git_pass(git_attr_get_many(g_repo, "macro_bad", 6, names, values));
+ cl_git_pass(git_attr_get_many(g_repo, 0, "macro_bad", 6, names, values));
/* these three just confirm that the "mymacro" rule ran */
cl_assert(GIT_ATTR_UNSPECIFIED(values[0]));
diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c
index 1e269ae42..06f51a16b 100644
--- a/tests-clar/diff/tree.c
+++ b/tests-clar/diff/tree.c
@@ -5,7 +5,6 @@ static git_repository *g_repo = NULL;
void test_diff_tree__initialize(void)
{
- g_repo = cl_git_sandbox_init("attr");
}
void test_diff_tree__cleanup(void)
@@ -19,15 +18,16 @@ void test_diff_tree__0(void)
const char *a_commit = "605812a";
const char *b_commit = "370fe9ec22";
const char *c_commit = "f5b0af1fb4f5c";
- 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_tree *c = resolve_commit_oid_to_tree(g_repo, c_commit);
+ git_tree *a, *b, *c;
git_diff_options opts = {0};
git_diff_list *diff = NULL;
diff_expects exp;
- cl_assert(a);
- cl_assert(b);
+ g_repo = cl_git_sandbox_init("attr");
+
+ cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
+ cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
+ cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
opts.context_lines = 1;
opts.interhunk_lines = 1;
@@ -87,12 +87,7 @@ void test_diff_tree__options(void)
const char *b_commit = "605812ab7fe421fdd";
const char *c_commit = "f5b0af1fb4f5";
const char *d_commit = "a97cc019851";
-
- 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_tree *c = resolve_commit_oid_to_tree(g_repo, c_commit);
- git_tree *d = resolve_commit_oid_to_tree(g_repo, d_commit);
-
+ git_tree *a, *b, *c, *d;
git_diff_options opts = {0};
git_diff_list *diff = NULL;
diff_expects actual;
@@ -133,8 +128,12 @@ void test_diff_tree__options(void)
diff_expects *expected;
int i;
- cl_assert(a);
- cl_assert(b);
+ g_repo = cl_git_sandbox_init("attr");
+
+ cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
+ cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
+ cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
+ cl_assert((d = resolve_commit_oid_to_tree(g_repo, d_commit)) != NULL);
for (i = 0; test_expects[i].files > 0; i++) {
memset(&actual, 0, sizeof(actual)); /* clear accumulator */
@@ -168,3 +167,44 @@ void test_diff_tree__options(void)
git_tree_free(c);
git_tree_free(d);
}
+
+void test_diff_tree__bare(void)
+{
+ const char *a_commit = "8496071c1b46c85";
+ const char *b_commit = "be3563ae3f79";
+ git_tree *a, *b;
+ git_diff_options opts = {0};
+ git_diff_list *diff = NULL;
+ diff_expects exp;
+
+ g_repo = cl_git_sandbox_init("testrepo.git");
+
+ cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
+ cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
+
+ opts.context_lines = 1;
+ opts.interhunk_lines = 1;
+
+ memset(&exp, 0, sizeof(exp));
+
+ cl_git_pass(git_diff_tree_to_tree(g_repo, &opts, a, b, &diff));
+
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert(exp.files == 3);
+ cl_assert(exp.file_adds == 2);
+ cl_assert(exp.file_dels == 0);
+ cl_assert(exp.file_mods == 1);
+
+ cl_assert(exp.hunks == 3);
+
+ cl_assert(exp.lines == 4);
+ cl_assert(exp.line_ctxt == 0);
+ cl_assert(exp.line_adds == 3);
+ cl_assert(exp.line_dels == 1);
+
+ git_diff_list_free(diff);
+ git_tree_free(a);
+ git_tree_free(b);
+}
diff --git a/tests-clar/resources/attr_index/.gitted/HEAD b/tests-clar/resources/attr_index/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/attr_index/.gitted/config b/tests-clar/resources/attr_index/.gitted/config
new file mode 100644
index 000000000..af107929f
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/config
@@ -0,0 +1,6 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
diff --git a/tests-clar/resources/attr_index/.gitted/description b/tests-clar/resources/attr_index/.gitted/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/attr_index/.gitted/index b/tests-clar/resources/attr_index/.gitted/index
new file mode 100644
index 000000000..d87480332
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/attr_index/.gitted/info/exclude b/tests-clar/resources/attr_index/.gitted/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/attr_index/.gitted/info/refs b/tests-clar/resources/attr_index/.gitted/info/refs
new file mode 100644
index 000000000..60feca293
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/info/refs
@@ -0,0 +1 @@
+58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master
diff --git a/tests-clar/resources/attr_index/.gitted/logs/HEAD b/tests-clar/resources/attr_index/.gitted/logs/HEAD
new file mode 100644
index 000000000..ffd298c04
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/logs/HEAD
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817070 -0700 commit (initial): Initial commit
+67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer <rb@github.com> 1335817296 -0700 commit: Adding some files in subtrees
+d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817353 -0700 HEAD^: updating HEAD
+67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer <rb@github.com> 1335817372 -0700 commit: Adding subtree data
diff --git a/tests-clar/resources/attr_index/.gitted/logs/refs/heads/master b/tests-clar/resources/attr_index/.gitted/logs/refs/heads/master
new file mode 100644
index 000000000..ffd298c04
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/logs/refs/heads/master
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817070 -0700 commit (initial): Initial commit
+67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer <rb@github.com> 1335817296 -0700 commit: Adding some files in subtrees
+d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817353 -0700 HEAD^: updating HEAD
+67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer <rb@github.com> 1335817372 -0700 commit: Adding subtree data
diff --git a/tests-clar/resources/attr_index/.gitted/objects/38/12cfef36615db1788d4e63f90028007e17a348 b/tests-clar/resources/attr_index/.gitted/objects/38/12cfef36615db1788d4e63f90028007e17a348
new file mode 100644
index 000000000..ee2991571
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/38/12cfef36615db1788d4e63f90028007e17a348
@@ -0,0 +1,3 @@
+x[
+ E*@PJ
+]&`w 'oMKDq45DF#!!=VZD.L:%L}!dCg*qв-LUkz~6閷W}}>g˾{f% G \ No newline at end of file
diff --git a/tests-clar/resources/attr_index/.gitted/objects/59/d942b8be2784bc96db9b22202c10815c9a077b b/tests-clar/resources/attr_index/.gitted/objects/59/d942b8be2784bc96db9b22202c10815c9a077b
new file mode 100644
index 000000000..ff33737db
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/59/d942b8be2784bc96db9b22202c10815c9a077b
@@ -0,0 +1 @@
+x 0 @@kR@]<K4nY)l(ahFHcc^ \ No newline at end of file
diff --git a/tests-clar/resources/attr_index/.gitted/objects/cd/f17ea3fe625ef812f4dce7f423f4f299287505 b/tests-clar/resources/attr_index/.gitted/objects/cd/f17ea3fe625ef812f4dce7f423f4f299287505
new file mode 100644
index 000000000..2a410057e
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/cd/f17ea3fe625ef812f4dce7f423f4f299287505
Binary files differ
diff --git a/tests-clar/resources/attr_index/.gitted/objects/f7/2502ddd01412bb20796ff812af56fd53b82b52 b/tests-clar/resources/attr_index/.gitted/objects/f7/2502ddd01412bb20796ff812af56fd53b82b52
new file mode 100644
index 000000000..048928000
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/f7/2502ddd01412bb20796ff812af56fd53b82b52
Binary files differ
diff --git a/tests-clar/resources/attr_index/.gitted/objects/info/packs b/tests-clar/resources/attr_index/.gitted/objects/info/packs
new file mode 100644
index 000000000..559dc741c
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/info/packs
@@ -0,0 +1,2 @@
+P pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack
+
diff --git a/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.idx b/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.idx
new file mode 100644
index 000000000..fbef4aa1d
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.idx
Binary files differ
diff --git a/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack b/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack
new file mode 100644
index 000000000..09c9e06d9
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/objects/pack/pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack
Binary files differ
diff --git a/tests-clar/resources/attr_index/.gitted/packed-refs b/tests-clar/resources/attr_index/.gitted/packed-refs
new file mode 100644
index 000000000..6b3e4decf
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master
diff --git a/tests-clar/resources/attr_index/.gitted/refs/heads/master b/tests-clar/resources/attr_index/.gitted/refs/heads/master
new file mode 100644
index 000000000..9b7562931
--- /dev/null
+++ b/tests-clar/resources/attr_index/.gitted/refs/heads/master
@@ -0,0 +1 @@
+3812cfef36615db1788d4e63f90028007e17a348
diff --git a/tests-clar/resources/attr_index/README.md b/tests-clar/resources/attr_index/README.md
new file mode 100644
index 000000000..59d942b8b
--- /dev/null
+++ b/tests-clar/resources/attr_index/README.md
@@ -0,0 +1 @@
+This is contains tests for when the index and work dir differ
diff --git a/tests-clar/resources/attr_index/README.txt b/tests-clar/resources/attr_index/README.txt
new file mode 100644
index 000000000..874c12b79
--- /dev/null
+++ b/tests-clar/resources/attr_index/README.txt
@@ -0,0 +1 @@
+This contains files for testing when the index and the workdir differ
diff --git a/tests-clar/resources/attr_index/gitattributes b/tests-clar/resources/attr_index/gitattributes
new file mode 100644
index 000000000..cdf17ea3f
--- /dev/null
+++ b/tests-clar/resources/attr_index/gitattributes
@@ -0,0 +1,4 @@
+* bar
+*.txt -foo beep=10
+*.md blargh=goop -bar
+
diff --git a/tests-clar/resources/attr_index/sub/sub/.gitattributes b/tests-clar/resources/attr_index/sub/sub/.gitattributes
new file mode 100644
index 000000000..060c9a261
--- /dev/null
+++ b/tests-clar/resources/attr_index/sub/sub/.gitattributes
@@ -0,0 +1,3 @@
+*.txt another=one again
+*.md bar=1234
+
diff --git a/tests-clar/resources/attr_index/sub/sub/README.md b/tests-clar/resources/attr_index/sub/sub/README.md
new file mode 100644
index 000000000..59652e349
--- /dev/null
+++ b/tests-clar/resources/attr_index/sub/sub/README.md
@@ -0,0 +1 @@
+More testing
diff --git a/tests-clar/resources/attr_index/sub/sub/README.txt b/tests-clar/resources/attr_index/sub/sub/README.txt
new file mode 100644
index 000000000..59652e349
--- /dev/null
+++ b/tests-clar/resources/attr_index/sub/sub/README.txt
@@ -0,0 +1 @@
+More testing
diff --git a/tests-clar/status/ignore.c b/tests-clar/status/ignore.c
index 94f8c3de3..e92d6a577 100644
--- a/tests-clar/status/ignore.c
+++ b/tests-clar/status/ignore.c
@@ -47,8 +47,8 @@ void test_status_ignore__0(void)
}
/* confirm that ignore files were cached */
- cl_assert(git_attr_cache__is_cached(g_repo, ".git/info/exclude"));
- cl_assert(git_attr_cache__is_cached(g_repo, ".gitignore"));
+ cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude"));
+ cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore"));
}