diff --git a/include/git2/common.h b/include/git2/common.h index d7df7327e..bb2e63637 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -136,7 +136,9 @@ typedef enum { GIT_OPT_SET_CACHE_OBJECT_LIMIT, GIT_OPT_SET_CACHE_MAX_SIZE, GIT_OPT_ENABLE_CACHING, - GIT_OPT_GET_CACHED_MEMORY + GIT_OPT_GET_CACHED_MEMORY, + GIT_OPT_GET_TEMPLATE_PATH, + GIT_OPT_SET_TEMPLATE_PATH } git_libgit2_opt_t; /** @@ -210,6 +212,18 @@ typedef enum { * > Get the current bytes in cache and the maximum that would be * > allowed in the cache. * + * * opts(GIT_OPT_GET_SEARCH_PATH, char *out, size_t len) + * + * > Get the default template path. + * > The path is written to the `out` + * > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. + * + * * opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path) + * + * > Set the default template path. + * > + * > - `path` directory of template. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure diff --git a/src/fileops.c b/src/fileops.c index bd845e982..5a5041cc3 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -583,7 +583,7 @@ clean_up: static int git_futils_guess_system_dirs(git_buf *out) { #ifdef GIT_WIN32 - return git_win32__find_system_dirs(out); + return git_win32__find_system_dirs(out, L"etc\\"); #else return git_buf_sets(out, "/etc"); #endif @@ -615,15 +615,25 @@ static int git_futils_guess_xdg_dirs(git_buf *out) #endif } +static int git_futils_guess_template_dirs(git_buf *out) +{ +#ifdef GIT_WIN32 + return git_win32__find_system_dirs(out, L"share\\git-core\\templates"); +#else + return git_buf_sets(out, "/usr/share/git-core/templates"); +#endif +} + typedef int (*git_futils_dirs_guess_cb)(git_buf *out); static git_buf git_futils__dirs[GIT_FUTILS_DIR__MAX] = - { GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT }; + { GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT }; static git_futils_dirs_guess_cb git_futils__dir_guess[GIT_FUTILS_DIR__MAX] = { git_futils_guess_system_dirs, git_futils_guess_global_dirs, git_futils_guess_xdg_dirs, + git_futils_guess_template_dirs, }; static void git_futils_dirs_global_shutdown(void) @@ -746,7 +756,8 @@ static int git_futils_find_in_dirlist( continue; GITERR_CHECK_ERROR(git_buf_set(path, scan, len)); - GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name)); + if (name) + GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name)); if (git_path_exists(path->ptr)) return 0; @@ -775,6 +786,12 @@ int git_futils_find_xdg_file(git_buf *path, const char *filename) path, filename, GIT_FUTILS_DIR_XDG, "global/xdg"); } +int git_futils_find_template_dir(git_buf *path) +{ + return git_futils_find_in_dirlist( + path, NULL, GIT_FUTILS_DIR_TEMPLATE, "template"); +} + int git_futils_fake_symlink(const char *old, const char *new) { int retcode = GIT_ERROR; diff --git a/src/fileops.h b/src/fileops.h index 16bc58e93..6bd693b99 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -306,11 +306,20 @@ extern int git_futils_find_xdg_file(git_buf *path, const char *filename); */ extern int git_futils_find_system_file(git_buf *path, const char *filename); +/** + * Find template directory. + * + * @param path buffer to write the full path into + * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error + */ +extern int git_futils_find_template_dir(git_buf *path); + typedef enum { GIT_FUTILS_DIR_SYSTEM = 0, GIT_FUTILS_DIR_GLOBAL = 1, GIT_FUTILS_DIR_XDG = 2, - GIT_FUTILS_DIR__MAX = 3, + GIT_FUTILS_DIR_TEMPLATE = 3, + GIT_FUTILS_DIR__MAX = 4, } git_futils_dir_t; /** diff --git a/src/repository.c b/src/repository.c index 76e8228b7..d1b7d9131 100644 --- a/src/repository.c +++ b/src/repository.c @@ -33,8 +33,6 @@ #define GIT_REPO_VERSION 0 -#define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" - static void set_odb(git_repository *repo, git_odb *odb) { if (odb) { @@ -1136,6 +1134,9 @@ static int repo_init_structure( if (external_tpl) { git_config *cfg; const char *tdir; + git_buf template_buf = GIT_BUF_INIT; + + git_futils_find_template_dir(&template_buf); if (opts->template_path) tdir = opts->template_path; @@ -1150,7 +1151,7 @@ static int repo_init_structure( return error; giterr_clear(); - tdir = GIT_TEMPLATE_DIR; + tdir = template_buf.ptr; } error = git_futils_cp_r(tdir, repo_dir, @@ -1158,14 +1159,17 @@ static int repo_init_structure( GIT_CPDIR_SIMPLE_TO_MODE, dmode); if (error < 0) { - if (strcmp(tdir, GIT_TEMPLATE_DIR) != 0) + if (strcmp(tdir, template_buf.ptr) != 0) { + git_buf_free(&template_buf); return error; + } /* if template was default, ignore error and use internal */ giterr_clear(); external_tpl = false; error = 0; } + git_buf_free(&template_buf); } /* Copy internal template diff --git a/src/util.c b/src/util.c index 151782346..162ed6f70 100644 --- a/src/util.c +++ b/src/util.c @@ -117,6 +117,19 @@ int git_libgit2_opts(int key, ...) *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; *(va_arg(ap, ssize_t *)) = git_cache__max_storage; break; + + case GIT_OPT_GET_TEMPLATE_PATH: + { + char *out = va_arg(ap, char *); + size_t outlen = va_arg(ap, size_t); + + error = git_futils_dirs_get_str(out, outlen, GIT_FUTILS_DIR_TEMPLATE); + } + break; + + case GIT_OPT_SET_TEMPLATE_PATH: + error = git_futils_dirs_set(GIT_FUTILS_DIR_TEMPLATE, va_arg(ap, const char *)); + break; } va_end(ap); diff --git a/src/win32/findfile.c b/src/win32/findfile.c index d8b8f60ca..a9e812e28 100644 --- a/src/win32/findfile.c +++ b/src/win32/findfile.c @@ -86,7 +86,7 @@ static wchar_t* win32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen) return (path != base) ? path : NULL; } -static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe) +static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe, const wchar_t *subdir) { wchar_t *env = _wgetenv(L"PATH"), lastch; struct git_win32__path root; @@ -110,8 +110,8 @@ static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe) wcscpy(&root.path[root.len], gitexe); if (_waccess(root.path, F_OK) == 0 && root.len > 5) { - /* replace "bin\\" or "cmd\\" with "etc\\" */ - wcscpy(&root.path[root.len - 4], L"etc\\"); + /* replace "bin\\" or "cmd\\" with subdir */ + wcscpy(&root.path[root.len - 4], subdir); win32_path_to_8(buf, root.path); return 0; @@ -122,7 +122,7 @@ static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe) } static int win32_find_git_in_registry( - git_buf *buf, const HKEY hieve, const wchar_t *key) + git_buf *buf, const HKEY hieve, const wchar_t *key, const wchar_t *subdir) { HKEY hKey; DWORD dwType = REG_SZ; @@ -143,7 +143,7 @@ static int win32_find_git_in_registry( return -1; } - wcscat(path16.path, L"etc\\"); + wcscat(path16.path, subdir); path16.len += 4; win32_path_to_8(buf, path16.path); @@ -180,26 +180,26 @@ static int win32_find_existing_dirs( return (git_buf_oom(out) ? -1 : 0); } -int git_win32__find_system_dirs(git_buf *out) +int git_win32__find_system_dirs(git_buf *out, const wchar_t *subdir) { git_buf buf = GIT_BUF_INIT; /* directories where git.exe & git.cmd are found */ - if (!win32_find_git_in_path(&buf, L"git.exe") && buf.size) + if (!win32_find_git_in_path(&buf, L"git.exe", subdir) && buf.size) git_buf_set(out, buf.ptr, buf.size); else git_buf_clear(out); - if (!win32_find_git_in_path(&buf, L"git.cmd") && buf.size) + if (!win32_find_git_in_path(&buf, L"git.cmd", subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); /* directories where git is installed according to registry */ if (!win32_find_git_in_registry( - &buf, HKEY_CURRENT_USER, REG_MSYSGIT_INSTALL_LOCAL) && buf.size) + &buf, HKEY_CURRENT_USER, REG_MSYSGIT_INSTALL_LOCAL, subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); if (!win32_find_git_in_registry( - &buf, HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL) && buf.size) + &buf, HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL, subdir) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); git_buf_free(&buf); diff --git a/src/win32/findfile.h b/src/win32/findfile.h index fc79e1b72..11bf7e620 100644 --- a/src/win32/findfile.h +++ b/src/win32/findfile.h @@ -19,7 +19,7 @@ extern int git_win32__expand_path( extern int git_win32__find_file( git_buf *path, const struct git_win32__path *root, const char *filename); -extern int git_win32__find_system_dirs(git_buf *out); +extern int git_win32__find_system_dirs(git_buf *out, const wchar_t *subpath); extern int git_win32__find_global_dirs(git_buf *out); extern int git_win32__find_xdg_dirs(git_buf *out);