apply: pass apply state to build_fake_ancestor()
[gitweb.git] / apply.c
diff --git a/apply.c b/apply.c
index 5e3780d281f838580cce02ca4d06e1b2382ab84a..a9a743cf9c7ec869aeb4d8f57b12e7bf638c202c 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -27,7 +27,7 @@ static void git_apply_config(void)
        git_config(git_default_config, NULL);
 }
 
-int parse_whitespace_option(struct apply_state *state, const char *option)
+static int parse_whitespace_option(struct apply_state *state, const char *option)
 {
        if (!option) {
                state->ws_error_action = warn_on_ws_error;
@@ -57,8 +57,8 @@ int parse_whitespace_option(struct apply_state *state, const char *option)
        return error(_("unrecognized whitespace option '%s'"), option);
 }
 
-int parse_ignorewhitespace_option(struct apply_state *state,
-                                 const char *option)
+static int parse_ignorewhitespace_option(struct apply_state *state,
+                                                const char *option)
 {
        if (!option || !strcmp(option, "no") ||
            !strcmp(option, "false") || !strcmp(option, "never") ||
@@ -112,6 +112,11 @@ void clear_apply_state(struct apply_state *state)
        /* &state->fn_table is cleared at the end of apply_patch() */
 }
 
+static void mute_routine(const char *msg, va_list params)
+{
+       /* do nothing */
+}
+
 int check_apply_state(struct apply_state *state, int force_apply)
 {
        int is_not_gitdir = !startup_info->have_repository;
@@ -125,8 +130,11 @@ int check_apply_state(struct apply_state *state, int force_apply)
                        return error(_("--3way outside a repository"));
                state->check_index = 1;
        }
-       if (state->apply_with_reject)
-               state->apply = state->apply_verbosely = 1;
+       if (state->apply_with_reject) {
+               state->apply = 1;
+               if (state->apply_verbosity == verbosity_normal)
+                       state->apply_verbosity = verbosity_verbose;
+       }
        if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
                state->apply = 0;
        if (state->check_index && is_not_gitdir)
@@ -141,6 +149,13 @@ int check_apply_state(struct apply_state *state, int force_apply)
        if (!state->lock_file)
                return error("BUG: state->lock_file should not be NULL");
 
+       if (state->apply_verbosity <= verbosity_silent) {
+               state->saved_error_routine = get_error_routine();
+               state->saved_warn_routine = get_warn_routine();
+               set_error_routine(mute_routine);
+               set_warn_routine(mute_routine);
+       }
+
        return 0;
 }
 
@@ -1620,8 +1635,9 @@ static void record_ws_error(struct apply_state *state,
                return;
 
        err = whitespace_error_string(result);
-       fprintf(stderr, "%s:%d: %s.\n%.*s\n",
-               state->patch_input_file, linenr, err, len, line);
+       if (state->apply_verbosity > verbosity_silent)
+               fprintf(stderr, "%s:%d: %s.\n%.*s\n",
+                       state->patch_input_file, linenr, err, len, line);
        free(err);
 }
 
@@ -1816,7 +1832,7 @@ static int parse_single_patch(struct apply_state *state,
                return error(_("new file %s depends on old contents"), patch->new_name);
        if (0 < patch->is_delete && newlines)
                return error(_("deleted file %s still has contents"), patch->old_name);
-       if (!patch->is_delete && !newlines && context)
+       if (!patch->is_delete && !newlines && context && state->apply_verbosity > verbosity_silent)
                fprintf_ln(stderr,
                           _("** warning: "
                             "file %s becomes empty but is not deleted"),
@@ -2911,7 +2927,7 @@ static int apply_one_fragment(struct apply_state *state,
                        /* Ignore it, we already handled it */
                        break;
                default:
-                       if (state->apply_verbosely)
+                       if (state->apply_verbosity > verbosity_normal)
                                error(_("invalid start of line: '%c'"), first);
                        applied_pos = -1;
                        goto out;
@@ -3026,7 +3042,7 @@ static int apply_one_fragment(struct apply_state *state,
                                state->apply = 0;
                }
 
-               if (state->apply_verbosely && applied_pos != pos) {
+               if (state->apply_verbosity > verbosity_normal && applied_pos != pos) {
                        int offset = applied_pos - pos;
                        if (state->apply_in_reverse)
                                offset = 0 - offset;
@@ -3041,14 +3057,14 @@ static int apply_one_fragment(struct apply_state *state,
                 * Warn if it was necessary to reduce the number
                 * of context lines.
                 */
-               if ((leading != frag->leading) ||
-                   (trailing != frag->trailing))
+               if ((leading != frag->leading ||
+                    trailing != frag->trailing) && state->apply_verbosity > verbosity_silent)
                        fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
                                             " to apply fragment at %d"),
                                   leading, trailing, applied_pos+1);
                update_image(state, img, applied_pos, &preimage, &postimage);
        } else {
-               if (state->apply_verbosely)
+               if (state->apply_verbosity > verbosity_normal)
                        error(_("while searching for:\n%.*s"),
                              (int)(old - oldlines), oldlines);
        }
@@ -3497,7 +3513,7 @@ static int load_current(struct apply_state *state,
        ce = active_cache[pos];
        if (lstat(name, &st)) {
                if (errno != ENOENT)
-                       return error(_("%s: %s"), name, strerror(errno));
+                       return error_errno("%s", name);
                if (checkout_target(&the_index, ce, &st))
                        return -1;
        }
@@ -3539,7 +3555,8 @@ static int try_threeway(struct apply_state *state,
                 read_blob_object(&buf, pre_sha1, patch->old_mode))
                return error("repository lacks the necessary blob to fall back on 3-way merge.");
 
-       fprintf(stderr, "Falling back to three-way merge...\n");
+       if (state->apply_verbosity > verbosity_silent)
+               fprintf(stderr, "Falling back to three-way merge...\n");
 
        img = strbuf_detach(&buf, &len);
        prepare_image(&tmp_image, img, len, 1);
@@ -3569,7 +3586,9 @@ static int try_threeway(struct apply_state *state,
        status = three_way_merge(image, patch->new_name,
                                 pre_sha1, our_sha1, post_sha1);
        if (status < 0) {
-               fprintf(stderr, "Failed to fall back on three-way merge...\n");
+               if (state->apply_verbosity > verbosity_silent)
+                       fprintf(stderr,
+                               "Failed to fall back on three-way merge...\n");
                return status;
        }
 
@@ -3581,9 +3600,15 @@ static int try_threeway(struct apply_state *state,
                        hashcpy(patch->threeway_stage[0].hash, pre_sha1);
                hashcpy(patch->threeway_stage[1].hash, our_sha1);
                hashcpy(patch->threeway_stage[2].hash, post_sha1);
-               fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
+               if (state->apply_verbosity > verbosity_silent)
+                       fprintf(stderr,
+                               "Applied patch to '%s' with conflicts.\n",
+                               patch->new_name);
        } else {
-               fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
+               if (state->apply_verbosity > verbosity_silent)
+                       fprintf(stderr,
+                               "Applied patch to '%s' cleanly.\n",
+                               patch->new_name);
        }
        return 0;
 }
@@ -3647,7 +3672,7 @@ static int check_preimage(struct apply_state *state,
        } else if (!state->cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
-                       return error(_("%s: %s"), old_name, strerror(errno));
+                       return error_errno("%s", old_name);
        }
 
        if (state->check_index && !previous) {
@@ -3669,7 +3694,7 @@ static int check_preimage(struct apply_state *state,
        } else if (stat_ret < 0) {
                if (patch->is_new < 0)
                        goto is_new;
-               return error(_("%s: %s"), old_name, strerror(errno));
+               return error_errno("%s", old_name);
        }
 
        if (!state->cached && !previous)
@@ -3728,7 +3753,7 @@ static int check_to_create(struct apply_state *state,
 
                return EXISTS_IN_WORKTREE;
        } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
-               return error("%s: %s", new_name, strerror(errno));
+               return error_errno("%s", new_name);
        }
        return 0;
 }
@@ -3956,7 +3981,7 @@ static int check_patch_list(struct apply_state *state, struct patch *patch)
        prepare_fn_table(state, patch);
        while (patch) {
                int res;
-               if (state->apply_verbosely)
+               if (state->apply_verbosity > verbosity_normal)
                        say_patch_name(stderr,
                                       _("Checking patch %s..."), patch);
                res = check_patch(state, patch);
@@ -4017,7 +4042,7 @@ static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20
 }
 
 /* Build an index that contains the just the files needed for a 3way merge */
-static int build_fake_ancestor(struct patch *list, const char *filename)
+static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 {
        struct patch *patch;
        struct index_state result = { NULL };
@@ -4064,12 +4089,13 @@ static int build_fake_ancestor(struct patch *list, const char *filename)
                }
        }
 
-       hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
+       hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR);
        res = write_locked_index(&result, &lock, COMMIT_LOCK);
        discard_index(&result);
 
        if (res)
-               return error("Could not write temporary index to %s", filename);
+               return error("Could not write temporary index to %s",
+                            state->fake_ancestor);
 
        return 0;
 }
@@ -4247,9 +4273,9 @@ static int add_index_file(struct apply_state *state,
                if (!state->cached) {
                        if (lstat(path, &st) < 0) {
                                free(ce);
-                               return error(_("unable to stat newly "
-                                              "created file '%s': %s"),
-                                            path, strerror(errno));
+                               return error_errno(_("unable to stat newly "
+                                                    "created file '%s'"),
+                                                  path);
                        }
                        fill_stat_cache_info(ce, &st);
                }
@@ -4472,7 +4498,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
        }
 
        if (!cnt) {
-               if (state->apply_verbosely)
+               if (state->apply_verbosity > verbosity_normal)
                        say_patch_name(stderr,
                                       _("Applied patch %s cleanly."), patch);
                return 0;
@@ -4489,7 +4515,8 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
                            "Applying patch %%s with %d rejects...",
                            cnt),
                    cnt);
