builtin / send-pack.con commit fetch: refactor ref update status formatting code (d0b39a0)
   1#include "builtin.h"
   2#include "commit.h"
   3#include "refs.h"
   4#include "pkt-line.h"
   5#include "sideband.h"
   6#include "run-command.h"
   7#include "remote.h"
   8#include "connect.h"
   9#include "send-pack.h"
  10#include "quote.h"
  11#include "transport.h"
  12#include "version.h"
  13#include "sha1-array.h"
  14#include "gpg-interface.h"
  15#include "gettext.h"
  16
  17static const char * const send_pack_usage[] = {
  18        N_("git send-pack [--all | --mirror] [--dry-run] [--force] "
  19          "[--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] "
  20          "[<host>:]<directory> [<ref>...]\n"
  21          "  --all and explicit <ref> specification are mutually exclusive."),
  22        NULL,
  23};
  24
  25static struct send_pack_args args;
  26
  27static void print_helper_status(struct ref *ref)
  28{
  29        struct strbuf buf = STRBUF_INIT;
  30
  31        for (; ref; ref = ref->next) {
  32                const char *msg = NULL;
  33                const char *res;
  34
  35                switch(ref->status) {
  36                case REF_STATUS_NONE:
  37                        res = "error";
  38                        msg = "no match";
  39                        break;
  40
  41                case REF_STATUS_OK:
  42                        res = "ok";
  43                        break;
  44
  45                case REF_STATUS_UPTODATE:
  46                        res = "ok";
  47                        msg = "up to date";
  48                        break;
  49
  50                case REF_STATUS_REJECT_NONFASTFORWARD:
  51                        res = "error";
  52                        msg = "non-fast forward";
  53                        break;
  54
  55                case REF_STATUS_REJECT_FETCH_FIRST:
  56                        res = "error";
  57                        msg = "fetch first";
  58                        break;
  59
  60                case REF_STATUS_REJECT_NEEDS_FORCE:
  61                        res = "error";
  62                        msg = "needs force";
  63                        break;
  64
  65                case REF_STATUS_REJECT_STALE:
  66                        res = "error";
  67                        msg = "stale info";
  68                        break;
  69
  70                case REF_STATUS_REJECT_ALREADY_EXISTS:
  71                        res = "error";
  72                        msg = "already exists";
  73                        break;
  74
  75                case REF_STATUS_REJECT_NODELETE:
  76                case REF_STATUS_REMOTE_REJECT:
  77                        res = "error";
  78                        break;
  79
  80                case REF_STATUS_EXPECTING_REPORT:
  81                default:
  82                        continue;
  83                }
  84
  85                strbuf_reset(&buf);
  86                strbuf_addf(&buf, "%s %s", res, ref->name);
  87                if (ref->remote_status)
  88                        msg = ref->remote_status;
  89                if (msg) {
  90                        strbuf_addch(&buf, ' ');
  91                        quote_two_c_style(&buf, "", msg, 0);
  92                }
  93                strbuf_addch(&buf, '\n');
  94
  95                write_or_die(1, buf.buf, buf.len);
  96        }
  97        strbuf_release(&buf);
  98}
  99
 100static int send_pack_config(const char *k, const char *v, void *cb)
 101{
 102        git_gpg_config(k, v, NULL);
 103
 104        if (!strcmp(k, "push.gpgsign")) {
 105                const char *value;
 106                if (!git_config_get_value("push.gpgsign", &value)) {
 107                        switch (git_config_maybe_bool("push.gpgsign", value)) {
 108                        case 0:
 109                                args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
 110                                break;
 111                        case 1:
 112                                args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
 113                                break;
 114                        default:
 115                                if (value && !strcasecmp(value, "if-asked"))
 116                                        args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
 117                                else
 118                                        return error("Invalid value for '%s'", k);
 119                        }
 120                }
 121        }
 122        return 0;
 123}
 124
 125int cmd_send_pack(int argc, const char **argv, const char *prefix)
 126{
 127        int i, nr_refspecs = 0;
 128        const char **refspecs = NULL;
 129        const char *remote_name = NULL;
 130        struct remote *remote = NULL;
 131        const char *dest = NULL;
 132        int fd[2];
 133        struct child_process *conn;
 134        struct sha1_array extra_have = SHA1_ARRAY_INIT;
 135        struct sha1_array shallow = SHA1_ARRAY_INIT;
 136        struct ref *remote_refs, *local_refs;
 137        int ret;
 138        int helper_status = 0;
 139        int send_all = 0;
 140        int verbose = 0;
 141        const char *receivepack = "git-receive-pack";
 142        unsigned dry_run = 0;
 143        unsigned send_mirror = 0;
 144        unsigned force_update = 0;
 145        unsigned quiet = 0;
 146        int push_cert = 0;
 147        unsigned use_thin_pack = 0;
 148        unsigned atomic = 0;
 149        unsigned stateless_rpc = 0;
 150        int flags;
 151        unsigned int reject_reasons;
 152        int progress = -1;
 153        int from_stdin = 0;
 154        struct push_cas_option cas = {0};
 155
 156        struct option options[] = {
 157                OPT__VERBOSITY(&verbose),
 158                OPT_STRING(0, "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
 159                OPT_STRING(0, "exec", &receivepack, "receive-pack", N_("receive pack program")),
 160                OPT_STRING(0, "remote", &remote_name, "remote", N_("remote name")),
 161                OPT_BOOL(0, "all", &send_all, N_("push all refs")),
 162                OPT_BOOL('n' , "dry-run", &dry_run, N_("dry run")),
 163                OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")),
 164                OPT_BOOL('f', "force", &force_update, N_("force updates")),
 165                { OPTION_CALLBACK,
 166                  0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
 167                  PARSE_OPT_OPTARG, option_parse_push_signed },
 168                OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
 169                OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")),
 170                OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
 171                OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
 172                OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
 173                OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
 174                { OPTION_CALLBACK,
 175                  0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
 176                  N_("require old value of ref to be at this value"),
 177                  PARSE_OPT_OPTARG, parseopt_push_cas_option },
 178                OPT_END()
 179        };
 180
 181        git_config(send_pack_config, NULL);
 182        argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
 183        if (argc > 0) {
 184                dest = argv[0];
 185                refspecs = (const char **)(argv + 1);
 186                nr_refspecs = argc - 1;
 187        }
 188
 189        if (!dest)
 190                usage_with_options(send_pack_usage, options);
 191
 192        args.verbose = verbose;
 193        args.dry_run = dry_run;
 194        args.send_mirror = send_mirror;
 195        args.force_update = force_update;
 196        args.quiet = quiet;
 197        args.push_cert = push_cert;
 198        args.progress = progress;
 199        args.use_thin_pack = use_thin_pack;
 200        args.atomic = atomic;
 201        args.stateless_rpc = stateless_rpc;
 202
 203        if (from_stdin) {
 204                struct argv_array all_refspecs = ARGV_ARRAY_INIT;
 205
 206                for (i = 0; i < nr_refspecs; i++)
 207                        argv_array_push(&all_refspecs, refspecs[i]);
 208
 209                if (args.stateless_rpc) {
 210                        const char *buf;
 211                        while ((buf = packet_read_line(0, NULL)))
 212                                argv_array_push(&all_refspecs, buf);
 213                } else {
 214                        struct strbuf line = STRBUF_INIT;
 215                        while (strbuf_getline(&line, stdin) != EOF)
 216                                argv_array_push(&all_refspecs, line.buf);
 217                        strbuf_release(&line);
 218                }
 219
 220                refspecs = all_refspecs.argv;
 221                nr_refspecs = all_refspecs.argc;
 222        }
 223
 224        /*
 225         * --all and --mirror are incompatible; neither makes sense
 226         * with any refspecs.
 227         */
 228        if ((nr_refspecs > 0 && (send_all || args.send_mirror)) ||
 229            (send_all && args.send_mirror))
 230                usage_with_options(send_pack_usage, options);
 231
 232        if (remote_name) {
 233                remote = remote_get(remote_name);
 234                if (!remote_has_url(remote, dest)) {
 235                        die("Destination %s is not a uri for %s",
 236                            dest, remote_name);
 237                }
 238        }
 239
 240        if (progress == -1)
 241                progress = !args.quiet && isatty(2);
 242        args.progress = progress;
 243
 244        if (args.stateless_rpc) {
 245                conn = NULL;
 246                fd[0] = 0;
 247                fd[1] = 1;
 248        } else {
 249                conn = git_connect(fd, dest, receivepack,
 250                        args.verbose ? CONNECT_VERBOSE : 0);
 251        }
 252
 253        get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL,
 254                         &extra_have, &shallow);
 255
 256        transport_verify_remote_names(nr_refspecs, refspecs);
 257
 258        local_refs = get_local_heads();
 259
 260        flags = MATCH_REFS_NONE;
 261
 262        if (send_all)
 263                flags |= MATCH_REFS_ALL;
 264        if (args.send_mirror)
 265                flags |= MATCH_REFS_MIRROR;
 266
 267        /* match them up */
 268        if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
 269                return -1;
 270
 271        if (!is_empty_cas(&cas))
 272                apply_push_cas(&cas, remote, remote_refs);
 273
 274        set_ref_status_for_push(remote_refs, args.send_mirror,
 275                args.force_update);
 276
 277        ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
 278
 279        if (helper_status)
 280                print_helper_status(remote_refs);
 281
 282        close(fd[1]);
 283        close(fd[0]);
 284
 285        ret |= finish_connect(conn);
 286
 287        if (!helper_status)
 288                transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
 289
 290        if (!args.dry_run && remote) {
 291                struct ref *ref;
 292                for (ref = remote_refs; ref; ref = ref->next)
 293                        transport_update_tracking_ref(remote, ref, args.verbose);
 294        }
 295
 296        if (!ret && !transport_refs_pushed(remote_refs))
 297                fprintf(stderr, "Everything up-to-date\n");
 298
 299        return ret;
 300}