Merge branch 'sb/unpack-trees-super-prefix'
authorJunio C Hamano <gitster@pobox.com>
Fri, 3 Feb 2017 19:25:18 +0000 (11:25 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 3 Feb 2017 19:25:18 +0000 (11:25 -0800)
"git read-tree" and its underlying unpack_trees() machinery learned
to report problematic paths prefixed with the --super-prefix option.

* sb/unpack-trees-super-prefix:
unpack-trees: support super-prefix option
t1001: modernize style
t1000: modernize style
read-tree: use OPT_BOOL instead of OPT_SET_INT

1  2 
git.c
unpack-trees.c
diff --combined git.c
index 1cf125cd2800df74759b8762c5ea01ede13c6938,50e559c2a81db071b12a7b9d07840105b175db84..c887272b129968db161a152ce8a91aca4439ca3c
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -424,7 -424,6 +424,7 @@@ static struct cmd_struct commands[] = 
        { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
        { "diff-index", cmd_diff_index, RUN_SETUP },
        { "diff-tree", cmd_diff_tree, RUN_SETUP },
 +      { "difftool", cmd_difftool, RUN_SETUP | NEED_WORK_TREE },
        { "fast-export", cmd_fast_export, RUN_SETUP },
        { "fetch", cmd_fetch, RUN_SETUP },
        { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
        { "fsck-objects", cmd_fsck, RUN_SETUP },
        { "gc", cmd_gc, RUN_SETUP },
        { "get-tar-commit-id", cmd_get_tar_commit_id },
 -      { "grep", cmd_grep, RUN_SETUP_GENTLY },
 +      { "grep", cmd_grep, RUN_SETUP_GENTLY | SUPPORT_SUPER_PREFIX },
        { "hash-object", cmd_hash_object },
        { "help", cmd_help },
        { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
        { "prune-packed", cmd_prune_packed, RUN_SETUP },
        { "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
        { "push", cmd_push, RUN_SETUP },
-       { "read-tree", cmd_read_tree, RUN_SETUP },
+       { "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
        { "receive-pack", cmd_receive_pack },
        { "reflog", cmd_reflog, RUN_SETUP },
        { "remote", cmd_remote, RUN_SETUP },
@@@ -576,7 -575,8 +576,7 @@@ static void handle_builtin(int argc, co
  
  static void execv_dashed_external(const char **argv)
  {
 -      struct strbuf cmd = STRBUF_INIT;
 -      const char *tmp;
 +      struct child_process cmd = CHILD_PROCESS_INIT;
        int status;
  
        if (get_super_prefix())
                use_pager = check_pager_config(argv[0]);
        commit_pager_choice();
  
 -      strbuf_addf(&cmd, "git-%s", argv[0]);
 +      argv_array_pushf(&cmd.args, "git-%s", argv[0]);
 +      argv_array_pushv(&cmd.args, argv + 1);
 +      cmd.clean_on_exit = 1;
 +      cmd.wait_after_clean = 1;
 +      cmd.silent_exec_failure = 1;
  
 -      /*
 -       * argv[0] must be the git command, but the argv array
 -       * belongs to the caller, and may be reused in
 -       * subsequent loop iterations. Save argv[0] and
 -       * restore it on error.
 -       */
 -      tmp = argv[0];
 -      argv[0] = cmd.buf;
 -
 -      trace_argv_printf(argv, "trace: exec:");
 +      trace_argv_printf(cmd.args.argv, "trace: exec:");
  
        /*
 -       * if we fail because the command is not found, it is
 -       * OK to return. Otherwise, we just pass along the status code.
 +       * If we fail because the command is not found, it is
 +       * OK to return. Otherwise, we just pass along the status code,
 +       * or our usual generic code if we were not even able to exec
 +       * the program.
         */
 -      status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT);
 -      if (status >= 0 || errno != ENOENT)
 +      status = run_command(&cmd);
 +      if (status >= 0)
                exit(status);
 -
 -      argv[0] = tmp;
 -
 -      strbuf_release(&cmd);
 +      else if (errno != ENOENT)
 +              exit(128);
  }
  
  static int run_argv(int *argcp, const char ***argv)
diff --combined unpack-trees.c
index 129d49ff4517ae0f6c843a9f53c1617f3c2cb3ca,eee4865804bc1bec4795203b0853d4045b9e791a..3a8ee19fe837aae6939c3a6b902f6b067dcde9e4
@@@ -52,6 -52,41 +52,41 @@@ static const char *unpack_plumbing_erro
          ? ((o)->msgs[(type)])      \
          : (unpack_plumbing_errors[(type)]) )
  
+ static const char *super_prefixed(const char *path)
+ {
+       /*
+        * It is necessary and sufficient to have two static buffers
+        * here, as the return value of this function is fed to
+        * error() using the unpack_*_errors[] templates we see above.
+        */
+       static struct strbuf buf[2] = {STRBUF_INIT, STRBUF_INIT};
+       static int super_prefix_len = -1;
+       static unsigned idx = ARRAY_SIZE(buf) - 1;
+       if (super_prefix_len < 0) {
+               const char *super_prefix = get_super_prefix();
+               if (!super_prefix) {
+                       super_prefix_len = 0;
+               } else {
+                       int i;
+                       for (i = 0; i < ARRAY_SIZE(buf); i++)
+                               strbuf_addstr(&buf[i], super_prefix);
+                       super_prefix_len = buf[0].len;
+               }
+       }
+       if (!super_prefix_len)
+               return path;
+       if (++idx >= ARRAY_SIZE(buf))
+               idx = 0;
+       strbuf_setlen(&buf[idx], super_prefix_len);
+       strbuf_addstr(&buf[idx], path);
+       return buf[idx].buf;
+ }
  void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                                  const char *cmd)
  {
@@@ -172,7 -207,7 +207,7 @@@ static int add_rejected_path(struct unp
                             const char *path)
  {
        if (!o->show_all_errors)
-               return error(ERRORMSG(o, e), path);
+               return error(ERRORMSG(o, e), super_prefixed(path));
  
        /*
         * Otherwise, insert in a list for future display by
@@@ -196,7 -231,7 +231,7 @@@ static void display_error_msgs(struct u
                        something_displayed = 1;
                        for (i = 0; i < rejects->nr; i++)
                                strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-                       error(ERRORMSG(o, e), path.buf);
+                       error(ERRORMSG(o, e), super_prefixed(path.buf));
                        strbuf_release(&path);
                }
                string_list_clear(rejects, 0);
@@@ -218,42 -253,29 +253,42 @@@ static void unlink_entry(const struct c
        schedule_dir_for_removal(ce->name, ce_namelen(ce));
  }
  
 -static int check_updates(struct unpack_trees_options *o,
 -                       const struct checkout *state)
 +static struct progress *get_progress(struct unpack_trees_options *o)
  {
        unsigned cnt = 0, total = 0;
 +      struct index_state *index = &o->result;
 +
 +      if (!o->update || !o->verbose_update)
 +              return NULL;
 +
 +      for (; cnt < index->cache_nr; cnt++) {
 +              const struct cache_entry *ce = index->cache[cnt];
 +              if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE))
 +                      total++;
 +      }
 +
 +      return start_progress_delay(_("Checking out files"),
 +                                  total, 50, 1);
 +}
 +
 +static int check_updates(struct unpack_trees_options *o)
 +{
 +      unsigned cnt = 0;
 +      int errs = 0;
        struct progress *progress = NULL;
        struct index_state *index = &o->result;
 +      struct checkout state = CHECKOUT_INIT;
        int i;
 -      int errs = 0;
  
 -      if (o->update && o->verbose_update) {
 -              for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
 -                      const struct cache_entry *ce = index->cache[cnt];
 -                      if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE))
 -                              total++;
 -              }
 +      state.force = 1;
 +      state.quiet = 1;
 +      state.refresh_cache = 1;
 +      state.istate = index;
  
 -              progress = start_progress_delay(_("Checking out files"),
 -                                              total, 50, 1);
 -              cnt = 0;
 -      }
 +      progress = get_progress(o);
  
        if (o->update)
 -              git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
 +              git_attr_set_direction(GIT_ATTR_CHECKOUT, index);
        for (i = 0; i < index->cache_nr; i++) {
                const struct cache_entry *ce = index->cache[i];
  
                        display_progress(progress, ++cnt);
                        if (o->update && !o->dry_run)
                                unlink_entry(ce);
 -                      continue;
                }
        }
 -      remove_marked_cache_entries(&o->result);
 +      remove_marked_cache_entries(index);
        remove_scheduled_dirs();
  
        for (i = 0; i < index->cache_nr; i++) {
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
                        if (o->update && !o->dry_run) {
 -                              errs |= checkout_entry(ce, state, NULL);
 +                              errs |= checkout_entry(ce, &state, NULL);
                        }
                }
        }
@@@ -1106,9 -1129,14 +1141,9 @@@ int unpack_trees(unsigned len, struct t
        int i, ret;
        static struct cache_entry *dfc;
        struct exclude_list el;
 -      struct checkout state = CHECKOUT_INIT;
  
        if (len > MAX_UNPACK_TREES)
                die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
 -      state.force = 1;
 -      state.quiet = 1;
 -      state.refresh_cache = 1;
 -      state.istate = &o->result;
  
        memset(&el, 0, sizeof(el));
        if (!core_apply_sparse_checkout || !o->update)
        }
  
        o->src_index = NULL;
 -      ret = check_updates(o, &state) ? (-2) : 0;
 +      ret = check_updates(o) ? (-2) : 0;
        if (o->dst_index) {
                if (!ret) {
                        if (!o->result.cache_tree)
@@@ -1925,7 -1953,9 +1960,9 @@@ int bind_merge(const struct cache_entr
                             o->merge_size);
        if (a && old)
                return o->gently ? -1 :
-                       error(ERRORMSG(o, ERROR_BIND_OVERLAP), a->name, old->name);
+                       error(ERRORMSG(o, ERROR_BIND_OVERLAP),
+                             super_prefixed(a->name),
+                             super_prefixed(old->name));
        if (!a)
                return keep_entry(old, o);
        else