ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VALID
[gitweb.git] / transport.c
index efecb65258ba95ee743f0e3ca178e74e2756e7d1..afec5b731aa39f8bf9d647528c1a314bf677a26b 100644 (file)
@@ -158,7 +158,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
-               die ("Could not make temporary directory");
+               die_errno ("Could not make temporary directory");
        temp_dir_len = temp_dir.len;
 
        strbuf_addstr(&buf, rsync_url(transport->url));
@@ -321,7 +321,7 @@ static int rsync_transport_push(struct transport *transport,
 
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
-               die ("Could not make temporary directory");
+               die_errno ("Could not make temporary directory");
        strbuf_addch(&temp_dir, '/');
 
        if (flags & TRANSPORT_PUSH_ALL) {
@@ -396,7 +396,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
 {
        const char **argv;
        int argc;
-       int err;
 
        if (flags & TRANSPORT_PUSH_MIRROR)
                return error("http transport does not support mirror mode");
@@ -416,20 +415,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
        while (refspec_nr--)
                argv[argc++] = *refspec++;
        argv[argc] = NULL;
-       err = run_command_v_opt(argv, RUN_GIT_CMD);
-       switch (err) {
-       case -ERR_RUN_COMMAND_FORK:
-               error("unable to fork for %s", argv[0]);
-       case -ERR_RUN_COMMAND_EXEC:
-               error("unable to exec %s", argv[0]);
-               break;
-       case -ERR_RUN_COMMAND_WAITPID:
-       case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
-       case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
-       case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
-               error("%s died with strange error", argv[0]);
-       }
-       return !!err;
+       return !!run_command_v_opt(argv, RUN_GIT_CMD);
 }
 
 static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
@@ -439,9 +425,7 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
        char *ref_name;
        char *refs_url;
        int i = 0;
-
-       struct active_request_slot *slot;
-       struct slot_results results;
+       int http_ret;
 
        struct ref *refs = NULL;
        struct ref *ref = NULL;
@@ -461,25 +445,16 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
 
-       slot = get_active_slot();
-       slot->results = &results;
-       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
-
-       if (start_active_slot(slot)) {
-               run_active_slot(slot);
-               if (results.curl_result != CURLE_OK) {
-                       strbuf_release(&buffer);
-                       if (missing_target(&results))
-                               die("%s not found: did you run git update-server-info on the server?", refs_url);
-                       else
-                               die("%s download error - %s", refs_url, curl_errorstr);
-               }
-       } else {
-               strbuf_release(&buffer);
-               die("Unable to start HTTP request");
+       http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
+       switch (http_ret) {
+       case HTTP_OK:
+               break;
+       case HTTP_MISSING_TARGET:
+               die("%s not found: did you run git update-server-info on the"
+                   " server?", refs_url);
+       default:
+               http_error(refs_url, http_ret);
+               die("HTTP request failed");
        }
 
        data = buffer.buf;
@@ -519,6 +494,8 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
                free(ref);
        }
 
+       strbuf_release(&buffer);
+       free(refs_url);
        return refs;
 }
 
@@ -690,6 +667,21 @@ static int fetch_refs_via_pack(struct transport *transport,
        return (refs ? 0 : -1);
 }
 
+static int push_had_errors(struct ref *ref)
+{
+       for (; ref; ref = ref->next) {
+               switch (ref->status) {
+               case REF_STATUS_NONE:
+               case REF_STATUS_UPTODATE:
+               case REF_STATUS_OK:
+                       break;
+               default:
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 static int refs_pushed(struct ref *ref)
 {
        for (; ref; ref = ref->next) {
@@ -728,19 +720,30 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb
 
 #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)
+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
 {
-       fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
-       if (from)
-               fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
-       else
-               fputs(prettify_ref(to), stderr);
-       if (msg) {
-               fputs(" (", stderr);
-               fputs(msg, stderr);
-               fputc(')', stderr);
+       if (porcelain) {
+               if (from)
+                       fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+               else
+                       fprintf(stdout, "%c\t:%s\t", flag, to->name);
+               if (msg)
+                       fprintf(stdout, "%s (%s)\n", summary, msg);
+               else
+                       fprintf(stdout, "%s\n", summary);
+       } else {
+               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);
        }
-       fputc('\n', stderr);
 }
 
 static const char *status_abbrev(unsigned char sha1[20])
@@ -748,15 +751,15 @@ 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)
+static void print_ok_ref_status(struct ref *ref, int porcelain)
 {
        if (ref->deletion)
-               print_ref_status('-', "[deleted]", ref, NULL, NULL);
+               print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
        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);
+                       "[new branch]"),
+                       ref, ref->peer_ref, NULL, porcelain);
        else {
                char quickref[84];
                char type;
@@ -774,50 +777,51 @@ static void print_ok_ref_status(struct ref *ref)
                }
                strcat(quickref, status_abbrev(ref->new_sha1));
 
-               print_ref_status(type, quickref, ref, ref->peer_ref, msg);
+               print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
        }
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
 {
        if (!count)
                fprintf(stderr, "To %s\n", dest);
 
        switch(ref->status) {
        case REF_STATUS_NONE:
-               print_ref_status('X', "[no match]", ref, NULL, NULL);
+               print_ref_status('X', "[no match]", ref, NULL, NULL, porcelain);
                break;
        case REF_STATUS_REJECT_NODELETE:
                print_ref_status('!', "[rejected]", ref, NULL,
-                               "remote does not support deleting refs");
+                                                "remote does not support deleting refs", porcelain);
                break;
        case REF_STATUS_UPTODATE:
                print_ref_status('=', "[up to date]", ref,
-                               ref->peer_ref, NULL);
+                                                ref->peer_ref, NULL, porcelain);
                break;
        case REF_STATUS_REJECT_NONFASTFORWARD:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                               "non-fast forward");
+                                                "non-fast forward", porcelain);
                break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
