travis-ci: switch to Xcode 10.1 macOS image
[gitweb.git] / match-trees.c
index 8ca7c68f5f28758f28d96ee3880f00bdf0523263..2b6d31ef9d35d9422e7ef90792651dcb7a2f9189 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "tree.h"
 #include "tree-walk.h"
+#include "object-store.h"
 
 static int score_missing(unsigned mode, const char *path)
 {
@@ -48,17 +49,17 @@ static int score_matches(unsigned mode1, unsigned mode2, const char *path)
 }
 
 static void *fill_tree_desc_strict(struct tree_desc *desc,
-                                  const unsigned char *hash)
+                                  const struct object_id *hash)
 {
        void *buffer;
        enum object_type type;
        unsigned long size;
 
-       buffer = read_sha1_file(hash, &type, &size);
+       buffer = read_object_file(hash, &type, &size);
        if (!buffer)
-               die("unable to read tree (%s)", sha1_to_hex(hash));
+               die("unable to read tree (%s)", oid_to_hex(hash));
        if (type != OBJ_TREE)
-               die("%s is not a tree", sha1_to_hex(hash));
+               die("%s is not a tree", oid_to_hex(hash));
        init_tree_desc(desc, buffer, size);
        return buffer;
 }
@@ -73,7 +74,7 @@ static int base_name_entries_compare(const struct name_entry *a,
 /*
  * Inspect two trees, and give a score that tells how similar they are.
  */
-static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
+static int score_trees(const struct object_id *hash1, const struct object_id *hash2)
 {
        struct tree_desc one;
        struct tree_desc two;
@@ -82,34 +83,43 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
        int score = 0;
 
        for (;;) {
-               struct name_entry e1, e2;
-               int got_entry_from_one = tree_entry(&one, &e1);
-               int got_entry_from_two = tree_entry(&two, &e2);
                int cmp;
 
-               if (got_entry_from_one && got_entry_from_two)
-                       cmp = base_name_entries_compare(&e1, &e2);
-               else if (got_entry_from_one)
+               if (one.size && two.size)
+                       cmp = base_name_entries_compare(&one.entry, &two.entry);
+               else if (one.size)
                        /* two lacks this entry */
                        cmp = -1;
-               else if (got_entry_from_two)
+               else if (two.size)
                        /* two has more entries */
                        cmp = 1;
                else
                        break;
 
-               if (cmp < 0)
+               if (cmp < 0) {
                        /* path1 does not appear in two */
-                       score += score_missing(e1.mode, e1.path);
-               else if (cmp > 0)
+                       score += score_missing(one.entry.mode, one.entry.path);
+                       update_tree_entry(&one);
+               } else if (cmp > 0) {
                        /* path2 does not appear in one */
-                       score += score_missing(e2.mode, e2.path);
-               else if (oidcmp(e1.oid, e2.oid))
-                       /* they are different */
-                       score += score_differs(e1.mode, e2.mode, e1.path);
-               else
-                       /* same subtree or blob */
-                       score += score_matches(e1.mode, e2.mode, e1.path);
+                       score += score_missing(two.entry.mode, two.entry.path);
+                       update_tree_entry(&two);
+               } else {
+                       /* path appears in both */
+                       if (!oideq(one.entry.oid, two.entry.oid)) {
+                               /* they are different */
+                               score += score_differs(one.entry.mode,
+                                                      two.entry.mode,
+                                                      one.entry.path);
+                       } else {
+                               /* same subtree or blob */
+                               score += score_matches(one.entry.mode,
+                                                      two.entry.mode,
+                                                      one.entry.path);
+                       }
+                       update_tree_entry(&one);
+                       update_tree_entry(&two);
+               }
        }
        free(one_buf);
        free(two_buf);
@@ -119,8 +129,8 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
 /*
  * Match one itself and its subtrees with two and pick the best match.
  */
-static void match_trees(const unsigned char *hash1,
-                       const unsigned char *hash2,
+static void match_trees(const struct object_id *hash1,
+                       const struct object_id *hash2,
                        int *best_score,
                        char **best_match,
                        const char *base,
@@ -138,7 +148,7 @@ static void match_trees(const unsigned char *hash1,
                elem = tree_entry_extract(&one, &path, &mode);
                if (!S_ISDIR(mode))
                        goto next;
-               score = score_trees(elem->hash, hash2);
+               score = score_trees(elem, hash2);
                if (*best_score < score) {
                        free(*best_match);
                        *best_match = xstrfmt("%s%s", base, path);
@@ -146,7 +156,7 @@ static void match_trees(const unsigned char *hash1,
                }
                if (recurse_limit) {
                        char *newbase = xstrfmt("%s%s/", base, path);
-                       match_trees(elem->hash, hash2, best_score, best_match,
+                       match_trees(elem, hash2, best_score, best_match,
                                    newbase, recurse_limit - 1);
                        free(newbase);
                }
@@ -158,22 +168,20 @@ static void match_trees(const unsigned char *hash1,
 }
 
 /*
- * A tree "hash1" has a subdirectory at "prefix".  Come up with a
- * tree object by replacing it with another tree "hash2".
+ * A tree "oid1" has a subdirectory at "prefix".  Come up with a tree object by
+ * replacing it with another tree "oid2".
  */
-static int splice_tree(const unsigned char *hash1,
-                      const char *prefix,
-                      const unsigned char *hash2,
-                      unsigned char *result)
+static int splice_tree(const struct object_id *oid1, const char *prefix,
+                      const struct object_id *oid2, struct object_id *result)
 {
        char *subpath;
        int toplen;
        char *buf;
        unsigned long sz;
        struct tree_desc desc;
-       unsigned char *rewrite_here;
-       const unsigned char *rewrite_with;
-       unsigned char subtree[20];
+       struct object_id *rewrite_here;
+       const struct object_id *rewrite_with;
+       struct object_id subtree;
        enum object_type type;
        int status;
 
@@ -182,9 +190,9 @@ static int splice_tree(const unsigned char *hash1,
        if (*subpath)
                subpath++;
 
-       buf = read_sha1_file(hash1, &type, &sz);
+       buf = read_object_file(oid1, &type, &sz);
        if (!buf)
-               die("cannot read tree %s", sha1_to_hex(hash1));
+               die("cannot read tree %s", oid_to_hex(oid1));
        init_tree_desc(&desc, buf, sz);
 
        rewrite_here = NULL;
@@ -197,26 +205,26 @@ static int splice_tree(const unsigned char *hash1,
                if (strlen(name) == toplen &&
                    !memcmp(name, prefix, toplen)) {
                        if (!S_ISDIR(mode))
-                               die("entry %s in tree %s is not a tree",
-                                   name, sha1_to_hex(hash1));
-                       rewrite_here = (unsigned char *) oid->hash;
+                               die("entry %s in tree %s is not a tree", name,
+                                   oid_to_hex(oid1));
+                       rewrite_here = (struct object_id *)oid;
                        break;
                }
                update_tree_entry(&desc);
        }
        if (!rewrite_here)
-               die("entry %.*s not found in tree %s",
-                   toplen, prefix, sha1_to_hex(hash1));
+               die("entry %.*s not found in tree %s", toplen, prefix,
+                   oid_to_hex(oid1));
        if (*subpath) {
-               status = splice_tree(rewrite_here, subpath, hash2, subtree);
+               status = splice_tree(rewrite_here, subpath, oid2, &subtree);
                if (status)
                        return status;
-               rewrite_with = subtree;
+               rewrite_with = &subtree;
+       } else {
+               rewrite_with = oid2;
        }
-       else
-               rewrite_with = hash2;
-       hashcpy(rewrite_here, rewrite_with);
-       status = write_sha1_file(buf, sz, tree_type, result);
+       oidcpy(rewrite_here, rewrite_with);
+       status = write_object_file(buf, sz, tree_type, result);
        free(buf);
        return status;
 }
@@ -245,7 +253,7 @@ void shift_tree(const struct object_id *hash1,
        if (!depth_limit)
                depth_limit = 2;
 
-       add_score = del_score = score_trees(hash1->hash, hash2->hash);
+       add_score = del_score = score_trees(hash1, hash2);
        add_prefix = xcalloc(1, 1);
        del_prefix = xcalloc(1, 1);
 
@@ -253,13 +261,13 @@ void shift_tree(const struct object_id *hash1,
         * See if one's subtree resembles two; if so we need to prefix
         * two with a few fake trees to match the prefix.
         */
-       match_trees(hash1->hash, hash2->hash, &add_score, &add_prefix, "", depth_limit);
+       match_trees(hash1, hash2, &add_score, &add_prefix, "", depth_limit);
 
        /*
         * See if two's subtree resembles one; if so we need to
         * pick only subtree of two.
         */
-       match_trees(hash2->hash, hash1->hash, &del_score, &del_prefix, "", depth_limit);
+       match_trees(hash2, hash1, &del_score, &del_prefix, "", depth_limit);
 
        /* Assume we do not have to do any shifting */
        oidcpy(shifted, hash2);
@@ -271,7 +279,7 @@ void shift_tree(const struct object_id *hash1,
                if (!*del_prefix)
                        return;
 
-               if (get_tree_entry(hash2->hash, del_prefix, shifted->hash, &mode))
+               if (get_tree_entry(hash2, del_prefix, shifted, &mode))
                        die("cannot find path %s in tree %s",
                            del_prefix, oid_to_hex(hash2));
                return;
@@ -280,7 +288,7 @@ void shift_tree(const struct object_id *hash1,
        if (!*add_prefix)
                return;
 
-       splice_tree(hash1->hash, add_prefix, hash2->hash, shifted->hash);
+       splice_tree(hash1, add_prefix, hash2, shifted);
 }
 
 /*
@@ -298,27 +306,27 @@ void shift_tree_by(const struct object_id *hash1,
        unsigned candidate = 0;
 
        /* Can hash2 be a tree at shift_prefix in tree hash1? */
-       if (!get_tree_entry(hash1->hash, shift_prefix, sub1.hash, &mode1) &&
+       if (!get_tree_entry(hash1, shift_prefix, &sub1, &mode1) &&
            S_ISDIR(mode1))
                candidate |= 1;
 
        /* Can hash1 be a tree at shift_prefix in tree hash2? */
-       if (!get_tree_entry(hash2->hash, shift_prefix, sub2.hash, &mode2) &&
+       if (!get_tree_entry(hash2, shift_prefix, &sub2, &mode2) &&
            S_ISDIR(mode2))
                candidate |= 2;
 
        if (candidate == 3) {
                /* Both are plausible -- we need to evaluate the score */
-               int best_score = score_trees(hash1->hash, hash2->hash);
+               int best_score = score_trees(hash1, hash2);
                int score;
 
                candidate = 0;
-               score = score_trees(sub1.hash, hash2->hash);
+               score = score_trees(&sub1, hash2);
                if (score > best_score) {
                        candidate = 1;
                        best_score = score;
                }
-               score = score_trees(sub2.hash, hash1->hash);
+               score = score_trees(&sub2, hash1);
                if (score > best_score)
                        candidate = 2;
        }
@@ -334,7 +342,7 @@ void shift_tree_by(const struct object_id *hash1,
                 * shift tree2 down by adding shift_prefix above it
                 * to match tree1.
                 */
-               splice_tree(hash1->hash, shift_prefix, hash2->hash, shifted->hash);
+               splice_tree(hash1, shift_prefix, hash2, shifted);
        else
                /*
                 * shift tree2 up by removing shift_prefix from it