i18n: rebase-interactive: mark strings for translation
[gitweb.git] / rerere.c
index 2b870e02a2bc12cb6925f57b3983021c5224c513..aaadec17d867d521fc0eaab7fcdd2e871bdf1267 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -21,8 +21,6 @@ static int rerere_enabled = -1;
 /* automatically update cleanly resolved paths to the index */
 static int rerere_autoupdate;
 
-static char *merge_rr_path;
-
 static int rerere_dir_nr;
 static int rerere_dir_alloc;
 
@@ -202,7 +200,7 @@ static struct rerere_id *new_rerere_id(unsigned char *sha1)
 static void read_rr(struct string_list *rr)
 {
        struct strbuf buf = STRBUF_INIT;
-       FILE *in = fopen(merge_rr_path, "r");
+       FILE *in = fopen(git_path_merge_rr(), "r");
 
        if (!in)
                return;
@@ -503,8 +501,7 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output
                error("There were errors while writing %s (%s)",
                      path, strerror(io.io.wrerror));
        if (io.io.output && fclose(io.io.output))
-               io.io.wrerror = error("Failed to flush %s: %s",
-                                     path, strerror(errno));
+               io.io.wrerror = error_errno("Failed to flush %s", path);
 
        if (hunk_no < 0) {
                if (output)
@@ -600,6 +597,8 @@ static int find_conflict(struct string_list *conflict)
 int rerere_remaining(struct string_list *merge_rr)
 {
        int i;
+       if (setup_rerere(merge_rr, RERERE_READONLY))
+               return 0;
        if (read_cache() < 0)
                return error("Could not read index");
 
@@ -621,6 +620,33 @@ int rerere_remaining(struct string_list *merge_rr)
        return 0;
 }
 
+/*
+ * Try using the given conflict resolution "ID" to see
+ * if that recorded conflict resolves cleanly what we
+ * got in the "cur".
+ */
+static int try_merge(const struct rerere_id *id, const char *path,
+                    mmfile_t *cur, mmbuffer_t *result)
+{
+       int ret;
+       mmfile_t base = {NULL, 0}, other = {NULL, 0};
+
+       if (read_mmfile(&base, rerere_path(id, "preimage")) ||
+           read_mmfile(&other, rerere_path(id, "postimage")))
+               ret = 1;
+       else
+               /*
+                * A three-way merge. Note that this honors user-customizable
+                * low-level merge driver settings.
+                */
+               ret = ll_merge(result, path, &base, NULL, cur, "", &other, "", NULL);
+
+       free(base.ptr);
+       free(other.ptr);
+
+       return ret;
+}
+
 /*
  * Find the conflict identified by "id"; the change between its
  * "preimage" (i.e. a previous contents with conflict markers) and its
@@ -635,30 +661,20 @@ static int merge(const struct rerere_id *id, const char *path)
 {
        FILE *f;
        int ret;
-       mmfile_t cur = {NULL, 0}, base = {NULL, 0}, other = {NULL, 0};
+       mmfile_t cur = {NULL, 0};
        mmbuffer_t result = {NULL, 0};
 
        /*
         * Normalize the conflicts in path and write it out to
         * "thisimage" temporary file.
         */
-       if (handle_file(path, NULL, rerere_path(id, "thisimage")) < 0) {
+       if ((handle_file(path, NULL, rerere_path(id, "thisimage")) < 0) ||
+           read_mmfile(&cur, rerere_path(id, "thisimage"))) {
                ret = 1;
                goto out;
        }
 
-       if (read_mmfile(&cur, rerere_path(id, "thisimage")) ||
-           read_mmfile(&base, rerere_path(id, "preimage")) ||
-           read_mmfile(&other, rerere_path(id, "postimage"))) {
-               ret = 1;
-               goto out;
-       }
-
-       /*
-        * A three-way merge. Note that this honors user-customizable
-        * low-level merge driver settings.
-        */
-       ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", NULL);
+       ret = try_merge(id, path, &cur, &result);
        if (ret)
                goto out;
 
@@ -667,25 +683,20 @@ static int merge(const struct rerere_id *id, const char *path)
         * Mark that "postimage" was used to help gc.
         */
        if (utime(rerere_path(id, "postimage"), NULL) < 0)
-               warning("failed utime() on %s: %s",
-                       rerere_path(id, "postimage"),
-                       strerror(errno));
+               warning_errno("failed utime() on %s",
+                             rerere_path(id, "postimage"));
 
        /* Update "path" with the resolution */
        f = fopen(path, "w");
        if (!f)
-               return error("Could not open %s: %s", path,
-                            strerror(errno));
+               return error_errno("Could not open %s", path);
        if (fwrite(result.ptr, result.size, 1, f) != 1)
-               error("Could not write %s: %s", path, strerror(errno));
+               error_errno("Could not write %s", path);
        if (fclose(f))
-               return error("Writing %s failed: %s", path,
-                            strerror(errno));
+               return error_errno("Writing %s failed", path);
 
 out:
        free(cur.ptr);
-       free(base.ptr);
-       free(other.ptr);
        free(result.ptr);
 
        return ret;
@@ -855,21 +866,21 @@ static void git_rerere_config(void)
        git_config(git_default_config, NULL);
 }
 
+static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
+
 static int is_rerere_enabled(void)
 {
-       const char *rr_cache;
        int rr_cache_exists;
 
        if (!rerere_enabled)
                return 0;
 
-       rr_cache = git_path("rr-cache");
-       rr_cache_exists = is_directory(rr_cache);
+       rr_cache_exists = is_directory(git_path_rr_cache());
        if (rerere_enabled < 0)
                return rr_cache_exists;
 
-       if (!rr_cache_exists && mkdir_in_gitdir(rr_cache))
-               die("Could not create directory %s", rr_cache);
+       if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
+               die("Could not create directory %s", git_path_rr_cache());
        return 1;
 }
 
@@ -883,9 +894,11 @@ int setup_rerere(struct string_list *merge_rr, int flags)
 
        if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
                rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
-       merge_rr_path = git_pathdup("MERGE_RR");
-       fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
-                                      LOCK_DIE_ON_ERROR);
+       if (flags & RERERE_READONLY)
+               fd = 0;
+       else
+               fd = hold_lock_file_for_update(&write_lock, git_path_merge_rr(),
+                                              LOCK_DIE_ON_ERROR);
        read_rr(merge_rr);
        return fd;
 }