-                               ref->deletion ? NULL : ref->peer_ref,
-                               ref->remote_status);
+                                                ref->deletion ? NULL : ref->peer_ref,
+                                                ref->remote_status, porcelain);
                break;
        case REF_STATUS_EXPECTING_REPORT:
                print_ref_status('!', "[remote failure]", ref,
-                               ref->deletion ? NULL : ref->peer_ref,
-                               "remote failed to report status");
+                                                ref->deletion ? NULL : ref->peer_ref,
+                                                "remote failed to report status", porcelain);
                break;
        case REF_STATUS_OK:
-               print_ok_ref_status(ref);
+               print_ok_ref_status(ref, porcelain);
                break;
        }
 
        return 1;
 }
 
-static void print_push_status(const char *dest, struct ref *refs, int verbose)
+static void print_push_status(const char *dest, struct ref *refs,
+                                                         int verbose, int porcelain)
 {
        struct ref *ref;
        int n = 0;
@@ -825,18 +829,18 @@ static void print_push_status(const char *dest, struct ref *refs, int verbose)
        if (verbose) {
                for (ref = refs; ref; ref = ref->next)
                        if (ref->status == REF_STATUS_UPTODATE)
-                               n += print_one_push_status(ref, dest, n);
+                               n += print_one_push_status(ref, dest, n, porcelain);
        }
 
        for (ref = refs; ref; ref = ref->next)
                if (ref->status == REF_STATUS_OK)
-                       n += print_one_push_status(ref, dest, n);
+                       n += print_one_push_status(ref, dest, n, porcelain);
 
        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);
+                       n += print_one_push_status(ref, dest, n, porcelain);
        }
 }
 
@@ -889,6 +893,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
        args.use_thin_pack = data->thin;
        args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
+       args.quiet = !!(flags & TRANSPORT_PUSH_QUIET);
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
 
        ret = send_pack(&args, data->fd, data->conn, remote_refs,
@@ -1003,10 +1008,11 @@ int transport_push(struct transport *transport,
        if (transport->push_refs) {
                struct ref *remote_refs =
                        transport->get_refs_list(transport, 1);
-               struct ref **remote_tail;
                struct ref *local_refs = get_local_heads();
                int match_flags = MATCH_REFS_NONE;
                int verbose = flags & TRANSPORT_PUSH_VERBOSE;
+               int quiet = flags & TRANSPORT_PUSH_QUIET;
+               int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
                int ret;
 
                if (flags & TRANSPORT_PUSH_ALL)
@@ -1014,17 +1020,16 @@ int transport_push(struct transport *transport,
                if (flags & TRANSPORT_PUSH_MIRROR)
                        match_flags |= MATCH_REFS_MIRROR;
 
-               remote_tail = &remote_refs;
-               while (*remote_tail)
-                       remote_tail = &((*remote_tail)->next);
-               if (match_refs(local_refs, remote_refs, &remote_tail,
+               if (match_refs(local_refs, &remote_refs,
                               refspec_nr, refspec, match_flags)) {
                        return -1;
                }
 
                ret = transport->push_refs(transport, remote_refs, flags);
 
-               print_push_status(transport->url, remote_refs, verbose);
+               if (!quiet || push_had_errors(remote_refs))
+                       print_push_status(transport->url, remote_refs,
+                                       verbose | porcelain, porcelain);
 
                if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
                        struct ref *ref;
@@ -1083,3 +1088,51 @@ int transport_disconnect(struct transport *transport)
        free(transport);
        return ret;
 }
+
+/*
+ * Strip username (and password) from an url and return
+ * it in a newly allocated string.
+ */
+char *transport_anonymize_url(const char *url)
+{
+       char *anon_url, *scheme_prefix, *anon_part;
+       size_t anon_len, prefix_len = 0;
+
+       anon_part = strchr(url, '@');
+       if (is_local(url) || !anon_part)
+               goto literal_copy;
+
+       anon_len = strlen(++anon_part);
+       scheme_prefix = strstr(url, "://");
+       if (!scheme_prefix) {
+               if (!strchr(anon_part, ':'))
+                       /* cannot be "me@there:/path/name" */
+                       goto literal_copy;
+       } else {
+               const char *cp;
+               /* make sure scheme is reasonable */
+               for (cp = url; cp < scheme_prefix; cp++) {
+                       switch (*cp) {
+                               /* RFC 1738 2.1 */
+                       case '+': case '.': case '-':
+                               break; /* ok */
+                       default:
+                               if (isalnum(*cp))
+                                       break;
+                               /* it isn't */
+                               goto literal_copy;
+                       }
+               }
+               /* @ past the first slash does not count */
+               cp = strchr(scheme_prefix + 3, '/');
+               if (cp && cp < anon_part)
+                       goto literal_copy;
+               prefix_len = scheme_prefix - url + 3;
+       }
+       anon_url = xcalloc(1, 1 + prefix_len + anon_len);
+       memcpy(anon_url, url, prefix_len);
+       memcpy(anon_url + prefix_len, anon_part, anon_len);
+       return anon_url;
+literal_copy:
+       return xstrdup(url);
+}