promisor-remote: parse remote.*.partialclonefilter
[git/git.git] / promisor-remote.c
index c249b80..826890f 100644 (file)
@@ -1,6 +1,8 @@
 #include "cache.h"
+#include "object-store.h"
 #include "promisor-remote.h"
 #include "config.h"
+#include "fetch-object.h"
 
 static struct promisor_remote *promisors;
 static struct promisor_remote **promisors_tail = &promisors;
@@ -38,6 +40,18 @@ static struct promisor_remote *promisor_remote_lookup(const char *remote_name,
        return NULL;
 }
 
+static void promisor_remote_move_to_tail(struct promisor_remote *r,
+                                        struct promisor_remote *previous)
+{
+       if (previous)
+               previous->next = r->next;
+       else
+               promisors = r->next ? r->next : r;
+       r->next = NULL;
+       *promisors_tail = r;
+       promisors_tail = &r->next;
+}
+
 static int promisor_remote_config(const char *var, const char *value, void *data)
 {
        const char *name;
@@ -61,19 +75,63 @@ static int promisor_remote_config(const char *var, const char *value, void *data
                free(remote_name);
                return 0;
        }
+       if (!strcmp(subkey, "partialclonefilter")) {
+               struct promisor_remote *r;
+               char *remote_name = xmemdupz(name, namelen);
+
+               r = promisor_remote_lookup(remote_name, NULL);
+               if (!r)
+                       r = promisor_remote_new(remote_name);
+
+               free(remote_name);
+
+               if (!r)
+                       return 0;
+
+               return git_config_string(&r->partial_clone_filter, var, value);
+       }
 
        return 0;
 }
 
+static int initialized;
+
 static void promisor_remote_init(void)
 {
-       static int initialized;
-
        if (initialized)
                return;
        initialized = 1;
 
        git_config(promisor_remote_config, NULL);
+
+       if (repository_format_partial_clone) {
+               struct promisor_remote *o, *previous;
+
+               o = promisor_remote_lookup(repository_format_partial_clone,
+                                          &previous);
+               if (o)
+                       promisor_remote_move_to_tail(o, previous);
+               else
+                       promisor_remote_new(repository_format_partial_clone);
+       }
+}
+
+static void promisor_remote_clear(void)
+{
+       while (promisors) {
+               struct promisor_remote *r = promisors;
+               promisors = promisors->next;
+               free(r);
+       }
+
+       promisors_tail = &promisors;
+}
+
+void promisor_remote_reinit(void)
+{
+       initialized = 0;
+       promisor_remote_clear();
+       promisor_remote_init();
 }
 
 struct promisor_remote *promisor_remote_find(const char *remote_name)
@@ -90,3 +148,68 @@ int has_promisor_remote(void)
 {
        return !!promisor_remote_find(NULL);
 }
+
+static int remove_fetched_oids(struct repository *repo,
+                              struct object_id **oids,
+                              int oid_nr, int to_free)
+{
+       int i, remaining_nr = 0;
+       int *remaining = xcalloc(oid_nr, sizeof(*remaining));
+       struct object_id *old_oids = *oids;
+       struct object_id *new_oids;
+
+       for (i = 0; i < oid_nr; i++)
+               if (oid_object_info_extended(repo, &old_oids[i], NULL,
+                                            OBJECT_INFO_SKIP_FETCH_OBJECT)) {
+                       remaining[i] = 1;
+                       remaining_nr++;
+               }
+
+       if (remaining_nr) {
+               int j = 0;
+               new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
+               for (i = 0; i < oid_nr; i++)
+                       if (remaining[i])
+                               oidcpy(&new_oids[j++], &old_oids[i]);
+               *oids = new_oids;
+               if (to_free)
+                       free(old_oids);
+       }
+
+       free(remaining);
+
+       return remaining_nr;
+}
+
+int promisor_remote_get_direct(struct repository *repo,
+                              const struct object_id *oids,
+                              int oid_nr)
+{
+       struct promisor_remote *r;
+       struct object_id *remaining_oids = (struct object_id *)oids;
+       int remaining_nr = oid_nr;
+       int to_free = 0;
+       int res = -1;
+
+       promisor_remote_init();
+
+       for (r = promisors; r; r = r->next) {
+               if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
+                       if (remaining_nr == 1)
+                               continue;
+                       remaining_nr = remove_fetched_oids(repo, &remaining_oids,
+                                                        remaining_nr, to_free);
+                       if (remaining_nr) {
+                               to_free = 1;
+                               continue;
+                       }
+               }
+               res = 0;
+               break;
+       }
+
+       if (to_free)
+               free(remaining_oids);
+
+       return res;
+}