#include "cache.h"
#include "transport.h"
#include "run-command.h"
+#ifndef NO_CURL
#include "http.h"
+#endif
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "send-pack.h"
#include "walker.h"
#include "bundle.h"
#include "dir.h"
return;
for (;;) {
- int cmp, len;
+ int cmp = cmp, len;
if (!fgets(buffer, sizeof(buffer), f)) {
fclose(f);
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;
}
}
-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;
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 */
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);
} 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;
/* 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)
{
free(dest);
return 0;
}
+#endif /* NO_CURL */
static int disconnect_walker(struct transport *transport)
{
return 0;
}
-static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
+#ifndef NO_CURL
+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++;
return !!err;
}
-#ifndef NO_CURL
-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;
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')
i++;
}
- free(buffer.buffer);
+ strbuf_release(&buffer);
return refs;
}
return fetch_objs_via_walker(transport, nr_objs, to_fetch);
}
-#else
-
-static struct ref *get_refs_via_curl(const struct transport *transport)
-{
- die("Cannot fetch from '%s' without curl ...", transport->url);
- return NULL;
-}
-
-static int fetch_objs_via_curl(struct transport *transport,
- int nr_objs, struct ref **to_fetch)
-{
- die("Cannot fetch from '%s' without curl ...", transport->url);
- return -1;
-}
-
#endif
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;
unsigned thin : 1;
unsigned keep : 1;
int depth;
+ struct child_process *conn;
+ int fd[2];
const char *uploadpack;
const char *receivepack;
};
return 1;
}
-static struct ref *get_refs_via_connect(const struct transport *transport)
+static int connect_setup(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);
-
- get_remote_heads(fd[0], &refs, 0, NULL, 0);
- packet_flush(fd[1]);
+ data->conn = git_connect(data->fd, transport->url, data->uploadpack, 0);
+ return 0;
+}
- finish_connect(pid);
+static struct ref *get_refs_via_connect(struct transport *transport)
+{
+ struct git_transport_data *data = transport->data;
+ struct ref *refs;
- free(dest);
+ connect_setup(transport);
+ get_remote_heads(data->fd[0], &refs, 0, NULL, 0);
return refs;
}
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;
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;
- 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)
{
- 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;
}
} else if (!prefixcmp(url, "http://")
|| !prefixcmp(url, "https://")
|| !prefixcmp(url, "ftp://")) {
+#ifdef NO_CURL
+ error("git was compiled without libcurl support.");
+#else
ret->get_refs_list = get_refs_via_curl;
ret->fetch = fetch_objs_via_curl;
ret->push = curl_transport_push;
+#endif
ret->disconnect = disconnect_walker;
} else if (is_local(url) && is_file(url)) {
ret->disconnect = disconnect_git;
data->thin = 1;
+ data->conn = NULL;
data->uploadpack = "git-upload-pack";
if (remote && remote->uploadpack)
data->uploadpack = remote->uploadpack;
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);