Commit eadc0e03f12038ec9ef91fe779b7f94b3a32b80d

Vicent Martí 2012-06-05T13:41:13

Merge pull request #747 from nulltoken/topic/init-filemode Make git_repository_init() value "core.filemode" and "core.ignorecase"

diff --git a/src/repository.c b/src/repository.c
index 5120356..7181708 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -655,7 +655,46 @@ static int repo_init_createhead(const char *git_dir)
 	return 0;
 }
 
-static int repo_init_config(const char *git_dir, int is_bare)
+static bool is_chmod_supported(const char *file_path)
+{
+	struct stat st1, st2;
+	static int _is_supported = -1;
+
+	if (_is_supported > -1)
+		return _is_supported;
+
+	if (p_stat(file_path, &st1) < 0)
+		return false;
+
+	if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0)
+		return false;
+
+	if (p_stat(file_path, &st2) < 0)
+		return false;
+
+	_is_supported = (st1.st_mode != st2.st_mode);
+	return _is_supported;
+}
+
+static bool is_filesystem_case_insensitive(const char *gitdir_path)
+{
+	git_buf path = GIT_BUF_INIT;
+	static int _is_insensitive = -1;
+
+	if (_is_insensitive > -1)
+		return _is_insensitive;
+
+	if (git_buf_joinpath(&path, gitdir_path, "CoNfIg") < 0)
+		goto cleanup;
+
+	_is_insensitive = git_path_exists(git_buf_cstr(&path));
+
+cleanup:
+	git_buf_free(&path);
+	return _is_insensitive;
+}
+
+static int repo_init_config(const char *git_dir, bool is_bare, bool is_reinit)
 {
 	git_buf cfg_path = GIT_BUF_INIT;
 	git_config *config = NULL;
@@ -670,13 +709,17 @@ static int repo_init_config(const char *git_dir, int is_bare)
 	if (git_buf_joinpath(&cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO) < 0)
 		return -1;
 
-	if (git_config_open_ondisk(&config, cfg_path.ptr) < 0) {
+	if (git_config_open_ondisk(&config, git_buf_cstr(&cfg_path)) < 0) {
 		git_buf_free(&cfg_path);
 		return -1;
 	}
 
 	SET_REPO_CONFIG(bool, "core.bare", is_bare);
 	SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION);
+	SET_REPO_CONFIG(bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path)));
+	
+	if (!is_reinit && is_filesystem_case_insensitive(git_dir))
+		SET_REPO_CONFIG(bool, "core.ignorecase", true);
 	/* TODO: what other defaults? */
 
 	git_buf_free(&cfg_path);
@@ -790,30 +833,35 @@ static int repo_init_structure(const char *git_dir, int is_bare)
 int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
 {
 	git_buf repository_path = GIT_BUF_INIT;
+	bool is_reinit;
+	int result = -1;
 
 	assert(repo_out && path);
 
 	if (git_buf_joinpath(&repository_path, path, is_bare ? "" : GIT_DIR) < 0)
-		return -1;
+		goto cleanup;
 
-	if (git_path_isdir(repository_path.ptr) == true) {
-		if (valid_repository_path(&repository_path) == true) {
-			int res = repo_init_reinit(repo_out, repository_path.ptr, is_bare);
-			git_buf_free(&repository_path);
-			return res;
-		}
+	is_reinit = git_path_isdir(repository_path.ptr) && valid_repository_path(&repository_path);
+
+	if (is_reinit) {
+		if (repo_init_reinit(repo_out, repository_path.ptr, is_bare) < 0)
+			goto cleanup;
+
+		result = repo_init_config(repository_path.ptr, is_bare, is_reinit);
 	}
 
 	if (repo_init_structure(repository_path.ptr, is_bare) < 0 ||
-		repo_init_config(repository_path.ptr, is_bare) < 0 || 
+		repo_init_config(repository_path.ptr, is_bare, is_reinit) < 0 || 
 		repo_init_createhead(repository_path.ptr) < 0 ||
 		git_repository_open(repo_out, repository_path.ptr) < 0) {
-		git_buf_free(&repository_path);
-		return -1;
+		goto cleanup;
 	}
 
+	result = 0;
+
+cleanup:
 	git_buf_free(&repository_path);
-	return 0;
+	return result;
 }
 
 int git_repository_head_detached(git_repository *repo)
diff --git a/src/win32/msvc-compat.h b/src/win32/msvc-compat.h
index 3ef09c8..ccc091c 100644
--- a/src/win32/msvc-compat.h
+++ b/src/win32/msvc-compat.h
@@ -21,6 +21,7 @@
 /* stat: file mode type testing macros */
 #	define _S_IFLNK 0120000
 #	define S_IFLNK _S_IFLNK
+#	define S_IXUSR 00100
 
 #	define S_ISDIR(m)	(((m) & _S_IFMT) == _S_IFDIR)
 #	define S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c
index 7f16b5b..af54b22 100644
--- a/tests-clar/repo/init.c
+++ b/tests-clar/repo/init.c
@@ -165,3 +165,71 @@ void test_repo_init__additional_templates(void)
 
 	git_buf_free(&path);
 }
+
+static void assert_config_entry_on_init(const char *config_key, int expected_value)
+{
+	git_config *config;
+	int current_value;
+
+	cl_set_cleanup(&cleanup_repository, "config_entry");
+	
+	cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1));
+	git_repository_config(&config, _repo);
+
+	if (expected_value >= 0) {
+		cl_git_pass(git_config_get_bool(&current_value, config, config_key));
+
+		cl_assert_equal_i(expected_value, current_value);
+	} else {
+		int error = git_config_get_bool(&current_value, config, config_key);
+
+		cl_assert_equal_i(expected_value, error);
+	}
+
+	git_config_free(config);
+}
+
+void test_repo_init__detect_filemode(void)
+{
+#ifdef GIT_WIN32
+	assert_config_entry_on_init("core.filemode", false);
+#else
+	assert_config_entry_on_init("core.filemode", true);
+#endif
+}
+
+#define CASE_INSENSITIVE_FILESYSTEM (defined GIT_WIN32 || defined __APPLE__)
+
+void test_repo_init__detect_ignorecase(void)
+{
+#if CASE_INSENSITIVE_FILESYSTEM
+	assert_config_entry_on_init("core.ignorecase", true);
+#else
+	assert_config_entry_on_init("core.ignorecase", GIT_ENOTFOUND);
+#endif
+}
+
+void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
+{
+	git_config *config;
+	int current_value;
+
+	/* Init a new repo */
+	test_repo_init__detect_ignorecase();
+
+	/* Change the "core.ignorecase" config value to something unlikely */
+	git_repository_config(&config, _repo);
+	git_config_set_int32(config, "core.ignorecase", 42);
+	git_config_free(config);
+	git_repository_free(_repo);
+
+	/* Reinit the repository */
+	cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1));
+	git_repository_config(&config, _repo);
+
+	/* Ensure the "core.ignorecase" config value hasn't been updated */
+	cl_git_pass(git_config_get_int32(&current_value, config, "core.ignorecase"));
+	cl_assert_equal_i(42, current_value);
+
+	git_config_free(config);
+}