Merge branch 'bw/grep-recurse-submodules'
[gitweb.git] / tree-walk.c
index cd4bb2c38bdf40f497ece781ce3a9e61de6b4399..6a42e402b00a3da90a008adf6e4c68dc8c45e516 100644 (file)
@@ -22,31 +22,60 @@ static const char *get_mode(const char *str, unsigned int *modep)
        return str;
 }
 
-static void decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size)
+static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err)
 {
        const char *path;
        unsigned int mode, len;
 
-       if (size < 24 || buf[size - 21])
-               die("corrupt tree file");
+       if (size < 23 || buf[size - 21]) {
+               strbuf_addstr(err, _("too-short tree object"));
+               return -1;
+       }
 
        path = get_mode(buf, &mode);
-       if (!path || !*path)
-               die("corrupt tree file");
+       if (!path) {
+               strbuf_addstr(err, _("malformed mode in tree entry"));
+               return -1;
+       }
+       if (!*path) {
+               strbuf_addstr(err, _("empty filename in tree entry"));
+               return -1;
+       }
        len = strlen(path) + 1;
 
        /* Initialize the descriptor entry */
        desc->entry.path = path;
        desc->entry.mode = canon_mode(mode);
-       desc->entry.sha1 = (const unsigned char *)(path + len);
+       desc->entry.oid  = (const struct object_id *)(path + len);
+
+       return 0;
 }
 
-void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
+static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer, unsigned long size, struct strbuf *err)
 {
        desc->buffer = buffer;
        desc->size = size;
        if (size)
-               decode_tree_entry(desc, buffer, size);
+               return decode_tree_entry(desc, buffer, size, err);
+       return 0;
+}
+
+void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (init_tree_desc_internal(desc, buffer, size, &err))
+               die("%s", err.buf);
+       strbuf_release(&err);
+}
+
+int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size)
+{
+       struct strbuf err = STRBUF_INIT;
+       int result = init_tree_desc_internal(desc, buffer, size, &err);
+       if (result)
+               error("%s", err.buf);
+       strbuf_release(&err);
+       return result;
 }
 
 void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
@@ -73,21 +102,44 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
        *a = t->entry;
 }
 
-void update_tree_entry(struct tree_desc *desc)
+static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
 {
        const void *buf = desc->buffer;
-       const unsigned char *end = desc->entry.sha1 + 20;
+       const unsigned char *end = desc->entry.oid->hash + 20;
        unsigned long size = desc->size;
        unsigned long len = end - (const unsigned char *)buf;
 
        if (size < len)
-               die("corrupt tree file");
+               die(_("too-short tree file"));
        buf = end;
        size -= len;
        desc->buffer = buf;
        desc->size = size;
        if (size)
-               decode_tree_entry(desc, buf, size);
+               return decode_tree_entry(desc, buf, size, err);
+       return 0;
+}
+
+void update_tree_entry(struct tree_desc *desc)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (update_tree_entry_internal(desc, &err))
+               die("%s", err.buf);
+       strbuf_release(&err);
+}
+
+int update_tree_entry_gently(struct tree_desc *desc)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (update_tree_entry_internal(desc, &err)) {
+               error("%s", err.buf);
+               strbuf_release(&err);
+               /* Stop processing this tree after error */
+               desc->size = 0;
+               return -1;
+       }
+       strbuf_release(&err);
+       return 0;
 }
 
 int tree_entry(struct tree_desc *desc, struct name_entry *entry)
@@ -100,6 +152,17 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
        return 1;
 }
 
+int tree_entry_gently(struct tree_desc *desc, struct name_entry *entry)
+{
+       if (!desc->size)
+               return 0;
+
+       *entry = desc->entry;
+       if (update_tree_entry_gently(desc))
+               return 0;
+       return 1;
+}
+
 void setup_traverse_info(struct traverse_info *info, const char *base)
 {
        int pathlen = strlen(base);
@@ -110,7 +173,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
                pathlen--;
        info->pathlen = pathlen ? pathlen + 1 : 0;
        info->name.path = base;
-       info->name.sha1 = (void *)(base + pathlen + 1);
+       info->name.oid = (void *)(base + pathlen + 1);
        if (pathlen)
                info->prev = &dummy;
 }
@@ -433,10 +496,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
        int namelen = strlen(name);
        while (t->size) {
                const char *entry;
-               const unsigned char *sha1;
+               const struct object_id *oid;
                int entrylen, cmp;
 
-               sha1 = tree_entry_extract(t, &entry, mode);
+               oid = tree_entry_extract(t, &entry, mode);
                entrylen = tree_entry_len(&t->entry);
                update_tree_entry(t);
                if (entrylen > namelen)
@@ -447,7 +510,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (cmp < 0)
                        break;
                if (entrylen == namelen) {
-                       hashcpy(result, sha1);
+                       hashcpy(result, oid->hash);
                        return 0;
                }
                if (name[entrylen] != '/')
@@ -455,10 +518,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (!S_ISDIR(*mode))
                        break;
                if (++entrylen == namelen) {
-                       hashcpy(result, sha1);
+                       hashcpy(result, oid->hash);
                        return 0;
                }
-               return get_tree_entry(sha1, name + entrylen, result, mode);
+               return get_tree_entry(oid->hash, name + entrylen, result, mode);
        }
        return -1;
 }
@@ -526,7 +589,6 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_s
        int i;
 
        init_tree_desc(&t, NULL, 0UL);
-       strbuf_init(result_path, 0);
        strbuf_addstr(&namebuf, name);
        hashcpy(current_tree_sha1, tree_sha1);
 
@@ -941,6 +1003,19 @@ static enum interesting do_match(const struct name_entry *entry,
                                 */
                                if (ps->recursive && S_ISDIR(entry->mode))
                                        return entry_interesting;
+
+                               /*
+                                * When matching against submodules with
+                                * wildcard characters, ensure that the entry
+                                * at least matches up to the first wild
+                                * character.  More accurate matching can then
+                                * be performed in the submodule itself.
+                                */
+                               if (ps->recursive && S_ISGITLINK(entry->mode) &&
+                                   !ps_strncmp(item, match + baselen,
+                                               entry->path,
+                                               item->nowildcard_len - baselen))
+                                       return entry_interesting;
                        }
 
                        continue;
@@ -977,6 +1052,21 @@ static enum interesting do_match(const struct name_entry *entry,
                        strbuf_setlen(base, base_offset + baselen);
                        return entry_interesting;
                }
+
+               /*
+                * When matching against submodules with
+                * wildcard characters, ensure that the entry
+                * at least matches up to the first wild
+                * character.  More accurate matching can then
+                * be performed in the submodule itself.
+                */
+               if (ps->recursive && S_ISGITLINK(entry->mode) &&
+                   !ps_strncmp(item, match, base->buf + base_offset,
+                               item->nowildcard_len)) {
+                       strbuf_setlen(base, base_offset + baselen);
+                       return entry_interesting;
+               }
+
                strbuf_setlen(base, base_offset + baselen);
 
                /*
@@ -984,7 +1074,7 @@ static enum interesting do_match(const struct name_entry *entry,
                 * later on.
                 * max_depth is ignored but we may consider support it
                 * in future, see
-                * http://thread.gmane.org/gmane.comp.version-control.git/163757/focus=163840
+                * https://public-inbox.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
                 */
                if (ps->recursive && S_ISDIR(entry->mode))
                        return entry_interesting;