Skip to content

Commit

Permalink
Push code for transport library
Browse files Browse the repository at this point in the history
This moves the code to call push backends into a library that can be
extended to make matching fetch and push decisions based on the URL it
gets, and which could be changed to have built-in implementations
instead of calling external programs.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Daniel Barkalow authored and Junio C Hamano committed Sep 19, 2007
1 parent 2d4177c commit 9b28851
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 62 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ LIB_OBJS = \
write_or_die.o trace.o list-objects.o grep.o match-trees.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
transport.o

BUILTIN_OBJS = \
builtin-add.o \
Expand Down
82 changes: 21 additions & 61 deletions builtin-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
#include "run-command.h"
#include "builtin.h"
#include "remote.h"
#include "transport.h"

static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";

static int all, force, thin, verbose;
static int all, thin, verbose;
static const char *receivepack;

static const char **refspec;
Expand Down Expand Up @@ -43,80 +44,38 @@ static void set_refspecs(const char **refs, int nr)
}
}

static int do_push(const char *repo)
static int do_push(const char *repo, int flags)
{
int i, errs;
int common_argc;
const char **argv;
int argc;
struct remote *remote = remote_get(repo);

if (!remote)
die("bad repository '%s'", repo);

if (remote->receivepack) {
char *rp = xmalloc(strlen(remote->receivepack) + 16);
sprintf(rp, "--receive-pack=%s", remote->receivepack);
receivepack = rp;
}
if (!refspec && !all && remote->push_refspec_nr) {
refspec = remote->push_refspec;
refspec_nr = remote->push_refspec_nr;
}

argv = xmalloc((refspec_nr + 10) * sizeof(char *));
argv[0] = "dummy-send-pack";
argc = 1;
if (all)
argv[argc++] = "--all";
if (force)
argv[argc++] = "--force";
if (receivepack)
argv[argc++] = receivepack;
common_argc = argc;

errs = 0;
for (i = 0; i < remote->uri_nr; i++) {
struct transport *transport =
transport_get(remote, remote->uri[i], 0);
int err;
int dest_argc = common_argc;
int dest_refspec_nr = refspec_nr;
const char **dest_refspec = refspec;
const char *dest = remote->uri[i];
const char *sender = "send-pack";
if (!prefixcmp(dest, "http://") ||
!prefixcmp(dest, "https://"))
sender = "http-push";
else {
char *rem = xmalloc(strlen(remote->name) + 10);
sprintf(rem, "--remote=%s", remote->name);
argv[dest_argc++] = rem;
if (thin)
argv[dest_argc++] = "--thin";
}
argv[0] = sender;
argv[dest_argc++] = dest;
while (dest_refspec_nr--)
argv[dest_argc++] = *dest_refspec++;
argv[dest_argc] = NULL;
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
if (thin)
transport_set_option(transport, TRANS_OPT_THIN, "yes");

if (verbose)
fprintf(stderr, "Pushing to %s\n", dest);
err = run_command_v_opt(argv, RUN_GIT_CMD);
fprintf(stderr, "Pushing to %s\n", remote->uri[i]);
err = transport_push(transport, refspec_nr, refspec, flags);
err |= transport_disconnect(transport);

if (!err)
continue;

error("failed to push to '%s'", remote->uri[i]);
switch (err) {
case -ERR_RUN_COMMAND_FORK:
error("unable to fork for %s", sender);
case -ERR_RUN_COMMAND_EXEC:
error("unable to exec %s", sender);
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", sender);
}
errs++;
}
return !!errs;
Expand All @@ -125,6 +84,7 @@ static int do_push(const char *repo)
int cmd_push(int argc, const char **argv, const char *prefix)
{
int i;
int flags = 0;
const char *repo = NULL; /* default repository */

for (i = 1; i < argc; i++) {
Expand All @@ -144,15 +104,15 @@ int cmd_push(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--all")) {
all = 1;
flags |= TRANSPORT_PUSH_ALL;
continue;
}
if (!strcmp(arg, "--tags")) {
add_refspec("refs/tags/*");
continue;
}
if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
force = 1;
flags |= TRANSPORT_PUSH_FORCE;
continue;
}
if (!strcmp(arg, "--thin")) {
Expand All @@ -164,11 +124,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
continue;
}
if (!prefixcmp(arg, "--receive-pack=")) {
receivepack = arg;
receivepack = arg + 15;
continue;
}
if (!prefixcmp(arg, "--exec=")) {
receivepack = arg;
receivepack = arg + 7;
continue;
}
usage(push_usage);
Expand All @@ -177,5 +137,5 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if (all && refspec)
usage(push_usage);

return do_push(repo);
return do_push(repo, flags);
}
196 changes: 196 additions & 0 deletions transport.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#include "cache.h"
#include "transport.h"
#include "run-command.h"

static const struct transport_ops rsync_transport;

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 *));
argv[0] = "http-push";
argc = 1;
if (flags & TRANSPORT_PUSH_ALL)
argv[argc++] = "--all";
if (flags & TRANSPORT_PUSH_FORCE)
argv[argc++] = "--force";
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;
}

