]> git.proxmox.com Git - libgit2.git/blob - tests/repo/init.c
git_repository_init: include dotfiles when copying templates
[libgit2.git] / tests / repo / init.c
1 #include "clar_libgit2.h"
2 #include "fileops.h"
3 #include "repository.h"
4 #include "config.h"
5 #include "path.h"
6 #include "config/config_helpers.h"
7
8 enum repo_mode {
9 STANDARD_REPOSITORY = 0,
10 BARE_REPOSITORY = 1
11 };
12
13 static git_repository *_repo = NULL;
14 static git_buf _global_path = GIT_BUF_INIT;
15 static git_buf _tmp_path = GIT_BUF_INIT;
16 static mode_t g_umask = 0;
17
18 void test_repo_init__initialize(void)
19 {
20 _repo = NULL;
21
22 /* load umask if not already loaded */
23 if (!g_umask) {
24 g_umask = p_umask(022);
25 (void)p_umask(g_umask);
26 }
27
28 git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
29 &_global_path);
30 }
31
32 void test_repo_init__cleanup(void)
33 {
34 git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
35 _global_path.ptr);
36 git_buf_free(&_global_path);
37
38 if (_tmp_path.size > 0 && git_path_isdir(_tmp_path.ptr))
39 git_futils_rmdir_r(_tmp_path.ptr, NULL, GIT_RMDIR_REMOVE_FILES);
40 git_buf_free(&_tmp_path);
41 }
42
43 static void cleanup_repository(void *path)
44 {
45 git_repository_free(_repo);
46 _repo = NULL;
47
48 cl_fixture_cleanup((const char *)path);
49 }
50
51 static void ensure_repository_init(
52 const char *working_directory,
53 int is_bare,
54 const char *expected_path_repository,
55 const char *expected_working_directory)
56 {
57 const char *workdir;
58
59 cl_assert(!git_path_isdir(working_directory));
60
61 cl_git_pass(git_repository_init(&_repo, working_directory, is_bare));
62
63 workdir = git_repository_workdir(_repo);
64 if (workdir != NULL || expected_working_directory != NULL) {
65 cl_assert(
66 git__suffixcmp(workdir, expected_working_directory) == 0
67 );
68 }
69
70 cl_assert(
71 git__suffixcmp(git_repository_path(_repo), expected_path_repository) == 0
72 );
73
74 cl_assert(git_repository_is_bare(_repo) == is_bare);
75
76 #ifdef GIT_WIN32
77 if (!is_bare) {
78 DWORD fattrs = GetFileAttributes(git_repository_path(_repo));
79 cl_assert((fattrs & FILE_ATTRIBUTE_HIDDEN) != 0);
80 }
81 #endif
82
83 cl_assert(git_repository_is_empty(_repo));
84 }
85
86 void test_repo_init__standard_repo(void)
87 {
88 cl_set_cleanup(&cleanup_repository, "testrepo");
89 ensure_repository_init("testrepo/", 0, "testrepo/.git/", "testrepo/");
90 }
91
92 void test_repo_init__standard_repo_noslash(void)
93 {
94 cl_set_cleanup(&cleanup_repository, "testrepo");
95 ensure_repository_init("testrepo", 0, "testrepo/.git/", "testrepo/");
96 }
97
98 void test_repo_init__bare_repo(void)
99 {
100 cl_set_cleanup(&cleanup_repository, "testrepo.git");
101 ensure_repository_init("testrepo.git/", 1, "testrepo.git/", NULL);
102 }
103
104 void test_repo_init__bare_repo_noslash(void)
105 {
106 cl_set_cleanup(&cleanup_repository, "testrepo.git");
107 ensure_repository_init("testrepo.git", 1, "testrepo.git/", NULL);
108 }
109
110 void test_repo_init__bare_repo_escaping_current_workdir(void)
111 {
112 git_buf path_repository = GIT_BUF_INIT;
113 git_buf path_current_workdir = GIT_BUF_INIT;
114
115 cl_git_pass(git_path_prettify_dir(&path_current_workdir, ".", NULL));
116
117 cl_git_pass(git_buf_joinpath(&path_repository, git_buf_cstr(&path_current_workdir), "a/b/c"));
118 cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), GIT_DIR_MODE));
119
120 /* Change the current working directory */
121 cl_git_pass(chdir(git_buf_cstr(&path_repository)));
122
123 /* Initialize a bare repo with a relative path escaping out of the current working directory */
124 cl_git_pass(git_repository_init(&_repo, "../d/e.git", 1));
125 cl_git_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/"));
126
127 git_repository_free(_repo);
128
129 /* Open a bare repo with a relative path escaping out of the current working directory */
130 cl_git_pass(git_repository_open(&_repo, "../d/e.git"));
131
132 cl_git_pass(chdir(git_buf_cstr(&path_current_workdir)));
133
134 git_buf_free(&path_current_workdir);
135 git_buf_free(&path_repository);
136
137 cleanup_repository("a");
138 }
139
140 void test_repo_init__reinit_bare_repo(void)
141 {
142 cl_set_cleanup(&cleanup_repository, "reinit.git");
143
144 /* Initialize the repository */
145 cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
146 git_repository_free(_repo);
147
148 /* Reinitialize the repository */
149 cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
150 }
151
152 void test_repo_init__reinit_too_recent_bare_repo(void)
153 {
154 git_config *config;
155
156 /* Initialize the repository */
157 cl_git_pass(git_repository_init(&_repo, "reinit.git", 1));
158 git_repository_config(&config, _repo);
159
160 /*
161 * Hack the config of the repository to make it look like it has
162 * been created by a recenter version of git/libgit2
163 */
164 cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 42));
165
166 git_config_free(config);
167 git_repository_free(_repo);
168
169 /* Try to reinitialize the repository */
170 cl_git_fail(git_repository_init(&_repo, "reinit.git", 1));
171
172 cl_fixture_cleanup("reinit.git");
173 }
174
175 void test_repo_init__additional_templates(void)
176 {
177 git_buf path = GIT_BUF_INIT;
178
179 cl_set_cleanup(&cleanup_repository, "tester");
180
181 ensure_repository_init("tester", 0, "tester/.git/", "tester/");
182
183 cl_git_pass(
184 git_buf_joinpath(&path, git_repository_path(_repo), "description"));
185 cl_assert(git_path_isfile(git_buf_cstr(&path)));
186
187 cl_git_pass(
188 git_buf_joinpath(&path, git_repository_path(_repo), "info/exclude"));
189 cl_assert(git_path_isfile(git_buf_cstr(&path)));
190
191 cl_git_pass(
192 git_buf_joinpath(&path, git_repository_path(_repo), "hooks"));
193 cl_assert(git_path_isdir(git_buf_cstr(&path)));
194 /* won't confirm specific contents of hooks dir since it may vary */
195
196 git_buf_free(&path);
197 }
198
199 static void assert_config_entry_on_init_bytype(
200 const char *config_key, int expected_value, bool is_bare)
201 {
202 git_config *config;
203 int error, current_value;
204 const char *repo_path = is_bare ?
205 "config_entry/test.bare.git" : "config_entry/test.non.bare.git";
206
207 cl_set_cleanup(&cleanup_repository, "config_entry");
208
209 cl_git_pass(git_repository_init(&_repo, repo_path, is_bare));
210
211 cl_git_pass(git_repository_config(&config, _repo));
212 error = git_config_get_bool(&current_value, config, config_key);
213 git_config_free(config);
214
215 if (expected_value >= 0) {
216 cl_assert_equal_i(0, error);
217 cl_assert_equal_i(expected_value, current_value);
218 } else {
219 cl_assert_equal_i(expected_value, error);
220 }
221 }
222
223 static void assert_config_entry_on_init(
224 const char *config_key, int expected_value)
225 {
226 assert_config_entry_on_init_bytype(config_key, expected_value, true);
227 git_repository_free(_repo);
228
229 assert_config_entry_on_init_bytype(config_key, expected_value, false);
230 }
231
232 void test_repo_init__detect_filemode(void)
233 {
234 assert_config_entry_on_init("core.filemode", cl_is_chmod_supported());
235 }
236
237 void test_repo_init__detect_ignorecase(void)
238 {
239 struct stat st;
240 bool found_without_match;
241
242 cl_git_write2file("testCAPS", "whatever\n", 0, O_CREAT | O_WRONLY, 0666);
243 found_without_match = (p_stat("Testcaps", &st) == 0);
244 cl_must_pass(p_unlink("testCAPS"));
245
246 assert_config_entry_on_init(
247 "core.ignorecase", found_without_match ? true : GIT_ENOTFOUND);
248 }
249
250 void test_repo_init__detect_precompose_unicode_required(void)
251 {
252 #ifdef GIT_USE_ICONV
253 char *composed = "ḱṷṓn", *decomposed = "ḱṷṓn";
254 struct stat st;
255 bool found_with_nfd;
256
257 cl_git_write2file(composed, "whatever\n", 0, O_CREAT | O_WRONLY, 0666);
258 found_with_nfd = (p_stat(decomposed, &st) == 0);
259 cl_must_pass(p_unlink(composed));
260
261 assert_config_entry_on_init("core.precomposeunicode", found_with_nfd);
262 #else
263 assert_config_entry_on_init("core.precomposeunicode", GIT_ENOTFOUND);
264 #endif
265 }
266
267 void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
268 {
269 git_config *config;
270 int current_value;
271
272 /* Init a new repo */
273 cl_set_cleanup(&cleanup_repository, "not.overwrite.git");
274 cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
275
276 /* Change the "core.ignorecase" config value to something unlikely */
277 git_repository_config(&config, _repo);
278 git_config_set_int32(config, "core.ignorecase", 42);
279 git_config_free(config);
280 git_repository_free(_repo);
281 _repo = NULL;
282
283 /* Reinit the repository */
284 cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1));
285 git_repository_config(&config, _repo);
286
287 /* Ensure the "core.ignorecase" config value hasn't been updated */
288 cl_git_pass(git_config_get_int32(&current_value, config, "core.ignorecase"));
289 cl_assert_equal_i(42, current_value);
290
291 git_config_free(config);
292 }
293
294 void test_repo_init__reinit_overwrites_filemode(void)
295 {
296 int expected = cl_is_chmod_supported(), current_value;
297
298 /* Init a new repo */
299 cl_set_cleanup(&cleanup_repository, "overwrite.git");
300 cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
301
302 /* Change the "core.filemode" config value to something unlikely */
303 cl_repo_set_bool(_repo, "core.filemode", !expected);
304
305 git_repository_free(_repo);
306 _repo = NULL;
307
308 /* Reinit the repository */
309 cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1));
310
311 /* Ensure the "core.filemode" config value has been reset */
312 current_value = cl_repo_get_bool(_repo, "core.filemode");
313 cl_assert_equal_i(expected, current_value);
314 }
315
316 void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
317 {
318 assert_config_entry_on_init_bytype("core.logallrefupdates", GIT_ENOTFOUND, true);
319 git_repository_free(_repo);
320 assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
321 }
322
323 void test_repo_init__extended_0(void)
324 {
325 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
326
327 /* without MKDIR this should fail */
328 cl_git_fail(git_repository_init_ext(&_repo, "extended", &opts));
329
330 /* make the directory first, then it should succeed */
331 cl_git_pass(git_futils_mkdir("extended", 0775, 0));
332 cl_git_pass(git_repository_init_ext(&_repo, "extended", &opts));
333
334 cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/extended/"));
335 cl_assert(!git__suffixcmp(git_repository_path(_repo), "/extended/.git/"));
336 cl_assert(!git_repository_is_bare(_repo));
337 cl_assert(git_repository_is_empty(_repo));
338
339 cleanup_repository("extended");
340 }
341
342 void test_repo_init__extended_1(void)
343 {
344 git_reference *ref;
345 git_remote *remote;
346 struct stat st;
347 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
348
349 opts.flags = GIT_REPOSITORY_INIT_MKPATH |
350 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
351 opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
352 opts.workdir_path = "../c_wd";
353 opts.description = "Awesomest test repository evah";
354 opts.initial_head = "development";
355 opts.origin_url = "https://github.com/libgit2/libgit2.git";
356
357 cl_git_pass(git_repository_init_ext(&_repo, "root/b/c.git", &opts));
358
359 cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/c_wd/"));
360 cl_assert(!git__suffixcmp(git_repository_path(_repo), "/c.git/"));
361 cl_assert(git_path_isfile("root/b/c_wd/.git"));
362 cl_assert(!git_repository_is_bare(_repo));
363 /* repo will not be counted as empty because we set head to "development" */
364 cl_assert(!git_repository_is_empty(_repo));
365
366 cl_git_pass(git_path_lstat(git_repository_path(_repo), &st));
367 cl_assert(S_ISDIR(st.st_mode));
368 if (cl_is_chmod_supported())
369 cl_assert((S_ISGID & st.st_mode) == S_ISGID);
370 else
371 cl_assert((S_ISGID & st.st_mode) == 0);
372
373 cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD"));
374 cl_assert(git_reference_type(ref) == GIT_REF_SYMBOLIC);
375 cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref));
376 git_reference_free(ref);
377
378 cl_git_pass(git_remote_lookup(&remote, _repo, "origin"));
379 cl_assert_equal_s("origin", git_remote_name(remote));
380 cl_assert_equal_s(opts.origin_url, git_remote_url(remote));
381 git_remote_free(remote);
382
383 git_repository_free(_repo);
384 cl_fixture_cleanup("root");
385 }
386
387 void test_repo_init__relative_gitdir(void)
388 {
389 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
390 git_buf dot_git_content = GIT_BUF_INIT;
391
392 opts.workdir_path = "../c_wd";
393 opts.flags =
394 GIT_REPOSITORY_INIT_MKPATH |
395 GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
396 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
397
398 /* make the directory first, then it should succeed */
399 cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
400
401 cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
402 cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
403 cl_assert(!git_repository_is_bare(_repo));
404 cl_assert(git_repository_is_empty(_repo));
405
406 /* Verify that the gitlink and worktree entries are relative */
407
408 /* Verify worktree */
409 assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
410
411 /* Verify gitlink */
412 cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
413 cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
414
415 git_buf_free(&dot_git_content);
416 cleanup_repository("root");
417 }
418
419 void test_repo_init__relative_gitdir_2(void)
420 {
421 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
422 git_buf dot_git_content = GIT_BUF_INIT;
423 git_buf full_path = GIT_BUF_INIT;
424
425 cl_git_pass(git_path_prettify(&full_path, ".", NULL));
426 cl_git_pass(git_buf_joinpath(&full_path, full_path.ptr, "root/b/c_wd"));
427
428 opts.workdir_path = full_path.ptr;
429 opts.flags =
430 GIT_REPOSITORY_INIT_MKPATH |
431 GIT_REPOSITORY_INIT_RELATIVE_GITLINK |
432 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
433
434 /* make the directory first, then it should succeed */
435 cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts));
436 git_buf_free(&full_path);
437
438 cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/"));
439 cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/"));
440 cl_assert(!git_repository_is_bare(_repo));
441 cl_assert(git_repository_is_empty(_repo));
442
443 /* Verify that the gitlink and worktree entries are relative */
444
445 /* Verify worktree */
446 assert_config_entry_value(_repo, "core.worktree", "../c_wd/");
447
448 /* Verify gitlink */
449 cl_git_pass(git_futils_readbuffer(&dot_git_content, "root/b/c_wd/.git"));
450 cl_assert_equal_s("gitdir: ../my_repository/", dot_git_content.ptr);
451
452 git_buf_free(&dot_git_content);
453 cleanup_repository("root");
454 }
455
456 #define CLEAR_FOR_CORE_FILEMODE(M) ((M) &= ~0177)
457
458 static void assert_hooks_match(
459 const char *template_dir,
460 const char *repo_dir,
461 const char *hook_path,
462 bool core_filemode)
463 {
464 git_buf expected = GIT_BUF_INIT;
465 git_buf actual = GIT_BUF_INIT;
466 struct stat expected_st, st;
467
468 cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path));
469 cl_git_pass(git_path_lstat(expected.ptr, &expected_st));
470
471 cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path));
472 cl_git_pass(git_path_lstat(actual.ptr, &st));
473
474 cl_assert(expected_st.st_size == st.st_size);
475
476 if (GIT_MODE_TYPE(expected_st.st_mode) != GIT_FILEMODE_LINK) {
477 mode_t expected_mode =
478 GIT_MODE_TYPE(expected_st.st_mode) |
479 (GIT_PERMS_FOR_WRITE(expected_st.st_mode) & ~g_umask);
480
481 if (!core_filemode) {
482 CLEAR_FOR_CORE_FILEMODE(expected_mode);
483 CLEAR_FOR_CORE_FILEMODE(st.st_mode);
484 }
485
486 cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o");
487 }
488
489 git_buf_free(&expected);
490 git_buf_free(&actual);
491 }
492
493 static void assert_mode_seems_okay(
494 const char *base, const char *path,
495 git_filemode_t expect_mode, bool expect_setgid, bool core_filemode)
496 {
497 git_buf full = GIT_BUF_INIT;
498 struct stat st;
499
500 cl_git_pass(git_buf_joinpath(&full, base, path));
501 cl_git_pass(git_path_lstat(full.ptr, &st));
502 git_buf_free(&full);
503
504 if (!core_filemode) {
505 CLEAR_FOR_CORE_FILEMODE(expect_mode);
506 CLEAR_FOR_CORE_FILEMODE(st.st_mode);
507 expect_setgid = false;
508 }
509
510 if (S_ISGID != 0)
511 cl_assert_equal_b(expect_setgid, (st.st_mode & S_ISGID) != 0);
512
513 cl_assert_equal_b(
514 GIT_PERMS_IS_EXEC(expect_mode), GIT_PERMS_IS_EXEC(st.st_mode));
515
516 cl_assert_equal_i_fmt(
517 GIT_MODE_TYPE(expect_mode), GIT_MODE_TYPE(st.st_mode), "%07o");
518 }
519
520 static const char *template_sandbox(const char *name)
521 {
522 git_buf hooks_path = GIT_BUF_INIT, link_path = GIT_BUF_INIT,
523 dotfile_path = GIT_BUF_INIT;
524 const char *path = cl_fixture(name);
525
526 cl_fixture_sandbox(name);
527
528 /* create a symlink from link.sample to update.sample if the filesystem
529 * supports it.
530 */
531
532 cl_git_pass(git_buf_joinpath(&hooks_path, name, "hooks"));
533 cl_git_pass(git_buf_joinpath(&link_path, hooks_path.ptr, "link.sample"));
534
535 #ifdef GIT_WIN32
536 cl_git_mkfile(link_path.ptr, "#!/bin/sh\necho hello, world\n");
537 #else
538 cl_must_pass(symlink("update.sample", link_path.ptr));
539 #endif
540
541 /* create a file starting with a dot */
542 cl_git_pass(git_buf_joinpath(&dotfile_path, hooks_path.ptr, ".dotfile"));
543 cl_git_mkfile(dotfile_path.ptr, "something\n");
544 git_buf_free(&dotfile_path);
545
546 git_buf_free(&dotfile_path);
547 git_buf_free(&link_path);
548 git_buf_free(&hooks_path);
549
550 return path;
551 }
552
553 static void configure_templatedir(const char *template_path)
554 {
555 git_buf config_path = GIT_BUF_INIT;
556 git_buf config_data = GIT_BUF_INIT;
557
558 cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH,
559 GIT_CONFIG_LEVEL_GLOBAL, &_tmp_path));
560 cl_git_pass(git_buf_puts(&_tmp_path, ".tmp"));
561 cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH,
562 GIT_CONFIG_LEVEL_GLOBAL, _tmp_path.ptr));
563
564 cl_must_pass(p_mkdir(_tmp_path.ptr, 0777));
565
566 cl_git_pass(git_buf_joinpath(&config_path, _tmp_path.ptr, ".gitconfig"));
567
568 cl_git_pass(git_buf_printf(&config_data,
569 "[init]\n\ttemplatedir = \"%s\"\n", template_path));
570
571 cl_git_mkfile(config_path.ptr, config_data.ptr);
572
573 git_buf_free(&config_path);
574 git_buf_free(&config_data);
575 }
576
577 static void validate_templates(git_repository *repo, const char *template_path)
578 {
579 git_buf template_description = GIT_BUF_INIT;
580 git_buf repo_description = GIT_BUF_INIT;
581 git_buf expected = GIT_BUF_INIT;
582 git_buf actual = GIT_BUF_INIT;
583 int filemode;
584
585 cl_git_pass(git_buf_joinpath(&template_description, template_path,
586 "description"));
587 cl_git_pass(git_buf_joinpath(&repo_description, git_repository_path(repo),
588 "description"));
589
590 cl_git_pass(git_futils_readbuffer(&expected, template_description.ptr));
591 cl_git_pass(git_futils_readbuffer(&actual, repo_description.ptr));
592
593 cl_assert_equal_s(expected.ptr, actual.ptr);
594
595 filemode = cl_repo_get_bool(repo, "core.filemode");
596
597 assert_hooks_match(
598 template_path, git_repository_path(repo),
599 "hooks/update.sample", filemode);
600
601 assert_hooks_match(
602 template_path, git_repository_path(repo),
603 "hooks/link.sample", filemode);
604
605 assert_hooks_match(
606 template_path, git_repository_path(repo),
607 "hooks/.dotfile", filemode);
608
609 git_buf_free(&expected);
610 git_buf_free(&actual);
611 git_buf_free(&repo_description);
612 git_buf_free(&template_description);
613 }
614
615 void test_repo_init__external_templates_specified_in_options(void)
616 {
617 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
618
619 cl_set_cleanup(&cleanup_repository, "templated.git");
620 template_sandbox("template");
621
622 opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
623 GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
624 opts.template_path = "template";
625
626 cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
627
628 cl_assert(git_repository_is_bare(_repo));
629
630 cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/"));
631
632 validate_templates(_repo, "template");
633 cl_fixture_cleanup("template");
634 }
635
636 void test_repo_init__external_templates_specified_in_config(void)
637 {
638 git_buf template_path = GIT_BUF_INIT;
639
640 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
641
642 cl_set_cleanup(&cleanup_repository, "templated.git");
643 template_sandbox("template");
644
645 cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
646 "template"));
647
648 configure_templatedir(template_path.ptr);
649
650 opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
651 GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
652
653 cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
654
655 validate_templates(_repo, "template");
656 cl_fixture_cleanup("template");
657
658 git_buf_free(&template_path);
659 }
660
661 void test_repo_init__external_templates_with_leading_dot(void)
662 {
663 git_buf template_path = GIT_BUF_INIT;
664
665 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
666
667 cl_set_cleanup(&cleanup_repository, "templated.git");
668 template_sandbox("template");
669
670 cl_must_pass(p_rename("template", ".template_with_leading_dot"));
671
672 cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
673 ".template_with_leading_dot"));
674
675 configure_templatedir(template_path.ptr);
676
677 opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
678 GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
679
680 cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
681
682 validate_templates(_repo, ".template_with_leading_dot");
683 cl_fixture_cleanup(".template_with_leading_dot");
684
685 git_buf_free(&template_path);
686 }
687
688 void test_repo_init__extended_with_template_and_shared_mode(void)
689 {
690 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
691 int filemode = true;
692 const char *repo_path = NULL;
693
694 cl_set_cleanup(&cleanup_repository, "init_shared_from_tpl");
695 template_sandbox("template");
696
697 opts.flags = GIT_REPOSITORY_INIT_MKPATH |
698 GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
699 opts.template_path = "template";
700 opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
701
702 cl_git_pass(git_repository_init_ext(&_repo, "init_shared_from_tpl", &opts));
703
704 cl_assert(!git_repository_is_bare(_repo));
705 cl_assert(!git__suffixcmp(git_repository_path(_repo), "/init_shared_from_tpl/.git/"));
706
707 filemode = cl_repo_get_bool(_repo, "core.filemode");
708
709 repo_path = git_repository_path(_repo);
710 assert_mode_seems_okay(repo_path, "hooks",
711 GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
712 assert_mode_seems_okay(repo_path, "info",
713 GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
714 assert_mode_seems_okay(repo_path, "description",
715 GIT_FILEMODE_BLOB, false, filemode);
716
717 validate_templates(_repo, "template");
718
719 cl_fixture_cleanup("template");
720 }
721
722 void test_repo_init__can_reinit_an_initialized_repository(void)
723 {
724 git_repository *reinit;
725
726 cl_set_cleanup(&cleanup_repository, "extended");
727
728 cl_git_pass(git_futils_mkdir("extended", 0775, 0));
729 cl_git_pass(git_repository_init(&_repo, "extended", false));
730
731 cl_git_pass(git_repository_init(&reinit, "extended", false));
732
733 cl_assert_equal_s(git_repository_path(_repo), git_repository_path(reinit));
734
735 git_repository_free(reinit);
736 }
737
738 void test_repo_init__init_with_initial_commit(void)
739 {
740 git_index *index;
741
742 cl_set_cleanup(&cleanup_repository, "committed");
743
744 /* Initialize the repository */
745 cl_git_pass(git_repository_init(&_repo, "committed", 0));
746
747 /* Init will be automatically created when requested for a new repo */
748 cl_git_pass(git_repository_index(&index, _repo));
749
750 /* Create a file so we can commit it
751 *
752 * If you are writing code outside the test suite, you can create this
753 * file any way that you like, such as:
754 * FILE *fp = fopen("committed/file.txt", "w");
755 * fputs("some stuff\n", fp);
756 * fclose(fp);
757 * We like to use the help functions because they do error detection
758 * in a way that's easily compatible with our test suite.
759 */
760 cl_git_mkfile("committed/file.txt", "some stuff\n");
761
762 /* Add file to the index */
763 cl_git_pass(git_index_add_bypath(index, "file.txt"));
764 cl_git_pass(git_index_write(index));
765
766 /* Intentionally not using cl_repo_commit_from_index here so this code
767 * can be used as an example of how an initial commit is typically
768 * made to a repository...
769 */
770
771 /* Make sure we're ready to use git_signature_default :-) */
772 {
773 git_config *cfg, *local;
774 cl_git_pass(git_repository_config(&cfg, _repo));
775 cl_git_pass(git_config_open_level(&local, cfg, GIT_CONFIG_LEVEL_LOCAL));
776 cl_git_pass(git_config_set_string(local, "user.name", "Test User"));
777 cl_git_pass(git_config_set_string(local, "user.email", "t@example.com"));
778 git_config_free(local);
779 git_config_free(cfg);
780 }
781
782 /* Create a commit with the new contents of the index */
783 {
784 git_signature *sig;
785 git_oid tree_id, commit_id;
786 git_tree *tree;
787
788 cl_git_pass(git_signature_default(&sig, _repo));
789 cl_git_pass(git_index_write_tree(&tree_id, index));
790 cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
791
792 cl_git_pass(git_commit_create_v(
793 &commit_id, _repo, "HEAD", sig, sig,
794 NULL, "First", tree, 0));
795
796 git_tree_free(tree);
797 git_signature_free(sig);
798 }
799
800 git_index_free(index);
801 }
802
803 void test_repo_init__at_filesystem_root(void)
804 {
805 git_repository *repo;
806 const char *sandbox = clar_sandbox_path();
807 git_buf root = GIT_BUF_INIT;
808 int root_len;
809
810 if (!cl_is_env_set("GITTEST_INVASIVE_FS_STRUCTURE"))
811 cl_skip();
812
813 root_len = git_path_root(sandbox);
814 cl_assert(root_len >= 0);
815
816 git_buf_put(&root, sandbox, root_len+1);
817 git_buf_joinpath(&root, root.ptr, "libgit2_test_dir");
818
819 cl_assert(!git_path_exists(root.ptr));
820
821 cl_git_pass(git_repository_init(&repo, root.ptr, 0));
822 cl_assert(git_path_isdir(root.ptr));
823 cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
824
825 git_buf_free(&root);
826 git_repository_free(repo);
827 }