Start preparing the API documents.
[gitweb.git] / transport.c
index 46da754078f3c679e62124fb7e7468e44d85dafc..4e151a9e878b402fd0b70c31057b9bcfcff7d9b7 100644 (file)
@@ -6,6 +6,7 @@
 #endif
 #include "pkt-line.h"
 #include "fetch-pack.h"
+#include "send-pack.h"
 #include "walker.h"
 #include "bundle.h"
 #include "dir.h"
@@ -107,7 +108,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
                return;
 
        for (;;) {
-               int cmp, len;
+               int cmp = cmp, len;
 
                if (!fgets(buffer, sizeof(buffer), f)) {
                        fclose(f);
@@ -141,7 +142,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
        }
 }
 
-static struct ref *get_refs_via_rsync(const struct transport *transport)
+static struct ref *get_refs_via_rsync(struct transport *transport)
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        struct ref dummy, *tail = &dummy;
@@ -281,7 +282,10 @@ static int rsync_transport_push(struct transport *transport,
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        int result = 0, i;
        struct child_process rsync;
-       const char *args[8];
+       const char *args[10];
+
+       if (flags & TRANSPORT_PUSH_MIRROR)
+               return error("rsync transport does not support mirror mode");
 
        /* first push the objects */
 
@@ -291,14 +295,19 @@ static int rsync_transport_push(struct transport *transport,
        memset(&rsync, 0, sizeof(rsync));
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
-       args[0] = "rsync";
-       args[1] = (transport->verbose > 0) ? "-av" : "-a";
-       args[2] = "--ignore-existing";
-       args[3] = "--exclude";
-       args[4] = "info";
-       args[5] = get_object_directory();;
-       args[6] = buf.buf;
-       args[7] = NULL;
+       i = 0;
+       args[i++] = "rsync";
+       args[i++] = "-a";
+       if (flags & TRANSPORT_PUSH_DRY_RUN)
+               args[i++] = "--dry-run";
+       if (transport->verbose > 0)
+               args[i++] = "-v";
+       args[i++] = "--ignore-existing";
+       args[i++] = "--exclude";
+       args[i++] = "info";
+       args[i++] = get_object_directory();
+       args[i++] = buf.buf;
+       args[i++] = NULL;
 
        if (run_command(&rsync))
                return error("Could not push objects to %s", transport->url);
@@ -316,7 +325,11 @@ static int rsync_transport_push(struct transport *transport,
        } else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec))
                return -1;
 
-       i = (flags & TRANSPORT_PUSH_FORCE) ? 2 : 3;
+       i = 2;
+       if (flags & TRANSPORT_PUSH_DRY_RUN)
+               args[i++] = "--dry-run";
+       if (!(flags & TRANSPORT_PUSH_FORCE))
+               args[i++] = "--ignore-existing";
        args[i++] = temp_dir.buf;
        args[i++] = transport->url;
        args[i++] = NULL;
@@ -335,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)
 {
@@ -361,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)
 {
@@ -371,18 +386,26 @@ 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)
                argv[argc++] = "--all";
        if (flags & TRANSPORT_PUSH_FORCE)
                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++;
@@ -403,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)
+static struct ref *get_refs_via_curl(struct transport *transport)
 {
-       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(const struct transport *transport)
-{
-       struct buffer buffer;
+       struct strbuf buffer = STRBUF_INIT;
        char *data, *start, *mid;
        char *ref_name;
        char *refs_url;
@@ -431,11 +441,6 @@ static struct ref *get_refs_via_curl(const struct transport *transport)
        struct ref *ref = NULL;
        struct ref *last_ref = NULL;
 
-       data = xmalloc(4096);
-       buffer.size = 4096;
-       buffer.posn = 0;
-       buffer.buffer = data;
-
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
 
@@ -447,30 +452,33 @@ static struct ref *get_refs_via_curl(const struct transport *transport)
        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')
@@ -493,7 +501,7 @@ static struct ref *get_refs_via_curl(const struct transport *transport)
                i++;
        }
 
-       free(buffer.buffer);
+       strbuf_release(&buffer);
 
        return refs;
 }
@@ -513,7 +521,7 @@ struct bundle_transport_data {
        struct bundle_header header;
 };
 
-static struct ref *get_refs_from_bundle(const struct transport *transport)
+static struct ref *get_refs_from_bundle(struct transport *transport)
 {
        struct bundle_transport_data *data = transport->data;
        struct ref *result = NULL;
@@ -585,23 +593,18 @@ static int set_git_option(struct transport *connection,
        return 1;
 }
 
-static struct ref *get_refs_via_connect(const struct transport *transport)
+static struct ref *get_refs_via_connect(struct transport *transport)
 {
        struct git_transport_data *data = transport->data;
        struct ref *refs;
        int fd[2];
-       pid_t pid;
        char *dest = xstrdup(transport->url);
-
-       pid = git_connect(fd, dest, data->uploadpack, 0);
-
-       if (pid < 0)
-               die("Failed to connect to \"%s\"", 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(pid);
+       finish_connect(conn);
 
        free(dest);
 
@@ -637,51 +640,23 @@ static int fetch_refs_via_pack(struct transport *transport,
        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;
-       const char **argv;
-       char *rem;
-       int argc;
-       int err;
+       struct send_pack_args args;
 
-       argv = xmalloc((refspec_nr + 11) * sizeof(char *));
-       argv[0] = "send-pack";
-       argc = 1;
-       if (flags & TRANSPORT_PUSH_ALL)
-               argv[argc++] = "--all";
-       if (flags & TRANSPORT_PUSH_FORCE)
-               argv[argc++] = "--force";
-       if (data->receivepack) {
-               char *rp = xmalloc(strlen(data->receivepack) + 16);
-               sprintf(rp, "--receive-pack=%s", data->receivepack);
-               argv[argc++] = rp;
-       }
-       if (data->thin)
-               argv[argc++] = "--thin";
-       rem = xmalloc(strlen(transport->remote->name) + 10);
-       sprintf(rem, "--remote=%s", transport->remote->name);
-       argv[argc++] = rem;
-       argv[argc++] = transport->url;
-       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;
+       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 = !!(flags & TRANSPORT_PUSH_VERBOSE);
+       args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
+
+       return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec);
 }
 
 static int disconnect_git(struct transport *transport)
@@ -773,7 +748,7 @@ int transport_push(struct transport *transport,
        return transport->push(transport, refspec_nr, refspec, flags);
 }
 
-struct ref *transport_get_remote_refs(struct transport *transport)
+const struct ref *transport_get_remote_refs(struct transport *transport)
 {
        if (!transport->remote_refs)
                transport->remote_refs = transport->get_refs_list(transport);