Sync with 2.18.1
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:50:45 +0000 (11:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:50:45 +0000 (11:50 -0700)
* maint-2.18:
Git 2.18.1
Git 2.17.2
fsck: detect submodule paths starting with dash
fsck: detect submodule urls starting with dash
Git 2.16.5
Git 2.15.3
Git 2.14.5
submodule-config: ban submodule paths that start with a dash
submodule-config: ban submodule urls that start with dash
submodule--helper: use "--" to signal end of clone options

1  2 
builtin/submodule--helper.c
fsck.c
submodule-config.c
index f6fb8991f3a81b0b2dd895c1e8550b5bda5ea99a,1902b6c3199e104416b430d5a1ae2ac06d7c899d..5e6f2db4cdbcf9e88ddfc1890359f7f2f86b2cd2
@@@ -55,7 -55,7 +55,7 @@@ static char *get_default_remote(void
  
  static int print_default_remote(int argc, const char **argv, const char *prefix)
  {
 -      const char *remote;
 +      char *remote;
  
        if (argc != 1)
                die(_("submodule--helper print-default-remote takes no arguments"));
@@@ -64,7 -64,6 +64,7 @@@
        if (remote)
                printf("%s\n", remote);
  
 +      free(remote);
        return 0;
  }
  
@@@ -331,7 -330,7 +331,7 @@@ static int module_list_compute(int argc
        for (i = 0; i < active_nr; i++) {
                const struct cache_entry *ce = active_cache[i];
  
 -              if (!match_pathspec(pathspec, ce->name, ce_namelen(ce),
 +              if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),
                                    0, ps_matched, 1) ||
                    !S_ISGITLINK(ce->ce_mode))
                        continue;
@@@ -441,149 -440,6 +441,149 @@@ static void for_each_listed_submodule(c
                fn(list->entries[i], cb_data);
  }
  
 +struct cb_foreach {
 +      int argc;
 +      const char **argv;
 +      const char *prefix;
 +      int quiet;
 +      int recursive;
 +};
 +#define CB_FOREACH_INIT { 0 }
 +
 +static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 +                                     void *cb_data)
 +{
 +      struct cb_foreach *info = cb_data;
 +      const char *path = list_item->name;
 +      const struct object_id *ce_oid = &list_item->oid;
 +
 +      const struct submodule *sub;
 +      struct child_process cp = CHILD_PROCESS_INIT;
 +      char *displaypath;
 +
 +      displaypath = get_submodule_displaypath(path, info->prefix);
 +
 +      sub = submodule_from_path(the_repository, &null_oid, path);
 +
 +      if (!sub)
 +              die(_("No url found for submodule path '%s' in .gitmodules"),
 +                      displaypath);
 +
 +      if (!is_submodule_populated_gently(path, NULL))
 +              goto cleanup;
 +
 +      prepare_submodule_repo_env(&cp.env_array);
 +
 +      /*
 +       * For the purpose of executing <command> in the submodule,
 +       * separate shell is used for the purpose of running the
 +       * child process.
 +       */
 +      cp.use_shell = 1;
 +      cp.dir = path;
 +
 +      /*
 +       * NEEDSWORK: the command currently has access to the variables $name,
 +       * $sm_path, $displaypath, $sha1 and $toplevel only when the command
 +       * contains a single argument. This is done for maintaining a faithful
 +       * translation from shell script.
 +       */
 +      if (info->argc == 1) {
 +              char *toplevel = xgetcwd();
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              argv_array_pushf(&cp.env_array, "name=%s", sub->name);
 +              argv_array_pushf(&cp.env_array, "sm_path=%s", path);
 +              argv_array_pushf(&cp.env_array, "displaypath=%s", displaypath);
 +              argv_array_pushf(&cp.env_array, "sha1=%s",
 +                              oid_to_hex(ce_oid));
 +              argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel);
 +
 +              /*
 +               * Since the path variable was accessible from the script
 +               * before porting, it is also made available after porting.
 +               * The environment variable "PATH" has a very special purpose
 +               * on windows. And since environment variables are
 +               * case-insensitive in windows, it interferes with the
 +               * existing PATH variable. Hence, to avoid that, we expose
 +               * path via the args argv_array and not via env_array.
 +               */
 +              sq_quote_buf(&sb, path);
 +              argv_array_pushf(&cp.args, "path=%s; %s",
 +                               sb.buf, info->argv[0]);
 +              strbuf_release(&sb);
 +              free(toplevel);
 +      } else {
 +              argv_array_pushv(&cp.args, info->argv);
 +      }
 +
 +      if (!info->quiet)
 +              printf(_("Entering '%s'\n"), displaypath);
 +
 +      if (info->argv[0] && run_command(&cp))
 +              die(_("run_command returned non-zero status for %s\n."),
 +                      displaypath);
 +
 +      if (info->recursive) {
 +              struct child_process cpr = CHILD_PROCESS_INIT;
 +
 +              cpr.git_cmd = 1;
 +              cpr.dir = path;
 +              prepare_submodule_repo_env(&cpr.env_array);
 +
 +              argv_array_pushl(&cpr.args, "--super-prefix", NULL);
 +              argv_array_pushf(&cpr.args, "%s/", displaypath);
 +              argv_array_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
 +                              NULL);
 +
 +              if (info->quiet)
 +                      argv_array_push(&cpr.args, "--quiet");
 +
 +              argv_array_pushv(&cpr.args, info->argv);
 +
 +              if (run_command(&cpr))
 +                      die(_("run_command returned non-zero status while "
 +                              "recursing in the nested submodules of %s\n."),
 +                              displaypath);
 +      }
 +
 +cleanup:
 +      free(displaypath);
 +}
 +
 +static int module_foreach(int argc, const char **argv, const char *prefix)
 +{
 +      struct cb_foreach info = CB_FOREACH_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +
 +      struct option module_foreach_options[] = {
 +              OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")),
 +              OPT_BOOL(0, "recursive", &info.recursive,
 +                       N_("Recurse into nested submodules")),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule--helper foreach [--quiet] [--recursive] <command>"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_foreach_options,
 +                           git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN);
 +
 +      if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.argc = argc;
 +      info.argv = argv;
 +      info.prefix = prefix;
 +
 +      for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
  struct init_cb {
        const char *prefix;
        unsigned int flags;
@@@ -1024,6 -880,7 +1024,6 @@@ static void sync_submodule_cb(const str
  {
        struct sync_cb *info = cb_data;
        sync_submodule(list_item->name, info->prefix, info->flags);
 -
  }
  
  static int module_sync(int argc, const char **argv, const char *prefix)
@@@ -1233,6 -1090,7 +1233,7 @@@ static int clone_submodule(const char *
        if (gitdir && *gitdir)
                argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
  
+       argv_array_push(&cp.args, "--");
        argv_array_push(&cp.args, url);
        argv_array_push(&cp.args, path);
  
@@@ -1705,8 -1563,8 +1706,8 @@@ static int update_clone_task_finished(i
        return 0;
  }
  
 -static int gitmodules_update_clone_config(const char *var, const char *value,
 -                                        void *cb)
 +static int git_update_clone_config(const char *var, const char *value,
 +                                 void *cb)
  {
        int *max_jobs = cb;
        if (!strcmp(var, "submodule.fetchjobs"))
@@@ -1756,8 -1614,8 +1757,8 @@@ static int update_clone(int argc, cons
        };
        suc.prefix = prefix;
  
 -      config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
 -      git_config(gitmodules_update_clone_config, &max_jobs);
 +      update_clone_config_from_gitmodules(&max_jobs);
 +      git_config(git_update_clone_config, &max_jobs);
  
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
@@@ -2019,7 -1877,6 +2020,7 @@@ static struct cmd_struct commands[] = 
        {"relative-path", resolve_relative_path, 0},
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
 +      {"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
        {"status", module_status, SUPPORT_SUPER_PREFIX},
        {"print-default-remote", print_default_remote, 0},
diff --combined fsck.c
index a0cee0be590020e4ff4b42da86c322ba4d0010ae,51f61ffbc21918361111a2e1069be3aac54b6584..0f56977d6aa6499c06e31eddb8ed4afe484fcdc4
--- 1/fsck.c
--- 2/fsck.c
+++ b/fsck.c
@@@ -1,6 -1,4 +1,6 @@@
  #include "cache.h"
 +#include "object-store.h"
 +#include "repository.h"
  #include "object.h"
  #include "blob.h"
  #include "tree.h"
@@@ -16,7 -14,6 +16,7 @@@
  #include "packfile.h"
  #include "submodule-config.h"
  #include "config.h"
 +#include "help.h"
  
  static struct oidset gitmodules_found = OIDSET_INIT;
  static struct oidset gitmodules_done = OIDSET_INIT;
        FUNC(ZERO_PADDED_DATE, ERROR) \
        FUNC(GITMODULES_MISSING, ERROR) \
        FUNC(GITMODULES_BLOB, ERROR) \
 -      FUNC(GITMODULES_PARSE, ERROR) \
 +      FUNC(GITMODULES_LARGE, ERROR) \
        FUNC(GITMODULES_NAME, ERROR) \
        FUNC(GITMODULES_SYMLINK, ERROR) \
+       FUNC(GITMODULES_URL, ERROR) \
+       FUNC(GITMODULES_PATH, ERROR) \
        /* warnings */ \
        FUNC(BAD_FILEMODE, WARN) \
        FUNC(EMPTY_NAME, WARN) \
@@@ -78,7 -77,6 +80,7 @@@
        FUNC(ZERO_PADDED_FILEMODE, WARN) \
        FUNC(NUL_IN_COMMIT, WARN) \
        /* infos (reported as warnings, but ignored by default) */ \
 +      FUNC(GITMODULES_PARSE, INFO) \
        FUNC(BAD_TAG_NAME, INFO) \
        FUNC(MISSING_TAGGER_ENTRY, INFO)
  
@@@ -90,60 -88,37 +92,60 @@@ enum fsck_msg_id 
  #undef MSG_ID
  
  #define STR(x) #x
 -#define MSG_ID(id, msg_type) { STR(id), NULL, FSCK_##msg_type },
 +#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
  static struct {
        const char *id_string;
        const char *downcased;
 +      const char *camelcased;
        int msg_type;
  } msg_id_info[FSCK_MSG_MAX + 1] = {
        FOREACH_MSG_ID(MSG_ID)
 -      { NULL, NULL, -1 }
 +      { NULL, NULL, NULL, -1 }
  };
  #undef MSG_ID
  
 -static int parse_msg_id(const char *text)
 +static void prepare_msg_ids(void)
  {
        int i;
  
 -      if (!msg_id_info[0].downcased) {
 -              /* convert id_string to lower case, without underscores. */
 -              for (i = 0; i < FSCK_MSG_MAX; i++) {
 -                      const char *p = msg_id_info[i].id_string;
 -                      int len = strlen(p);
 -                      char *q = xmalloc(len);
 -
 -                      msg_id_info[i].downcased = q;
 -                      while (*p)
 -                              if (*p == '_')
 -                                      p++;
 -                              else
 -                                      *(q)++ = tolower(*(p)++);
 -                      *q = '\0';
 +      if (msg_id_info[0].downcased)
 +              return;
 +
 +      /* convert id_string to lower case, without underscores. */
 +      for (i = 0; i < FSCK_MSG_MAX; i++) {
 +              const char *p = msg_id_info[i].id_string;
 +              int len = strlen(p);
 +              char *q = xmalloc(len);
 +
 +              msg_id_info[i].downcased = q;
 +              while (*p)
 +                      if (*p == '_')
 +                              p++;
 +                      else
 +                              *(q)++ = tolower(*(p)++);
 +              *q = '\0';
 +
 +              p = msg_id_info[i].id_string;
 +              q = xmalloc(len);
 +              msg_id_info[i].camelcased = q;
 +              while (*p) {
 +                      if (*p == '_') {
 +                              p++;
 +                              if (*p)
 +                                      *q++ = *p++;
 +                      } else {
 +                              *q++ = tolower(*p++);
 +                      }
                }
 +              *q = '\0';
        }
 +}
 +
 +static int parse_msg_id(const char *text)
 +{
 +      int i;
 +
 +      prepare_msg_ids();
  
        for (i = 0; i < FSCK_MSG_MAX; i++)
                if (!strcmp(text, msg_id_info[i].downcased))
        return -1;
  }
  
 +void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)
 +{
 +      int i;
 +
 +      prepare_msg_ids();
 +
 +      for (i = 0; i < FSCK_MSG_MAX; i++)
 +              list_config_item(list, prefix, msg_id_info[i].camelcased);
 +}
 +
  static int fsck_msg_type(enum fsck_msg_id msg_id,
        struct fsck_options *options)
  {
@@@ -318,13 -283,6 +320,13 @@@ static void append_msg_id(struct strbu
        strbuf_addstr(sb, ": ");
  }
  
 +static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
 +{
 +      if (opts && opts->skiplist && obj)
 +              return oid_array_lookup(opts->skiplist, &obj->oid) >= 0;
 +      return 0;
 +}
 +
  __attribute__((format (printf, 4, 5)))
  static int report(struct fsck_options *options, struct object *object,
        enum fsck_msg_id id, const char *fmt, ...)
        if (msg_type == FSCK_IGNORE)
                return 0;
  
 -      if (options->skiplist && object &&
 -                      oid_array_lookup(options->skiplist, &object->oid) >= 0)
 +      if (object_on_skiplist(options, object))
                return 0;
  
        if (msg_type == FSCK_FATAL)
@@@ -414,14 -373,14 +416,14 @@@ static int fsck_walk_tree(struct tree *
                        continue;
  
                if (S_ISDIR(entry.mode)) {
 -                      obj = (struct object *)lookup_tree(entry.oid);
 +                      obj = (struct object *)lookup_tree(the_repository, entry.oid);
                        if (name && obj)
                                put_object_name(options, obj, "%s%s/", name,
                                        entry.path);
                        result = options->walk(obj, OBJ_TREE, data, options);
                }
                else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
 -                      obj = (struct object *)lookup_blob(entry.oid);
 +                      obj = (struct object *)lookup_blob(the_repository, entry.oid);
                        if (name && obj)
                                put_object_name(options, obj, "%s%s", name,
                                        entry.path);
@@@ -519,7 -478,7 +521,7 @@@ int fsck_walk(struct object *obj, void 
                return -1;
  
        if (obj->type == OBJ_NONE)
 -              parse_object(&obj->oid);
 +              parse_object(the_repository, &obj->oid);
  
        switch (obj->type) {
        case OBJ_BLOB:
@@@ -804,7 -763,7 +806,7 @@@ static int fsck_commit_buffer(struct co
                buffer = p + 1;
                parent_line_count++;
        }
 -      graft = lookup_commit_graft(&commit->object.oid);
 +      graft = lookup_commit_graft(the_repository, &commit->object.oid);
        parent_count = commit_list_count(commit->parents);
        if (graft) {
                if (graft->nr_parent == -1 && !parent_count)
@@@ -992,6 -951,18 +994,18 @@@ static int fsck_gitmodules_fn(const cha
                                    FSCK_MSG_GITMODULES_NAME,
                                    "disallowed submodule name: %s",
                                    name);
+       if (!strcmp(key, "url") && value &&
+           looks_like_command_line_option(value))
+               data->ret |= report(data->options, data->obj,
+                                   FSCK_MSG_GITMODULES_URL,
+                                   "disallowed submodule url: %s",
+                                   value);
+       if (!strcmp(key, "path") && value &&
+           looks_like_command_line_option(value))
+               data->ret |= report(data->options, data->obj,
+                                   FSCK_MSG_GITMODULES_PATH,
+                                   "disallowed submodule path: %s",
+                                   value);
        free(name);
  
        return 0;
@@@ -1001,15 -972,11 +1015,15 @@@ static int fsck_blob(struct blob *blob
                     unsigned long size, struct fsck_options *options)
  {
        struct fsck_gitmodules_data data;
 +      struct config_options config_opts = { 0 };
  
        if (!oidset_contains(&gitmodules_found, &blob->object.oid))
                return 0;
        oidset_insert(&gitmodules_done, &blob->object.oid);
  
 +      if (object_on_skiplist(options, &blob->object))
 +              return 0;
 +
        if (!buf) {
                /*
                 * A missing buffer here is a sign that the caller found the
                 * that an error.
                 */
                return report(options, &blob->object,
 -                            FSCK_MSG_GITMODULES_PARSE,
 +                            FSCK_MSG_GITMODULES_LARGE,
                              ".gitmodules too large to parse");
        }
  
        data.obj = &blob->object;
        data.options = options;
        data.ret = 0;
 +      config_opts.error_action = CONFIG_ERROR_SILENT;
        if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
 -                              ".gitmodules", buf, size, &data))
 +                              ".gitmodules", buf, size, &data, &config_opts))
                data.ret |= report(options, &blob->object,
                                   FSCK_MSG_GITMODULES_PARSE,
                                   "could not parse gitmodules blob");
@@@ -1082,7 -1048,7 +1096,7 @@@ int fsck_finish(struct fsck_options *op
                if (oidset_contains(&gitmodules_done, oid))
                        continue;
  
 -              blob = lookup_blob(oid);
 +              blob = lookup_blob(the_repository, oid);
                if (!blob) {
                        struct object *obj = lookup_unknown_object(oid->hash);
                        ret |= report(options, obj,
diff --combined submodule-config.c
index fc2c41b947cb471deef42323c83f8b28f42780d6,6b212bae31c31edb651a381cfb473d3de7ae7ca6..0b2f1647abb935ba63e9230baf0ba7fcef95d19c
@@@ -4,7 -4,6 +4,7 @@@
  #include "submodule-config.h"
  #include "submodule.h"
  #include "strbuf.h"
 +#include "object-store.h"
  #include "parse-options.h"
  
  /*
@@@ -384,6 -383,12 +384,12 @@@ static void warn_multiple_config(const 
                        commit_string, name, option);
  }
  
+ static void warn_command_line_option(const char *var, const char *value)
+ {
+       warning(_("ignoring '%s' which may be interpreted as"
+                 " a command-line option: %s"), var, value);
+ }
  struct parse_config_parameter {
        struct submodule_cache *cache;
        const struct object_id *treeish_name;
@@@ -409,6 -414,8 +415,8 @@@ static int parse_config(const char *var
        if (!strcmp(item.buf, "path")) {
                if (!value)
                        ret = config_error_nonbool(var);
+               else if (looks_like_command_line_option(value))
+                       warn_command_line_option(var, value);
                else if (!me->overwrite && submodule->path)
                        warn_multiple_config(me->treeish_name, submodule->name,
                                        "path");
        } else if (!strcmp(item.buf, "url")) {
                if (!value) {
                        ret = config_error_nonbool(var);
+               } else if (looks_like_command_line_option(value)) {
+                       warn_command_line_option(var, value);
                } else if (!me->overwrite && submodule->url) {
                        warn_multiple_config(me->treeish_name, submodule->name,
                                        "url");
@@@ -562,7 -571,7 +572,7 @@@ static const struct submodule *config_f
        parameter.gitmodules_oid = &oid;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
 -                      config, config_size, &parameter);
 +                      config, config_size, &parameter, NULL);
        strbuf_release(&rev);
        free(config);
  
@@@ -592,23 -601,6 +602,23 @@@ static void submodule_cache_check_init(
        submodule_cache_init(repo->submodule_cache);
  }
  
 +/*
 + * Note: This function is private for a reason, the '.gitmodules' file should
 + * not be used as as a mechanism to retrieve arbitrary configuration stored in
 + * the repository.
 + *
 + * Runs the provided config function on the '.gitmodules' file found in the
 + * working directory.
 + */
 +static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 +{
 +      if (repo->worktree) {
 +              char *file = repo_worktree_path(repo, GITMODULES_FILE);
 +              git_config_from_file(fn, file, data);
 +              free(file);
 +      }
 +}
 +
  static int gitmodules_cb(const char *var, const char *value, void *data)
  {
        struct repository *repo = data;
@@@ -626,11 -618,19 +636,11 @@@ void repo_read_gitmodules(struct reposi
  {
        submodule_cache_check_init(repo);
  
 -      if (repo->worktree) {
 -              char *gitmodules;
 -
 -              if (repo_read_index(repo) < 0)
 -                      return;
 -
 -              gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
 -
 -              if (!is_gitmodules_unmerged(repo->index))
 -                      git_config_from_file(gitmodules_cb, gitmodules, repo);
 +      if (repo_read_index(repo) < 0)
 +              return;
  
 -              free(gitmodules);
 -      }
 +      if (!is_gitmodules_unmerged(repo->index))
 +              config_from_gitmodules(gitmodules_cb, repo, repo);
  
        repo->submodule_cache->gitmodules_read = 1;
  }
@@@ -681,45 -681,3 +691,45 @@@ void submodule_free(struct repository *
        if (r->submodule_cache)
                submodule_cache_clear(r->submodule_cache);
  }
 +
 +struct fetch_config {
 +      int *max_children;
 +      int *recurse_submodules;
 +};
 +
 +static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 +{
 +      struct fetch_config *config = cb;
 +      if (!strcmp(var, "submodule.fetchjobs")) {
 +              *(config->max_children) = parse_submodule_fetchjobs(var, value);
 +              return 0;
 +      } else if (!strcmp(var, "fetch.recursesubmodules")) {
 +              *(config->recurse_submodules) = parse_fetch_recurse_submodules_arg(var, value);
 +              return 0;
 +      }
 +
 +      return 0;
 +}
 +
 +void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules)
 +{
 +      struct fetch_config config = {
 +              .max_children = max_children,
 +              .recurse_submodules = recurse_submodules
 +      };
 +      config_from_gitmodules(gitmodules_fetch_config, the_repository, &config);
 +}
 +
 +static int gitmodules_update_clone_config(const char *var, const char *value,
 +                                        void *cb)
 +{
 +      int *max_jobs = cb;
 +      if (!strcmp(var, "submodule.fetchjobs"))
 +              *max_jobs = parse_submodule_fetchjobs(var, value);
 +      return 0;
 +}
 +
 +void update_clone_config_from_gitmodules(int *max_jobs)
 +{
 +      config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
 +}