[PATCH] allow git to use the PATH for finding subcommands and help docs
+ check PATH for git_exec_path after other locations but before builtin
+ prepend MANPATH and PERL5LIB in addition to PATH
Signed-off-by: Scott R Parish <srp@srparish.net>
---
exec_cmd.c | 50 ++++++++++++++++++++++++++++++++++++++-
git.c | 76 +++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 102 insertions(+), 24 deletions(-)
diff --git a/exec_cmd.c b/exec_cmd.c
index 9b74ed2..c6ecca9 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -13,19 +13,67 @@ void git_set_exec_path(const char *exec_path)
}
+/* Return the first path in PATH that git is found in or NULL if not found */
+char *git_path_from_env(void)
+{
+ const char *env_paths = getenv("PATH");
+ const char *git = "/git";
+ int git_len = strlen(git);
+ char *paths, *path, *colon, *git_path;
+ int path_len;
+ struct stat st;
+
+ if (!env_paths)
+ return NULL;
+
+ path_len = strlen(env_paths);
+ path = paths = xmalloc(path_len + 1);
+ memcpy(paths, env_paths, path_len + 1);
+
+ while ((char *)1 != path) {
+ if ((colon = strchr(path, ':')))
+ *colon = 0;
+
+ path_len = strlen(path);
+ git_path = xmalloc(path_len + git_len + 1);
+ memcpy(git_path, path, path_len);
+ memcpy(git_path + path_len, git, git_len + 1);
+
+ if (!stat(git_path, &st)) { /* found */
+ free(paths);
+ git_path[path_len] = 0;
+ return git_path;
+ }
+
+ free(git_path);
+ path = colon + 1;
+ }
+
+ free(paths);
+ return NULL;
+}
+
+
/* Returns the highest-priority, location to look for git programs. */
const char *git_exec_path(void)
{
- const char *env;
+ const char *env, *path;
if (current_exec_path)
return current_exec_path;
env = getenv(EXEC_PATH_ENVIRONMENT);
if (env && *env) {
+ current_exec_path = env;
return env;
}
+ if ((path = git_path_from_env())) {
+ current_exec_path = path;
+ return path;
+ }
+
+ current_exec_path = builtin_exec_path;
return builtin_exec_path;
}
diff --git a/git.c b/git.c
index 9eaca1d..252ee7c 100644
--- a/git.c
+++ b/git.c
@@ -6,26 +6,56 @@
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
-static void prepend_to_path(const char *dir, int len)
+static void prepend_to_env(const char *env, const char *basedir,
+ const char *subdir, const char *env_default)
{
- const char *old_path = getenv("PATH");
- char *path;
- int path_len = len;
-
- if (!old_path)
- old_path = "/usr/local/bin:/usr/bin:/bin";
-
- path_len = len + strlen(old_path) + 1;
-
- path = xmalloc(path_len + 1);
+ const char *old = getenv(env);
+ int basedir_len = strlen(basedir);
+ int subdir_len = strlen(subdir);
+ char *new;
+ int old_len;
+
+ if (!old)
+ old = env_default;
+
+ old_len = strlen(old);
+
+ new = xmalloc(basedir_len + subdir_len + old_len + 1);
+
+ memcpy(new, basedir, basedir_len);
+ memcpy(new + basedir_len, subdir, subdir_len);
+ memcpy(new + basedir_len + subdir_len, old, old_len + 1);
+
+ if (setenv(env, new, 1))
+ fprintf(stderr, "Setenv failed: %s\n", strerror(errno));
+
+ free(new);
+}
- memcpy(path, dir, len);
- path[len] = ':';
- memcpy(path + len + 1, old_path, path_len - len);
+static void prepend_to_envs(const char *dir, int len)
+{
+ char *slash;
+ char *basedir;
+
+ /* basedir is dir with "/bin" stripped off */
+ basedir = xmalloc(len + 1);
+ memcpy(basedir, dir, len + 1);
+
+ if ((slash = strrchr(basedir, '/'))) {
+ *slash = 0;
+ while (slash == basedir + --len) /* found trailing slash */
+ if ((slash = strrchr(basedir, '/')))
+ *slash = 0;
+ }
- setenv("PATH", path, 1);
+ prepend_to_env("PATH", basedir, "/bin:",
+ "/usr/local/bin:/usr/bin:/bin");
+ prepend_to_env("MANPATH", basedir, "/share/man:",
+ "/usr/local/share/man:/usr/share/man");
+ prepend_to_env("PERL5LIB", basedir, "/lib/perl5:",
+ "/usr/lib/perl5");
- free(path);
+ free(basedir);
}
static int handle_options(const char*** argv, int* argc, int* envchanged)
@@ -414,8 +444,7 @@ int main(int argc, const char **argv)
*/
if (slash) {
*slash++ = 0;
- if (*cmd == '/')
- exec_path = cmd;
+ exec_path = cmd;
cmd = slash;
}
@@ -453,14 +482,15 @@ int main(int argc, const char **argv)
/*
* We execute external git command via execv_git_cmd(),
* which looks at "--exec-path" option, GIT_EXEC_PATH
- * environment, and $(gitexecdir) in Makefile while built,
- * in this order. For scripted commands, we prepend
- * the value of the exec_path variable to the PATH.
+ * environment, PATH environment, and $(gitexecdir) in
+ * Makefile while built, in this order. For scripted
+ * commands, we prepend the value of the exec_path
+ * variable to the PATH.
*/
if (exec_path)
- prepend_to_path(exec_path, strlen(exec_path));
+ prepend_to_envs(exec_path, strlen(exec_path));
exec_path = git_exec_path();
- prepend_to_path(exec_path, strlen(exec_path));
+ prepend_to_envs(exec_path, strlen(exec_path));
while (1) {
/* See if it's an internal command */
--
1.5.3.4.206.g58ba4-dirty