From 6eb996b5707b6d14cf9875a9231f4e909a443665 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 5 Aug 2009 01:01:53 -0400 Subject: Add support for external programs for handling native fetches transport_get() can call transport_native_helper_init() to have list and fetch-ref operations handled by running a separate program as: git remote- [] This program then accepts, on its stdin, "list" and "fetch " commands; the former prints out a list of available refs and either their hashes or what they are symrefs to, while the latter fetches them into the local object database and prints a newline when done. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt new file mode 100644 index 0000000..173ee23 --- /dev/null +++ b/Documentation/git-remote-helpers.txt @@ -0,0 +1,71 @@ +git-remote-helpers(1) +===================== + +NAME +---- +git-remote-helpers - Helper programs for interoperation with remote git + +SYNOPSIS +-------- +'git remote-' + +DESCRIPTION +----------- + +These programs are normally not used directly by end users, but are +invoked by various git programs that interact with remote repositories +when the repository they would operate on will be accessed using +transport code not linked into the main git binary. Various particular +helper programs will behave as documented here. + +COMMANDS +-------- + +Commands are given by the caller on the helper's standard input, one per line. + +'capabilities':: + Lists the capabilities of the helper, one per line, ending + with a blank line. + +'list':: + Lists the refs, one per line, in the format " + [ ...]". The value may be a hex sha1 hash, "@" for + a symref, or "?" to indicate that the helper could not get the + value of the ref. A space-separated list of attributes follows + the name; unrecognized attributes are ignored. After the + complete list, outputs a blank line. + +'fetch' :: + Fetches the given object, writing the necessary objects to the + database. Outputs a blank line when the fetch is + complete. Only objects which were reported in the ref list + with a sha1 may be fetched this way. ++ +Supported if the helper has the "fetch" capability. + +If a fatal error occurs, the program writes the error message to +stderr and exits. The caller should expect that a suitable error +message has been printed if the child closes the connection without +completing a valid response for the current command. + +Additional commands may be supported, as may be determined from +capabilities reported by the helper. + +CAPABILITIES +------------ + +'fetch':: + This helper supports the 'fetch' command. + +REF LIST ATTRIBUTES +------------------- + +None are defined yet, but the caller must accept any which are supplied. + +Documentation +------------- +Documentation by Daniel Barkalow. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index daf4296..504646a 100644 --- a/Makefile +++ b/Makefile @@ -549,6 +549,7 @@ LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += trace.o LIB_OBJS += transport.o +LIB_OBJS += transport-helper.o LIB_OBJS += tree-diff.o LIB_OBJS += tree.o LIB_OBJS += tree-walk.o diff --git a/transport-helper.c b/transport-helper.c new file mode 100644 index 0000000..c982bb2 --- /dev/null +++ b/transport-helper.c @@ -0,0 +1,168 @@ +#include "cache.h" +#include "transport.h" + +#include "run-command.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" + +struct helper_data +{ + const char *name; + struct child_process *helper; + unsigned fetch : 1; +}; + +static struct child_process *get_helper(struct transport *transport) +{ + struct helper_data *data = transport->data; + struct strbuf buf = STRBUF_INIT; + struct child_process *helper; + FILE *file; + + if (data->helper) + return data->helper; + + helper = xcalloc(1, sizeof(*helper)); + helper->in = -1; + helper->out = -1; + helper->err = 0; + helper->argv = xcalloc(4, sizeof(*helper->argv)); + strbuf_addf(&buf, "remote-%s", data->name); + helper->argv[0] = strbuf_detach(&buf, NULL); + helper->argv[1] = transport->remote->name; + helper->argv[2] = transport->url; + helper->git_cmd = 1; + if (start_command(helper)) + die("Unable to run helper: git %s", helper->argv[0]); + data->helper = helper; + + write_in_full(data->helper->in, "capabilities\n", 13); + file = fdopen(helper->out, "r"); + while (1) { + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + + if (!*buf.buf) + break; + if (!strcmp(buf.buf, "fetch")) + data->fetch = 1; + } + return data->helper; +} + +static int disconnect_helper(struct transport *transport) +{ + struct helper_data *data = transport->data; + if (data->helper) { + write_in_full(data->helper->in, "\n", 1); + close(data->helper->in); + finish_command(data->helper); + free((char *)data->helper->argv[0]); + free(data->helper->argv); + free(data->helper); + data->helper = NULL; + } + return 0; +} + +static int fetch_with_fetch(struct transport *transport, + int nr_heads, const struct ref **to_fetch) +{ + struct child_process *helper = get_helper(transport); + FILE *file = fdopen(helper->out, "r"); + int i; + struct strbuf buf = STRBUF_INIT; + + for (i = 0; i < nr_heads; i++) { + struct ref *posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + write_in_full(helper->in, "fetch ", 6); + write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40); + write_in_full(helper->in, " ", 1); + write_in_full(helper->in, posn->name, strlen(posn->name)); + write_in_full(helper->in, "\n", 1); + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + } + return 0; +} + +static int fetch(struct transport *transport, + int nr_heads, const struct ref **to_fetch) +{ + struct helper_data *data = transport->data; + int i, count; + + count = 0; + for (i = 0; i < nr_heads; i++) + if (!(to_fetch[i]->status & REF_STATUS_UPTODATE)) + count++; + + if (!count) + return 0; + + if (data->fetch) + return fetch_with_fetch(transport, nr_heads, to_fetch); + + return -1; +} + +static struct ref *get_refs_list(struct transport *transport, int for_push) +{ + struct child_process *helper; + struct ref *ret = NULL; + struct ref **tail = &ret; + struct ref *posn; + struct strbuf buf = STRBUF_INIT; + FILE *file; + + helper = get_helper(transport); + write_in_full(helper->in, "list\n", 5); + + file = fdopen(helper->out, "r"); + while (1) { + char *eov, *eon; + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + + if (!*buf.buf) + break; + + eov = strchr(buf.buf, ' '); + if (!eov) + die("Malformed response in ref list: %s", buf.buf); + eon = strchr(eov + 1, ' '); + *eov = '\0'; + if (eon) + *eon = '\0'; + *tail = alloc_ref(eov + 1); + if (buf.buf[0] == '@') + (*tail)->symref = xstrdup(buf.buf + 1); + else if (buf.buf[0] != '?') + get_sha1_hex(buf.buf, (*tail)->old_sha1); + tail = &((*tail)->next); + } + strbuf_release(&buf); + + for (posn = ret; posn; posn = posn->next) + resolve_remote_symref(posn, ret); + + return ret; +} + +int transport_helper_init(struct transport *transport) +{ + struct helper_data *data = xcalloc(sizeof(*data), 1); + char *eom = strchr(transport->url, ':'); + if (!eom) + return -1; + data->name = xstrndup(transport->url, eom - transport->url); + + transport->data = data; + transport->get_refs_list = get_refs_list; + transport->fetch = fetch; + transport->disconnect = disconnect_helper; + return 0; +} diff --git a/transport.h b/transport.h index 51b5397..df87264 100644 --- a/transport.h +++ b/transport.h @@ -77,4 +77,7 @@ void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); char *transport_anonymize_url(const char *url); +/* Transport methods defined outside transport.c */ +int transport_helper_init(struct transport *transport); + #endif -- cgit v0.10.2-6-g49f6 From a2d725b7bdf756ade7680945ebc3fb62e5dd8bcc Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 5 Aug 2009 01:01:56 -0400 Subject: Use an external program to implement fetching with curl Use the transport native helper mechanism to fetch by http (and ftp, etc). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 504646a..35117fc 100644 --- a/Makefile +++ b/Makefile @@ -981,6 +981,7 @@ else CURL_LIBCURL = -lcurl endif BUILTIN_OBJS += builtin-http-fetch.o + PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X EXTLIBS += $(CURL_LIBCURL) LIB_OBJS += http.o http-walker.o curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) @@ -1491,6 +1492,10 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +git-remote-http$X git-remote-https$X git-remote-ftp$X: remote-curl.o http.o http-walker.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h diff --git a/remote-curl.c b/remote-curl.c new file mode 100644 index 0000000..ad6a163 --- /dev/null +++ b/remote-curl.c @@ -0,0 +1,139 @@ +#include "cache.h" +#include "remote.h" +#include "strbuf.h" +#include "walker.h" +#include "http.h" + +static struct ref *get_refs(struct walker *walker, const char *url) +{ + struct strbuf buffer = STRBUF_INIT; + char *data, *start, *mid; + char *ref_name; + char *refs_url; + int i = 0; + int http_ret; + + struct ref *refs = NULL; + struct ref *ref = NULL; + struct ref *last_ref = NULL; + + refs_url = xmalloc(strlen(url) + 11); + sprintf(refs_url, "%s/info/refs", url); + + 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; + start = NULL; + mid = data; + while (i < buffer.len) { + if (!start) { + start = &data[i]; + } + if (data[i] == '\t') + mid = &data[i]; + if (data[i] == '\n') { + data[i] = 0; + ref_name = mid + 1; + ref = xmalloc(sizeof(struct ref) + + strlen(ref_name) + 1); + memset(ref, 0, sizeof(struct ref)); + strcpy(ref->name, ref_name); + get_sha1_hex(start, ref->old_sha1); + if (!refs) + refs = ref; + if (last_ref) + last_ref->next = ref; + last_ref = ref; + start = NULL; + } + i++; + } + + strbuf_release(&buffer); + + ref = alloc_ref("HEAD"); + if (!walker->fetch_ref(walker, ref) && + !resolve_remote_symref(ref, refs)) { + ref->next = refs; + refs = ref; + } else { + free(ref); + } + + strbuf_release(&buffer); + free(refs_url); + return refs; +} + +int main(int argc, const char **argv) +{ + struct remote *remote; + struct strbuf buf = STRBUF_INIT; + const char *url; + struct walker *walker = NULL; + + setup_git_directory(); + if (argc < 2) { + fprintf(stderr, "Remote needed\n"); + return 1; + } + + remote = remote_get(argv[1]); + + if (argc > 2) { + url = argv[2]; + } else { + url = remote->url[0]; + } + + do { + if (strbuf_getline(&buf, stdin, '\n') == EOF) + break; + if (!prefixcmp(buf.buf, "fetch ")) { + char *obj = buf.buf + strlen("fetch "); + if (!walker) + walker = get_http_walker(url, remote); + walker->get_all = 1; + walker->get_tree = 1; + walker->get_history = 1; + walker->get_verbosely = 0; + walker->get_recover = 0; + if (walker_fetch(walker, 1, &obj, NULL, NULL)) + die("Fetch failed."); + printf("\n"); + fflush(stdout); + } else if (!strcmp(buf.buf, "list")) { + struct ref *refs; + struct ref *posn; + if (!walker) + walker = get_http_walker(url, remote); + refs = get_refs(walker, url); + for (posn = refs; posn; posn = posn->next) { + if (posn->symref) + printf("@%s %s\n", posn->symref, posn->name); + else + printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name); + } + printf("\n"); + fflush(stdout); + } else if (!strcmp(buf.buf, "capabilities")) { + printf("fetch\n"); + printf("\n"); + fflush(stdout); + } else { + return 1; + } + strbuf_reset(&buf); + } while (1); + return 0; +} diff --git a/transport.c b/transport.c index de0d587..9935c85 100644 --- a/transport.c +++ b/transport.c @@ -1,9 +1,6 @@ #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" @@ -352,45 +349,6 @@ static int rsync_transport_push(struct transport *transport, return result; } -/* 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, const struct ref **to_fetch) -{ - char *dest = xstrdup(transport->url); - struct walker *walker = transport->data; - char **objs = xmalloc(nr_objs * sizeof(*objs)); - int i; - - walker->get_all = 1; - walker->get_tree = 1; - walker->get_history = 1; - walker->get_verbosely = transport->verbose >= 0; - walker->get_recover = 0; - - for (i = 0; i < nr_objs; i++) - objs[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1)); - - if (walker_fetch(walker, nr_objs, objs, NULL, NULL)) - die("Fetch failed."); - - for (i = 0; i < nr_objs; i++) - free(objs[i]); - free(objs); - free(dest); - return 0; -} -#endif /* NO_CURL */ - -static int disconnect_walker(struct transport *transport) -{ - struct walker *walker = transport->data; - if (walker) - walker_free(walker); - return 0; -} - #ifndef NO_CURL static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { @@ -432,96 +390,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons return !!err; } -static struct ref *get_refs_via_curl(struct transport *transport, int for_push) -{ - struct strbuf buffer = STRBUF_INIT; - char *data, *start, *mid; - char *ref_name; - char *refs_url; - int i = 0; - int http_ret; - - struct ref *refs = NULL; - struct ref *ref = NULL; - struct ref *last_ref = NULL; - - struct walker *walker; - - if (for_push) - return NULL; - - if (!transport->data) - transport->data = get_http_walker(transport->url, - transport->remote); - - walker = transport->data; - - refs_url = xmalloc(strlen(transport->url) + 11); - sprintf(refs_url, "%s/info/refs", transport->url); - - 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; - start = NULL; - mid = data; - while (i < buffer.len) { - if (!start) - start = &data[i]; - if (data[i] == '\t') - mid = &data[i]; - if (data[i] == '\n') { - data[i] = 0; - ref_name = mid + 1; - ref = xmalloc(sizeof(struct ref) + - strlen(ref_name) + 1); - memset(ref, 0, sizeof(struct ref)); - strcpy(ref->name, ref_name); - get_sha1_hex(start, ref->old_sha1); - if (!refs) - refs = ref; - if (last_ref) - last_ref->next = ref; - last_ref = ref; - start = NULL; - } - i++; - } - - strbuf_release(&buffer); - - ref = alloc_ref("HEAD"); - if (!walker->fetch_ref(walker, ref) && - !resolve_remote_symref(ref, refs)) { - ref->next = refs; - refs = ref; - } else { - free(ref); - } - - strbuf_release(&buffer); - free(refs_url); - return refs; -} - -static int fetch_objs_via_curl(struct transport *transport, - int nr_objs, const struct ref **to_fetch) -{ - if (!transport->data) - transport->data = get_http_walker(transport->url, - transport->remote); - return fetch_objs_via_walker(transport, nr_objs, to_fetch); -} - #endif struct bundle_transport_data { @@ -950,14 +818,12 @@ struct transport *transport_get(struct remote *remote, const char *url) } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { + transport_helper_init(ret); #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)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); -- cgit v0.10.2-6-g49f6 From 1088261f6fc90324014b5306cca4171987da85ce Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 5 Aug 2009 01:01:59 -0400 Subject: git-http-fetch: not a builtin This splits up git-http-fetch so that it isn't built-in. It also removes the general dependency on curl, because it is no longer used by any built-in code. Because they are no longer LIB_OBJS, add LIB_H to the dependencies of http-related object files, and remove http.h from the dependencies of transport.o Signed-off-by: Linus Torvalds Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 35117fc..0ebf9dd 100644 --- a/Makefile +++ b/Makefile @@ -980,10 +980,7 @@ else else CURL_LIBCURL = -lcurl endif - BUILTIN_OBJS += builtin-http-fetch.o PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X - EXTLIBS += $(CURL_LIBCURL) - LIB_OBJS += http.o http-walker.o curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1486,8 +1483,13 @@ git-imap-send$X: imap-send.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) -http.o http-walker.o http-push.o transport.o: http.h +http.o http-walker.o http-push.o: http.h +http.o http-walker.o: $(LIB_H) + +git-http-fetch$X: revision.o http.o http-push.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c deleted file mode 100644 index f3e63d7..0000000 --- a/builtin-http-fetch.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "cache.h" -#include "walker.h" - -int cmd_http_fetch(int argc, const char **argv, const char *prefix) -{ - struct walker *walker; - int commits_on_stdin = 0; - int commits; - const char **write_ref = NULL; - char **commit_id; - const char *url; - char *rewritten_url = NULL; - int arg = 1; - int rc = 0; - int get_tree = 0; - int get_history = 0; - int get_all = 0; - int get_verbosely = 0; - int get_recover = 0; - - git_config(git_default_config, NULL); - - while (arg < argc && argv[arg][0] == '-') { - if (argv[arg][1] == 't') { - get_tree = 1; - } else if (argv[arg][1] == 'c') { - get_history = 1; - } else if (argv[arg][1] == 'a') { - get_all = 1; - get_tree = 1; - get_history = 1; - } else if (argv[arg][1] == 'v') { - get_verbosely = 1; - } else if (argv[arg][1] == 'w') { - write_ref = &argv[arg + 1]; - arg++; - } else if (!strcmp(argv[arg], "--recover")) { - get_recover = 1; - } else if (!strcmp(argv[arg], "--stdin")) { - commits_on_stdin = 1; - } - arg++; - } - if (argc < arg + 2 - commits_on_stdin) { - usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); - return 1; - } - if (commits_on_stdin) { - commits = walker_targets_stdin(&commit_id, &write_ref); - } else { - commit_id = (char **) &argv[arg++]; - commits = 1; - } - url = argv[arg]; - if (url && url[strlen(url)-1] != '/') { - rewritten_url = xmalloc(strlen(url)+2); - strcpy(rewritten_url, url); - strcat(rewritten_url, "/"); - url = rewritten_url; - } - - walker = get_http_walker(url, NULL); - walker->get_tree = get_tree; - walker->get_history = get_history; - walker->get_all = get_all; - walker->get_verbosely = get_verbosely; - walker->get_recover = get_recover; - - rc = walker_fetch(walker, commits, commit_id, write_ref, url); - - if (commits_on_stdin) - walker_targets_free(commits, commit_id, write_ref); - - if (walker->corrupt_object_found) { - fprintf(stderr, -"Some loose object were found to be corrupt, but they might be just\n" -"a false '404 Not Found' error message sent with incorrect HTTP\n" -"status code. Suggest running 'git fsck'.\n"); - } - - walker_free(walker); - - free(rewritten_url); - - return rc; -} diff --git a/git.c b/git.c index 807d875..c1e8f05 100644 --- a/git.c +++ b/git.c @@ -309,9 +309,6 @@ static void handle_internal_command(int argc, const char **argv) { "get-tar-commit-id", cmd_get_tar_commit_id }, { "grep", cmd_grep, RUN_SETUP | USE_PAGER }, { "help", cmd_help }, -#ifndef NO_CURL - { "http-fetch", cmd_http_fetch, RUN_SETUP }, -#endif { "init", cmd_init_db }, { "init-db", cmd_init_db }, { "log", cmd_log, RUN_SETUP | USE_PAGER }, diff --git a/http-fetch.c b/http-fetch.c new file mode 100644 index 0000000..e8f44ba --- /dev/null +++ b/http-fetch.c @@ -0,0 +1,89 @@ +#include "cache.h" +#include "walker.h" + +int main(int argc, const char **argv) +{ + const char *prefix; + struct walker *walker; + int commits_on_stdin = 0; + int commits; + const char **write_ref = NULL; + char **commit_id; + const char *url; + char *rewritten_url = NULL; + int arg = 1; + int rc = 0; + int get_tree = 0; + int get_history = 0; + int get_all = 0; + int get_verbosely = 0; + int get_recover = 0; + + prefix = setup_git_directory(); + + git_config(git_default_config, NULL); + + while (arg < argc && argv[arg][0] == '-') { + if (argv[arg][1] == 't') { + get_tree = 1; + } else if (argv[arg][1] == 'c') { + get_history = 1; + } else if (argv[arg][1] == 'a') { + get_all = 1; + get_tree = 1; + get_history = 1; + } else if (argv[arg][1] == 'v') { + get_verbosely = 1; + } else if (argv[arg][1] == 'w') { + write_ref = &argv[arg + 1]; + arg++; + } else if (!strcmp(argv[arg], "--recover")) { + get_recover = 1; + } else if (!strcmp(argv[arg], "--stdin")) { + commits_on_stdin = 1; + } + arg++; + } + if (argc < arg + 2 - commits_on_stdin) { + usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); + return 1; + } + if (commits_on_stdin) { + commits = walker_targets_stdin(&commit_id, &write_ref); + } else { + commit_id = (char **) &argv[arg++]; + commits = 1; + } + url = argv[arg]; + if (url && url[strlen(url)-1] != '/') { + rewritten_url = xmalloc(strlen(url)+2); + strcpy(rewritten_url, url); + strcat(rewritten_url, "/"); + url = rewritten_url; + } + + walker = get_http_walker(url, NULL); + walker->get_tree = get_tree; + walker->get_history = get_history; + walker->get_all = get_all; + walker->get_verbosely = get_verbosely; + walker->get_recover = get_recover; + + rc = walker_fetch(walker, commits, commit_id, write_ref, url); + + if (commits_on_stdin) + walker_targets_free(commits, commit_id, write_ref); + + if (walker->corrupt_object_found) { + fprintf(stderr, +"Some loose object were found to be corrupt, but they might be just\n" +"a false '404 Not Found' error message sent with incorrect HTTP\n" +"status code. Suggest running 'git fsck'.\n"); + } + + walker_free(walker); + + free(rewritten_url); + + return rc; +} diff --git a/transport-helper.c b/transport-helper.c index c982bb2..43fdc0a 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -75,7 +75,7 @@ static int fetch_with_fetch(struct transport *transport, struct strbuf buf = STRBUF_INIT; for (i = 0; i < nr_heads; i++) { - struct ref *posn = to_fetch[i]; + const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; write_in_full(helper->in, "fetch ", 6); -- cgit v0.10.2-6-g49f6 From f395cd06755c7563df7d0a0408807199c3f60635 Mon Sep 17 00:00:00 2001 From: Mike Ralphson Date: Thu, 6 Aug 2009 14:14:44 +0100 Subject: Add transport native helper executables to .gitignore Signed-off-by: Mike Ralphson Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 41c0b20..096857e 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,9 @@ git-receive-pack git-reflog git-relink git-remote +git-remote-ftp +git-remote-http +git-remote-https git-repack git-repo-config git-request-pull -- cgit v0.10.2-6-g49f6 From ae209bd34914c05d141030b3affcf276f07e2490 Mon Sep 17 00:00:00 2001 From: Mike Ralphson Date: Thu, 6 Aug 2009 14:14:45 +0100 Subject: http-fetch: Fix Makefile dependancies Specify git-http-fetch's dependancies explicitly rather than inheriting from git-http-push, as that may not be built if the libcurl version is too old or NO_EXPAT is defined Signed-off-by: Mike Ralphson Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 0ebf9dd..2900057 100644 --- a/Makefile +++ b/Makefile @@ -1487,7 +1487,7 @@ http.o http-walker.o http-push.o: http.h http.o http-walker.o: $(LIB_H) -git-http-fetch$X: revision.o http.o http-push.o $(GITLIBS) +git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) -- cgit v0.10.2-6-g49f6 From 17fd9f571f5596b0e69e143bf6d72a19c780dd25 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 7 Aug 2009 00:21:33 -0400 Subject: Makefile: git-http-fetch does not need expat This appears to be a bad cut-and-paste in commit 1088261f. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 2900057..e29b15f 100644 --- a/Makefile +++ b/Makefile @@ -1489,7 +1489,7 @@ http.o http-walker.o: $(LIB_H) git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ - $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) + $(LIBS) $(CURL_LIBCURL) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -- cgit v0.10.2-6-g49f6 From 611c7f6a373fc6e7140f81bf9c26bde9f78390d4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 6 Aug 2009 22:08:09 -0700 Subject: Makefile: do not link three copies of git-remote-* programs Instead, link only one and make the rest hardlinks/copies, like we do for the built-ins. Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index e29b15f..5f4d0c9 100644 --- a/Makefile +++ b/Makefile @@ -980,7 +980,8 @@ else else CURL_LIBCURL = -lcurl endif - PROGRAMS += git-remote-http$X git-remote-https$X git-remote-ftp$X git-http-fetch$X + CURL_SYNONYMS = git-remote-https$X git-remote-ftp$X + PROGRAMS += git-remote-http$X $(CURL_SYNONYMS) git-http-fetch$X curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1256,6 +1257,7 @@ ifndef V QUIET_LINK = @echo ' ' LINK $@; QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; + QUIET_LNCP = @echo ' ' LN/CP $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ $(MAKE) $(PRINT_DIR) -C $$subdir @@ -1494,10 +1496,16 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -git-remote-http$X git-remote-https$X git-remote-ftp$X: remote-curl.o http.o http-walker.o $(GITLIBS) +git-remote-http$X: remote-curl.o http.o http-walker.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +$(CURL_SYNONYMS): git-remote-http$X + $(QUIET_LNCP)$(RM) $@ && \ + ln $< $@ 2>/dev/null || \ + ln -s $< $@ 2>/dev/null || \ + cp $< $@ + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h -- cgit v0.10.2-6-g49f6 From ad17f01399a9220b78678b322bd42b0a29898e01 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 7 Aug 2009 12:09:29 -0700 Subject: Makefile: install hardlinks for git-remote- supported by libcurl if possible Instead of installing/copying three programs separately, just install one and try to make hardlinks to the other two. Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 5f4d0c9..438cffb 100644 --- a/Makefile +++ b/Makefile @@ -383,7 +383,8 @@ BUILT_INS += git-stage$X BUILT_INS += git-status$X BUILT_INS += git-whatchanged$X -# what 'all' will build and 'install' will install, in gitexecdir +# what 'all' will build and 'install' will install in gitexecdir, +# excluding programs for built-in commands ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in gitexecdir @@ -1661,7 +1662,7 @@ export gitexec_instdir install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' + $(INSTALL) $(filter-out $(CURL_SYNONYMS), $(ALL_PROGRAMS)) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL @@ -1687,6 +1688,12 @@ endif ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git$X" "$$execdir/$$p" || exit; \ done; } && \ + { for p in $(CURL_SYNONYMS); do \ + $(RM) "$$execdir/$$p" && \ + ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ + ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ + cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \ + done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: -- cgit v0.10.2-6-g49f6 From c9e388bb48bdafdf19574add915ab0ce33a1907d Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 3 Sep 2009 22:13:49 -0400 Subject: Make the "traditionally-supported" URLs a special case Instead of trying to make http://, https://, and ftp:// URLs indicative of some sort of pattern of transport helper usage, make them a special case which runs the "curl" helper, and leave the mechanism by which arbitrary helpers will be chosen entirely to future work. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 438cffb..8c44e35 100644 --- a/Makefile +++ b/Makefile @@ -981,8 +981,7 @@ else else CURL_LIBCURL = -lcurl endif - CURL_SYNONYMS = git-remote-https$X git-remote-ftp$X - PROGRAMS += git-remote-http$X $(CURL_SYNONYMS) git-http-fetch$X + PROGRAMS += git-remote-curl$X git-http-fetch$X curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT @@ -1497,16 +1496,10 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -git-remote-http$X: remote-curl.o http.o http-walker.o $(GITLIBS) +git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -$(CURL_SYNONYMS): git-remote-http$X - $(QUIET_LNCP)$(RM) $@ && \ - ln $< $@ 2>/dev/null || \ - ln -s $< $@ 2>/dev/null || \ - cp $< $@ - $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h @@ -1688,12 +1681,6 @@ endif ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \ cp "$$execdir/git$X" "$$execdir/$$p" || exit; \ done; } && \ - { for p in $(CURL_SYNONYMS); do \ - $(RM) "$$execdir/$$p" && \ - ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ - ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \ - cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \ - done; } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: diff --git a/transport-helper.c b/transport-helper.c index 43fdc0a..4684877 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -152,13 +152,10 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) return ret; } -int transport_helper_init(struct transport *transport) +int transport_helper_init(struct transport *transport, const char *name) { struct helper_data *data = xcalloc(sizeof(*data), 1); - char *eom = strchr(transport->url, ':'); - if (!eom) - return -1; - data->name = xstrndup(transport->url, eom - transport->url); + data->name = name; transport->data = data; transport->get_refs_list = get_refs_list; diff --git a/transport.c b/transport.c index 9935c85..b654d71 100644 --- a/transport.c +++ b/transport.c @@ -818,7 +818,7 @@ struct transport *transport_get(struct remote *remote, const char *url) } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { - transport_helper_init(ret); + transport_helper_init(ret, "curl"); #ifdef NO_CURL error("git was compiled without libcurl support."); #else diff --git a/transport.h b/transport.h index df87264..b49c10f 100644 --- a/transport.h +++ b/transport.h @@ -78,6 +78,6 @@ int transport_disconnect(struct transport *transport); char *transport_anonymize_url(const char *url); /* Transport methods defined outside transport.c */ -int transport_helper_init(struct transport *transport); +int transport_helper_init(struct transport *transport, const char *name); #endif -- cgit v0.10.2-6-g49f6 From 2d14d65ce7b136b0fb18dcf27e5caff67829f658 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 3 Sep 2009 22:13:51 -0400 Subject: Use a clearer style to issue commands to remote helpers This style is overkill for some commands, but it's worthwhile to use the same style to issue all commands, and it's useful to avoid open-coding string lengths. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/transport-helper.c b/transport-helper.c index 4684877..b1ea7e6 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -37,7 +37,10 @@ static struct child_process *get_helper(struct transport *transport) die("Unable to run helper: git %s", helper->argv[0]); data->helper = helper; - write_in_full(data->helper->in, "capabilities\n", 13); + strbuf_addstr(&buf, "capabilities\n"); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); + file = fdopen(helper->out, "r"); while (1) { if (strbuf_getline(&buf, file, '\n') == EOF) @@ -78,11 +81,12 @@ static int fetch_with_fetch(struct transport *transport, const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; - write_in_full(helper->in, "fetch ", 6); - write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40); - write_in_full(helper->in, " ", 1); - write_in_full(helper->in, posn->name, strlen(posn->name)); - write_in_full(helper->in, "\n", 1); + + strbuf_addf(&buf, "fetch %s %s\n", + sha1_to_hex(posn->old_sha1), posn->name); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); + if (strbuf_getline(&buf, file, '\n') == EOF) exit(128); /* child died, message supplied already */ } @@ -119,7 +123,10 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) FILE *file; helper = get_helper(transport); - write_in_full(helper->in, "list\n", 5); + + strbuf_addstr(&buf, "list\n"); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); file = fdopen(helper->out, "r"); while (1) { -- cgit v0.10.2-6-g49f6 From 85cdaa468d9449bbc5889ba94359c77ccafb65cd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 11 Sep 2009 22:35:30 -0700 Subject: Makefile: remove remnant of separate http/https/ftp helpers Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 096857e..46c26cd 100644 --- a/.gitignore +++ b/.gitignore @@ -104,9 +104,7 @@ git-receive-pack git-reflog git-relink git-remote -git-remote-ftp -git-remote-http -git-remote-https +git-remote-curl git-repack git-repo-config git-request-pull diff --git a/Makefile b/Makefile index 8c44e35..1ac02d1 100644 --- a/Makefile +++ b/Makefile @@ -1655,7 +1655,7 @@ export gitexec_instdir install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) $(filter-out $(CURL_SYNONYMS), $(ALL_PROGRAMS)) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' + $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install ifndef NO_PERL -- cgit v0.10.2-6-g49f6