Add API access to shortlog
[gitweb.git] / transport.c
index f4577b7fc6cc95260045403e075597e54dfce526..397983d1155bed967bd48ad47dbbb81cb2e45168 100644 (file)
@@ -118,7 +118,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
                if (hexval(buffer[0]) > 0xf)
                        continue;
                len = strlen(buffer);
-               if (buffer[len - 1] == '\n')
+               if (len && buffer[len - 1] == '\n')
                        buffer[--len] = '\0';
                if (len < 41)
                        continue;
@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,
        struct child_process rsync;
        const char *args[10];
 
+       if (flags & TRANSPORT_PUSH_MIRROR)
+               return error("rsync transport does not support mirror mode");
+
        /* first push the objects */
 
        strbuf_addstr(&buf, transport->url);
@@ -345,6 +348,7 @@ static int rsync_transport_push(struct transport *transport,
 
 /* Generic functions for using commit walkers */
 
+#ifndef NO_CURL /* http fetch is the only user */
 static int fetch_objs_via_walker(struct transport *transport,
                                 int nr_objs, struct ref **to_fetch)
 {
@@ -371,6 +375,7 @@ static int fetch_objs_via_walker(struct transport *transport,
        free(dest);
        return 0;
 }
+#endif /* NO_CURL */
 
 static int disconnect_walker(struct transport *transport)
 {
@@ -381,12 +386,16 @@ static int disconnect_walker(struct transport *transport)
 }
 
 #ifndef NO_CURL
-static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
+static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
+{
        const char **argv;
        int argc;
        int err;
 
-       argv = xmalloc((refspec_nr + 11) * sizeof(char *));
+       if (flags & TRANSPORT_PUSH_MIRROR)
+               return error("http transport does not support mirror mode");
+
+       argv = xmalloc((refspec_nr + 12) * sizeof(char *));
        argv[0] = "http-push";
        argc = 1;
        if (flags & TRANSPORT_PUSH_ALL)
@@ -395,6 +404,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
                argv[argc++] = "--force";
        if (flags & TRANSPORT_PUSH_DRY_RUN)
                argv[argc++] = "--dry-run";
+       if (flags & TRANSPORT_PUSH_VERBOSE)
+               argv[argc++] = "--verbose";
        argv[argc++] = transport->url;
        while (refspec_nr--)
                argv[argc++] = *refspec++;
@@ -415,22 +426,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
        return !!err;
 }
 
-static int missing__target(int code, int result)
-{
-       return  /* file:// URL -- do we ever use one??? */
-               (result == CURLE_FILE_COULDNT_READ_FILE) ||
-               /* http:// and https:// URL */
-               (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
-               /* ftp:// URL */
-               (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
-               ;
-}
-
-#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
-
 static struct ref *get_refs_via_curl(struct transport *transport)
 {
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *data, *start, *mid;
        char *ref_name;
        char *refs_url;
@@ -443,46 +441,43 @@ static struct ref *get_refs_via_curl(struct transport *transport)
        struct ref *ref = NULL;
        struct ref *last_ref = NULL;
 
-       data = xmalloc(4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
+       if (!transport->data)
+               transport->data = get_http_walker(transport->url);
 
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
 
-       http_init();
-
        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 (transport->remote->http_proxy)
+               curl_easy_setopt(slot->curl, CURLOPT_PROXY,
+                                transport->remote->http_proxy);
+
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
+                       strbuf_release(&buffer);
                        if (missing_target(&results)) {
-                               free(buffer.buffer);
                                return NULL;
                        } else {
-                               free(buffer.buffer);
                                error("%s", curl_errorstr);
                                return NULL;
                        }
                }
        } else {
-               free(buffer.buffer);
+               strbuf_release(&buffer);
                error("Unable to start request");
                return NULL;
        }
 
-       http_cleanup();
-
-       data = buffer.buffer;
+       data = buffer.buf;
        start = NULL;
        mid = data;
-       while (i < buffer.posn) {
+       while (i < buffer.len) {
                if (!start)
                        start = &data[i];
                if (data[i] == '\t')
@@ -505,7 +500,7 @@ static struct ref *get_refs_via_curl(struct transport *transport)
                i++;
        }
 
-       free(buffer.buffer);
+       strbuf_release(&buffer);
 
        return refs;
 }
@@ -567,6 +562,8 @@ struct git_transport_data {
        unsigned thin : 1;
        unsigned keep : 1;
        int depth;
+       struct child_process *conn;
+       int fd[2];
        const char *uploadpack;
        const char *receivepack;
 };
@@ -597,20 +594,20 @@ static int set_git_option(struct transport *connection,
        return 1;
 }
 
+static int connect_setup(struct transport *transport)
+{
+       struct git_transport_data *data = transport->data;
+       data->conn = git_connect(data->fd, transport->url, data->uploadpack, 0);
+       return 0;
+}
+
 static struct ref *get_refs_via_connect(struct transport *transport)
 {
        struct git_transport_data *data = transport->data;
        struct ref *refs;
-       int fd[2];
-       char *dest = xstrdup(transport->url);
-       struct child_process *conn = git_connect(fd, dest, data->uploadpack, 0);
-
-       get_remote_heads(fd[0], &refs, 0, NULL, 0);
-       packet_flush(fd[1]);
 
-       finish_connect(conn);
-
-       free(dest);
+       connect_setup(transport);
+       get_remote_heads(data->fd[0], &refs, 0, NULL, 0);
 
        return refs;
 }
@@ -621,7 +618,7 @@ static int fetch_refs_via_pack(struct transport *transport,
        struct git_transport_data *data = transport->data;
        char **heads = xmalloc(nr_heads * sizeof(*heads));
        char **origh = xmalloc(nr_heads * sizeof(*origh));
-       struct ref *refs;
+       const struct ref *refs;
        char *dest = xstrdup(transport->url);
        struct fetch_pack_args args;
        int i;
@@ -636,26 +633,42 @@ static int fetch_refs_via_pack(struct transport *transport,
 
        for (i = 0; i < nr_heads; i++)
                origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
-       refs = fetch_pack(&args, dest, nr_heads, heads, &transport->pack_lockfile);
+
+       refs = transport_get_remote_refs(transport);
+       if (!data->conn) {
+               struct ref *refs_tmp;
+               connect_setup(transport);
+               get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0);
+               free_refs(refs_tmp);
+       }
+
+       refs = fetch_pack(&args, data->fd, data->conn, transport->remote_refs,
+                         dest, nr_heads, heads, &transport->pack_lockfile);
+       close(data->fd[0]);
+       close(data->fd[1]);
+       if (finish_connect(data->conn))
+               refs = NULL;
+       data->conn = NULL;
 
        for (i = 0; i < nr_heads; i++)
                free(origh[i]);
        free(origh);
        free(heads);
-       free_refs(refs);
        free(dest);
-       return 0;
+       return (refs ? 0 : -1);
 }
 
-static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
+static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
+{
        struct git_transport_data *data = transport->data;
        struct send_pack_args args;
 
        args.receivepack = data->receivepack;
        args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
+       args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
        args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
        args.use_thin_pack = data->thin;
-       args.verbose = transport->verbose;
+       args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
 
        return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec);
@@ -663,7 +676,15 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
 
 static int disconnect_git(struct transport *transport)
 {
-       free(transport->data);
+       struct git_transport_data *data = transport->data;
+       if (data->conn) {
+               packet_flush(data->fd[1]);
+               close(data->fd[0]);
+               close(data->fd[1]);
+               finish_connect(data->conn);
+       }
+
+       free(data);
        return 0;
 }
 
@@ -723,6 +744,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                ret->disconnect = disconnect_git;
 
                data->thin = 1;
+               data->conn = NULL;
                data->uploadpack = "git-upload-pack";
                if (remote && remote->uploadpack)
                        data->uploadpack = remote->uploadpack;