Merge branch 'jk/run-command-use-shell'
authorJunio C Hamano <gitster@pobox.com>
Sun, 17 Jan 2010 23:58:15 +0000 (15:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 17 Jan 2010 23:58:15 +0000 (15:58 -0800)
* jk/run-command-use-shell:
t4030, t4031: work around bogus MSYS bash path conversion
diff: run external diff helper with shell
textconv: use shell to run helper
editor: use run_command's shell feature
run-command: optimize out useless shell calls
run-command: convert simple callsites to use_shell
t0021: use $SHELL_PATH for the filter script
run-command: add "use shell" option

1  2 
diff.c
diff --combined diff.c
index 04beb26a6a8aa46b5b0721b71236553cf549061b,3b235e39ba13d407c4c472f91e658fa45902327b..5d713145879d88339a3ea6bef207129f3cac3fef
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -194,7 -194,6 +194,7 @@@ struct emit_callback 
        struct diff_words_data *diff_words;
        int *found_changesp;
        FILE *file;
 +      struct strbuf *header;
  };
  
  static int count_lines(const char *data, int size)
@@@ -798,11 -797,6 +798,11 @@@ static void fn_out_consume(void *priv, 
        const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
  
 +      if (ecbdata->header) {
 +              fprintf(ecbdata->file, "%s", ecbdata->header->buf);
 +              strbuf_reset(ecbdata->header);
 +              ecbdata->header = NULL;
 +      }
        *(ecbdata->found_changesp) = 1;
  
        if (ecbdata->label_path[0]) {
@@@ -1607,7 -1601,6 +1607,7 @@@ static void builtin_diff(const char *na
        const char *reset = diff_get_color_opt(o, DIFF_RESET);
        const char *a_prefix, *b_prefix;
        const char *textconv_one = NULL, *textconv_two = NULL;
 +      struct strbuf header = STRBUF_INIT;
  
        if (DIFF_OPT_TST(o, SUBMODULE_LOG) &&
                        (!one->mode || S_ISGITLINK(one->mode)) &&
        b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
        lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
 -      fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
 +      strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
        if (lbl[0][0] == '/') {
                /* /dev/null */
 -              fprintf(o->file, "%snew file mode %06o%s\n", set, two->mode, reset);
 +              strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
        }
        else if (lbl[1][0] == '/') {
 -              fprintf(o->file, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
 +              strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
        }
        else {
                if (one->mode != two->mode) {
 -                      fprintf(o->file, "%sold mode %06o%s\n", set, one->mode, reset);
 -                      fprintf(o->file, "%snew mode %06o%s\n", set, two->mode, reset);
 +                      strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
 +                      strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
                }
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
 +
                /*
                 * we do not run diff between different kind
                 * of objects.
                if (complete_rewrite &&
                    (textconv_one || !diff_filespec_is_binary(one)) &&
                    (textconv_two || !diff_filespec_is_binary(two))) {
 +                      fprintf(o->file, "%s", header.buf);
 +                      strbuf_reset(&header);
                        emit_rewrite_diff(name_a, name_b, one, two,
                                                textconv_one, textconv_two, o);
                        o->found_changes = 1;
                if (mf1.size == mf2.size &&
                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
                        goto free_ab_and_return;
 +              fprintf(o->file, "%s", header.buf);
 +              strbuf_reset(&header);
                if (DIFF_OPT_TST(o, BINARY))
                        emit_binary_diff(o->file, &mf1, &mf2);
                else
                struct emit_callback ecbdata;
                const struct userdiff_funcname *pe;
  
 +              if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS)) {
 +                      fprintf(o->file, "%s", header.buf);
 +                      strbuf_reset(&header);
 +              }
 +
                if (textconv_one) {
                        size_t size;
                        mf1.ptr = run_textconv(textconv_one, one, &size);
                if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
                        check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.file = o->file;
 +              ecbdata.header = header.len ? &header : NULL;
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
        }
  
   free_ab_and_return:
 +      strbuf_release(&header);
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
        free(a_one);
@@@ -1997,7 -1978,7 +1997,7 @@@ static int reuse_worktree_file(const ch
         * If ce is marked as "assume unchanged", there is no
         * guarantee that work tree matches what we are looking for.
         */
 -      if (ce->ce_flags & CE_VALID)
 +      if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
                return 0;
  
        /*
@@@ -2294,7 -2275,7 +2294,7 @@@ static void run_external_diff(const cha
        }
        *arg = NULL;
        fflush(NULL);
-       retval = run_command_v_opt(spawn_arg, 0);
+       retval = run_command_v_opt(spawn_arg, RUN_USING_SHELL);
        remove_tempfile();
        if (retval) {
                fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@@ -2570,20 -2551,6 +2570,20 @@@ int diff_setup_done(struct diff_option
        if (count > 1)
                die("--name-only, --name-status, --check and -s are mutually exclusive");
  
 +      /*
 +       * Most of the time we can say "there are changes"
 +       * only by checking if there are changed paths, but
 +       * --ignore-whitespace* options force us to look
 +       * inside contents.
 +       */
 +
 +      if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
 +          DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
 +          DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
 +              DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
 +      else
 +              DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
 +
        if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
                options->detect_rename = DIFF_DETECT_COPY;
  
         * to have found.  It does not make sense not to return with
         * exit code in such a case either.
         */
 -      if (DIFF_OPT_TST(options, QUIET)) {
 +      if (DIFF_OPT_TST(options, QUICK)) {
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
@@@ -2835,7 -2802,7 +2835,7 @@@ int diff_opt_parse(struct diff_options 
        else if (!strcmp(arg, "--exit-code"))
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        else if (!strcmp(arg, "--quiet"))
 -              DIFF_OPT_SET(options, QUIET);
 +              DIFF_OPT_SET(options, QUICK);
        else if (!strcmp(arg, "--ext-diff"))
                DIFF_OPT_SET(options, ALLOW_EXTERNAL);
        else if (!strcmp(arg, "--no-ext-diff"))
@@@ -3542,18 -3509,6 +3542,18 @@@ free_queue
        q->nr = q->alloc = 0;
        if (options->close_file)
                fclose(options->file);
 +
 +      /*
 +       * Report the content-level differences with HAS_CHANGES;
 +       * diff_addremove/diff_change does not set the bit when
 +       * DIFF_FROM_CONTENTS is in effect (e.g. with -w).
 +       */
 +      if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
 +              if (options->found_changes)
 +                      DIFF_OPT_SET(options, HAS_CHANGES);
 +              else
 +                      DIFF_OPT_CLR(options, HAS_CHANGES);
 +      }
  }
  
  static void diffcore_apply_filter(const char *filter)
@@@ -3690,7 -3645,7 +3690,7 @@@ void diffcore_std(struct diff_options *
        diff_resolve_rename_copy();
        diffcore_apply_filter(options->filter);
  
 -      if (diff_queued_diff.nr)
 +      if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
                DIFF_OPT_SET(options, HAS_CHANGES);
        else
                DIFF_OPT_CLR(options, HAS_CHANGES);
@@@ -3750,8 -3705,7 +3750,8 @@@ void diff_addremove(struct diff_option
                fill_filespec(two, sha1, mode);
  
        diff_queue(&diff_queued_diff, one, two);
 -      DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +              DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
  void diff_change(struct diff_options *options,
        fill_filespec(two, new_sha1, new_mode);
  
        diff_queue(&diff_queued_diff, one, two);
 -      DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +              DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
  void diff_unmerge(struct diff_options *options,
@@@ -3818,18 -3771,17 +3818,19 @@@ static char *run_textconv(const char *p
        *arg = NULL;
  
        memset(&child, 0, sizeof(child));
+       child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
        if (start_command(&child) != 0 ||
            strbuf_read(&buf, child.out, 0) < 0 ||
            finish_command(&child) != 0) {
 +              close(child.out);
                strbuf_release(&buf);
                remove_tempfile();
                error("error running textconv command '%s'", pgm);
                return NULL;
        }
 +      close(child.out);
        remove_tempfile();
  
        return strbuf_detach(&buf, outsize);