merge script: improve log message subject
[gitweb.git] / cache-tree.c
index cfe937b0f12896160e728f9bdec4d4594f13bd3a..d91743775dfbe98d99d8ab25a270af320c8b984e 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "tree.h"
+#include "tree-walk.h"
 #include "cache-tree.h"
 
 #ifndef DEBUG
@@ -155,13 +156,17 @@ static int verify_cache(struct cache_entry **cache,
        funny = 0;
        for (i = 0; i < entries; i++) {
                struct cache_entry *ce = cache[i];
-               if (ce_stage(ce)) {
+               if (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) {
                        if (10 < ++funny) {
                                fprintf(stderr, "...\n");
                                break;
                        }
-                       fprintf(stderr, "%s: unmerged (%s)\n",
-                               ce->name, sha1_to_hex(ce->sha1));
+                       if (ce_stage(ce))
+                               fprintf(stderr, "%s: unmerged (%s)\n",
+                                       ce->name, sha1_to_hex(ce->sha1));
+                       else
+                               fprintf(stderr, "%s: not added yet\n",
+                                       ce->name);
                }
        }
        if (funny)
@@ -320,13 +325,14 @@ static int update_one(struct cache_tree *it,
                }
                else {
                        sha1 = ce->sha1;
-                       mode = ntohl(ce->ce_mode);
+                       mode = ce->ce_mode;
                        entlen = pathlen - baselen;
                }
                if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))
-                       return error("invalid object %s", sha1_to_hex(sha1));
+                       return error("invalid object %06o %s for '%.*s'",
+                               mode, sha1_to_hex(sha1), entlen+baselen, path);
 
-               if (!ce->ce_mode)
+               if (ce->ce_flags & CE_REMOVE)
                        continue; /* entry being removed */
 
                strbuf_grow(&buffer, entlen + 100);
@@ -507,8 +513,10 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size)
        return read_one(&buffer, &size);
 }
 
-struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
+static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
 {
+       if (!it)
+               return NULL;
        while (*path) {
                const char *slash;
                struct cache_tree_sub *sub;
@@ -532,3 +540,127 @@ struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
        }
        return it;
 }
+
+int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
+{
+       int entries, was_valid, newfd;
+       struct lock_file *lock_file;
+
+       /*
+        * We can't free this memory, it becomes part of a linked list
+        * parsed atexit()
+        */
+       lock_file = xcalloc(1, sizeof(struct lock_file));
+
+       newfd = hold_locked_index(lock_file, 1);
+
+       entries = read_cache();
+       if (entries < 0)
+               return WRITE_TREE_UNREADABLE_INDEX;
+       if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
+               cache_tree_free(&(active_cache_tree));
+
+       if (!active_cache_tree)
+               active_cache_tree = cache_tree();
+
+       was_valid = cache_tree_fully_valid(active_cache_tree);
+       if (!was_valid) {
+               int missing_ok = flags & WRITE_TREE_MISSING_OK;
+
+               if (cache_tree_update(active_cache_tree,
+                                     active_cache, active_nr,
+                                     missing_ok, 0) < 0)
+                       return WRITE_TREE_UNMERGED_INDEX;
+               if (0 <= newfd) {
+                       if (!write_cache(newfd, active_cache, active_nr) &&
+                           !commit_lock_file(lock_file))
+                               newfd = -1;
+               }
+               /* Not being able to write is fine -- we are only interested
+                * in updating the cache-tree part, and if the next caller
+                * ends up using the old index with unupdated cache-tree part
+                * it misses the work we did here, but that is just a
+                * performance penalty and not a big deal.
+                */
+       }
+
+       if (prefix) {
+               struct cache_tree *subtree =
+                       cache_tree_find(active_cache_tree, prefix);
+               if (!subtree)
+                       return WRITE_TREE_PREFIX_ERROR;
+               hashcpy(sha1, subtree->sha1);
+       }
+       else
+               hashcpy(sha1, active_cache_tree->sha1);
+
+       if (0 <= newfd)
+               rollback_lock_file(lock_file);
+
+       return 0;
+}
+
+static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
+{
+       struct tree_desc desc;
+       struct name_entry entry;
+       int cnt;
+
+       hashcpy(it->sha1, tree->object.sha1);
+       init_tree_desc(&desc, tree->buffer, tree->size);
+       cnt = 0;
+       while (tree_entry(&desc, &entry)) {
+               if (!S_ISDIR(entry.mode))
+                       cnt++;
+               else {
+                       struct cache_tree_sub *sub;
+                       struct tree *subtree = lookup_tree(entry.sha1);
+                       if (!subtree->object.parsed)
+                               parse_tree(subtree);
+                       sub = cache_tree_sub(it, entry.path);
+                       sub->cache_tree = cache_tree();
+                       prime_cache_tree_rec(sub->cache_tree, subtree);
+                       cnt += sub->cache_tree->entry_count;
+               }
+       }
+       it->entry_count = cnt;
+}
+
+void prime_cache_tree(struct cache_tree **it, struct tree *tree)
+{
+       cache_tree_free(it);
+       *it = cache_tree();
+       prime_cache_tree_rec(*it, tree);
+}
+
+/*
+ * find the cache_tree that corresponds to the current level without
+ * exploding the full path into textual form.  The root of the
+ * cache tree is given as "root", and our current level is "info".
+ * (1) When at root level, info->prev is NULL, so it is "root" itself.
+ * (2) Otherwise, find the cache_tree that corresponds to one level
+ *     above us, and find ourselves in there.
+ */
+static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root,
+                                                        struct traverse_info *info)
+{
+       struct cache_tree *our_parent;
+
+       if (!info->prev)
+               return root;
+       our_parent = find_cache_tree_from_traversal(root, info->prev);
+       return cache_tree_find(our_parent, info->name.path);
+}
+
+int cache_tree_matches_traversal(struct cache_tree *root,
+                                struct name_entry *ent,
+                                struct traverse_info *info)
+{
+       struct cache_tree *it;
+
+       it = find_cache_tree_from_traversal(root, info);
+       it = cache_tree_find(it, ent->path);
+       if (it && it->entry_count > 0 && !hashcmp(ent->sha1, it->sha1))
+               return it->entry_count;
+       return 0;
+}