t5500, t5539: tests for shallow depth since a specific date
[gitweb.git] / upload-pack.c
index 7ce97ecd90f275ff5f5ed9e052ceafea95791069..5269461cf1fac4ba5fb8fbc8e73f90e3a83dc269 100644 (file)
@@ -14,6 +14,7 @@
 #include "sigchain.h"
 #include "version.h"
 #include "string-list.h"
+#include "argv-array.h"
 
 static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
 
@@ -451,7 +452,7 @@ static int is_our_ref(struct object *o)
        return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
 }
 
-static void check_non_tip(void)
+static int has_unreachable(struct object_array *src)
 {
        static const char *argv[] = {
                "rev-list", "--stdin", NULL,
@@ -461,14 +462,6 @@ static void check_non_tip(void)
        char namebuf[42]; /* ^ + SHA-1 + LF */
        int i;
 
-       /*
-        * In the normal in-process case without
-        * uploadpack.allowReachableSHA1InWant,
-        * non-tip requests can never happen.
-        */
-       if (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))
-               goto error;
-
        cmd.argv = argv;
        cmd.git_cmd = 1;
        cmd.no_stderr = 1;
@@ -498,8 +491,8 @@ static void check_non_tip(void)
                        goto error;
        }
        namebuf[40] = '\n';
-       for (i = 0; i < want_obj.nr; i++) {
-               o = want_obj.objects[i].item;
+       for (i = 0; i < src->nr; i++) {
+               o = src->objects[i].item;
                if (is_our_ref(o))
                        continue;
                memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
@@ -530,7 +523,7 @@ static void check_non_tip(void)
        sigchain_pop(SIGPIPE);
 
        /* All the non-tip ones are ancestors of what we advertised */
-       return;
+       return 0;
 
 error:
        sigchain_pop(SIGPIPE);
@@ -539,10 +532,28 @@ static void check_non_tip(void)
                close(cmd.in);
        if (cmd.out >= 0)
                close(cmd.out);
+       return 1;
+}
+
+static void check_non_tip(void)
+{
+       int i;
 
+       /*
+        * In the normal in-process case without
+        * uploadpack.allowReachableSHA1InWant,
+        * non-tip requests can never happen.
+        */
+       if (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))
+               goto error;
+       if (!has_unreachable(&want_obj))
+               /* All the non-tip ones are ancestors of what we advertised */
+               return;
+
+error:
        /* Pick one of them (we know there at least is one) */
        for (i = 0; i < want_obj.nr; i++) {
-               o = want_obj.objects[i].item;
+               struct object *o = want_obj.objects[i].item;
                if (!is_our_ref(o))
                        die("git upload-pack: not our ref %s",
                            oid_to_hex(&o->oid));
@@ -619,11 +630,25 @@ static void deepen(int depth, const struct object_array *shallows)
        packet_flush(1);
 }
 
+static void deepen_by_rev_list(int ac, const char **av,
+                              struct object_array *shallows)
+{
+       struct commit_list *result;
+
+       result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
+       send_shallow(result);
+       free_commit_list(result);
+       send_unshallow(shallows);
+       packet_flush(1);
+}
+
 static void receive_needs(void)
 {
        struct object_array shallows = OBJECT_ARRAY_INIT;
        int depth = 0;
        int has_non_tip = 0;
+       unsigned long deepen_since = 0;
+       int deepen_rev_list = 0;
 
        shallow_nr = 0;
        for (;;) {
@@ -660,6 +685,16 @@ static void receive_needs(void)
                                die("Invalid deepen: %s", line);
                        continue;
                }
+               if (skip_prefix(line, "deepen-since ", &arg)) {
+                       char *end = NULL;
+                       deepen_since = strtoul(arg, &end, 0);
+                       if (!end || *end || !deepen_since ||
+                           /* revisions.c's max_age -1 is special */
+                           deepen_since == -1)
+                               die("Invalid deepen-since: %s", line);
+                       deepen_rev_list = 1;
+                       continue;
+               }
                if (!skip_prefix(line, "want ", &arg) ||
                    get_sha1_hex(arg, sha1_buf))
                        die("git upload-pack: protocol error, "
@@ -711,10 +746,26 @@ static void receive_needs(void)
        if (!use_sideband && daemon_mode)
                no_progress = 1;
 
-       if (depth == 0 && shallows.nr == 0)
+       if (depth == 0 && !deepen_rev_list && shallows.nr == 0)
                return;
+       if (depth > 0 && deepen_rev_list)
+               die("git upload-pack: deepen and deepen-since cannot be used together");
        if (depth > 0)
                deepen(depth, &shallows);
+       else if (deepen_rev_list) {
+               struct argv_array av = ARGV_ARRAY_INIT;
+               int i;
+
+               argv_array_push(&av, "rev-list");
+               if (deepen_since)
+                       argv_array_pushf(&av, "--max-age=%lu", deepen_since);
+               for (i = 0; i < want_obj.nr; i++) {
+                       struct object *o = want_obj.objects[i].item;
+                       argv_array_push(&av, oid_to_hex(&o->oid));
+               }
+               deepen_by_rev_list(av.argc, av.argv, &shallows);
+               argv_array_clear(&av);
+       }
        else
                if (shallows.nr > 0) {
                        int i;
@@ -763,7 +814,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
                    int flag, void *cb_data)
 {
        static const char *capabilities = "multi_ack thin-pack side-band"
-               " side-band-64k ofs-delta shallow no-progress"
+               " side-band-64k ofs-delta shallow deepen-since no-progress"
                " include-tag multi_ack_detailed";
        const char *refname_nons = strip_namespace(refname);
        struct object_id peeled;