-       say_patch_name(stderr, sb.buf, patch);
+       if (state->apply_verbosity > verbosity_silent)
+               say_patch_name(stderr, sb.buf, patch);
        strbuf_release(&sb);
 
        cnt = strlen(patch->new_name);
@@ -4503,7 +4530,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
 
        rej = fopen(namebuf, "w");
        if (!rej)
-               return error(_("cannot open %s: %s"), namebuf, strerror(errno));
+               return error_errno(_("cannot open %s"), namebuf);
 
        /* Normal git tools never deal with .rej, so do not pretend
         * this is a git patch by saying --git or giving extended
@@ -4516,10 +4543,12 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
             frag;
             cnt++, frag = frag->next) {
                if (!frag->rejected) {
-                       fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
+                       if (state->apply_verbosity > verbosity_silent)
+                               fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
                        continue;
                }
-               fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
+               if (state->apply_verbosity > verbosity_silent)
+                       fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
                fprintf(rej, "%.*s", frag->size, frag->patch);
                if (frag->patch[frag->size-1] != '\n')
                        fputc('\n', rej);
@@ -4568,8 +4597,10 @@ static int write_out_results(struct apply_state *state, struct patch *list)
                struct string_list_item *item;
 
                string_list_sort(&cpath);
-               for_each_string_list_item(item, &cpath)
-                       fprintf(stderr, "U %s\n", item->string);
+               if (state->apply_verbosity > verbosity_silent) {
+                       for_each_string_list_item(item, &cpath)
+                               fprintf(stderr, "U %s\n", item->string);
+               }
                string_list_clear(&cpath, 0);
 
                rerere(0);
@@ -4626,7 +4657,7 @@ static int apply_patch(struct apply_state *state,
                        listp = &patch->next;
                }
                else {
-                       if (state->apply_verbosely)
+                       if (state->apply_verbosity > verbosity_normal)
                                say_patch_name(stderr, _("Skipped patch '%s'."), patch);
                        free_patch(patch);
                        skipped_patch++;
@@ -4679,18 +4710,18 @@ static int apply_patch(struct apply_state *state,
        }
 
        if (state->fake_ancestor &&
-           build_fake_ancestor(list, state->fake_ancestor)) {
+           build_fake_ancestor(state, list)) {
                res = -128;
                goto end;
        }
 
-       if (state->diffstat)
+       if (state->diffstat && state->apply_verbosity > verbosity_silent)
                stat_patch_list(state, list);
 
-       if (state->numstat)
+       if (state->numstat && state->apply_verbosity > verbosity_silent)
                numstat_patch_list(state, list);
 
-       if (state->summary)
+       if (state->summary && state->apply_verbosity > verbosity_silent)
                summary_patch_list(list);
 
 end:
@@ -4700,16 +4731,16 @@ static int apply_patch(struct apply_state *state,
        return res;
 }
 
-int apply_option_parse_exclude(const struct option *opt,
-                              const char *arg, int unset)
+static int apply_option_parse_exclude(const struct option *opt,
+                                     const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
        add_name_limit(state, arg, 1);
        return 0;
 }
 
-int apply_option_parse_include(const struct option *opt,
-                              const char *arg, int unset)
+static int apply_option_parse_include(const struct option *opt,
+                                     const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
        add_name_limit(state, arg, 0);
@@ -4717,9 +4748,9 @@ int apply_option_parse_include(const struct option *opt,
        return 0;
 }
 
-int apply_option_parse_p(const struct option *opt,
-                        const char *arg,
-                        int unset)
+static int apply_option_parse_p(const struct option *opt,
+                               const char *arg,
+                               int unset)
 {
        struct apply_state *state = opt->value;
        state->p_value = atoi(arg);
@@ -4727,8 +4758,8 @@ int apply_option_parse_p(const struct option *opt,
        return 0;
 }
 
-int apply_option_parse_space_change(const struct option *opt,
-                                   const char *arg, int unset)
+static int apply_option_parse_space_change(const struct option *opt,
+                                          const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
        if (unset)
@@ -4738,8 +4769,8 @@ int apply_option_parse_space_change(const struct option *opt,
        return 0;
 }
 
-int apply_option_parse_whitespace(const struct option *opt,
-                                 const char *arg, int unset)
+static int apply_option_parse_whitespace(const struct option *opt,
+                                        const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
        state->whitespace_option = arg;
@@ -4748,8 +4779,8 @@ int apply_option_parse_whitespace(const struct option *opt,
        return 0;
 }
 
-int apply_option_parse_directory(const struct option *opt,
-                                const char *arg, int unset)
+static int apply_option_parse_directory(const struct option *opt,
+                                       const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
        strbuf_reset(&state->root);
@@ -4846,7 +4877,7 @@ int apply_all_patches(struct apply_state *state,
                state->newfd = -1;
        }
 
-       return !!errs;
+       res = !!errs;
 
 end:
        if (state->newfd >= 0) {
@@ -4854,5 +4885,89 @@ int apply_all_patches(struct apply_state *state,
                state->newfd = -1;
        }
 
+       if (state->apply_verbosity <= verbosity_silent) {
+               set_error_routine(state->saved_error_routine);
+               set_warn_routine(state->saved_warn_routine);
+       }
+
+       if (res > -1)
+               return res;
        return (res == -1 ? 1 : 128);
 }
+
+int apply_parse_options(int argc, const char **argv,
+                       struct apply_state *state,
+                       int *force_apply, int *options,
+                       const char * const *apply_usage)
+{
+       struct option builtin_apply_options[] = {
+               { OPTION_CALLBACK, 0, "exclude", state, N_("path"),
+                       N_("don't apply changes matching the given path"),
+                       0, apply_option_parse_exclude },
+               { OPTION_CALLBACK, 0, "include", state, N_("path"),
+                       N_("apply changes matching the given path"),
+                       0, apply_option_parse_include },
+               { OPTION_CALLBACK, 'p', NULL, state, N_("num"),
+                       N_("remove <num> leading slashes from traditional diff paths"),
+                       0, apply_option_parse_p },
+               OPT_BOOL(0, "no-add", &state->no_add,
+                       N_("ignore additions made by the patch")),
+               OPT_BOOL(0, "stat", &state->diffstat,
+                       N_("instead of applying the patch, output diffstat for the input")),
+               OPT_NOOP_NOARG(0, "allow-binary-replacement"),
+               OPT_NOOP_NOARG(0, "binary"),
+               OPT_BOOL(0, "numstat", &state->numstat,
+                       N_("show number of added and deleted lines in decimal notation")),
+               OPT_BOOL(0, "summary", &state->summary,
+                       N_("instead of applying the patch, output a summary for the input")),
+               OPT_BOOL(0, "check", &state->check,
+                       N_("instead of applying the patch, see if the patch is applicable")),
+               OPT_BOOL(0, "index", &state->check_index,
+                       N_("make sure the patch is applicable to the current index")),
+               OPT_BOOL(0, "cached", &state->cached,
+                       N_("apply a patch without touching the working tree")),
+               OPT_BOOL(0, "unsafe-paths", &state->unsafe_paths,
+                       N_("accept a patch that touches outside the working area")),
+               OPT_BOOL(0, "apply", force_apply,
+                       N_("also apply the patch (use with --stat/--summary/--check)")),
+               OPT_BOOL('3', "3way", &state->threeway,
+                        N_( "attempt three-way merge if a patch does not apply")),
+               OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
+                       N_("build a temporary index based on embedded index information")),
+               /* Think twice before adding "--nul" synonym to this */
+               OPT_SET_INT('z', NULL, &state->line_termination,
+                       N_("paths are separated with NUL character"), '\0'),
+               OPT_INTEGER('C', NULL, &state->p_context,
+                               N_("ensure at least <n> lines of context match")),
+               { OPTION_CALLBACK, 0, "whitespace", state, N_("action"),
+                       N_("detect new or modified lines that have whitespace errors"),
+                       0, apply_option_parse_whitespace },
+               { OPTION_CALLBACK, 0, "ignore-space-change", state, NULL,
+                       N_("ignore changes in whitespace when finding context"),
+                       PARSE_OPT_NOARG, apply_option_parse_space_change },
+               { OPTION_CALLBACK, 0, "ignore-whitespace", state, NULL,
+                       N_("ignore changes in whitespace when finding context"),
+                       PARSE_OPT_NOARG, apply_option_parse_space_change },
+               OPT_BOOL('R', "reverse", &state->apply_in_reverse,
+                       N_("apply the patch in reverse")),
+               OPT_BOOL(0, "unidiff-zero", &state->unidiff_zero,
+                       N_("don't expect at least one line of context")),
+               OPT_BOOL(0, "reject", &state->apply_with_reject,
+                       N_("leave the rejected hunks in corresponding *.rej files")),
+               OPT_BOOL(0, "allow-overlap", &state->allow_overlap,
+                       N_("allow overlapping hunks")),
+               OPT__VERBOSE(&state->apply_verbosity, N_("be verbose")),
+               OPT_BIT(0, "inaccurate-eof", options,
+                       N_("tolerate incorrectly detected missing new-line at the end of file"),
+                       APPLY_OPT_INACCURATE_EOF),
+               OPT_BIT(0, "recount", options,
+                       N_("do not trust the line counts in the hunk headers"),
+                       APPLY_OPT_RECOUNT),
+               { OPTION_CALLBACK, 0, "directory", state, N_("root"),
+                       N_("prepend <root> to all filenames"),
+                       0, apply_option_parse_directory },
+               OPT_END()
+       };
+
+       return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+}