apply: further split load_preimage()
[gitweb.git] / builtin / apply.c
index 35460c940c5082b2c9369038d131d0582c406331..ee1a960890a160ae6c5b61ed5130a4da8eca7de8 100644 (file)
@@ -371,8 +371,8 @@ static void prepare_image(struct image *image, char *buf, size_t len,
 static void clear_image(struct image *image)
 {
        free(image->buf);
-       image->buf = NULL;
-       image->len = 0;
+       free(image->line_allocated);
+       memset(image, 0, sizeof(*image));
 }
 
 /* fmt must contain _one_ %s and no other substitution */
@@ -2930,20 +2930,17 @@ static int apply_fragments(struct image *img, struct patch *patch)
        return 0;
 }
 
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
 {
-       if (!ce)
-               return 0;
-
-       if (S_ISGITLINK(ce->ce_mode)) {
+       if (S_ISGITLINK(mode)) {
                strbuf_grow(buf, 100);
-               strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+               strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
        } else {
                enum object_type type;
                unsigned long sz;
                char *result;
 
-               result = read_sha1_file(ce->sha1, &type, &sz);
+               result = read_sha1_file(sha1, &type, &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
@@ -2952,6 +2949,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
        return 0;
 }
 
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+{
+       if (!ce)
+               return 0;
+       return read_blob_object(buf, ce->sha1, ce->ce_mode);
+}
+
 static struct patch *in_fn_table(const char *name)
 {
        struct string_list_item *item;
@@ -3030,47 +3034,117 @@ static void prepare_fn_table(struct patch *patch)
        }
 }
 
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int checkout_target(struct cache_entry *ce, struct stat *st)
+{
+       struct checkout costate;
+
+       memset(&costate, 0, sizeof(costate));
+       costate.base_dir = "";
+       costate.refresh_cache = 1;
+       if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+               return error(_("cannot checkout %s"), ce->name);
+       return 0;
+}
+
+static struct patch *previous_patch(struct patch *patch, int *gone)
+{
+       struct patch *previous;
+
+       *gone = 0;
+       if (patch->is_copy || patch->is_rename)
+               return NULL; /* "git" patches do not depend on the order */
+
+       previous = in_fn_table(patch->old_name);
+       if (!previous)
+               return NULL;
+
+       if (to_be_deleted(previous))
+               return NULL; /* the deletion hasn't happened yet */
+
+       if (was_deleted(previous))
+               *gone = 1;
+
+       return previous;
+}
+
+#define SUBMODULE_PATCH_WITHOUT_INDEX 1
+
+static int load_patch_target(struct strbuf *buf,
+                            struct cache_entry *ce,
+                            struct stat *st,
+                            const char *name,
+                            unsigned expected_mode)
+{
+       if (cached) {
+               if (read_file_or_gitlink(ce, buf))
+                       return error(_("read of %s failed"), name);
+       } else if (name) {
+               if (S_ISGITLINK(expected_mode)) {
+                       if (ce)
+                               return read_file_or_gitlink(ce, buf);
+                       else
+                               return SUBMODULE_PATCH_WITHOUT_INDEX;
+               } else {
+                       if (read_old_data(st, name, buf))
+                               return error(_("read of %s failed"), name);
+               }
+       }
+       return 0;
+}
+
+/*
+ * We are about to apply "patch"; populate the "image" with the
+ * current version we have, from the working tree or from the index,
+ * depending on the situation e.g. --cached/--index.  If we are
+ * applying a non-git patch that incrementally updates the tree,
+ * we read from the result of a previous diff.
+ */
+static int load_preimage(struct image *image,
+                        struct patch *patch, struct stat *st, struct cache_entry *ce)
 {
        struct strbuf buf = STRBUF_INIT;
-       struct image image;
        size_t len;
        char *img;
-       struct patch *tpatch;
+       struct patch *previous;
+       int status;
 
-       if (!(patch->is_copy || patch->is_rename) &&
-           (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
-               if (was_deleted(tpatch)) {
-                       return error(_("patch %s has been renamed/deleted"),
-                               patch->old_name);
-               }
+       previous = previous_patch(patch, &status);
+       if (status)
+               return error(_("path %s has been renamed/deleted"),
+                            patch->old_name);
+       if (previous) {
                /* We have a patched copy in memory; use that. */
-               strbuf_add(&buf, tpatch->result, tpatch->resultsize);
-       } else if (cached) {
-               if (read_file_or_gitlink(ce, &buf))
+               strbuf_add(&buf, previous->result, previous->resultsize);
+       } else {
+               status = load_patch_target(&buf, ce, st,
+                                          patch->old_name, patch->old_mode);
+               if (status < 0)
+                       return status;
+               else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
+                       /*
+                        * There is no way to apply subproject
+                        * patch without looking at the index.
+                        * NEEDSWORK: shouldn't this be flagged
+                        * as an error???
+                        */
+                       free_fragment_list(patch->fragments);
+                       patch->fragments = NULL;
+               } else if (status) {
                        return error(_("read of %s failed"), patch->old_name);
-       } else if (patch->old_name) {
-               if (S_ISGITLINK(patch->old_mode)) {
-                       if (ce) {
-                               read_file_or_gitlink(ce, &buf);
-                       } else {
-                               /*
-                                * There is no way to apply subproject
-                                * patch without looking at the index.
-                                * NEEDSWORK: shouldn't this be flagged
-                                * as an error???
-                                */
-                               free_fragment_list(patch->fragments);
-                               patch->fragments = NULL;
-                       }
-               } else {
-                       if (read_old_data(st, patch->old_name, &buf))
-                               return error(_("read of %s failed"), patch->old_name);
                }
        }
 
        img = strbuf_detach(&buf, &len);
-       prepare_image(&image, img, len, !patch->is_binary);
+       prepare_image(image, img, len, !patch->is_binary);
+       return 0;
+}
+
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+{
+       struct image image;
+
+       if (load_preimage(&image, patch, st, ce) < 0)
+               return -1;
 
        if (apply_fragments(&image, patch) < 0)
                return -1; /* note with --reject this succeeds. */
@@ -3118,39 +3192,41 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
        return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 }
 
+/*
+ * If "patch" that we are looking at modifies or deletes what we have,
+ * we would want it not to lose any local modification we have, either
+ * in the working tree or in the index.
+ *
+ * This also decides if a non-git patch is a creation patch or a
+ * modification to an existing empty file.  We do not check the state
+ * of the current tree for a creation patch in this function; the caller
+ * check_patch() separately makes sure (and errors out otherwise) that
+ * the path the patch creates does not exist in the current tree.
+ */
 static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
 {
        const char *old_name = patch->old_name;
-       struct patch *tpatch = NULL;
-       int stat_ret = 0;
+       struct patch *previous = NULL;
+       int stat_ret = 0, status;
        unsigned st_mode = 0;
 
-       /*
-        * Make sure that we do not have local modifications from the
-        * index when we are looking at the index.  Also make sure
-        * we have the preimage file to be patched in the work tree,
-        * unless --cached, which tells git to apply only in the index.
-        */
        if (!old_name)
                return 0;
 
        assert(patch->is_new <= 0);
+       previous = previous_patch(patch, &status);
 
-       if (!(patch->is_copy || patch->is_rename) &&
-           (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
-               if (was_deleted(tpatch))
-                       return error(_("%s: has been deleted/renamed"), old_name);
-               st_mode = tpatch->new_mode;
+       if (status)
+               return error(_("path %s has been renamed/deleted"), old_name);
+       if (previous) {
+               st_mode = previous->new_mode;
        } else if (!cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
                        return error(_("%s: %s"), old_name, strerror(errno));
        }
 
-       if (to_be_deleted(tpatch))
-               tpatch = NULL;
-
-       if (check_index && !tpatch) {
+       if (check_index && !previous) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
@@ -3159,13 +3235,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                }
                *ce = active_cache[pos];
                if (stat_ret < 0) {
-                       struct checkout costate;
-                       /* checkout */
-                       memset(&costate, 0, sizeof(costate));
-                       costate.base_dir = "";
-                       costate.refresh_cache = 1;
-                       if (checkout_entry(*ce, &costate, NULL) ||
-                           lstat(old_name, st))
+                       if (checkout_target(*ce, st))
                                return -1;
                }
                if (!cached && verify_index_match(*ce, st))
@@ -3178,7 +3248,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                return error(_("%s: %s"), old_name, strerror(errno));
        }
 
-       if (!cached && !tpatch)
+       if (!cached && !previous)
                st_mode = ce_mode_from_stat(*ce, st->st_mode);
 
        if (patch->is_new < 0)