Merge branch 'nd/clone-connectivity-shortcut'
authorJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2013 21:30:01 +0000 (14:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2013 21:30:01 +0000 (14:30 -0700)
* nd/clone-connectivity-shortcut:
smart http: use the same connectivity check on cloning

1  2 
Documentation/git-fetch-pack.txt
Documentation/gitremote-helpers.txt
remote-curl.c
transport-helper.c
index 1e717543470c0440a72812a046bcadf0e52e4953,461a632fb7b25c259e05afc53e9e91df1fb8c3a7..444b805d350a6111d56b53d19fe155eb7b79038b
@@@ -10,9 -10,9 +10,9 @@@ SYNOPSI
  --------
  [verse]
  'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
 -                              [--upload-pack=<git-upload-pack>]
 -                              [--depth=<n>] [--no-progress]
 -                              [-v] [<host>:]<directory> [<refs>...]
 +      [--upload-pack=<git-upload-pack>]
 +      [--depth=<n>] [--no-progress]
 +      [-v] [<host>:]<directory> [<refs>...]
  
  DESCRIPTION
  -----------
@@@ -90,6 -90,10 +90,10 @@@ be in a separate packet, and the list m
  --no-progress::
        Do not show the progress.
  
+ --check-self-contained-and-connected::
+       Output "connectivity-ok" if the received pack is
+       self-contained and connected.
  -v::
        Run verbosely.
  
index 0827f691396ba698d3976eba1eddedd9e7ff3e9e,e33bd6a716ca69f89024d90f9bd8795ebece4b72..bc069c23df85ae200d8b21fdf9a4662c72152377
@@@ -143,6 -143,10 +143,10 @@@ Supported commands: 'list', 'fetch'
  +
  Supported commands: 'list', 'import'.
  
+ 'check-connectivity'::
+       Can guarantee that when a clone is requested, the received
+       pack is self contained and is connected.
  If a helper advertises 'connect', Git will use it if possible and
  fall back to another capability if the helper requests so when
  connecting (see the 'connect' command under COMMANDS).
@@@ -159,11 -163,11 +163,11 @@@ Miscellaneous capabilitie
        carried out.
  
  'refspec' <refspec>::
 -      This modifies the 'import' capability, allowing the produced
 -      fast-import stream to modify refs in a private namespace
 -      instead of writing to refs/heads or refs/remotes directly.
 +      For remote helpers that implement 'import' or 'export', this capability
 +      allows the refs to be constrained to a private namespace, instead of
 +      writing to refs/heads or refs/remotes directly.
        It is recommended that all importers providing the 'import'
 -      capability use this.
 +      capability use this. It's mandatory for 'export'.
  +
  A helper advertising the capability
  `refspec refs/heads/*:refs/svn/origin/branches/*`
@@@ -174,8 -178,8 +178,8 @@@ ref
  This capability can be advertised multiple times.  The first
  applicable refspec takes precedence.  The left-hand of refspecs
  advertised with this capability must cover all refs reported by
 -the list command.  If a helper does not need a specific 'refspec'
 -capability then it should advertise `refspec *:*`.
 +the list command.  If no 'refspec' capability is advertised,
 +there is an implied `refspec *:*`.
  
  'bidi-import'::
        This modifies the 'import' capability.
@@@ -270,6 -274,9 +274,9 @@@ Optionally may output a 'lock <file>' l
  GIT_DIR/objects/pack which is keeping a pack until refs can be
  suitably updated.
  +
+ If option 'check-connectivity' is requested, the helper must output
+ 'connectivity-ok' if the clone is self-contained and connected.
+ +
  Supported if the helper has the "fetch" capability.
  
  'push' +<src>:<dst>::
@@@ -416,6 -423,9 +423,9 @@@ set by Git if the remote helper has th
        must not rely on this option being set before
        connect request occurs.
  
+ 'option check-connectivity' \{'true'|'false'\}::
+       Request the helper to check connectivity of a clone.
  SEE ALSO
  --------
  linkgit:git-remote[1]
diff --combined remote-curl.c
index 5b3ce9eed299e312c132b590ea4926cfb019a271,c3157e877ba3a56a00fa58fa94f4b2f84fdf6d46..6918668dc24dc67fcb2870a4c1e6c795987ef323
@@@ -7,7 -7,6 +7,7 @@@
  #include "run-command.h"
  #include "pkt-line.h"
  #include "sideband.h"
 +#include "argv-array.h"
  
  static struct remote *remote;
  static const char *url; /* always ends with a trailing slash */
@@@ -16,6 -15,7 +16,7 @@@ struct options 
        int verbosity;
        unsigned long depth;
        unsigned progress : 1,
+               check_self_contained_and_connected : 1,
                followtags : 1,
                dry_run : 1,
                thin : 1;
@@@ -67,6 -67,15 +68,15 @@@ static int set_option(const char *name
                        return -1;
                return 0;
        }
+       else if (!strcmp(name, "check-connectivity")) {
+               if (!strcmp(value, "true"))
+                       options.check_self_contained_and_connected = 1;
+               else if (!strcmp(value, "false"))
+                       options.check_self_contained_and_connected = 0;
+               else
+                       return -1;
+               return 0;
+       }
        else {
                return 1 /* unsupported */;
        }
@@@ -654,7 -663,7 +664,7 @@@ static int fetch_git(struct discovery *
        struct strbuf preamble = STRBUF_INIT;
        char *depth_arg = NULL;
        int argc = 0, i, err;
-       const char *argv[15];
+       const char *argv[16];
  
        argv[argc++] = "fetch-pack";
        argv[argc++] = "--stateless-rpc";
                argv[argc++] = "-v";
                argv[argc++] = "-v";
        }
+       if (options.check_self_contained_and_connected)
+               argv[argc++] = "--check-self-contained-and-connected";
        if (!options.progress)
                argv[argc++] = "--no-progress";
        if (options.depth) {
@@@ -788,35 -799,36 +800,35 @@@ static int push_dav(int nr_spec, char *
  static int push_git(struct discovery *heads, int nr_spec, char **specs)
  {
        struct rpc_state rpc;
 -      const char **argv;
 -      int argc = 0, i, err;
 +      int i, err;
 +      struct argv_array args;
 +
 +      argv_array_init(&args);
 +      argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
 +                       NULL);
  
 -      argv = xmalloc((10 + nr_spec) * sizeof(char*));
 -      argv[argc++] = "send-pack";
 -      argv[argc++] = "--stateless-rpc";
 -      argv[argc++] = "--helper-status";
        if (options.thin)
 -              argv[argc++] = "--thin";
 +              argv_array_push(&args, "--thin");
        if (options.dry_run)
 -              argv[argc++] = "--dry-run";
 +              argv_array_push(&args, "--dry-run");
        if (options.verbosity == 0)
 -              argv[argc++] = "--quiet";
 +              argv_array_push(&args, "--quiet");
        else if (options.verbosity > 1)
 -              argv[argc++] = "--verbose";
 -      argv[argc++] = options.progress ? "--progress" : "--no-progress";
 -      argv[argc++] = url;
 +              argv_array_push(&args, "--verbose");
 +      argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
 +      argv_array_push(&args, url);
        for (i = 0; i < nr_spec; i++)
 -              argv[argc++] = specs[i];
 -      argv[argc++] = NULL;
 +              argv_array_push(&args, specs[i]);
  
        memset(&rpc, 0, sizeof(rpc));
        rpc.service_name = "git-receive-pack",
 -      rpc.argv = argv;
 +      rpc.argv = args.argv;
  
        err = rpc_service(&rpc, heads);
        if (rpc.result.len)
                write_or_die(1, rpc.result.buf, rpc.result.len);
        strbuf_release(&rpc.result);
 -      free(argv);
 +      argv_array_clear(&args);
        return err;
  }
  
@@@ -939,6 -951,7 +951,7 @@@ int main(int argc, const char **argv
                        printf("fetch\n");
                        printf("option\n");
                        printf("push\n");
+                       printf("check-connectivity\n");
                        printf("\n");
                        fflush(stdout);
                } else {
diff --combined transport-helper.c
index 63cabc37e37dd338d3d9ee0764f099840d937600,fe1b7021d70b1014b9e7801c87175f7bf45875e6..bec3b721fae56bb3936091ada0b5d5290f3ca4c2
@@@ -11,7 -11,6 +11,7 @@@
  #include "thread-utils.h"
  #include "sigchain.h"
  #include "argv-array.h"
 +#include "refs.h"
  
  static int debug;
  
@@@ -27,6 -26,7 +27,7 @@@ struct helper_data 
                push : 1,
                connect : 1,
                signed_tags : 1,
+               check_connectivity : 1,
                no_disconnect_req : 1;
        char *export_marks;
        char *import_marks;
@@@ -48,7 -48,7 +49,7 @@@ static void sendline(struct helper_dat
                die_errno("Full write to remote helper failed");
  }
  
 -static int recvline_fh(FILE *helper, struct strbuf *buffer)
 +static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
  {
        strbuf_reset(buffer);
        if (debug)
@@@ -66,7 -66,7 +67,7 @@@
  
  static int recvline(struct helper_data *helper, struct strbuf *buffer)
  {
 -      return recvline_fh(helper->out, buffer);
 +      return recvline_fh(helper->out, buffer, helper->name);
  }
  
  static void xchgline(struct helper_data *helper, struct strbuf *buffer)
@@@ -186,6 -186,8 +187,8 @@@ static struct child_process *get_helper
                        data->bidi_import = 1;
                else if (!strcmp(capname, "export"))
                        data->export = 1;
+               else if (!strcmp(capname, "check-connectivity"))
+                       data->check_connectivity = 1;
                else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
                        ALLOC_GROW(refspecs,
                                   refspec_nr + 1,
                for (i = 0; i < refspec_nr; i++)
                        free((char *)refspecs[i]);
                free(refspecs);
 +      } else if (data->import || data->bidi_import || data->export) {
 +              warning("This remote helper should implement refspec capability.");
        }
        strbuf_release(&buf);
        if (debug)
@@@ -349,6 -349,9 +352,9 @@@ static int fetch_with_fetch(struct tran
        struct strbuf buf = STRBUF_INIT;
  
        standard_options(transport);
+       if (data->check_connectivity &&
+           data->transport_options.check_self_contained_and_connected)
+               set_helper_option(transport, "check-connectivity", "true");
  
        for (i = 0; i < nr_heads; i++) {
                const struct ref *posn = to_fetch[i];
                        else
                                transport->pack_lockfile = xstrdup(name);
                }
+               else if (data->check_connectivity &&
+                        data->transport_options.check_self_contained_and_connected &&
+                        !strcmp(buf.buf, "connectivity-ok"))
+                       data->transport_options.self_contained_and_connected = 1;
                else if (!buf.len)
                        break;
                else
@@@ -476,7 -483,7 +486,7 @@@ static int fetch_with_import(struct tra
         * were fetching.
         *
         * (If no "refspec" capability was specified, for historical
 -       * reasons we default to *:*.)
 +       * reasons we default to the equivalent of *:*.)
         *
         * Store the result in to_fetch[i].old_sha1.  Callers such
         * as "git fetch" can use the value to write feedback to the
@@@ -543,7 -550,7 +553,7 @@@ static int process_connect_service(stru
                goto exit;
  
        sendline(data, &cmdbuf);
 -      recvline_fh(input, &cmdbuf);
 +      recvline_fh(input, &cmdbuf, name);
        if (!strcmp(cmdbuf.buf, "")) {
                data->no_disconnect_req = 1;
                if (debug)
@@@ -625,7 -632,7 +635,7 @@@ static int fetch(struct transport *tran
        return -1;
  }
  
 -static void push_update_ref_status(struct strbuf *buf,
 +static int push_update_ref_status(struct strbuf *buf,
                                   struct ref **ref,
                                   struct ref *remote_refs)
  {
                *ref = find_ref_by_name(remote_refs, refname);
        if (!*ref) {
                warning("helper reported unexpected status of %s", refname);
 -              return;
 +              return 1;
        }
  
        if ((*ref)->status != REF_STATUS_NONE) {
                 * status reported by the remote helper if the latter is 'no match'.
                 */
                if (status == REF_STATUS_NONE)
 -                      return;
 +                      return 1;
        }
  
        (*ref)->status = status;
        (*ref)->remote_status = msg;
 +      return !(status == REF_STATUS_OK);
  }
  
  static void push_update_refs_status(struct helper_data *data,
        struct strbuf buf = STRBUF_INIT;
        struct ref *ref = remote_refs;
        for (;;) {
 +              char *private;
 +
                recvline(data, &buf);
                if (!buf.len)
                        break;
  
 -              push_update_ref_status(&buf, &ref, remote_refs);
 +              if (push_update_ref_status(&buf, &ref, remote_refs))
 +                      continue;
 +
 +              if (!data->refspecs)
 +                      continue;
 +
 +              /* propagate back the update to the remote namespace */
 +              private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
 +              if (!private)
 +                      continue;
 +              update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
 +              free(private);
        }
        strbuf_release(&buf);
  }
@@@ -806,14 -799,6 +816,14 @@@ static int push_refs_with_export(struc
        struct string_list revlist_args = STRING_LIST_INIT_NODUP;
        struct strbuf buf = STRBUF_INIT;
  
 +      if (!data->refspecs)
 +              die("remote-helper doesn't support push; refspec needed");
 +
 +      if (flags & TRANSPORT_PUSH_DRY_RUN) {
 +              if (set_helper_option(transport, "dry-run", "true") != 0)
 +                      die("helper %s does not support dry-run", data->name);
 +      }
 +
        helper = get_helper(transport);
  
        write_constant(helper->in, "export\n");
                char *private;
                unsigned char sha1[20];
  
 -              if (!data->refspecs)
 -                      continue;
 +              if (ref->deletion)
 +                      die("remote-helpers do not support ref deletion");
 +
                private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
                if (private && !get_sha1(private, sha1)) {
                        strbuf_addf(&buf, "^%s", private);
                }
                free(private);
  
 -              if (ref->deletion) {
 +              if (ref->deletion)
                        die("remote-helpers do not support ref deletion");
 -              }
  
 -              if (ref->peer_ref)
 +              if (ref->peer_ref) {
 +                      if (strcmp(ref->peer_ref->name, ref->name))
 +                              die("remote-helpers do not support old:new syntax");
                        string_list_append(&revlist_args, ref->peer_ref->name);
 -
 +              }
        }
  
        if (get_exporter(transport, &exporter, &revlist_args))
@@@ -982,7 -965,6 +992,7 @@@ int transport_helper_init(struct transp
  #define PBUFFERSIZE 8192
  
  /* Print bidirectional transfer loop debug message. */
 +__attribute__((format (printf, 1, 2)))
  static void transfer_debug(const char *fmt, ...)
  {
        va_list args;
@@@ -1068,7 -1050,7 +1078,7 @@@ static int udt_do_read(struct unidirect
                return -1;
        } else if (bytes == 0) {
                transfer_debug("%s EOF (with %i bytes in buffer)",
 -                      t->src_name, t->bufuse);
 +                      t->src_name, (int)t->bufuse);
                t->state = SSTATE_FLUSHING;
        } else if (bytes > 0) {
                t->bufuse += bytes;
@@@ -1132,7 -1114,7 +1142,7 @@@ static void *udt_copy_task_routine(voi
  #ifndef NO_PTHREADS
  
  /*
 - * Join thread, with apporiate errors on failure. Name is name for the
 + * Join thread, with appropriate errors on failure. Name is name for the
   * thread (for error messages). Returns 0 on success, 1 on failure.
   */
  static int tloop_join(pthread_t thread, const char *name)
@@@ -1198,7 -1180,7 +1208,7 @@@ static void udt_kill_transfer(struct un
  }
  
  /*
 - * Join process, with apporiate errors on failure. Name is name for the
 + * Join process, with appropriate errors on failure. Name is name for the
   * process (for error messages). Returns 0 on success, 1 on failure.
   */
  static int tloop_join(pid_t pid, const char *name)