Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Martí <vicent@github.com>2013-03-19 03:17:14 +0400
committerVicent Martí <vicent@github.com>2013-03-19 03:17:14 +0400
commit5b27bf7e5bfd5c2f92a15c0058c801d49faf8403 (patch)
treeeb4e79c950ec3260ad8a532b4d84dae2ad60ae5d /src/fileops.c
parent50eb8520d06ac0c484a0ce3a3fba6c5da25ec976 (diff)
parent324602514fec5ba04fa236c67d633f9b18ad9845 (diff)
Merge pull request #1417 from arrbee/opts-for-paths
Implement opts interface for global/system file search paths
Diffstat (limited to 'src/fileops.c')
-rw-r--r--src/fileops.c209
1 files changed, 160 insertions, 49 deletions
diff --git a/src/fileops.c b/src/fileops.c
index e33377eac..d6244711f 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -558,75 +558,186 @@ clean_up:
return error;
}
-int git_futils_find_system_file(git_buf *path, const char *filename)
+
+static int git_futils_guess_system_dirs(git_buf *out)
{
#ifdef GIT_WIN32
- // try to find git.exe/git.cmd on path
- if (!win32_find_system_file_using_path(path, filename))
- return 0;
+ return git_win32__find_system_dirs(out);
+#else
+ return git_buf_sets(out, "/etc");
+#endif
+}
- // try to find msysgit installation path using registry
- if (!win32_find_system_file_using_registry(path, filename))
- return 0;
+static int git_futils_guess_global_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_global_dirs(out);
#else
- if (git_buf_joinpath(path, "/etc", filename) < 0)
- return -1;
+ return git_buf_sets(out, getenv("HOME"));
+#endif
+}
- if (git_path_exists(path->ptr) == true)
- return 0;
+static int git_futils_guess_xdg_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_xdg_dirs(out);
+#else
+ const char *env = NULL;
+
+ if ((env = getenv("XDG_CONFIG_HOME")) != NULL)
+ return git_buf_joinpath(out, env, "git");
+ else if ((env = getenv("HOME")) != NULL)
+ return git_buf_joinpath(out, env, ".config/git");
+
+ git_buf_clear(out);
+ return 0;
#endif
+}
- git_buf_clear(path);
- giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename);
- return GIT_ENOTFOUND;
+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 };
+
+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,
+};
+
+static int git_futils_check_selector(git_futils_dir_t which)
+{
+ if (which < GIT_FUTILS_DIR__MAX)
+ return 0;
+ giterr_set(GITERR_INVALID, "config directory selector out of range");
+ return -1;
}
-int git_futils_find_global_file(git_buf *path, const char *filename)
+int git_futils_dirs_get(const git_buf **out, git_futils_dir_t which)
{
-#ifdef GIT_WIN32
- struct win32_path root;
- static const wchar_t *tmpls[4] = {
- L"%HOME%\\",
- L"%HOMEDRIVE%%HOMEPATH%\\",
- L"%USERPROFILE%\\",
- NULL,
- };
- const wchar_t **tmpl;
-
- for (tmpl = tmpls; *tmpl != NULL; tmpl++) {
- /* try to expand environment variable, skipping if not set */
- if (win32_expand_path(&root, *tmpl) != 0 || root.path[0] == L'%')
+ assert(out);
+
+ *out = NULL;
+
+ GITERR_CHECK_ERROR(git_futils_check_selector(which));
+
+ if (!git_buf_len(&git_futils__dirs[which]))
+ GITERR_CHECK_ERROR(
+ git_futils__dir_guess[which](&git_futils__dirs[which]));
+
+ *out = &git_futils__dirs[which];
+ return 0;
+}
+
+int git_futils_dirs_get_str(char *out, size_t outlen, git_futils_dir_t which)
+{
+ const git_buf *path = NULL;
+
+ GITERR_CHECK_ERROR(git_futils_check_selector(which));
+ GITERR_CHECK_ERROR(git_futils_dirs_get(&path, which));
+
+ if (!out || path->size >= outlen) {
+ giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path");
+ return GIT_EBUFS;
+ }
+
+ git_buf_copy_cstr(out, outlen, path);
+ return 0;
+}
+
+#define PATH_MAGIC "$PATH"
+
+int git_futils_dirs_set(git_futils_dir_t which, const char *search_path)
+{
+ const char *expand_path = NULL;
+ git_buf merge = GIT_BUF_INIT;
+
+ GITERR_CHECK_ERROR(git_futils_check_selector(which));
+
+ if (search_path != NULL)
+ expand_path = strstr(search_path, PATH_MAGIC);
+
+ /* init with default if not yet done and needed (ignoring error) */
+ if ((!search_path || expand_path) &&
+ !git_buf_len(&git_futils__dirs[which]))
+ git_futils__dir_guess[which](&git_futils__dirs[which]);
+
+ /* if $PATH is not referenced, then just set the path */
+ if (!expand_path)
+ return git_buf_sets(&git_futils__dirs[which], search_path);
+
+ /* otherwise set to join(before $PATH, old value, after $PATH) */
+ if (expand_path > search_path)
+ git_buf_set(&merge, search_path, expand_path - search_path);
+
+ if (git_buf_len(&git_futils__dirs[which]))
+ git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR,
+ merge.ptr, git_futils__dirs[which].ptr);
+
+ expand_path += strlen(PATH_MAGIC);
+ if (*expand_path)
+ git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path);
+
+ git_buf_swap(&git_futils__dirs[which], &merge);
+ git_buf_free(&merge);
+
+ return git_buf_oom(&git_futils__dirs[which]) ? -1 : 0;
+}
+
+void git_futils_dirs_free(void)
+{
+ int i;
+ for (i = 0; i < GIT_FUTILS_DIR__MAX; ++i)
+ git_buf_free(&git_futils__dirs[i]);
+}
+
+static int git_futils_find_in_dirlist(
+ git_buf *path, const char *name, git_futils_dir_t which, const char *label)
+{
+ size_t len;
+ const char *scan, *next = NULL;
+ const git_buf *syspath;
+
+ GITERR_CHECK_ERROR(git_futils_dirs_get(&syspath, which));
+
+ for (scan = git_buf_cstr(syspath); scan; scan = next) {
+ for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR);
+ next && next > scan && next[-1] == '\\';
+ next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR))
+ /* find unescaped separator or end of string */;
+
+ len = next ? (size_t)(next++ - scan) : strlen(scan);
+ if (!len)
continue;
- /* try to look up file under path */
- if (!win32_find_file(path, &root, filename))
+ GITERR_CHECK_ERROR(git_buf_set(path, scan, len));
+ GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name));
+
+ if (git_path_exists(path->ptr))
return 0;
}
- giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
git_buf_clear(path);
-
+ giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name);
return GIT_ENOTFOUND;
-#else
- const char *home = getenv("HOME");
-
- if (home == NULL) {
- giterr_set(GITERR_OS, "Global file lookup failed. "
- "Cannot locate the user's home directory");
- return GIT_ENOTFOUND;
- }
+}
- if (git_buf_joinpath(path, home, filename) < 0)
- return -1;
+int git_futils_find_system_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_SYSTEM, "system");
+}
- if (git_path_exists(path->ptr) == false) {
- giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
- git_buf_clear(path);
- return GIT_ENOTFOUND;
- }
+int git_futils_find_global_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_GLOBAL, "global");
+}
- return 0;
-#endif
+int git_futils_find_xdg_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_XDG, "global/xdg");
}
int git_futils_fake_symlink(const char *old, const char *new)