Merge branch 'ml/send-pack-transport-refactor'
authorJunio C Hamano <gitster@pobox.com>
Tue, 2 Mar 2010 20:44:09 +0000 (12:44 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 2 Mar 2010 20:44:09 +0000 (12:44 -0800)
* ml/send-pack-transport-refactor:
refactor duplicated code in builtin-send-pack.c and transport.c

1  2 
builtin-send-pack.c
transport.c
transport.h
diff --combined builtin-send-pack.c
index 2183a470524048eabef1b0f31499c5d04aec5850,cbda3117d8ee27629e888172ab424c0e0c93ceed..6019eac9182e22f2d485acdb83be209dbc49968a
@@@ -7,6 -7,7 +7,7 @@@
  #include "remote.h"
  #include "send-pack.h"
  #include "quote.h"
+ #include "transport.h"
  
  static const char send_pack_usage[] =
  "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@@ -169,156 -170,6 +170,6 @@@ static int receive_status(int in, struc
        return ret;
  }
  
- static void update_tracking_ref(struct remote *remote, struct ref *ref)
- {
-       struct refspec rs;
-       if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
-               return;
-       rs.src = ref->name;
-       rs.dst = NULL;
-       if (!remote_find_tracking(remote, &rs)) {
-               if (args.verbose)
-                       fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
-               if (ref->deletion) {
-                       delete_ref(rs.dst, NULL, 0);
-               } else
-                       update_ref("update by push", rs.dst,
-                                       ref->new_sha1, NULL, 0, 0);
-               free(rs.dst);
-       }
- }
- #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
- static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
- {
-       fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
-       if (from)
-               fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
-       else
-               fputs(prettify_refname(to->name), stderr);
-       if (msg) {
-               fputs(" (", stderr);
-               fputs(msg, stderr);
-               fputc(')', stderr);
-       }
-       fputc('\n', stderr);
- }
- static const char *status_abbrev(unsigned char sha1[20])
- {
-       return find_unique_abbrev(sha1, DEFAULT_ABBREV);
- }
- static void print_ok_ref_status(struct ref *ref)
- {
-       if (ref->deletion)
-               print_ref_status('-', "[deleted]", ref, NULL, NULL);
-       else if (is_null_sha1(ref->old_sha1))
-               print_ref_status('*',
-                       (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
-                         "[new branch]"),
-                       ref, ref->peer_ref, NULL);
-       else {
-               char quickref[84];
-               char type;
-               const char *msg;
-               strcpy(quickref, status_abbrev(ref->old_sha1));
-               if (ref->nonfastforward) {
-                       strcat(quickref, "...");
-                       type = '+';
-                       msg = "forced update";
-               } else {
-                       strcat(quickref, "..");
-                       type = ' ';
-                       msg = NULL;
-               }
-               strcat(quickref, status_abbrev(ref->new_sha1));
-               print_ref_status(type, quickref, ref, ref->peer_ref, msg);
-       }
- }
- static int print_one_push_status(struct ref *ref, const char *dest, int count)
- {
-       if (!count)
-               fprintf(stderr, "To %s\n", dest);
-       switch(ref->status) {
-       case REF_STATUS_NONE:
-               print_ref_status('X', "[no match]", ref, NULL, NULL);
-               break;
-       case REF_STATUS_REJECT_NODELETE:
-               print_ref_status('!', "[rejected]", ref, NULL,
-                               "remote does not support deleting refs");
-               break;
-       case REF_STATUS_UPTODATE:
-               print_ref_status('=', "[up to date]", ref,
-                               ref->peer_ref, NULL);
-               break;
-       case REF_STATUS_REJECT_NONFASTFORWARD:
-               print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                               "non-fast-forward");
-               break;
-       case REF_STATUS_REMOTE_REJECT:
-               print_ref_status('!', "[remote rejected]", ref,
-                               ref->deletion ? NULL : ref->peer_ref,
-                               ref->remote_status);
-               break;
-       case REF_STATUS_EXPECTING_REPORT:
-               print_ref_status('!', "[remote failure]", ref,
-                               ref->deletion ? NULL : ref->peer_ref,
-                               "remote failed to report status");
-               break;
-       case REF_STATUS_OK:
-               print_ok_ref_status(ref);
-               break;
-       }
-       return 1;
- }
- static void print_push_status(const char *dest, struct ref *refs)
- {
-       struct ref *ref;
-       int n = 0;
-       if (args.verbose) {
-               for (ref = refs; ref; ref = ref->next)
-                       if (ref->status == REF_STATUS_UPTODATE)
-                               n += print_one_push_status(ref, dest, n);
-       }
-       for (ref = refs; ref; ref = ref->next)
-               if (ref->status == REF_STATUS_OK)
-                       n += print_one_push_status(ref, dest, n);
-       for (ref = refs; ref; ref = ref->next) {
-               if (ref->status != REF_STATUS_NONE &&
-                   ref->status != REF_STATUS_UPTODATE &&
-                   ref->status != REF_STATUS_OK)
-                       n += print_one_push_status(ref, dest, n);
-       }
- }
- static int refs_pushed(struct ref *ref)
- {
-       for (; ref; ref = ref->next) {
-               switch(ref->status) {
-               case REF_STATUS_NONE:
-               case REF_STATUS_UPTODATE:
-                       break;
-               default:
-                       return 1;
-               }
-       }
-       return 0;
- }
  static void print_helper_status(struct ref *ref)
  {
        struct strbuf buf = STRBUF_INIT;
        strbuf_release(&buf);
  }
  
 +static int sideband_demux(int in, int out, void *data)
 +{
 +      int *fd = data;
 +      int ret = recv_sideband("send-pack", fd[0], out);
 +      close(out);
 +      return ret;
 +}
 +
  int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
        struct strbuf req_buf = STRBUF_INIT;
        struct ref *ref;
        int new_refs;
 -      int ask_for_status_report = 0;
        int allow_deleting_refs = 0;
 -      int expect_status_report = 0;
 +      int status_report = 0;
 +      int use_sideband = 0;
 +      unsigned cmds_sent = 0;
        int ret;
 +      struct async demux;
  
        /* Does the other end support the reporting? */
        if (server_supports("report-status"))
 -              ask_for_status_report = 1;
 +              status_report = 1;
        if (server_supports("delete-refs"))
                allow_deleting_refs = 1;
        if (server_supports("ofs-delta"))
                args->use_ofs_delta = 1;
 +      if (server_supports("side-band-64k"))
 +              use_sideband = 1;
  
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
                if (!ref->deletion)
                        new_refs++;
  
 -              if (!args->dry_run) {
 +              if (args->dry_run) {
 +                      ref->status = REF_STATUS_OK;
 +              } else {
                        char *old_hex = sha1_to_hex(ref->old_sha1);
                        char *new_hex = sha1_to_hex(ref->new_sha1);
  
 -                      if (ask_for_status_report) {
 -                              packet_buf_write(&req_buf, "%s %s %s%c%s",
 +                      if (!cmds_sent && (status_report || use_sideband)) {
 +                              packet_buf_write(&req_buf, "%s %s %s%c%s%s",
                                        old_hex, new_hex, ref->name, 0,
 -                                      "report-status");
 -                              ask_for_status_report = 0;
 -                              expect_status_report = 1;
 +                                      status_report ? " report-status" : "",
 +                                      use_sideband ? " side-band-64k" : "");
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
                                        old_hex, new_hex, ref->name);
 +                      ref->status = status_report ?
 +                              REF_STATUS_EXPECTING_REPORT :
 +                              REF_STATUS_OK;
 +                      cmds_sent++;
                }
 -              ref->status = expect_status_report ?
 -                      REF_STATUS_EXPECTING_REPORT :
 -                      REF_STATUS_OK;
        }
  
        if (args->stateless_rpc) {
 -              if (!args->dry_run) {
 +              if (!args->dry_run && cmds_sent) {
                        packet_buf_flush(&req_buf);
                        send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
                }
        }
        strbuf_release(&req_buf);
  
 -      if (new_refs && !args->dry_run) {
 +      if (use_sideband && cmds_sent) {
 +              memset(&demux, 0, sizeof(demux));
 +              demux.proc = sideband_demux;
 +              demux.data = fd;
 +              demux.out = -1;
 +              if (start_async(&demux))
 +                      die("receive-pack: unable to fork off sideband demultiplexer");
 +              in = demux.out;
 +      }
 +
 +      if (new_refs && cmds_sent) {
                if (pack_objects(out, remote_refs, extra_have, args) < 0) {
                        for (ref = remote_refs; ref; ref = ref->next)
                                ref->status = REF_STATUS_NONE;
 +                      if (use_sideband)
 +                              finish_async(&demux);
                        return -1;
                }
        }
 -      if (args->stateless_rpc && !args->dry_run)
 +      if (args->stateless_rpc && cmds_sent)
                packet_flush(out);
  
 -      if (expect_status_report)
 +      if (status_report && cmds_sent)
                ret = receive_status(in, remote_refs);
        else
                ret = 0;
        if (args->stateless_rpc)
                packet_flush(out);
  
 +      if (use_sideband && cmds_sent) {
 +              if (finish_async(&demux)) {
 +                      error("error in sideband demultiplexer");
 +                      ret = -1;
 +              }
 +              close(demux.out);
 +      }
 +
        if (ret < 0)
                return ret;
        for (ref = remote_refs; ref; ref = ref->next) {
        return 0;
  }
  
- static void verify_remote_names(int nr_heads, const char **heads)
- {
-       int i;
-       for (i = 0; i < nr_heads; i++) {
-               const char *local = heads[i];
-               const char *remote = strrchr(heads[i], ':');
-               if (*local == '+')
-                       local++;
-               /* A matching refspec is okay.  */
-               if (remote == local && remote[1] == '\0')
-                       continue;
-               remote = remote ? (remote + 1) : local;
-               switch (check_ref_format(remote)) {
-               case 0: /* ok */
-               case CHECK_REF_FORMAT_ONELEVEL:
-                       /* ok but a single level -- that is fine for
-                        * a match pattern.
-                        */
-               case CHECK_REF_FORMAT_WILDCARD:
-                       /* ok but ends with a pattern-match character */
-                       continue;
-               }
-               die("remote part of refspec is not a valid name in %s",
-                   heads[i]);
-       }
- }
  int cmd_send_pack(int argc, const char **argv, const char *prefix)
  {
        int i, nr_refspecs = 0;
        int send_all = 0;
        const char *receivepack = "git-receive-pack";
        int flags;
+       int nonfastforward = 0;
  
        argv++;
        for (i = 1; i < argc; i++, argv++) {
        get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
                         &extra_have);
  
-       verify_remote_names(nr_refspecs, refspecs);
+       transport_verify_remote_names(nr_refspecs, refspecs);
  
        local_refs = get_local_heads();
  
        ret |= finish_connect(conn);
  
        if (!helper_status)
-               print_push_status(dest, remote_refs);
+               transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
  
        if (!args.dry_run && remote) {
                struct ref *ref;
                for (ref = remote_refs; ref; ref = ref->next)
-                       update_tracking_ref(remote, ref);
+                       transport_update_tracking_ref(remote, ref, args.verbose);
        }
  
-       if (!ret && !refs_pushed(remote_refs))
+       if (!ret && !transport_refs_pushed(remote_refs))
                fprintf(stderr, "Everything up-to-date\n");
  
        return ret;
diff --combined transport.c
index 08e4fa0354d64e2b931be68ed8da111b97273523,6d7a1259a6f0e3a6f8ad8265a32cc0f063d9d3be..1a360cfb48545efbbb97969c6879262e321338cd
@@@ -573,7 -573,7 +573,7 @@@ static int push_had_errors(struct ref *
        return 0;
  }
  
static int refs_pushed(struct ref *ref)
int transport_refs_pushed(struct ref *ref)
  {
        for (; ref; ref = ref->next) {
                switch(ref->status) {
        return 0;
  }
  
static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
  {
        struct refspec rs;
  
        }
  }
  
- #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
  static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
  {
        if (porcelain) {
                else
                        fprintf(stdout, "%s\n", summary);
        } else {
-               fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
+               fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, summary);
                if (from)
                        fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
                else
@@@ -711,8 -709,8 +709,8 @@@ static int print_one_push_status(struc
        return 1;
  }
  
static void print_push_status(const char *dest, struct ref *refs,
-                             int verbose, int porcelain, int * nonfastforward)
void transport_print_push_status(const char *dest, struct ref *refs,
+                                 int verbose, int porcelain, int *nonfastforward)
  {
        struct ref *ref;
        int n = 0;
        }
  }
  
static void verify_remote_names(int nr_heads, const char **heads)
void transport_verify_remote_names(int nr_heads, const char **heads)
  {
        int i;
  
@@@ -918,7 -916,6 +916,7 @@@ struct transport *transport_get(struct 
        if (!remote)
                die("No remote provided to transport_get()");
  
 +      ret->got_remote_refs = 0;
        ret->remote = remote;
        helper = remote->foreign_vcs;
  
@@@ -1019,7 -1016,7 +1017,7 @@@ int transport_push(struct transport *tr
                   int *nonfastforward)
  {
        *nonfastforward = 0;
-       verify_remote_names(refspec_nr, refspec);
+       transport_verify_remote_names(refspec_nr, refspec);
  
        if (transport->push) {
                /* Maybe FIXME. But no important transport uses this case. */
                ret |= err;
  
                if (!quiet || err)
-                       print_push_status(transport->url, remote_refs,
+                       transport_print_push_status(transport->url, remote_refs,
                                        verbose | porcelain, porcelain,
                                        nonfastforward);
  
                if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
                        struct ref *ref;
                        for (ref = remote_refs; ref; ref = ref->next)
-                               update_tracking_ref(transport->remote, ref, verbose);
+                               transport_update_tracking_ref(transport->remote, ref, verbose);
                }
  
-               if (!quiet && !ret && !refs_pushed(remote_refs))
+               if (!quiet && !ret && !transport_refs_pushed(remote_refs))
                        fprintf(stderr, "Everything up-to-date\n");
                return ret;
        }
  
  const struct ref *transport_get_remote_refs(struct transport *transport)
  {
 -      if (!transport->remote_refs)
 +      if (!transport->got_remote_refs) {
                transport->remote_refs = transport->get_refs_list(transport, 0);
 +              transport->got_remote_refs = 1;
 +      }
  
        return transport->remote_refs;
  }
diff --combined transport.h
index 6dd9ae182fe12c53860a6af02461ff819d59fd6e,7a9bb57d99afab6c5dddfc244df88afd1b90534b..096f6e9478301395ca05d81eaac6e53e0acd69b0
@@@ -19,12 -19,6 +19,12 @@@ struct transport 
        void *data;
        const struct ref *remote_refs;
  
 +      /**
 +       * Indicates whether we already called get_refs_list(); set by
 +       * transport.c::transport_get_remote_refs().
 +       */
 +      unsigned got_remote_refs : 1;
 +
        /**
         * Returns 0 if successful, positive if the option is not
         * recognized or is inapplicable, and negative if the option
@@@ -98,6 -92,7 +98,7 @@@
  #define TRANSPORT_PUSH_PORCELAIN 32
  #define TRANSPORT_PUSH_QUIET 64
  #define TRANSPORT_PUSH_SET_UPSTREAM 128
+ #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
  
  /* Returns a transport suitable for the url */
  struct transport *transport_get(struct remote *, const char *);
@@@ -148,4 -143,14 +149,14 @@@ int transport_connect(struct transport 
  /* Transport methods defined outside transport.c */
  int transport_helper_init(struct transport *transport, const char *name);
  
+ /* common methods used by transport.c and builtin-send-pack.c */
+ void transport_verify_remote_names(int nr_heads, const char **heads);
+ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
+ int transport_refs_pushed(struct ref *ref);
+ void transport_print_push_status(const char *dest, struct ref *refs,
+                 int verbose, int porcelain, int *nonfastforward);
  #endif