Commit 6a67a812c224878483659c6f25ca21573d1c309b

Russell Belfer 2012-01-11T16:01:48

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.

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