From 5c042c5bf53ce630de6c54683d2544b80be45dcc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 26 Dec 2015 22:06:45 -0600 Subject: [PATCH 1/3] repo::init tests: test init.templatedir setting Ensure that `git_repository_init` honors the `init.templatedir` configuration setting. --- tests/repo/init.c | 143 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 44 deletions(-) diff --git a/tests/repo/init.c b/tests/repo/init.c index 7a9ec20f1..fb8b863c2 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -11,6 +11,7 @@ enum repo_mode { }; 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) @@ -22,6 +23,16 @@ 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_free(&_global_path); } static void cleanup_repository(void *path) @@ -527,13 +538,68 @@ static const char *template_sandbox(const char *name) return path; } -void test_repo_init__extended_with_template(void) +static void configure_templatedir(const char *template_path) { + git_buf config_path = GIT_BUF_INIT; + git_buf config_data = GIT_BUF_INIT; + + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, + GIT_CONFIG_LEVEL_GLOBAL, &config_path)); + cl_git_pass(git_buf_puts(&config_path, ".tmp")); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, + GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr)); + + cl_must_pass(p_mkdir(config_path.ptr, 0777)); + + cl_git_pass(git_buf_joinpath(&config_path, config_path.ptr, ".gitconfig")); + + cl_git_pass(git_buf_printf(&config_data, + "[init]\n\ttemplatedir = \"%s\"\n", template_path)); + + cl_git_mkfile(config_path.ptr, config_data.ptr); + + git_buf_free(&config_path); + git_buf_free(&config_data); +} + +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); + + git_buf_free(&expected); + git_buf_free(&actual); + git_buf_free(&repo_description); + git_buf_free(&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"); @@ -547,32 +613,41 @@ void test_repo_init__extended_with_template(void) 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")); - - cl_assert_equal_s(expected.ptr, actual.ptr); - - git_buf_free(&expected); - git_buf_free(&actual); - - filemode = cl_repo_get_bool(_repo, "core.filemode"); - - assert_hooks_match( - "template", git_repository_path(_repo), - "hooks/update.sample", filemode); - - assert_hooks_match( - "template", git_repository_path(_repo), - "hooks/link.sample", filemode); - + validate_templates(_repo, "template"); cl_fixture_cleanup("template"); } +void test_repo_init__external_templates_specified_in_config(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_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(), + "template")); + + 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)); + + cl_assert(git_repository_is_bare(_repo)); + + cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/")); + + validate_templates(_repo, "template"); + cl_fixture_cleanup("template"); + + git_buf_free(&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; @@ -592,16 +667,6 @@ void test_repo_init__extended_with_template_and_shared_mode(void) 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); @@ -610,17 +675,7 @@ void test_repo_init__extended_with_template_and_shared_mode(void) 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"); } From 002821837f0dd8d57c6c03b11159dff060cb1982 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 26 Dec 2015 22:32:17 -0600 Subject: [PATCH 2/3] repo::init tests: test a template dir with leading dot Ensure that we can handle template directories that begin with a leading dot. --- tests/repo/init.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/tests/repo/init.c b/tests/repo/init.c index fb8b863c2..b06a81347 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -12,6 +12,7 @@ enum repo_mode { static git_repository *_repo = NULL; static git_buf _global_path = GIT_BUF_INIT; +static git_buf _tmp_path = GIT_BUF_INIT; static mode_t g_umask = 0; void test_repo_init__initialize(void) @@ -33,6 +34,10 @@ void test_repo_init__cleanup(void) git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, _global_path.ptr); git_buf_free(&_global_path); + + if (_tmp_path.size > 0 && git_path_isdir(_tmp_path.ptr)) + git_futils_rmdir_r(_tmp_path.ptr, NULL, GIT_RMDIR_REMOVE_FILES); + git_buf_free(&_tmp_path); } static void cleanup_repository(void *path) @@ -544,14 +549,14 @@ static void configure_templatedir(const char *template_path) git_buf config_data = GIT_BUF_INIT; cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, - GIT_CONFIG_LEVEL_GLOBAL, &config_path)); - cl_git_pass(git_buf_puts(&config_path, ".tmp")); + GIT_CONFIG_LEVEL_GLOBAL, &_tmp_path)); + cl_git_pass(git_buf_puts(&_tmp_path, ".tmp")); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, - GIT_CONFIG_LEVEL_GLOBAL, config_path.ptr)); + GIT_CONFIG_LEVEL_GLOBAL, _tmp_path.ptr)); - cl_must_pass(p_mkdir(config_path.ptr, 0777)); + cl_must_pass(p_mkdir(_tmp_path.ptr, 0777)); - cl_git_pass(git_buf_joinpath(&config_path, config_path.ptr, ".gitconfig")); + cl_git_pass(git_buf_joinpath(&config_path, _tmp_path.ptr, ".gitconfig")); cl_git_pass(git_buf_printf(&config_data, "[init]\n\ttemplatedir = \"%s\"\n", template_path)); @@ -636,16 +641,39 @@ void test_repo_init__external_templates_specified_in_config(void) cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts)); - cl_assert(git_repository_is_bare(_repo)); - - cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/")); - validate_templates(_repo, "template"); cl_fixture_cleanup("template"); git_buf_free(&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_free(&template_path); +} + void test_repo_init__extended_with_template_and_shared_mode(void) { git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; From 62602547db2301493cf9681e3a76016ceb1e0b8b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 26 Dec 2015 22:39:22 -0600 Subject: [PATCH 3/3] git_repository_init: include dotfiles when copying templates Include dotfiles when copying template directory, which will handle both a template directory itself that begins with a dotfile, and any dotfiles inside the directory. --- src/repository.c | 4 +++- tests/repo/init.c | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/repository.c b/src/repository.c index 6234cd595..8a6fef0f6 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1438,7 +1438,9 @@ static int repo_init_structure( } if (tdir) { - uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | GIT_CPDIR_SIMPLE_TO_MODE; + uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | + GIT_CPDIR_SIMPLE_TO_MODE | + GIT_CPDIR_COPY_DOTFILES; if (opts->mode != GIT_REPOSITORY_INIT_SHARED_UMASK) cpflags |= GIT_CPDIR_CHMOD_DIRS; error = git_futils_cp_r(tdir, repo_dir, cpflags, dmode); diff --git a/tests/repo/init.c b/tests/repo/init.c index b06a81347..04d4a5c5e 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -519,7 +519,8 @@ static void assert_mode_seems_okay( 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); @@ -537,6 +538,12 @@ static const char *template_sandbox(const char *name) cl_must_pass(symlink("update.sample", link_path.ptr)); #endif + /* 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_free(&dotfile_path); + + git_buf_free(&dotfile_path); git_buf_free(&link_path); git_buf_free(&hooks_path); @@ -595,6 +602,10 @@ static void validate_templates(git_repository *repo, const char *template_path) template_path, git_repository_path(repo), "hooks/link.sample", filemode); + assert_hooks_match( + template_path, git_repository_path(repo), + "hooks/.dotfile", filemode); + git_buf_free(&expected); git_buf_free(&actual); git_buf_free(&repo_description);