refactor duplicated code in builtin-send-pack.c and transport.c
[gitweb.git] / builtin-send-pack.c
index 8fffdbf20058e9970af4b5e4a14349ecb4ff455c..cbda3117d8ee27629e888172ab424c0e0c93ceed 100644 (file)
@@ -7,6 +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 @@ static int receive_status(int in, struct ref *refs)
        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;
@@ -406,50 +257,20 @@ int send_pack(struct send_pack_args *args,
         */
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
-
-               if (ref->peer_ref)
-                       hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
-               else if (!args->send_mirror)
+               if (!ref->peer_ref && !args->send_mirror)
                        continue;
 
-               ref->deletion = is_null_sha1(ref->new_sha1);
-               if (ref->deletion && !allow_deleting_refs) {
-                       ref->status = REF_STATUS_REJECT_NODELETE;
-                       continue;
-               }
-               if (!ref->deletion &&
-                   !hashcmp(ref->old_sha1, ref->new_sha1)) {
-                       ref->status = REF_STATUS_UPTODATE;
+               /* Check for statuses set by set_ref_status_for_push() */
+               switch (ref->status) {
+               case REF_STATUS_REJECT_NONFASTFORWARD:
+               case REF_STATUS_UPTODATE:
                        continue;
+               default:
+                       ; /* do nothing */
                }
 
-               /* This part determines what can overwrite what.
-                * The rules are:
-                *
-                * (0) you can always use --force or +A:B notation to
-                *     selectively force individual ref pairs.
-                *
-                * (1) if the old thing does not exist, it is OK.
-                *
-                * (2) if you do not have the old thing, you are not allowed
-                *     to overwrite it; you would not know what you are losing
-                *     otherwise.
-                *
-                * (3) if both new and old are commit-ish, and new is a
-                *     descendant of old, it is OK.
-                *
-                * (4) regardless of all of the above, removing :B is
-                *     always allowed.
-                */
-
-               ref->nonfastforward =
-                   !ref->deletion &&
-                   !is_null_sha1(ref->old_sha1) &&
-                   (!has_sha1_file(ref->old_sha1)
-                     || !ref_newer(ref->new_sha1, ref->old_sha1));
-
-               if (ref->nonfastforward && !ref->force && !args->force_update) {
-                       ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
+               if (ref->deletion && !allow_deleting_refs) {
+                       ref->status = REF_STATUS_REJECT_NODELETE;
                        continue;
                }
 
@@ -519,37 +340,6 @@ int send_pack(struct send_pack_args *args,
        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;
@@ -566,6 +356,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        int send_all = 0;
        const char *receivepack = "git-receive-pack";
        int flags;
+       int nonfastforward = 0;
 
        argv++;
        for (i = 1; i < argc; i++, argv++) {
@@ -658,7 +449,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        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();
 
@@ -673,6 +464,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        if (match_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
                return -1;
 
+       set_ref_status_for_push(remote_refs, args.send_mirror,
+               args.force_update);
+
        ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
 
        if (helper_status)
@@ -684,15 +478,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        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;