static const struct transport_ops curl_transport = {
/* set_option */ NULL,
/* push */ curl_transport_push
};

static const struct transport_ops bundle_transport = {
};

struct git_transport_data {
unsigned thin : 1;

const char *receivepack;
};

static int set_git_option(struct transport *connection,
const char *name, const char *value)
{
struct git_transport_data *data = connection->data;
if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) {
data->receivepack = value;
return 0;
} else if (!strcmp(name, TRANS_OPT_THIN)) {
data->thin = !!value;
return 0;
}
return 1;
}

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;

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;
}

static const struct transport_ops git_transport = {
/* set_option */ set_git_option,
/* push */ git_transport_push
};

static int is_local(const char *url)
{
const char *colon = strchr(url, ':');
const char *slash = strchr(url, '/');
return !colon || (slash && slash < colon);
}

static int is_file(const char *url)
{
struct stat buf;
if (stat(url, &buf))
return 0;
return S_ISREG(buf.st_mode);
}

struct transport *transport_get(struct remote *remote, const char *url,
int fetch)
{
struct transport *ret = NULL;
if (!prefixcmp(url, "rsync://")) {
ret = xmalloc(sizeof(*ret));
ret->data = NULL;
ret->ops = &rsync_transport;
} else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") ||
!prefixcmp(url, "ftp://")) {
ret = xmalloc(sizeof(*ret));
ret->ops = &curl_transport;
ret->data = NULL;
} else if (is_local(url) && is_file(url)) {
ret = xmalloc(sizeof(*ret));
ret->data = NULL;
ret->ops = &bundle_transport;
} else {
struct git_transport_data *data = xcalloc(1, sizeof(*data));
ret = xcalloc(1, sizeof(*ret));
ret->data = data;
data->thin = 1;
data->receivepack = "git-receive-pack";
if (remote && remote->receivepack)
data->receivepack = remote->receivepack;
ret->ops = &git_transport;
}
if (ret) {
ret->remote = remote;
ret->url = url;
ret->fetch = !!fetch;
}
return ret;
}

int transport_set_option(struct transport *transport,
const char *name, const char *value)
{
int ret = 1;
if (transport->ops->set_option)
ret = transport->ops->set_option(transport, name, value);
if (ret < 0)
fprintf(stderr, "For '%s' option %s cannot be set to '%s'\n",
transport->url, name, value);
if (ret > 0)
fprintf(stderr, "For '%s' option %s is ignored\n",
transport->url, name);
return ret;
}

int transport_push(struct transport *transport,
int refspec_nr, const char **refspec, int flags)
{
if (!transport->ops->push)
return 1;
return transport->ops->push(transport, refspec_nr, refspec, flags);
}

int transport_disconnect(struct transport *transport)
{
int ret = 0;
if (transport->ops->disconnect)
ret = transport->ops->disconnect(transport);
free(transport);
return ret;
}
Loading

0 comments on commit 9b28851

Please sign in to comment.