#include "ref-cache.h"
#include "../iterator.h"
-/* FIXME: This declaration shouldn't be here */
-void read_loose_refs(const char *dirname, struct ref_dir *dir);
-
void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
{
ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
assert(entry->flag & REF_DIR);
dir = &entry->u.subdir;
if (entry->flag & REF_INCOMPLETE) {
- read_loose_refs(entry->name, dir);
+ if (!dir->cache->fill_ref_dir)
+ die("BUG: incomplete ref_store without fill_ref_dir function");
- /*
- * Manually add refs/bisect, which, being
- * per-worktree, might not appear in the directory
- * listing for refs/ in the main repo.
- */
- if (!strcmp(entry->name, "refs/")) {
- int pos = search_ref_dir(dir, "refs/bisect/", 12);
- if (pos < 0) {
- struct ref_entry *child_entry;
- child_entry = create_dir_entry(dir->ref_store,
- "refs/bisect/",
- 12, 1);
- add_entry_to_dir(dir, child_entry);
- }
- }
+ dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
entry->flag &= ~REF_INCOMPLETE;
}
return dir;
return ref;
}
-struct ref_cache *create_ref_cache(struct files_ref_store *refs)
+struct ref_cache *create_ref_cache(struct ref_store *refs,
+ fill_ref_dir_fn *fill_ref_dir)
{
struct ref_cache *ret = xcalloc(1, sizeof(*ret));
- ret->root = create_dir_entry(refs, "", 0, 1);
+ ret->ref_store = refs;
+ ret->fill_ref_dir = fill_ref_dir;
+ ret->root = create_dir_entry(ret, "", 0, 1);
return ret;
}
dir->entries = NULL;
}
-struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,
+struct ref_entry *create_dir_entry(struct ref_cache *cache,
const char *dirname, size_t len,
int incomplete)
{
struct ref_entry *direntry;
+
FLEX_ALLOC_MEM(direntry, name, dirname, len);
- direntry->u.subdir.ref_store = ref_store;
+ direntry->u.subdir.cache = cache;
direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
return direntry;
}
* therefore, create an empty record for it but mark
* the record complete.
*/
- entry = create_dir_entry(dir->ref_store, subdirname, len, 0);
+ entry = create_dir_entry(dir->cache, subdirname, len, 0);
add_entry_to_dir(dir, entry);
} else {
entry = dir->entries[entry_index];
return get_ref_dir(entry);
}
-struct ref_dir *find_containing_dir(struct ref_dir *dir,
- const char *refname, int mkdir)
+/*
+ * If refname is a reference name, find the ref_dir within the dir
+ * tree that should hold refname. If refname is a directory name
+ * (i.e., it ends in '/'), then return that ref_dir itself. dir must
+ * represent the top-level directory and must already be complete.
+ * Sort ref_dirs and recurse into subdirectories as necessary. If
+ * mkdir is set, then create any missing directories; otherwise,
+ * return NULL if the desired directory cannot be found.
+ */
+static struct ref_dir *find_containing_dir(struct ref_dir *dir,
+ const char *refname, int mkdir)
{
const char *slash;
for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
dir->sorted = dir->nr = i;
}
-int do_for_each_entry_in_dir(struct ref_dir *dir, int offset,
- each_ref_entry_fn fn, void *cb_data)
-{
- int i;
- assert(dir->sorted == dir->nr);
- for (i = offset; i < dir->nr; i++) {
- struct ref_entry *entry = dir->entries[i];
- int retval;
- if (entry->flag & REF_DIR) {
- struct ref_dir *subdir = get_ref_dir(entry);
- sort_ref_dir(subdir);
- retval = do_for_each_entry_in_dir(subdir, 0, fn, cb_data);
- } else {
- retval = fn(entry, cb_data);
- }
- if (retval)
- return retval;
- }
- return 0;
-}
-
-void prime_ref_dir(struct ref_dir *dir)
+/*
+ * Load all of the refs from `dir` (recursively) into our in-memory
+ * cache.
+ */
+static void prime_ref_dir(struct ref_dir *dir)
{
/*
* The hard work of loading loose refs is done by get_ref_dir(), so we
cache_ref_iterator_abort
};
-struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir)
+struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
+ const char *prefix,
+ int prime_dir)
{
+ struct ref_dir *dir;
struct cache_ref_iterator *iter;
struct ref_iterator *ref_iterator;
struct cache_ref_iterator_level *level;
+ dir = get_ref_dir(cache->root);
+ if (prefix && *prefix)
+ dir = find_containing_dir(dir, prefix, 0);
+ if (!dir)
+ /* There's nothing to iterate over. */
+ return empty_ref_iterator_begin();
+
+ if (prime_dir)
+ prime_ref_dir(dir);
+
iter = xcalloc(1, sizeof(*iter));
ref_iterator = &iter->base;
base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
level->index = -1;
level->dir = dir;
+ if (prefix && *prefix)
+ ref_iterator = prefix_ref_iterator_begin(ref_iterator,
+ prefix, 0);
+
return ref_iterator;
}