revision --simplify-merges: use decoration instead of commit->util field
[gitweb.git] / exec_cmd.c
index 9b74ed2f42ad9a452f5a1d9ab55d5ca1e1de2594..ce6741eb682b59ad638c7bee6ca31e2fcd53f281 100644 (file)
@@ -4,12 +4,27 @@
 #define MAX_ARGS       32
 
 extern char **environ;
-static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path;
+static const char *argv_exec_path;
+static const char *argv0_path;
 
-void git_set_exec_path(const char *exec_path)
+const char *system_path(const char *path)
 {
-       current_exec_path = exec_path;
+       if (!is_absolute_path(path) && argv0_path) {
+               struct strbuf d = STRBUF_INIT;
+               strbuf_addf(&d, "%s/%s", argv0_path, path);
+               path = strbuf_detach(&d, NULL);
+       }
+       return path;
+}
+
+void git_set_argv0_path(const char *path)
+{
+       argv0_path = path;
+}
+
+void git_set_argv_exec_path(const char *exec_path)
+{
+       argv_exec_path = exec_path;
 }
 
 
@@ -18,96 +33,78 @@ const char *git_exec_path(void)
 {
        const char *env;
 
-       if (current_exec_path)
-               return current_exec_path;
+       if (argv_exec_path)
+               return argv_exec_path;
 
        env = getenv(EXEC_PATH_ENVIRONMENT);
        if (env && *env) {
                return env;
        }
 
-       return builtin_exec_path;
+       return system_path(GIT_EXEC_PATH);
 }
 
+static void add_path(struct strbuf *out, const char *path)
+{
+       if (path && *path) {
+               if (is_absolute_path(path))
+                       strbuf_addstr(out, path);
+               else
+                       strbuf_addstr(out, make_nonrelative_path(path));
+
+               strbuf_addch(out, PATH_SEP);
+       }
+}
 
-int execv_git_cmd(const char **argv)
+void setup_path(void)
 {
-       char git_command[PATH_MAX + 1];
-       int i;
-       const char *paths[] = { current_exec_path,
-                               getenv(EXEC_PATH_ENVIRONMENT),
-                               builtin_exec_path };
-
-       for (i = 0; i < ARRAY_SIZE(paths); ++i) {
-               size_t len;
-               int rc;
-               const char *exec_dir = paths[i];
-               const char *tmp;
-
-               if (!exec_dir || !*exec_dir) continue;
-
-               if (*exec_dir != '/') {
-                       if (!getcwd(git_command, sizeof(git_command))) {
-                               fprintf(stderr, "git: cannot determine "
-                                       "current directory: %s\n",
-                                       strerror(errno));
-                               break;
-                       }
-                       len = strlen(git_command);
-
-                       /* Trivial cleanup */
-                       while (!prefixcmp(exec_dir, "./")) {
-                               exec_dir += 2;
-                               while (*exec_dir == '/')
-                                       exec_dir++;
-                       }
-
-                       rc = snprintf(git_command + len,
-                                     sizeof(git_command) - len, "/%s",
-                                     exec_dir);
-                       if (rc < 0 || rc >= sizeof(git_command) - len) {
-                               fprintf(stderr, "git: command name given "
-                                       "is too long.\n");
-                               break;
-                       }
-               } else {
-                       if (strlen(exec_dir) + 1 > sizeof(git_command)) {
-                               fprintf(stderr, "git: command name given "
-                                       "is too long.\n");
-                               break;
-                       }
-                       strcpy(git_command, exec_dir);
-               }
-
-               len = strlen(git_command);
-               rc = snprintf(git_command + len, sizeof(git_command) - len,
-                             "/git-%s", argv[0]);
-               if (rc < 0 || rc >= sizeof(git_command) - len) {
-                       fprintf(stderr,
-                               "git: command name given is too long.\n");
-                       break;
-               }
+       const char *old_path = getenv("PATH");
+       struct strbuf new_path;
 
-               /* argv[0] must be the git command, but the argv array
-                * belongs to the caller, and my be reused in
-                * subsequent loop iterations. Save argv[0] and
-                * restore it on error.
-                */
+       strbuf_init(&new_path, 0);
 
-               tmp = argv[0];
-               argv[0] = git_command;
+       add_path(&new_path, argv_exec_path);
+       add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
+       add_path(&new_path, system_path(GIT_EXEC_PATH));
+       add_path(&new_path, argv0_path);
 
-               trace_argv_printf(argv, -1, "trace: exec:");
+       if (old_path)
+               strbuf_addstr(&new_path, old_path);
+       else
+               strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
 
-               /* execve() can only ever return if it fails */
-               execve(git_command, (char **)argv, environ);
+       setenv("PATH", new_path.buf, 1);
 
-               trace_printf("trace: exec failed: %s\n", strerror(errno));
+       strbuf_release(&new_path);
+}
 
-               argv[0] = tmp;
-       }
-       return -1;
+const char **prepare_git_cmd(const char **argv)
+{
+       int argc;
+       const char **nargv;
+
+       for (argc = 0; argv[argc]; argc++)
+               ; /* just counting */
+       nargv = xmalloc(sizeof(*nargv) * (argc + 2));
 
+       nargv[0] = "git";
+       for (argc = 0; argv[argc]; argc++)
+               nargv[argc + 1] = argv[argc];
+       nargv[argc + 1] = NULL;
+       return nargv;
+}
+
+int execv_git_cmd(const char **argv) {
+       const char **nargv = prepare_git_cmd(argv);
+       trace_argv_printf(nargv, "trace: exec:");
+
+       /* execvp() can only ever return if it fails */
+       execvp("git", (char **)nargv);
+
+       trace_printf("trace: exec failed: %s\n", strerror(errno));
+
+       free(nargv);
+       return -1;
 }