Merge branch 'ls/travis-submitting-patches'
[gitweb.git] / builtin / submodule--helper.c
index 72e804ed4fa23b4c9b1bb0db1e0f59e9964eba45..3bd6883eff842ee139a3d24475401d75f65fe53e 100644 (file)
@@ -118,6 +118,55 @@ static int module_name(int argc, const char **argv, const char *prefix)
 
        return 0;
 }
+
+/*
+ * Rules to sanitize configuration variables that are Ok to be passed into
+ * submodule operations from the parent project using "-c". Should only
+ * include keys which are both (a) safe and (b) necessary for proper
+ * operation.
+ */
+static int submodule_config_ok(const char *var)
+{
+       if (starts_with(var, "credential."))
+               return 1;
+       return 0;
+}
+
+static int sanitize_submodule_config(const char *var, const char *value, void *data)
+{
+       struct strbuf *out = data;
+
+       if (submodule_config_ok(var)) {
+               if (out->len)
+                       strbuf_addch(out, ' ');
+
+               if (value)
+                       sq_quotef(out, "%s=%s", var, value);
+               else
+                       sq_quote_buf(out, var);
+       }
+
+       return 0;
+}
+
+static void prepare_submodule_repo_env(struct argv_array *out)
+{
+       const char * const *var;
+
+       for (var = local_repo_env; *var; var++) {
+               if (!strcmp(*var, CONFIG_DATA_ENVIRONMENT)) {
+                       struct strbuf sanitized_config = STRBUF_INIT;
+                       git_config_from_parameters(sanitize_submodule_config,
+                                                  &sanitized_config);
+                       argv_array_pushf(out, "%s=%s", *var, sanitized_config.buf);
+                       strbuf_release(&sanitized_config);
+               } else {
+                       argv_array_push(out, *var);
+               }
+       }
+
+}
+
 static int clone_submodule(const char *path, const char *gitdir, const char *url,
                           const char *depth, const char *reference, int quiet)
 {
@@ -139,7 +188,7 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
        argv_array_push(&cp.args, path);
 
        cp.git_cmd = 1;
-       cp.env = local_repo_env;
+       prepare_submodule_repo_env(&cp.env_array);
        cp.no_stdin = 1;
 
        return run_command(&cp);
@@ -147,11 +196,11 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
 
 static int module_clone(int argc, const char **argv, const char *prefix)
 {
-       const char *path = NULL, *name = NULL, *url = NULL;
+       const char *name = NULL, *url = NULL;
        const char *reference = NULL, *depth = NULL;
        int quiet = 0;
        FILE *submodule_dot_git;
-       char *sm_gitdir, *cwd, *p;
+       char *p, *path = NULL, *sm_gitdir;
        struct strbuf rel_path = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
 
@@ -180,16 +229,27 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 
        const char *const git_submodule_helper_usage[] = {
                N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
-                  "[--reference <repository>] [--name <name>] [--url <url>]"
-                  "[--depth <depth>] [--] [<path>...]"),
+                  "[--reference <repository>] [--name <name>] [--depth <depth>] "
+                  "--url <url> --path <path>"),
                NULL
        };
 
        argc = parse_options(argc, argv, prefix, module_clone_options,
                             git_submodule_helper_usage, 0);
 
+       if (argc || !url || !path || !*path)
+               usage_with_options(git_submodule_helper_usage,
+                                  module_clone_options);
+
        strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
-       sm_gitdir = strbuf_detach(&sb, NULL);
+       sm_gitdir = xstrdup(absolute_path(sb.buf));
+       strbuf_reset(&sb);
+
+       if (!is_absolute_path(path)) {
+               strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
+               path = strbuf_detach(&sb, NULL);
+       } else
+               path = xstrdup(path);
 
        if (!file_exists(sm_gitdir)) {
                if (safe_create_leading_directories_const(sm_gitdir) < 0)
@@ -206,49 +266,50 @@ static int module_clone(int argc, const char **argv, const char *prefix)
        }
 
        /* Write a .git file in the submodule to redirect to the superproject. */
-       if (safe_create_leading_directories_const(path) < 0)
-               die(_("could not create directory '%s'"), path);
-
-       if (path && *path)
-               strbuf_addf(&sb, "%s/.git", path);
-       else
-               strbuf_addstr(&sb, ".git");
-
+       strbuf_addf(&sb, "%s/.git", path);
        if (safe_create_leading_directories_const(sb.buf) < 0)
                die(_("could not create leading directories of '%s'"), sb.buf);
        submodule_dot_git = fopen(sb.buf, "w");
        if (!submodule_dot_git)
                die_errno(_("cannot open file '%s'"), sb.buf);
 
-       fprintf(submodule_dot_git, "gitdir: %s\n",
-               relative_path(sm_gitdir, path, &rel_path));
+       fprintf_or_die(submodule_dot_git, "gitdir: %s\n",
+                      relative_path(sm_gitdir, path, &rel_path));
        if (fclose(submodule_dot_git))
                die(_("could not close file %s"), sb.buf);
        strbuf_reset(&sb);
        strbuf_reset(&rel_path);
 
-       cwd = xgetcwd();
        /* Redirect the worktree of the submodule in the superproject's config */
-       if (!is_absolute_path(sm_gitdir)) {
-               strbuf_addf(&sb, "%s/%s", cwd, sm_gitdir);
-               free(sm_gitdir);
-               sm_gitdir = strbuf_detach(&sb, NULL);
-       }
-
-       strbuf_addf(&sb, "%s/%s", cwd, path);
        p = git_pathdup_submodule(path, "config");
        if (!p)
                die(_("could not get submodule directory for '%s'"), path);
        git_config_set_in_file(p, "core.worktree",
-                              relative_path(sb.buf, sm_gitdir, &rel_path));
+                              relative_path(path, sm_gitdir, &rel_path));
        strbuf_release(&sb);
        strbuf_release(&rel_path);
        free(sm_gitdir);
-       free(cwd);
+       free(path);
        free(p);
        return 0;
 }
 
+static int module_sanitize_config(int argc, const char **argv, const char *prefix)
+{
+       struct strbuf sanitized_config = STRBUF_INIT;
+
+       if (argc > 1)
+               usage(_("git submodule--helper sanitize-config"));
+
+       git_config_from_parameters(sanitize_submodule_config, &sanitized_config);
+       if (sanitized_config.len)
+               printf("%s\n", sanitized_config.buf);
+
+       strbuf_release(&sanitized_config);
+
+       return 0;
+}
+
 struct submodule_update_clone {
        /* index into 'list', the list of submodules to look into for cloning */
        int current;
@@ -509,6 +570,7 @@ static struct cmd_struct commands[] = {
        {"list", module_list},
        {"name", module_name},
        {"clone", module_clone},
+       {"sanitize-config", module_sanitize_config},
        {"update-clone", update_clone}
 };