builtin / send-pack.con commit difftool: address a couple of resource/memory leaks (5f3296c)
   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 oid_array extra_have = OID_ARRAY_INIT;
 135        struct oid_array shallow = OID_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        struct string_list push_options = STRING_LIST_INIT_NODUP;
 148        unsigned use_thin_pack = 0;
 149        unsigned atomic = 0;
 150        unsigned stateless_rpc = 0;
 151        int flags;
 152        unsigned int reject_reasons;
 153        int progress = -1;
 154        int from_stdin = 0;
 155        struct push_cas_option cas = {0};
 156
 157        struct option options[] = {
 158                OPT__VERBOSITY(&verbose),
 159                OPT_STRING(0, "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
 160                OPT_STRING(0, "exec", &receivepack, "receive-pack", N_("receive pack program")),
 161                OPT_STRING(0, "remote", &remote_name, "remote", N_("remote name")),
 162                OPT_BOOL(0, "all", &send_all, N_("push all refs")),
 163                OPT_BOOL('n' , "dry-run", &dry_run, N_("dry run")),
 164                OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")),
 165                OPT_BOOL('f', "force", &force_update, N_("force updates")),
 166                { OPTION_CALLBACK,
 167                  0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
 168                  PARSE_OPT_OPTARG, option_parse_push_signed },
 169                OPT_STRING_LIST(0, "push-option", &push_options,
 170                                N_("server-specific"),
 171                                N_("option to transmit")),
 172                OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
 173                OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")),
 174                OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
 175                OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
 176                OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
 177                OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
 178                { OPTION_CALLBACK,
 179                  0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
 180                  N_("require old value of ref to be at this value"),
 181                  PARSE_OPT_OPTARG, parseopt_push_cas_option },
 182                OPT_END()
 183        };
 184
 185        git_config(send_pack_config, NULL);
 186        argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
 187        if (argc > 0) {
 188                dest = argv[0];
 189                refspecs = (const char **)(argv + 1);
 190                nr_refspecs = argc - 1;
 191        }
 192
 193        if (!dest)
 194                usage_with_options(send_pack_usage, options);
 195
 196        args.verbose = verbose;
 197        args.dry_run = dry_run;
 198        args.send_mirror = send_mirror;
 199        args.force_update = force_update;
 200        args.quiet = quiet;
 201        args.push_cert = push_cert;
 202        args.progress = progress;
 203        args.use_thin_pack = use_thin_pack;
 204        args.atomic = atomic;
 205        args.stateless_rpc = stateless_rpc;
 206        args.push_options = push_options.nr ? &push_options : NULL;
 207
 208        if (from_stdin) {
 209                struct argv_array all_refspecs = ARGV_ARRAY_INIT;
 210
 211                for (i = 0; i < nr_refspecs; i++)
 212                        argv_array_push(&all_refspecs, refspecs[i]);
 213
 214                if (args.stateless_rpc) {
 215                        const char *buf;
 216                        while ((buf = packet_read_line(0, NULL)))
 217                                argv_array_push(&all_refspecs, buf);
 218                } else {
 219                        struct strbuf line = STRBUF_INIT;
 220                        while (strbuf_getline(&line, stdin) != EOF)
 221                                argv_array_push(&all_refspecs, line.buf);
 222                        strbuf_release(&line);
 223                }
 224
 225                refspecs = all_refspecs.argv;
 226                nr_refspecs = all_refspecs.argc;
 227        }
 228
 229        /*
 230         * --all and --mirror are incompatible; neither makes sense
 231         * with any refspecs.
 232         */
 233        if ((nr_refspecs > 0 && (send_all || args.send_mirror)) ||
 234            (send_all && args.send_mirror))
 235                usage_with_options(send_pack_usage, options);
 236
 237        if (remote_name) {
 238                remote = remote_get(remote_name);
 239                if (!remote_has_url(remote, dest)) {
 240                        die("Destination %s is not a uri for %s",
 241                            dest, remote_name);
 242                }
 243        }
 244
 245        if (progress == -1)
 246                progress = !args.quiet && isatty(2);
 247        args.progress = progress;
 248
 249        if (args.stateless_rpc) {
 250                conn = NULL;
 251                fd[0] = 0;
 252                fd[1] = 1;
 253        } else {
 254                conn = git_connect(fd, dest, receivepack,
 255                        args.verbose ? CONNECT_VERBOSE : 0);
 256        }
 257
 258        get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL,
 259                         &extra_have, &shallow);
 260
 261        transport_verify_remote_names(nr_refspecs, refspecs);
 262
 263        local_refs = get_local_heads();
 264
 265        flags = MATCH_REFS_NONE;
 266
 267        if (send_all)
 268                flags |= MATCH_REFS_ALL;
 269        if (args.send_mirror)
 270                flags |= MATCH_REFS_MIRROR;
 271
 272        /* match them up */
 273        if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
 274                return -1;
 275
 276        if (!is_empty_cas(&cas))
 277                apply_push_cas(&cas, remote, remote_refs);
 278
 279        set_ref_status_for_push(remote_refs, args.send_mirror,
 280                args.force_update);
 281
 282        ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
 283
 284        if (helper_status)
 285                print_helper_status(remote_refs);
 286
 287        close(fd[1]);
 288        close(fd[0]);
 289
 290        ret |= finish_connect(conn);
 291
 292        if (!helper_status)
 293                transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
 294
 295        if (!args.dry_run && remote) {
 296                struct ref *ref;
 297                for (ref = remote_refs; ref; ref = ref->next)
 298                        transport_update_tracking_ref(remote, ref, args.verbose);
 299        }
 300
 301        if (!ret && !transport_refs_pushed(remote_refs))
 302                fprintf(stderr, "Everything up-to-date\n");
 303
 304        return ret;
 305}