#include "config.h"
#include "path.h"
#include "config/config_helpers.h"
+#include "repo/repo_helpers.h"
enum repo_mode {
STANDARD_REPOSITORY = 0,
};
static git_repository *_repo = NULL;
+static git_buf _global_path = GIT_BUF_INIT;
static mode_t g_umask = 0;
void test_repo_init__initialize(void)
g_umask = p_umask(022);
(void)p_umask(g_umask);
}
+
+ git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
+ &_global_path);
+}
+
+void test_repo_init__cleanup(void)
+{
+ git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
+ _global_path.ptr);
+ git_buf_dispose(&_global_path);
+
+ cl_fixture_cleanup("tmp_global_path");
}
static void cleanup_repository(void *path)
cl_git_pass(git_path_prettify_dir(&path_current_workdir, ".", NULL));
cl_git_pass(git_buf_joinpath(&path_repository, git_buf_cstr(&path_current_workdir), "a/b/c"));
- cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), NULL, GIT_DIR_MODE));
+ cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), GIT_DIR_MODE));
/* Change the current working directory */
cl_git_pass(chdir(git_buf_cstr(&path_repository)));
cl_git_pass(chdir(git_buf_cstr(&path_current_workdir)));
- git_buf_free(&path_current_workdir);
- git_buf_free(&path_repository);
+ git_buf_dispose(&path_current_workdir);
+ git_buf_dispose(&path_repository);
cleanup_repository("a");
}
cl_assert(git_path_isdir(git_buf_cstr(&path)));
/* won't confirm specific contents of hooks dir since it may vary */
- git_buf_free(&path);
+ git_buf_dispose(&path);
}
static void assert_config_entry_on_init_bytype(
"core.ignorecase", found_without_match ? true : GIT_ENOTFOUND);
}
+/*
+ * Windows: if the filesystem supports symlinks (because we're running
+ * as administrator, or because the user has opted into it for normal
+ * users) then we can also opt-in explicitly by settings `core.symlinks`
+ * in the global config. Symlinks remain off by default.
+ */
+
+void test_repo_init__symlinks_win32_enabled_by_global_config(void)
+{
+#ifndef GIT_WIN32
+ cl_skip();
+#else
+ git_config *config, *repo_config;
+ int val;
+
+ if (!filesystem_supports_symlinks("link"))
+ cl_skip();
+
+ create_tmp_global_config("tmp_global_config", "core.symlinks", "true");
+
+ /*
+ * Create a new repository (can't use `assert_config_on_init` since we
+ * want to examine configuration levels with more granularity.)
+ */
+ cl_git_pass(git_repository_init(&_repo, "config_entry/test.non.bare.git", false));
+
+ /* Ensure that core.symlinks remains set (via the global config). */
+ cl_git_pass(git_repository_config(&config, _repo));
+ cl_git_pass(git_config_get_bool(&val, config, "core.symlinks"));
+ cl_assert_equal_i(1, val);
+
+ /*
+ * Ensure that the repository config does not set core.symlinks.
+ * It should remain inherited.
+ */
+ cl_git_pass(git_config_open_level(&repo_config, config, GIT_CONFIG_LEVEL_LOCAL));
+ cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&val, repo_config, "core.symlinks"));
+ git_config_free(repo_config);
+
+ git_config_free(config);
+#endif
+}
+
+void test_repo_init__symlinks_win32_off_by_default(void)
+{
+#ifndef GIT_WIN32
+ cl_skip();
+#else
+ assert_config_entry_on_init("core.symlinks", false);
+#endif
+}
+
+void test_repo_init__symlinks_posix_detected(void)
+{
+#ifdef GIT_WIN32
+ cl_skip();
+#else
+ assert_config_entry_on_init(
+ "core.symlinks", filesystem_supports_symlinks("link") ? GIT_ENOTFOUND : false);
+#endif
+}
+
void test_repo_init__detect_precompose_unicode_required(void)
{
#ifdef GIT_USE_ICONV
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
}
+void test_repo_init__empty_template_path(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ opts.template_path = "";
+
+ cl_git_pass(git_futils_mkdir("foo", 0755, 0));
+ cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts));
+
+ cleanup_repository("foo");
+}
+
void test_repo_init__extended_0(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
cl_git_fail(git_repository_init_ext(&_repo, "extended", &opts));
/* make the directory first, then it should succeed */
- cl_git_pass(git_futils_mkdir("extended", NULL, 0775, 0));
+ cl_git_pass(git_futils_mkdir("extended", 0775, 0));
cl_git_pass(git_repository_init_ext(&_repo, "extended", &opts));
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/extended/"));
cl_assert((S_ISGID & st.st_mode) == 0);
cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD"));
- cl_assert(git_reference_type(ref) == GIT_REF_SYMBOLIC);
+ cl_assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref));
git_reference_free(ref);
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
- git_buf_free(&dot_git_content);
+ git_buf_dispose(&dot_git_content);
cleanup_repository("root");
}
/* make the directory first, then it should succeed */
cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
- git_buf_free(&full_path);
+ git_buf_dispose(&full_path);
cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
- git_buf_free(&dot_git_content);
+ git_buf_dispose(&dot_git_content);
cleanup_repository("root");
}
cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o");
}
- git_buf_free(&expected);
- git_buf_free(&actual);
+ git_buf_dispose(&expected);
+ git_buf_dispose(&actual);
}
static void assert_mode_seems_okay(
cl_git_pass(git_buf_joinpath(&full, base, path));
cl_git_pass(git_path_lstat(full.ptr, &st));
- git_buf_free(&full);
+ git_buf_dispose(&full);
if (!core_filemode) {
CLEAR_FOR_CORE_FILEMODE(expect_mode);
static const char *template_sandbox(const char *name)
{
- git_buf hooks_path = GIT_BUF_INIT, link_path = GIT_BUF_INIT;
+ git_buf hooks_path = GIT_BUF_INIT, link_path = GIT_BUF_INIT,
+ dotfile_path = GIT_BUF_INIT;
const char *path = cl_fixture(name);
cl_fixture_sandbox(name);
cl_must_pass(symlink("update.sample", link_path.ptr));
#endif
- git_buf_free(&link_path);
- git_buf_free(&hooks_path);
+ /* create a file starting with a dot */
+ cl_git_pass(git_buf_joinpath(&dotfile_path, hooks_path.ptr, ".dotfile"));
+ cl_git_mkfile(dotfile_path.ptr, "something\n");
+ git_buf_dispose(&dotfile_path);
+
+ git_buf_dispose(&dotfile_path);
+ git_buf_dispose(&link_path);
+ git_buf_dispose(&hooks_path);
return path;
}
-void test_repo_init__extended_with_template(void)
+static void configure_templatedir(const char *template_path)
{
+ create_tmp_global_config("tmp_global_path", "init.templatedir", template_path);
+}
+
+static void validate_templates(git_repository *repo, const char *template_path)
+{
+ git_buf template_description = GIT_BUF_INIT;
+ git_buf repo_description = GIT_BUF_INIT;
git_buf expected = GIT_BUF_INIT;
git_buf actual = GIT_BUF_INIT;
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
int filemode;
+ cl_git_pass(git_buf_joinpath(&template_description, template_path,
+ "description"));
+ cl_git_pass(git_buf_joinpath(&repo_description, git_repository_path(repo),
+ "description"));
+
+ cl_git_pass(git_futils_readbuffer(&expected, template_description.ptr));
+ cl_git_pass(git_futils_readbuffer(&actual, repo_description.ptr));
+
+ cl_assert_equal_s(expected.ptr, actual.ptr);
+
+ filemode = cl_repo_get_bool(repo, "core.filemode");
+
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/update.sample", filemode);
+
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/link.sample", filemode);
+
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/.dotfile", filemode);
+
+ git_buf_dispose(&expected);
+ git_buf_dispose(&actual);
+ git_buf_dispose(&repo_description);
+ git_buf_dispose(&template_description);
+}
+
+void test_repo_init__external_templates_specified_in_options(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
cl_set_cleanup(&cleanup_repository, "templated.git");
template_sandbox("template");
cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/"));
- cl_git_pass(git_futils_readbuffer(&expected, "template/description"));
- cl_git_pass(git_futils_readbuffer(
- &actual, "templated.git/description"));
+ validate_templates(_repo, "template");
+ cl_fixture_cleanup("template");
+}
- cl_assert_equal_s(expected.ptr, actual.ptr);
+void test_repo_init__external_templates_specified_in_config(void)
+{
+ git_buf template_path = GIT_BUF_INIT;
- git_buf_free(&expected);
- git_buf_free(&actual);
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
- filemode = cl_repo_get_bool(_repo, "core.filemode");
+ cl_set_cleanup(&cleanup_repository, "templated.git");
+ template_sandbox("template");
- assert_hooks_match(
- "template", git_repository_path(_repo),
- "hooks/update.sample", filemode);
+ cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
+ "template"));
- assert_hooks_match(
- "template", git_repository_path(_repo),
- "hooks/link.sample", filemode);
+ configure_templatedir(template_path.ptr);
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
+ validate_templates(_repo, "template");
cl_fixture_cleanup("template");
+
+ git_buf_dispose(&template_path);
+}
+
+void test_repo_init__external_templates_with_leading_dot(void)
+{
+ git_buf template_path = GIT_BUF_INIT;
+
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
+ cl_set_cleanup(&cleanup_repository, "templated.git");
+ template_sandbox("template");
+
+ cl_must_pass(p_rename("template", ".template_with_leading_dot"));
+
+ cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
+ ".template_with_leading_dot"));
+
+ configure_templatedir(template_path.ptr);
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
+
+ validate_templates(_repo, ".template_with_leading_dot");
+ cl_fixture_cleanup(".template_with_leading_dot");
+
+ git_buf_dispose(&template_path);
}
void test_repo_init__extended_with_template_and_shared_mode(void)
{
- git_buf expected = GIT_BUF_INIT;
- git_buf actual = GIT_BUF_INIT;
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
int filemode = true;
const char *repo_path = NULL;
filemode = cl_repo_get_bool(_repo, "core.filemode");
- cl_git_pass(git_futils_readbuffer(
- &expected, "template/description"));
- cl_git_pass(git_futils_readbuffer(
- &actual, "init_shared_from_tpl/.git/description"));
-
- cl_assert_equal_s(expected.ptr, actual.ptr);
-
- git_buf_free(&expected);
- git_buf_free(&actual);
-
repo_path = git_repository_path(_repo);
assert_mode_seems_okay(repo_path, "hooks",
GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
assert_mode_seems_okay(repo_path, "description",
GIT_FILEMODE_BLOB, false, filemode);
- /* for a non-symlinked hook, it should have shared permissions now */
- assert_hooks_match(
- "template", git_repository_path(_repo),
- "hooks/update.sample", filemode);
-
- /* for a symlinked hook, the permissions still should match the
- * source link, not the GIT_REPOSITORY_INIT_SHARED_GROUP value
- */
- assert_hooks_match(
- "template", git_repository_path(_repo),
- "hooks/link.sample", filemode);
+ validate_templates(_repo, "template");
cl_fixture_cleanup("template");
}
cl_set_cleanup(&cleanup_repository, "extended");
- cl_git_pass(git_futils_mkdir("extended", NULL, 0775, 0));
+ cl_git_pass(git_futils_mkdir("extended", 0775, 0));
cl_git_pass(git_repository_init(&_repo, "extended", false));
cl_git_pass(git_repository_init(&reinit, "extended", false));
/* Initialize the repository */
cl_git_pass(git_repository_init(&_repo, "committed", 0));
- /* Init will be automatically created when requested for a new repo */
+ /* Index will be automatically created when requested for a new repo */
cl_git_pass(git_repository_index(&index, _repo));
/* Create a file so we can commit it
cl_assert(git_path_isdir(root.ptr));
cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
- git_buf_free(&root);
+ git_buf_dispose(&root);
git_repository_free(repo);
}