@@ -1023,12 +1036,43 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)
 
        /* Nuke the recorded resolution for the conflict */
        id = new_rerere_id(sha1);
-       id->variant = 0; /* for now */
+
+       for (id->variant = 0;
+            id->variant < id->collection->status_nr;
+            id->variant++) {
+               mmfile_t cur = { NULL, 0 };
+               mmbuffer_t result = {NULL, 0};
+               int cleanly_resolved;
+
+               if (!has_rerere_resolution(id))
+                       continue;
+
+               handle_cache(path, sha1, rerere_path(id, "thisimage"));
+               if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
+                       free(cur.ptr);
+                       error("Failed to update conflicted state in '%s'", path);
+                       goto fail_exit;
+               }
+               cleanly_resolved = !try_merge(id, path, &cur, &result);
+               free(result.ptr);
+               free(cur.ptr);
+               if (cleanly_resolved)
+                       break;
+       }
+
+       if (id->collection->status_nr <= id->variant) {
+               error("no remembered resolution for '%s'", path);
+               goto fail_exit;
+       }
+
        filename = rerere_path(id, "postimage");
-       if (unlink(filename))
-               return (errno == ENOENT
-                       ? error("no remembered resolution for %s", path)
-                       : error("cannot unlink %s: %s", filename, strerror(errno)));
+       if (unlink(filename)) {
+               if (errno == ENOENT)
+                       error("no remembered resolution for %s", path);
+               else
+                       error_errno("cannot unlink %s", filename);
+               goto fail_exit;
+       }
 
        /*
         * Update the preimage so that the user can resolve the
@@ -1047,6 +1091,10 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)
        item->util = id;
        fprintf(stderr, "Forgot resolution for %s\n", path);
        return 0;
+
+fail_exit:
+       free(id);
+       return -1;
 }
 
 int rerere_forget(struct pathspec *pathspec)
@@ -1059,6 +1107,8 @@ int rerere_forget(struct pathspec *pathspec)
                return error("Could not read index");
 
        fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
+       if (fd < 0)
+               return 0;
 
        /*
         * The paths may have been resolved (incorrectly);
@@ -1134,6 +1184,9 @@ void rerere_gc(struct string_list *rr)
        int cutoff_noresolve = 15;
        int cutoff_resolve = 60;
 
+       if (setup_rerere(rr, 0) < 0)
+               return;
+
        git_config_get_int("gc.rerereresolved", &cutoff_resolve);
        git_config_get_int("gc.rerereunresolved", &cutoff_noresolve);
        git_config(git_default_config, NULL);
@@ -1169,6 +1222,7 @@ void rerere_gc(struct string_list *rr)
        for (i = 0; i < to_remove.nr; i++)
                rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
        string_list_clear(&to_remove, 0);
+       rollback_lock_file(&write_lock);
 }
 
 /*
@@ -1182,6 +1236,9 @@ void rerere_clear(struct string_list *merge_rr)
 {
        int i;
 
+       if (setup_rerere(merge_rr, 0) < 0)
+               return;
+
        for (i = 0; i < merge_rr->nr; i++) {
                struct rerere_id *id = merge_rr->items[i].util;
                if (!has_rerere_resolution(id)) {
@@ -1189,5 +1246,6 @@ void rerere_clear(struct string_list *merge_rr)
                        rmdir(rerere_path(id, NULL));
                }
        }
-       unlink_or_warn(git_path("MERGE_RR"));
+       unlink_or_warn(git_path_merge_rr());
+       rollback_lock_file(&write_lock);
 }