Allow ignores (and attribs) for nonexistent files This fixes issue 532 that attributes (and gitignores) could not be checked for files that don't exist. It should be possible to query such things regardless of the existence of the file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
diff --git a/src/fileops.c b/src/fileops.c
index f481bb0..1d991b3 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -536,13 +536,25 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
int git_futils_dir_for_path(git_buf *dir, const char *path, const char *base)
{
- if (git_path_prettify(dir, path, base) == GIT_SUCCESS) {
- /* call dirname if this is not a directory */
- if (git_futils_isdir(dir->ptr) != GIT_SUCCESS)
- git_path_dirname_r(dir, dir->ptr);
+ int error = GIT_SUCCESS;
+
+ if (base != NULL && git_path_root(path) < 0)
+ error = git_buf_joinpath(dir, base, path);
+ else
+ error = git_buf_sets(dir, path);
- git_path_to_dir(dir);
+ if (error == GIT_SUCCESS) {
+ char buf[GIT_PATH_MAX];
+ if (p_realpath(dir->ptr, buf) != NULL)
+ error = git_buf_sets(dir, buf);
}
- return git_buf_lasterror(dir);
+ /* call dirname if this is not a directory */
+ if (error == GIT_SUCCESS && git_futils_isdir(dir->ptr) != GIT_SUCCESS)
+ error = git_path_dirname_r(dir, dir->ptr);
+
+ if (error == GIT_SUCCESS)
+ error = git_path_to_dir(dir);
+
+ return error;
}
diff --git a/src/fileops.h b/src/fileops.h
index f3f09ec..91903a7 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -104,8 +104,10 @@ extern int git_futils_rmdir_r(const char *path, int force);
/**
* Get the directory for a path.
*
- * If the path is a directory, this does nothing (save append a '/' as needed).
- * If path is a normal file, this gets the directory containing it.
+ * If the path is a directory, this does nothing (save append a '/' as
+ * needed). If path is a normal file, this gets the directory containing
+ * it. If the path does not exist, then this treats it a filename and
+ * returns the dirname of it.
*/
extern int git_futils_dir_for_path(git_buf *dir, const char *path, const char *base);
diff --git a/src/ignore.c b/src/ignore.c
index 8bf22e3..7639b7b 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -146,3 +146,17 @@ found:
return error;
}
+
+int git_ignore_is_ignored(git_repository *repo, const char *path, int *ignored)
+{
+ int error;
+ git_vector ignores = GIT_VECTOR_INIT;
+
+ if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
+ error = git_ignore__lookup(&ignores, path, ignored);
+
+ git_ignore__free(&ignores);
+
+ return error;
+}
+
diff --git a/src/ignore.h b/src/ignore.h
index 2954445..a6e6a1a 100644
--- a/src/ignore.h
+++ b/src/ignore.h
@@ -14,4 +14,6 @@ extern int git_ignore__for_path(git_repository *repo, const char *path, git_vect
extern void git_ignore__free(git_vector *stack);
extern int git_ignore__lookup(git_vector *stack, const char *path, int *ignored);
+extern int git_ignore_is_ignored(git_repository *repo, const char *path, int *ignored);
+
#endif
diff --git a/tests-clay/attr/repo.c b/tests-clay/attr/repo.c
index f87e7bf..3e9b9de 100644
--- a/tests-clay/attr/repo.c
+++ b/tests-clay/attr/repo.c
@@ -57,6 +57,7 @@ void test_attr_repo__get_one(void)
{ "subdir/subdir_test2.txt", "subattr", "yes" },
{ "subdir/subdir_test2.txt", "negattr", GIT_ATTR_FALSE },
{ "subdir/subdir_test2.txt", "another", "one" },
+ { "does-not-exist", "foo", "yes" },
{ NULL, NULL, NULL }
}, *scan;
diff --git a/tests-clay/status/worktree.c b/tests-clay/status/worktree.c
index 15cbb28..af6f005 100644
--- a/tests-clay/status/worktree.c
+++ b/tests-clay/status/worktree.c
@@ -1,5 +1,6 @@
#include "clay_libgit2.h"
#include "fileops.h"
+#include "ignore.h"
#include "status_data.h"
@@ -135,3 +136,19 @@ void test_status_worktree__single_file(void)
cl_assert(entry_statuses0[i] == status_flags);
}
}
+
+void test_status_worktree__ignores(void)
+{
+ int i, ignored;
+
+ for (i = 0; i < (int)entry_count0; i++) {
+ cl_git_pass(git_ignore_is_ignored(_repository, entry_paths0[i], &ignored));
+ cl_assert(ignored == (entry_statuses0[i] == GIT_STATUS_IGNORED));
+ }
+
+ cl_git_pass(git_ignore_is_ignored(_repository, "nonexistent_file", &ignored));
+ cl_assert(!ignored);
+
+ cl_git_pass(git_ignore_is_ignored(_repository, "ignored_nonexistent_file", &ignored));
+ cl_assert(ignored);
+}
diff --git a/tests/resources/attr/gitattributes b/tests/resources/attr/gitattributes
index 2b40c5a..c0c2a56 100644
--- a/tests/resources/attr/gitattributes
+++ b/tests/resources/attr/gitattributes
@@ -3,6 +3,7 @@ root_test2 -rootattr
root_test3 !rootattr
binfile binary
abc foo bar baz
+does-not-exist foo=yes
root_test2 multiattr
root_test3 multi2=foo