From 0ac77ec3150f43a5c2a6b1e47e9db5aafe53fb72 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 4 Jul 2009 21:26:40 +0200 Subject: run_command: report system call errors instead of returning error codes The motivation for this change is that system call failures are serious errors that should be reported to the user, but only few callers took the burden to decode the error codes that the functions returned into error messages. If at all, then only an unspecific error message was given. A prominent example is this: $ git upload-pack . | : fatal: unable to run 'git-upload-pack' In this example, git-upload-pack, the external command invoked through the git wrapper, dies due to SIGPIPE, but the git wrapper does not bother to report the real cause. In fact, this very error message is copied to the syslog if git-daemon's client aborts the connection early. With this change, system call failures are reported immediately after the failure and only a generic failure code is returned to the caller. In the above example the error is now to the point: $ git upload-pack . | : error: git-upload-pack died of signal Note that there is no error report if the invoked program terminated with a non-zero exit code, because it is reasonable to expect that the invoked program has already reported an error. (But many run_command call sites nevertheless write a generic error message.) There was one special return code that was used to identify the case where run_command failed because the requested program could not be exec'd. This special case is now treated like a system call failure with errno set to ENOENT. No error is reported in this case, because the call site in git.c expects this as a normal result. Therefore, the callers that carefully decoded the return value still check for this condition. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- transport.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 501a77b241..0885801a06 100644 --- a/transport.c +++ b/transport.c @@ -417,18 +417,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons 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: + if (err < 0 && errno == ENOENT) 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; } -- cgit v1.2.3 From c024beb56da679839d61f352d088b9a86823233a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 4 Jul 2009 21:26:42 +0200 Subject: run_command: report failure to execute the program, but optionally don't In the case where a program was not found, it was still the task of the caller to report an error to the user. Usually, this is an interesting case but only few callers actually reported a specific error (though many call sites report a generic error message regardless of the cause). With this change the error is reported by run_command, but since there is one call site in git.c that does not want that, an option is added to struct child_process, which is used to turn the error off. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- transport.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 0885801a06..802ce7f233 100644 --- a/transport.c +++ b/transport.c @@ -396,7 +396,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons { const char **argv; int argc; - int err; if (flags & TRANSPORT_PUSH_MIRROR) return error("http transport does not support mirror mode"); @@ -416,10 +415,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons while (refspec_nr--) argv[argc++] = *refspec++; argv[argc] = NULL; - err = run_command_v_opt(argv, RUN_GIT_CMD); - if (err < 0 && errno == ENOENT) - error("unable to exec %s", argv[0]); - return !!err; + return !!run_command_v_opt(argv, RUN_GIT_CMD); } static struct ref *get_refs_via_curl(struct transport *transport, int for_push) -- cgit v1.2.3 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 --- transport.c | 136 +----------------------------------------------------------- 1 file changed, 1 insertion(+), 135 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index de0d5874a3..9935c85cf3 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 v1.2.3 From 120703292b2828d3c35c937b7f5e75ec570a42e9 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 5 Aug 2009 16:22:36 -0400 Subject: transport: pass "quiet" flag to pack-objects When pushing over the git protocol, pack-objects gives progress reports about the pack being sent. If "push" is given the --quiet flag, it now passes "-q" to pack-objects, suppressing this output. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- transport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index de0d5874a3..c3191ed201 100644 --- a/transport.c +++ b/transport.c @@ -892,6 +892,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re args.force_update = !!(flags & TRANSPORT_PUSH_FORCE); args.use_thin_pack = data->thin; args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE); + args.quiet = !!(flags & TRANSPORT_PUSH_QUIET); args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); ret = send_pack(&args, data->fd, data->conn, remote_refs, -- cgit v1.2.3 From 481c7a6db907774d0f06565d00fd06500a7ae7a4 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 5 Aug 2009 16:23:26 -0400 Subject: transport: don't show push status if --quiet is given When --quiet is given, the user generally only wants to see errors. So let's suppress printing the ref status table unless there is an error, in which case we print out the whole table. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- transport.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index c3191ed201..a3d0145116 100644 --- a/transport.c +++ b/transport.c @@ -681,6 +681,21 @@ static int fetch_refs_via_pack(struct transport *transport, return (refs ? 0 : -1); } +static int push_had_errors(struct ref *ref) +{ + for (; ref; ref = ref->next) { + switch (ref->status) { + case REF_STATUS_NONE: + case REF_STATUS_UPTODATE: + case REF_STATUS_OK: + break; + default: + return 1; + } + } + return 0; +} + static int refs_pushed(struct ref *ref) { for (; ref; ref = ref->next) { @@ -1010,6 +1025,7 @@ int transport_push(struct transport *transport, struct ref *local_refs = get_local_heads(); int match_flags = MATCH_REFS_NONE; int verbose = flags & TRANSPORT_PUSH_VERBOSE; + int quiet = flags & TRANSPORT_PUSH_QUIET; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int ret; @@ -1025,7 +1041,9 @@ int transport_push(struct transport *transport, ret = transport->push_refs(transport, remote_refs, flags); - print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain); + if (!quiet || push_had_errors(remote_refs)) + print_push_status(transport->url, remote_refs, + verbose | porcelain, porcelain); if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { struct ref *ref; -- cgit v1.2.3 From 07436e43daf1a97d3d702090d6289f745bd5ad90 Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Sat, 8 Aug 2009 09:51:08 +0200 Subject: push: point to 'git pull' and 'git push --force' in case of non-fast forward 'git push' failing because of non-fast forward is a very common situation, and a beginner does not necessarily understand "fast forward" immediately. Add a new section to the git-push documentation and refer them to it. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano Signed-off-by: Nanako Shiraishi Signed-off-by: Junio C Hamano --- transport.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index de0d5874a3..f231b355f2 100644 --- a/transport.c +++ b/transport.c @@ -820,7 +820,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i } static void print_push_status(const char *dest, struct ref *refs, - int verbose, int porcelain) + int verbose, int porcelain, int * nonfastforward) { struct ref *ref; int n = 0; @@ -835,11 +835,14 @@ static void print_push_status(const char *dest, struct ref *refs, if (ref->status == REF_STATUS_OK) n += print_one_push_status(ref, dest, n, porcelain); + *nonfastforward = 0; for (ref = refs; ref; ref = ref->next) { if (ref->status != REF_STATUS_NONE && ref->status != REF_STATUS_UPTODATE && ref->status != REF_STATUS_OK) n += print_one_push_status(ref, dest, n, porcelain); + if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD) + *nonfastforward = 1; } } @@ -997,7 +1000,8 @@ int transport_set_option(struct transport *transport, } int transport_push(struct transport *transport, - int refspec_nr, const char **refspec, int flags) + int refspec_nr, const char **refspec, int flags, + int * nonfastforward) { verify_remote_names(refspec_nr, refspec); @@ -1024,7 +1028,7 @@ int transport_push(struct transport *transport, ret = transport->push_refs(transport, remote_refs, flags); - print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain); + print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, nonfastforward); if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { struct ref *ref; -- cgit v1.2.3 From 86386829d425a3d3ae6ce713c58328607e50e523 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 24 Aug 2009 00:04:09 -0400 Subject: fix simple deepening of a repo If all refs sent by the remote repo during a fetch are reachable locally, then no further conversation is performed with the remote. This check is skipped when the --depth argument is provided to allow the deepening of a shallow clone which corresponding remote repo has no changed. However, some additional filtering was added in commit c29727d5 to remove those refs which are equal on both sides. If the remote repo has not changed, then the list of refs to give the remote process becomes empty and simply attempting to deepen a shallow repo always fails. Let's stop being smart in that case and simply send the whole list over when that condition is met. The remote will do the right thing anyways. Test cases for this issue are also provided. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- transport.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index efecb65258..5342f1e2ec 100644 --- a/transport.c +++ b/transport.c @@ -1049,11 +1049,12 @@ const struct ref *transport_get_remote_refs(struct transport *transport) int transport_fetch_refs(struct transport *transport, const struct ref *refs) { int rc; - int nr_heads = 0, nr_alloc = 0; + int nr_heads = 0, nr_alloc = 0, nr_refs = 0; const struct ref **heads = NULL; const struct ref *rm; for (rm = refs; rm; rm = rm->next) { + nr_refs++; if (rm->peer_ref && !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1)) continue; @@ -1061,6 +1062,19 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs) heads[nr_heads++] = rm; } + if (!nr_heads) { + /* + * When deepening of a shallow repository is requested, + * then local and remote refs are likely to still be equal. + * Just feed them all to the fetch method in that case. + * This condition shouldn't be met in a non-deepening fetch + * (see builtin-fetch.c:quickfetch()). + */ + heads = xmalloc(nr_refs * sizeof(*heads)); + for (rm = refs; rm; rm = rm->next) + heads[nr_heads++] = rm; + } + rc = transport->fetch(transport, nr_heads, heads); free(heads); return rc; -- cgit v1.2.3 From 2e5ed5f21b5b978268d7e4823fe777fdff20f544 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 31 Aug 2009 15:28:34 -0400 Subject: push: teach --quiet to suppress "Everything up-to-date" This should have been part of 481c7a6, whose goal was to make "git push -q" silent unless there is an error. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index f7e1663d18..d6c35d91ce 100644 --- a/transport.c +++ b/transport.c @@ -1042,7 +1042,7 @@ int transport_push(struct transport *transport, update_tracking_ref(transport->remote, ref, verbose); } - if (!ret && !refs_pushed(remote_refs)) + if (!quiet && !ret && !refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); return ret; } -- cgit v1.2.3 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 --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 9935c85cf3..b654d71d5a 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 -- cgit v1.2.3 From bb8cccd01762d26c832b85d3b09798650e294c5f Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Sun, 20 Sep 2009 19:33:20 +0200 Subject: push: Correctly initialize nonfastforward in transport_push. The variable is assigned unconditionally in print_push_status, but print_push_status is not reached by all codepaths. In particular, this fixes a bug where "git push ... nonexisting-branch" was complaining about non-fast forward. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index f231b355f2..ce1d25e46e 100644 --- a/transport.c +++ b/transport.c @@ -1001,8 +1001,9 @@ int transport_set_option(struct transport *transport, int transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags, - int * nonfastforward) + int *nonfastforward) { + *nonfastforward = 0; verify_remote_names(refspec_nr, refspec); if (transport->push) -- cgit v1.2.3 From a75d7b54097ef0d0945cbe673a9940d6c561f95c Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 24 Oct 2009 11:31:32 +0300 Subject: Use 'fast-forward' all over the place It's a compound word. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 644a30a0b2..d81a42aec4 100644 --- a/transport.c +++ b/transport.c @@ -668,7 +668,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i break; case REF_STATUS_REJECT_NONFASTFORWARD: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "non-fast forward", porcelain); + "non-fast-forward", porcelain); break; case REF_STATUS_REMOTE_REJECT: print_ref_status('!', "[remote rejected]", ref, -- cgit v1.2.3 From ae4efe195752c27cb25fca9451852c0f4eebdb28 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 30 Oct 2009 17:47:30 -0700 Subject: Move WebDAV HTTP push under remote-curl The remote helper interface now supports the push capability, which can be used to ask the implementation to push one or more specs to the remote repository. For remote-curl we implement this by calling the existing WebDAV based git-http-push executable. Internally the helper interface uses the push_refs transport hook so that the complexity of the refspec parsing and matching can be reused between remote implementations. When possible however the helper protocol uses source ref name rather than the source SHA-1, thereby allowing the helper to access this name if it is useful. >From Clemens Buchacher : update http tests according to remote-curl capabilities o Pushing packed refs is now fixed. o The transport helper fails if refs are already up-to-date. Add a test for that. o The transport helper will notice if refs are already up-to-date. We therefore need to update server info in the unpacked-refs test. o The transport helper will purge deleted branches automatically. o Use a variable ($ORIG_HEAD) instead of full SHA-1 name. Signed-off-by: Tay Ray Chuan Signed-off-by: Clemens Buchacher Signed-off-by: Shawn O. Pearce CC: Daniel Barkalow CC: Mike Hommey Signed-off-by: Junio C Hamano --- transport.c | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 644a30a0b2..6d9652db94 100644 --- a/transport.c +++ b/transport.c @@ -349,35 +349,6 @@ static int rsync_transport_push(struct transport *transport, return result; } -#ifndef NO_CURL -static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) -{ - const char **argv; - int argc; - - 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++; - argv[argc] = NULL; - return !!run_command_v_opt(argv, RUN_GIT_CMD); -} - -#endif - struct bundle_transport_data { int fd; struct bundle_header header; @@ -826,8 +797,6 @@ struct transport *transport_get(struct remote *remote, const char *url) transport_helper_init(ret, "curl"); #ifdef NO_CURL error("git was compiled without libcurl support."); -#else - ret->push = curl_transport_push; #endif } else if (is_local(url) && is_file(url)) { -- cgit v1.2.3 From c1d45cf7b0c1953eed72a3018b5e557dbcd538e0 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Tue, 3 Nov 2009 21:38:51 -0500 Subject: Require a struct remote in transport_get() cmd_ls_remote() was calling transport_get() with a NULL remote and a non-NULL url in the case where it was run outside a git repository. This involved a bunch of ill-tested special cases. Instead, simply get the struct remote for the URL with remote_get(), which works fine outside a git repository, and can also take global options into account. This fixes a tiny and obscure bug where "git ls-remote" without a repo didn't support global url.*.insteadOf, even though "git clone" and "git ls-remote" in any repo did. Also, enforce that all callers provide a struct remote to transport_get(). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- transport.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 644a30a0b2..298dc46ec5 100644 --- a/transport.c +++ b/transport.c @@ -812,6 +812,9 @@ struct transport *transport_get(struct remote *remote, const char *url) { struct transport *ret = xcalloc(1, sizeof(*ret)); + if (!remote) + die("No remote provided to transport_get()"); + ret->remote = remote; ret->url = url; @@ -849,10 +852,10 @@ struct transport *transport_get(struct remote *remote, const char *url) data->thin = 1; data->conn = NULL; data->uploadpack = "git-upload-pack"; - if (remote && remote->uploadpack) + if (remote->uploadpack) data->uploadpack = remote->uploadpack; data->receivepack = "git-receive-pack"; - if (remote && remote->receivepack) + if (remote->receivepack) data->receivepack = remote->receivepack; } -- cgit v1.2.3 From de1a2fdd38b138c4e4fed6412783dcb74d63d2da Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 30 Oct 2009 17:47:41 -0700 Subject: Smart push over HTTP: client side The git-remote-curl backend detects if the remote server supports the git-receive-pack service, and if so, runs git-send-pack in a pipe to dump the command and pack data as a single POST request. The advertisements from the server that were obtained during the discovery are passed into git-send-pack before the POST request starts. This permits git-send-pack to operate largely unmodified. For smaller packs (those under 1 MiB) a HTTP/1.0 POST with a Content-Length is used, permitting interaction with any server. The 1 MiB limit is arbitrary, but is sufficent to fit most deltas created by human authors against text sources with the occasional small binary file (e.g. few KiB icon image). The configuration option http.postBuffer can be used to increase (or shink) this buffer if the default is not sufficient. For larger packs which cannot be spooled entirely into the helper's memory space (due to http.postBuffer being too small), the POST request requires HTTP/1.1 and sets "Transfer-Encoding: chunked". This permits the client to upload an unknown amount of data in one HTTP transaction without needing to pregenerate the entire pack file locally. Signed-off-by: Shawn O. Pearce CC: Daniel Barkalow Signed-off-by: Junio C Hamano --- transport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 6d9652db94..2ff16503be 100644 --- a/transport.c +++ b/transport.c @@ -731,6 +731,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re NULL); } + memset(&args, 0, sizeof(args)); args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR); args.force_update = !!(flags & TRANSPORT_PUSH_FORCE); args.use_thin_pack = data->thin; -- cgit v1.2.3 From fb0cc87ec0f1e9c13b27ea2c89127991d44ed3d3 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:22 +0100 Subject: Allow programs to not depend on remotes having urls For fetch and ls-remote, which use the first url of a remote, have transport_get() determine this by passing a remote and passing NULL for the url. For push, which uses every url of a remote, use each url in turn if there are any, and use NULL if there are none. This will allow the transport code to do something different if the location is not specified with a url. Also, have the message for a fetch say "foreign" if there is no url. Signed-off-by: Daniel Barkalow Signed-off-by: Sverre Rabbelier Signed-off-by: Junio C Hamano --- transport.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 644a30a0b2..9daa68609f 100644 --- a/transport.c +++ b/transport.c @@ -813,6 +813,9 @@ struct transport *transport_get(struct remote *remote, const char *url) struct transport *ret = xcalloc(1, sizeof(*ret)); ret->remote = remote; + + if (!url && remote && remote->url) + url = remote->url[0]; ret->url = url; if (!prefixcmp(url, "rsync:")) { -- cgit v1.2.3 From 3714831189b32591ffe33c08e209a9a61c25a2f6 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:24 +0100 Subject: Allow fetch to modify refs This allows the transport to use the null sha1 for a ref reported to be present in the remote repository to indicate that a ref exists but its actual value is presently unknown and will be set if the objects are fetched. Also adds documentation to the API to specify exactly what the methods should do and how they should interpret arguments. Signed-off-by: Daniel Barkalow Signed-off-by: Sverre Rabbelier Signed-off-by: Junio C Hamano --- transport.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 9daa68609f..5ae8db6335 100644 --- a/transport.c +++ b/transport.c @@ -204,7 +204,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) } static int fetch_objs_via_rsync(struct transport *transport, - int nr_objs, const struct ref **to_fetch) + int nr_objs, struct ref **to_fetch) { struct strbuf buf = STRBUF_INIT; struct child_process rsync; @@ -408,7 +408,7 @@ static struct ref *get_refs_from_bundle(struct transport *transport, int for_pus } static int fetch_refs_from_bundle(struct transport *transport, - int nr_heads, const struct ref **to_fetch) + int nr_heads, struct ref **to_fetch) { struct bundle_transport_data *data = transport->data; return unbundle(&data->header, data->fd); @@ -486,7 +486,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus } static int fetch_refs_via_pack(struct transport *transport, - int nr_heads, const struct ref **to_fetch) + int nr_heads, struct ref **to_fetch) { struct git_transport_data *data = transport->data; char **heads = xmalloc(nr_heads * sizeof(*heads)); @@ -926,16 +926,17 @@ const struct ref *transport_get_remote_refs(struct transport *transport) return transport->remote_refs; } -int transport_fetch_refs(struct transport *transport, const struct ref *refs) +int transport_fetch_refs(struct transport *transport, struct ref *refs) { int rc; int nr_heads = 0, nr_alloc = 0, nr_refs = 0; - const struct ref **heads = NULL; - const struct ref *rm; + struct ref **heads = NULL; + struct ref *rm; for (rm = refs; rm; rm = rm->next) { nr_refs++; if (rm->peer_ref && + !is_null_sha1(rm->old_sha1) && !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1)) continue; ALLOC_GROW(heads, nr_heads + 1, nr_alloc); -- cgit v1.2.3 From c578f51d52fe75e71d75566c2c216af989b65e6e Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:25 +0100 Subject: Add a config option for remotes to specify a foreign vcs If this is set, the url is not required, and the transport always uses a helper named "git-remote-". It is a separate configuration option in order to allow a sensible configuration for foreign systems which either have no meaningful urls for repositories or which require urls that do not specify the system used by the repository at that location. However, this only affects how the name of the helper is determined, not anything about the interaction with the helper, and the contruction is such that, if the foreign scm does happen to use a co-named url method, a url with that method may be used directly. Signed-off-by: Daniel Barkalow Signed-off-by: Sverre Rabbelier Signed-off-by: Junio C Hamano --- transport.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 5ae8db6335..13bab4e2a1 100644 --- a/transport.c +++ b/transport.c @@ -818,6 +818,11 @@ struct transport *transport_get(struct remote *remote, const char *url) url = remote->url[0]; ret->url = url; + if (remote && remote->foreign_vcs) { + transport_helper_init(ret, remote->foreign_vcs); + return ret; + } + if (!prefixcmp(url, "rsync:")) { ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; -- cgit v1.2.3 From 87422439d100f020cadb63b5da8495e5fbfb8fa3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Nov 2009 02:42:26 +0100 Subject: Allow specifying the remote helper in the url The common case for remote helpers will be to import some repository which can be specified by a single URL. Support this use case by allowing users to say: git clone hg::https://soc.googlecode.com/hg/ soc Signed-off-by: Johannes Schindelin Signed-off-by: Sverre Rabbelier Signed-off-by: Junio C Hamano --- transport.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 13bab4e2a1..5d814b50e4 100644 --- a/transport.c +++ b/transport.c @@ -818,6 +818,16 @@ struct transport *transport_get(struct remote *remote, const char *url) url = remote->url[0]; ret->url = url; + /* maybe it is a foreign URL? */ + if (url) { + const char *p = url; + + while (isalnum(*p)) + p++; + if (!prefixcmp(p, "::")) + remote->foreign_vcs = xstrndup(url, p - url); + } + if (remote && remote->foreign_vcs) { transport_helper_init(ret, remote->foreign_vcs); return ret; -- cgit v1.2.3 From 25d5cc488a75cc232e97af42759812d9aa398713 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Dec 2009 17:26:29 +0200 Subject: Pass unknown protocols to external protocol handlers Change URL handling to allow external protocol handlers to implement new protocols without the '::' syntax if helper name does not conflict with any built-in protocol. foo:// now invokes git-remote-foo with foo:// as the URL. Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 15 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3eea836a33..dea37d09b2 100644 --- a/transport.c +++ b/transport.c @@ -780,6 +780,44 @@ static int is_file(const char *url) return S_ISREG(buf.st_mode); } +static int is_url(const char *url) +{ + const char *url2, *first_slash; + + if (!url) + return 0; + url2 = url; + first_slash = strchr(url, '/'); + + /* Input with no slash at all or slash first can't be URL. */ + if (!first_slash || first_slash == url) + return 0; + /* Character before must be : and next must be /. */ + if (first_slash[-1] != ':' || first_slash[1] != '/') + return 0; + /* There must be something before the :// */ + if (first_slash == url + 1) + return 0; + /* + * Check all characters up to first slash - 1. Only alphanum + * is allowed. + */ + url2 = url; + while (url2 < first_slash - 1) { + if (!isalnum((unsigned char)*url2)) + return 0; + url2++; + } + + /* Valid enough. */ + return 1; +} + +static int external_specification_len(const char *url) +{ + return strchr(url, ':') - url; +} + struct transport *transport_get(struct remote *remote, const char *url) { struct transport *ret = xcalloc(1, sizeof(*ret)); @@ -805,30 +843,23 @@ struct transport *transport_get(struct remote *remote, const char *url) if (remote && remote->foreign_vcs) { transport_helper_init(ret, remote->foreign_vcs); - return ret; - } - - if (!prefixcmp(url, "rsync:")) { + } else if (!prefixcmp(url, "rsync:")) { ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; - - } else if (!prefixcmp(url, "http://") - || !prefixcmp(url, "https://") - || !prefixcmp(url, "ftp://")) { - transport_helper_init(ret, "curl"); -#ifdef NO_CURL - error("git was compiled without libcurl support."); -#endif - } else if (is_local(url) && is_file(url)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->get_refs_list = get_refs_from_bundle; ret->fetch = fetch_refs_from_bundle; ret->disconnect = close_bundle; - - } else { + } else if (!is_url(url) + || !prefixcmp(url, "file://") + || !prefixcmp(url, "git://") + || !prefixcmp(url, "ssh://") + || !prefixcmp(url, "git+ssh://") + || !prefixcmp(url, "ssh+git://")) { + /* These are builtin smart transports. */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->set_option = set_git_option; @@ -845,6 +876,21 @@ struct transport *transport_get(struct remote *remote, const char *url) data->receivepack = "git-receive-pack"; if (remote->receivepack) data->receivepack = remote->receivepack; + } else if (!prefixcmp(url, "http://") + || !prefixcmp(url, "https://") + || !prefixcmp(url, "ftp://")) { + /* These three are just plain special. */ + transport_helper_init(ret, "curl"); +#ifdef NO_CURL + error("git was compiled without libcurl support."); +#endif + } else { + /* Unknown protocol in URL. Pass to external handler. */ + int len = external_specification_len(url); + char *handler = xmalloc(len + 1); + handler[len] = 0; + strncpy(handler, url, len); + transport_helper_init(ret, handler); } return ret; -- cgit v1.2.3 From aa5af9749f53f7e44bef36c5c40918295430fb03 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Dec 2009 17:26:30 +0200 Subject: Refactor git transport options parsing Refactor the transport options parsing so that protocols that aren't directly smart transports (file://, git://, ssh:// & co) can record the smart transport options for the case if it turns that transport can actually be smart. Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 78 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 31 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index dea37d09b2..e6eb20ea94 100644 --- a/transport.c +++ b/transport.c @@ -395,41 +395,35 @@ static int close_bundle(struct transport *transport) } struct git_transport_data { - unsigned thin : 1; - unsigned keep : 1; - unsigned followtags : 1; - int depth; + struct git_transport_options options; struct child_process *conn; int fd[2]; - const char *uploadpack; - const char *receivepack; struct extra_have_objects extra_have; }; -static int set_git_option(struct transport *connection, +static int set_git_option(struct git_transport_options *opts, const char *name, const char *value) { - struct git_transport_data *data = connection->data; if (!strcmp(name, TRANS_OPT_UPLOADPACK)) { - data->uploadpack = value; + opts->uploadpack = value; return 0; } else if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) { - data->receivepack = value; + opts->receivepack = value; return 0; } else if (!strcmp(name, TRANS_OPT_THIN)) { - data->thin = !!value; + opts->thin = !!value; return 0; } else if (!strcmp(name, TRANS_OPT_FOLLOWTAGS)) { - data->followtags = !!value; + opts->followtags = !!value; return 0; } else if (!strcmp(name, TRANS_OPT_KEEP)) { - data->keep = !!value; + opts->keep = !!value; return 0; } else if (!strcmp(name, TRANS_OPT_DEPTH)) { if (!value) - data->depth = 0; + opts->depth = 0; else - data->depth = atoi(value); + opts->depth = atoi(value); return 0; } return 1; @@ -439,7 +433,8 @@ static int connect_setup(struct transport *transport, int for_push, int verbose) { struct git_transport_data *data = transport->data; data->conn = git_connect(data->fd, transport->url, - for_push ? data->receivepack : data->uploadpack, + for_push ? data->options.receivepack : + data->options.uploadpack, verbose ? CONNECT_VERBOSE : 0); return 0; } @@ -469,15 +464,15 @@ static int fetch_refs_via_pack(struct transport *transport, struct ref *refs_tmp = NULL; memset(&args, 0, sizeof(args)); - args.uploadpack = data->uploadpack; - args.keep_pack = data->keep; + args.uploadpack = data->options.uploadpack; + args.keep_pack = data->options.keep; args.lock_pack = 1; - args.use_thin_pack = data->thin; - args.include_tag = data->followtags; + args.use_thin_pack = data->options.thin; + args.include_tag = data->options.followtags; args.verbose = (transport->verbose > 0); args.quiet = (transport->verbose < 0); args.no_progress = args.quiet || (!transport->progress && !isatty(1)); - args.depth = data->depth; + args.depth = data->options.depth; for (i = 0; i < nr_heads; i++) origh[i] = heads[i] = xstrdup(to_fetch[i]->name); @@ -734,7 +729,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re memset(&args, 0, sizeof(args)); args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR); args.force_update = !!(flags & TRANSPORT_PUSH_FORCE); - args.use_thin_pack = data->thin; + args.use_thin_pack = data->options.thin; args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE); args.quiet = !!(flags & TRANSPORT_PUSH_QUIET); args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); @@ -847,12 +842,14 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; + ret->smart_options = NULL; } else if (is_local(url) && is_file(url)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->get_refs_list = get_refs_from_bundle; ret->fetch = fetch_refs_from_bundle; ret->disconnect = close_bundle; + ret->smart_options = NULL; } else if (!is_url(url) || !prefixcmp(url, "file://") || !prefixcmp(url, "git://") @@ -862,20 +859,14 @@ struct transport *transport_get(struct remote *remote, const char *url) /* These are builtin smart transports. */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; - ret->set_option = set_git_option; + ret->set_option = NULL; ret->get_refs_list = get_refs_via_connect; ret->fetch = fetch_refs_via_pack; ret->push_refs = git_transport_push; ret->disconnect = disconnect_git; + ret->smart_options = &(data->options); - data->thin = 1; data->conn = NULL; - data->uploadpack = "git-upload-pack"; - if (remote->uploadpack) - data->uploadpack = remote->uploadpack; - data->receivepack = "git-receive-pack"; - if (remote->receivepack) - data->receivepack = remote->receivepack; } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { @@ -893,14 +884,39 @@ struct transport *transport_get(struct remote *remote, const char *url) transport_helper_init(ret, handler); } + if (ret->smart_options) { + ret->smart_options->thin = 1; + ret->smart_options->uploadpack = "git-upload-pack"; + if (remote->uploadpack) + ret->smart_options->uploadpack = remote->uploadpack; + ret->smart_options->receivepack = "git-receive-pack"; + if (remote->receivepack) + ret->smart_options->receivepack = remote->receivepack; + } + return ret; } int transport_set_option(struct transport *transport, const char *name, const char *value) { + int git_reports = 1, protocol_reports = 1; + + if (transport->smart_options) + git_reports = set_git_option(transport->smart_options, + name, value); + if (transport->set_option) - return transport->set_option(transport, name, value); + protocol_reports = transport->set_option(transport, name, + value); + + /* If either report is 0, report 0 (success). */ + if (!git_reports || !protocol_reports) + return 0; + /* If either reports -1 (invalid value), report -1. */ + if ((git_reports == -1) || (protocol_reports == -1)) + return -1; + /* Otherwise if both report unknown, report unknown. */ return 1; } -- cgit v1.2.3 From 61b075bd3e69cbdc9010a7f817b2017455dd36a7 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Dec 2009 17:26:31 +0200 Subject: Support taking over transports Add support for taking over transports that turn out to be smart. Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index e6eb20ea94..ad25b98ae1 100644 --- a/transport.c +++ b/transport.c @@ -398,6 +398,7 @@ struct git_transport_data { struct git_transport_options options; struct child_process *conn; int fd[2]; + unsigned got_remote_heads : 1; struct extra_have_objects extra_have; }; @@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts, static int connect_setup(struct transport *transport, int for_push, int verbose) { struct git_transport_data *data = transport->data; + + if (data->conn) + return 0; + data->conn = git_connect(data->fd, transport->url, for_push ? data->options.receivepack : data->options.uploadpack, verbose ? CONNECT_VERBOSE : 0); + return 0; } @@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus connect_setup(transport, for_push, 0); get_remote_heads(data->fd[0], &refs, 0, NULL, for_push ? REF_NORMAL : 0, &data->extra_have); + data->got_remote_heads = 1; return refs; } @@ -477,9 +484,10 @@ 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); - if (!data->conn) { + if (!data->got_remote_heads) { connect_setup(transport, 0, 0); get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL); + data->got_remote_heads = 1; } refs = fetch_pack(&args, data->fd, data->conn, @@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport, if (finish_connect(data->conn)) refs = NULL; data->conn = NULL; + data->got_remote_heads = 0; free_refs(refs_tmp); @@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re struct send_pack_args args; int ret; - if (!data->conn) { + if (!data->got_remote_heads) { struct ref *tmp_refs; connect_setup(transport, 1, 0); get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL, NULL); + data->got_remote_heads = 1; } memset(&args, 0, sizeof(args)); @@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re close(data->fd[0]); ret |= finish_connect(data->conn); data->conn = NULL; + data->got_remote_heads = 0; return ret; } @@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport) { struct git_transport_data *data = transport->data; if (data->conn) { - packet_flush(data->fd[1]); + if (data->got_remote_heads) + packet_flush(data->fd[1]); close(data->fd[0]); close(data->fd[1]); finish_connect(data->conn); @@ -759,6 +771,32 @@ static int disconnect_git(struct transport *transport) return 0; } +void transport_take_over(struct transport *transport, + struct child_process *child) +{ + struct git_transport_data *data; + + if (!transport->smart_options) + die("Bug detected: Taking over transport requires non-NULL " + "smart_options field."); + + data = xcalloc(1, sizeof(*data)); + data->options = *transport->smart_options; + data->conn = child; + data->fd[0] = data->conn->out; + data->fd[1] = data->conn->in; + data->got_remote_heads = 0; + transport->data = data; + + transport->set_option = NULL; + transport->get_refs_list = get_refs_via_connect; + transport->fetch = fetch_refs_via_pack; + transport->push = NULL; + transport->push_refs = git_transport_push; + transport->disconnect = disconnect_git; + transport->smart_options = &(data->options); +} + static int is_local(const char *url) { const char *colon = strchr(url, ':'); @@ -867,6 +905,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->smart_options = &(data->options); data->conn = NULL; + data->got_remote_heads = 0; } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || !prefixcmp(url, "ftp://")) { @@ -927,9 +966,9 @@ int transport_push(struct transport *transport, *nonfastforward = 0; verify_remote_names(refspec_nr, refspec); - if (transport->push) + if (transport->push) { return transport->push(transport, refspec_nr, refspec, flags); - if (transport->push_refs) { + } else if (transport->push_refs) { struct ref *remote_refs = transport->get_refs_list(transport, 1); struct ref *local_refs = get_local_heads(); @@ -973,6 +1012,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport) { if (!transport->remote_refs) transport->remote_refs = transport->get_refs_list(transport, 0); + return transport->remote_refs; } @@ -1007,6 +1047,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs) } rc = transport->fetch(transport, nr_heads, heads); + free(heads); return rc; } -- cgit v1.2.3 From b236752a8722c77b5a9b4ed488a992ee05252843 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Dec 2009 17:26:33 +0200 Subject: Support remote archive from all smart transports Previously, remote archive required internal (non remote-helper) smart transport. Extend the remote archive to also support smart transports implemented by remote helpers. Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index ad25b98ae1..a7d67eba83 100644 --- a/transport.c +++ b/transport.c @@ -756,6 +756,17 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re return ret; } +static int connect_git(struct transport *transport, const char *name, + const char *executable, int fd[2]) +{ + struct git_transport_data *data = transport->data; + data->conn = git_connect(data->fd, transport->url, + executable, 0); + fd[0] = data->fd[0]; + fd[1] = data->fd[1]; + return 0; +} + static int disconnect_git(struct transport *transport) { struct git_transport_data *data = transport->data; @@ -901,6 +912,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->get_refs_list = get_refs_via_connect; ret->fetch = fetch_refs_via_pack; ret->push_refs = git_transport_push; + ret->connect = connect_git; ret->disconnect = disconnect_git; ret->smart_options = &(data->options); @@ -1061,6 +1073,15 @@ void transport_unlock_pack(struct transport *transport) } } +int transport_connect(struct transport *transport, const char *name, + const char *exec, int fd[2]) +{ + if (transport->connect) + return transport->connect(transport, name, exec, fd); + else + die("Operation not supported by protocol"); +} + int transport_disconnect(struct transport *transport) { int ret = 0; -- cgit v1.2.3 From 28ca0c90080ec933d82b0f7d050ea5fde2816c57 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Dec 2009 17:26:34 +0200 Subject: Remove special casing of http, https and ftp HTTP, HTTPS and FTP are no longer special to transport code. Also add support for FTPS (curl supports it so it is easy). Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index a7d67eba83..652bf0bd83 100644 --- a/transport.c +++ b/transport.c @@ -918,14 +918,6 @@ struct transport *transport_get(struct remote *remote, const char *url) data->conn = NULL; data->got_remote_heads = 0; - } else if (!prefixcmp(url, "http://") - || !prefixcmp(url, "https://") - || !prefixcmp(url, "ftp://")) { - /* These three are just plain special. */ - transport_helper_init(ret, "curl"); -#ifdef NO_CURL - error("git was compiled without libcurl support."); -#endif } else { /* Unknown protocol in URL. Pass to external handler. */ int len = external_specification_len(url); -- cgit v1.2.3 From 486a3d716427ac81594fe63d4e9cae64703dbc56 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Sat, 26 Dec 2009 01:12:03 +0800 Subject: check stderr with isatty() instead of stdout when deciding to show progress Make transport code (viz. transport.c::fetch_refs_via_pack() and transport-helper.c::standard_options()) that decides to show progress check if stderr is a terminal, instead of stdout. After all, progress reports (via the API in progress.[ch]) are sent to stderr. Update the documentation for git-clone to say "standard error" as well. Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 7362ec09b2..31c88f33a5 100644 --- a/transport.c +++ b/transport.c @@ -476,7 +476,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.include_tag = data->followtags; args.verbose = (transport->verbose > 0); args.quiet = (transport->verbose < 0); - args.no_progress = args.quiet || (!transport->progress && !isatty(1)); + args.no_progress = args.quiet || (!transport->progress && !isatty(2)); args.depth = data->depth; for (i = 0; i < nr_heads; i++) -- cgit v1.2.3 From 27a557a9ff9273ad47aa29c52e9903cf6405f7f7 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 9 Jan 2010 19:28:12 +0200 Subject: Reset possible helper before reusing remote structure If one had multiple URLs configured for remote with previous one having forced helper but the subsequent one not, like: url = foo::bar://baz url = ssh://example/example.git Then the subsequent URL is passed to foo helper, which isn't correct. Fix it to be parsed normally by resetting foreign VCS name before parsing the URL protocol. Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 652bf0bd83..b5332c018b 100644 --- a/transport.c +++ b/transport.c @@ -875,6 +875,9 @@ struct transport *transport_get(struct remote *remote, const char *url) url = remote->url[0]; ret->url = url; + /* In case previous URL had helper forced, reset it. */ + remote->foreign_vcs = NULL; + /* maybe it is a foreign URL? */ if (url) { const char *p = url; -- cgit v1.2.3 From 20e8b465a53e651cc3f50bd60f39d577ecdb7722 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Fri, 8 Jan 2010 10:12:42 +0800 Subject: refactor ref status logic for pushing Move the logic that detects up-to-date and non-fast-forward refs to a new function in remote.[ch], set_ref_status_for_push(). Make transport_push() invoke set_ref_status_for_push() before invoking the push_refs() implementation. (As a side-effect, the push_refs() implementation in transport-helper.c now knows of non-fast-forward pushes.) Removed logic for detecting up-to-date refs from the push_refs() implementation in transport-helper.c, as transport_push() has already done so for it. Make cmd_send_pack() invoke set_ref_status_for_push() before invoking send_pack(), as transport_push() can't do it for send_pack() here. Mark the test on the return status of non-fast-forward push to fail. Git now exits with success, as transport.c::transport_push() does not check for refs with status REF_STATUS_REJECT_NONFASTFORWARD nor does it indicate rejected pushes with its return value. Mark the test for ref status to succeed. As mentioned earlier, refs might be marked as non-fast-forwards, triggering the push status printing mechanism in transport.c. Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3eea836a33..12c4423f79 100644 --- a/transport.c +++ b/transport.c @@ -887,6 +887,10 @@ int transport_push(struct transport *transport, return -1; } + set_ref_status_for_push(remote_refs, + flags & TRANSPORT_PUSH_MIRROR, + flags & TRANSPORT_PUSH_FORCE); + ret = transport->push_refs(transport, remote_refs, flags); if (!quiet || push_had_errors(remote_refs)) -- cgit v1.2.3 From 4232826771d5bdc4cc0bd21188b6ee5f3e700a52 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Fri, 8 Jan 2010 10:12:43 +0800 Subject: transport.c::transport_push(): make ref status affect return value Use push_had_errors() to check the refs for errors and modify the return value. Mark the non-fast-forward push tests to succeed. Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 12c4423f79..9b23989117 100644 --- a/transport.c +++ b/transport.c @@ -875,7 +875,7 @@ int transport_push(struct transport *transport, int verbose = flags & TRANSPORT_PUSH_VERBOSE; int quiet = flags & TRANSPORT_PUSH_QUIET; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; - int ret; + int ret, err; if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; @@ -892,8 +892,11 @@ int transport_push(struct transport *transport, flags & TRANSPORT_PUSH_FORCE); ret = transport->push_refs(transport, remote_refs, flags); + err = push_had_errors(remote_refs); - if (!quiet || push_had_errors(remote_refs)) + ret |= err; + + if (!quiet || err) print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, nonfastforward); -- cgit v1.2.3 From b9cb07726a7a288244b585939850348f319e5e0c Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 15 Jan 2010 00:28:59 +0100 Subject: Fix uninitialized variable in get_refs_via_rsync(). This fixes a crash when cloning via rsync://. Signed-off-by: Richard Weinberger Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 7362ec09b2..42b2c59a7b 100644 --- a/transport.c +++ b/transport.c @@ -143,7 +143,7 @@ static const char *rsync_url(const char *url) static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) { struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; - struct ref dummy, *tail = &dummy; + struct ref dummy = {0}, *tail = &dummy; struct child_process rsync; const char *args[5]; int temp_dir_len; -- cgit v1.2.3 From e9fcd1e2121100d43d2d212eb6c6f1fc82aade1d Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 16 Jan 2010 23:45:31 +0200 Subject: Add push --set-upstream Frequent complaint is lack of easy way to set up upstream (tracking) references for git pull to work as part of push command. So add switch --set-upstream (-u) to do just that. Signed-off-by: Jeff King Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index b5332c018b..8cc287d442 100644 --- a/transport.c +++ b/transport.c @@ -8,6 +8,7 @@ #include "bundle.h" #include "dir.h" #include "refs.h" +#include "branch.h" /* rsync support */ @@ -135,6 +136,53 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list) } } +static void set_upstreams(struct transport *transport, struct ref *refs, + int pretend) +{ + struct ref *ref; + for (ref = refs; ref; ref = ref->next) { + const char *localname; + const char *tmp; + const char *remotename; + unsigned char sha[20]; + int flag = 0; + /* + * Check suitability for tracking. Must be successful / + * already up-to-date ref create/modify (not delete). + */ + if (ref->status != REF_STATUS_OK && + ref->status != REF_STATUS_UPTODATE) + continue; + if (!ref->peer_ref) + continue; + if (!ref->new_sha1 || is_null_sha1(ref->new_sha1)) + continue; + + /* Follow symbolic refs (mainly for HEAD). */ + localname = ref->peer_ref->name; + remotename = ref->name; + tmp = resolve_ref(localname, sha, 1, &flag); + if (tmp && flag & REF_ISSYMREF && + !prefixcmp(tmp, "refs/heads/")) + localname = tmp; + + /* Both source and destination must be local branches. */ + if (!localname || prefixcmp(localname, "refs/heads/")) + continue; + if (!remotename || prefixcmp(remotename, "refs/heads/")) + continue; + + if (!pretend) + install_branch_config(BRANCH_CONFIG_VERBOSE, + localname + 11, transport->remote->name, + remotename); + else + printf("Would set upstream of '%s' to '%s' of '%s'\n", + localname + 11, remotename + 11, + transport->remote->name); + } +} + static const char *rsync_url(const char *url) { return prefixcmp(url, "rsync://") ? skip_prefix(url, "rsync:") : url; @@ -974,6 +1022,10 @@ int transport_push(struct transport *transport, verify_remote_names(refspec_nr, refspec); if (transport->push) { + /* Maybe FIXME. But no important transport uses this case. */ + if (flags & TRANSPORT_PUSH_SET_UPSTREAM) + die("This transport does not support using --set-upstream"); + return transport->push(transport, refspec_nr, refspec, flags); } else if (transport->push_refs) { struct ref *remote_refs = @@ -983,6 +1035,7 @@ int transport_push(struct transport *transport, int verbose = flags & TRANSPORT_PUSH_VERBOSE; int quiet = flags & TRANSPORT_PUSH_QUIET; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; + int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int ret; if (flags & TRANSPORT_PUSH_ALL) @@ -1002,6 +1055,9 @@ int transport_push(struct transport *transport, verbose | porcelain, porcelain, nonfastforward); + if (flags & TRANSPORT_PUSH_SET_UPSTREAM) + set_upstreams(transport, remote_refs, pretend); + if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { struct ref *ref; for (ref = remote_refs; ref; ref = ref->next) -- cgit v1.2.3 From 4da504608ea94fbcac65eb287d8d5791bddefd88 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 27 Jan 2010 19:53:17 +0200 Subject: Fix remote..vcs remote..vcs causes remote->foreign_vcs to be set on entry to transport_get(). Unfortunately, the code assumed that any such entry is stale from previous round. Fix this by making VCS set by URL to be volatile w.r.t. transport_get() instead. Signed-off-by: Ilari Liusvaara Acked-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- transport.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 7714fdb6c6..87581b85a1 100644 --- a/transport.c +++ b/transport.c @@ -912,20 +912,19 @@ static int external_specification_len(const char *url) struct transport *transport_get(struct remote *remote, const char *url) { + const char *helper; struct transport *ret = xcalloc(1, sizeof(*ret)); if (!remote) die("No remote provided to transport_get()"); ret->remote = remote; + helper = remote->foreign_vcs; if (!url && remote && remote->url) url = remote->url[0]; ret->url = url; - /* In case previous URL had helper forced, reset it. */ - remote->foreign_vcs = NULL; - /* maybe it is a foreign URL? */ if (url) { const char *p = url; @@ -933,11 +932,11 @@ struct transport *transport_get(struct remote *remote, const char *url) while (isalnum(*p)) p++; if (!prefixcmp(p, "::")) - remote->foreign_vcs = xstrndup(url, p - url); + helper = xstrndup(url, p - url); } - if (remote && remote->foreign_vcs) { - transport_helper_init(ret, remote->foreign_vcs); + if (helper) { + transport_helper_init(ret, helper); } else if (!prefixcmp(url, "rsync:")) { ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; -- cgit v1.2.3 From cb21d8f032b3784ffa7b340abbafb8c4b122d2cc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 27 Jan 2010 12:22:37 -0800 Subject: transport_get(): drop unnecessary check for !remote At the beginning of the function we make sure remote is not NULL, and the remainder of the funciton already depends on it. Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 87581b85a1..3846aacb47 100644 --- a/transport.c +++ b/transport.c @@ -921,7 +921,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->remote = remote; helper = remote->foreign_vcs; - if (!url && remote && remote->url) + if (!url && remote->url) url = remote->url[0]; ret->url = url; -- cgit v1.2.3 From b0d66e156c5b312d468344569202d8ca4094f67f Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Tue, 16 Feb 2010 15:18:21 +0800 Subject: transport: add got_remote_refs flag transport_get_remote_refs() in tranport.c checks transport->remote_refs to determine whether transport->get_refs_list() should be invoked. The logic is "if it is NULL, we haven't run ls-remote to find out yet". However, transport->remote_refs could still be NULL while cloning from an empty repository. This causes get_refs_list() to be run unnecessarily. Introduce a flag, transport->got_remote_refs, to more explicitly record if we have run transport->get_refs_list() already. Signed-off-by: Tay Ray Chuan Acked-by: Jeff King Signed-off-by: Junio C Hamano --- transport.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3846aacb47..08e4fa0354 100644 --- a/transport.c +++ b/transport.c @@ -918,6 +918,7 @@ struct transport *transport_get(struct remote *remote, const char *url) if (!remote) die("No remote provided to transport_get()"); + ret->got_remote_refs = 0; ret->remote = remote; helper = remote->foreign_vcs; @@ -1079,8 +1080,10 @@ int transport_push(struct transport *transport, const struct ref *transport_get_remote_refs(struct transport *transport) { - if (!transport->remote_refs) + if (!transport->got_remote_refs) { transport->remote_refs = transport->get_refs_list(transport, 0); + transport->got_remote_refs = 1; + } return transport->remote_refs; } -- cgit v1.2.3 From f1863d0d16b9a5288671e17b7fa2eba8244ead2f Mon Sep 17 00:00:00 2001 From: Michael Lukashov Date: Tue, 16 Feb 2010 23:42:52 +0000 Subject: refactor duplicated code in builtin-send-pack.c and transport.c The following functions are (almost) identical: verify_remote_names update_tracking_ref refs_pushed print_push_status Move common versions of these functions to transport.c and rename them, as suggested by Jeff King and Junio C Hamano. These functions have been removed entirely from builtin-send-pack.c, since they are only used internally by print_push_status(): print_ref_status status_abbrev print_ok_ref_status print_one_push_status Also, move #define SUMMARY_WIDTH to transport.h and rename it TRANSPORT_SUMMARY_WIDTH as it is used in builtin-fetch.c and transport.c Signed-off-by: Michael Lukashov Acked-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3846aacb47..6d7a1259a6 100644 --- a/transport.c +++ b/transport.c @@ -573,7 +573,7 @@ static int push_had_errors(struct ref *ref) return 0; } -static int refs_pushed(struct ref *ref) +int transport_refs_pushed(struct ref *ref) { for (; ref; ref = ref->next) { switch(ref->status) { @@ -587,7 +587,7 @@ static int refs_pushed(struct ref *ref) return 0; } -static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) +void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) { struct refspec rs; @@ -609,8 +609,6 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref, int verb } } -#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) - static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain) { if (porcelain) { @@ -623,7 +621,7 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str else fprintf(stdout, "%s\n", summary); } else { - fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary); + fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, summary); if (from) fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); else @@ -711,8 +709,8 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i return 1; } -static void print_push_status(const char *dest, struct ref *refs, - int verbose, int porcelain, int * nonfastforward) +void transport_print_push_status(const char *dest, struct ref *refs, + int verbose, int porcelain, int *nonfastforward) { struct ref *ref; int n = 0; @@ -738,7 +736,7 @@ static void print_push_status(const char *dest, struct ref *refs, } } -static void verify_remote_names(int nr_heads, const char **heads) +void transport_verify_remote_names(int nr_heads, const char **heads) { int i; @@ -1018,7 +1016,7 @@ int transport_push(struct transport *transport, int *nonfastforward) { *nonfastforward = 0; - verify_remote_names(refspec_nr, refspec); + transport_verify_remote_names(refspec_nr, refspec); if (transport->push) { /* Maybe FIXME. But no important transport uses this case. */ @@ -1057,7 +1055,7 @@ int transport_push(struct transport *transport, ret |= err; if (!quiet || err) - print_push_status(transport->url, remote_refs, + transport_print_push_status(transport->url, remote_refs, verbose | porcelain, porcelain, nonfastforward); @@ -1067,10 +1065,10 @@ int transport_push(struct transport *transport, if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { struct ref *ref; for (ref = remote_refs; ref; ref = ref->next) - update_tracking_ref(transport->remote, ref, verbose); + transport_update_tracking_ref(transport->remote, ref, verbose); } - if (!quiet && !ret && !refs_pushed(remote_refs)) + if (!quiet && !ret && !transport_refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); return ret; } -- cgit v1.2.3 From 53a52ff33d42faf2dcceea5b33f8049bd9416555 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Tue, 23 Feb 2010 14:33:48 +0200 Subject: Allow '+', '-' and '.' in remote helper names According to relevant RFCs, in addition to alphanumerics, the following characters are valid in URL scheme parts: '+', '-' and '.', but currently only alphanumerics are allowed in remote helper names. Allow those three characters in remote helper names (both 'foo://' and 'foo::' syntax). Signed-off-by: Ilari Liusvaara Signed-off-by: Junio C Hamano --- transport.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3846aacb47..d3ec449859 100644 --- a/transport.c +++ b/transport.c @@ -872,6 +872,21 @@ static int is_file(const char *url) return S_ISREG(buf.st_mode); } +static int isurlschemechar(int first_flag, int ch) +{ + /* + * The set of valid URL schemes, as per STD66 (RFC3986) is + * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check + * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version + * of check used '[A-Za-z0-9]+' so not to break any remote + * helpers. + */ + int alphanumeric, special; + alphanumeric = ch > 0 && isalnum(ch); + special = ch == '+' || ch == '-' || ch == '.'; + return alphanumeric || (!first_flag && special); +} + static int is_url(const char *url) { const char *url2, *first_slash; @@ -896,7 +911,7 @@ static int is_url(const char *url) */ url2 = url; while (url2 < first_slash - 1) { - if (!isalnum((unsigned char)*url2)) + if (!isurlschemechar(url2 == url, (unsigned char)*url2)) return 0; url2++; } @@ -929,7 +944,7 @@ struct transport *transport_get(struct remote *remote, const char *url) if (url) { const char *p = url; - while (isalnum(*p)) + while (isurlschemechar(p == url, *p)) p++; if (!prefixcmp(p, "::")) helper = xstrndup(url, p - url); -- cgit v1.2.3 From bde873c52914b40377a12764cab926ee974c3f32 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Wed, 24 Feb 2010 20:50:23 +0800 Subject: fetch: refactor verbosity option handling into transport.[ch] transport_set_verbosity() is now provided to transport users. Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3846aacb47..1632c4d0aa 100644 --- a/transport.c +++ b/transport.c @@ -1013,6 +1013,14 @@ int transport_set_option(struct transport *transport, return 1; } +void transport_set_verbosity(struct transport *transport, int verbosity) +{ + if (verbosity >= 2) + transport->verbose = verbosity <= 3 ? verbosity : 3; + if (verbosity < 0) + transport->verbose = -1; +} + int transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags, int *nonfastforward) -- cgit v1.2.3 From 8afd8dc065c54d3c8d8e0397506aa99261703414 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Wed, 24 Feb 2010 20:50:24 +0800 Subject: push: support multiple levels of verbosity Remove the flags TRANSPORT_PUSH_QUIET and TRANSPORT_PUSH_VERBOSE; use transport->verbose instead to determine verbosity for pushing. Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 1632c4d0aa..0655f65c1b 100644 --- a/transport.c +++ b/transport.c @@ -788,8 +788,8 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR); args.force_update = !!(flags & TRANSPORT_PUSH_FORCE); args.use_thin_pack = data->options.thin; - args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE); - args.quiet = !!(flags & TRANSPORT_PUSH_QUIET); + args.verbose = (transport->verbose > 0); + args.quiet = (transport->verbose < 0); args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); ret = send_pack(&args, data->fd, data->conn, remote_refs, @@ -1039,8 +1039,8 @@ int transport_push(struct transport *transport, transport->get_refs_list(transport, 1); struct ref *local_refs = get_local_heads(); int match_flags = MATCH_REFS_NONE; - int verbose = flags & TRANSPORT_PUSH_VERBOSE; - int quiet = flags & TRANSPORT_PUSH_QUIET; + int verbose = (transport->verbose > 0); + int quiet = (transport->verbose < 0); int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int ret, err; -- cgit v1.2.3 From d01b3c02e8a066054c308ee2ce521a2ea44738d3 Mon Sep 17 00:00:00 2001 From: Tay Ray Chuan Date: Wed, 24 Feb 2010 20:50:26 +0800 Subject: transport->progress: use flag authoritatively Set transport->progress in transport.c::transport_set_verbosity() after checking for the appropriate conditions (eg. --progress, isatty(2)), and thereafter use it without having to check again. The rules used are as follows (processing aborts when a rule is satisfied): 1. Report progress, if force_progress is 1 (ie. --progress). 2. Don't report progress, if verbosity < 0 (ie. -q/--quiet). 3. Report progress if isatty(2) is 1. This changes progress reporting behaviour such that if both --progress and --quiet are specified, progress is reported. In two areas, the logic to determine whether to *not* show progress is changed to simply use the negation of transport->progress. This changes behaviour in some ways (see previous paragraph for details). Signed-off-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 0655f65c1b..e2cfabd7ee 100644 --- a/transport.c +++ b/transport.c @@ -526,7 +526,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.include_tag = data->options.followtags; args.verbose = (transport->verbose > 0); args.quiet = (transport->verbose < 0); - args.no_progress = args.quiet || (!transport->progress && !isatty(2)); + args.no_progress = !transport->progress; args.depth = data->options.depth; for (i = 0; i < nr_heads; i++) @@ -915,6 +915,8 @@ struct transport *transport_get(struct remote *remote, const char *url) const char *helper; struct transport *ret = xcalloc(1, sizeof(*ret)); + ret->progress = isatty(2); + if (!remote) die("No remote provided to transport_get()"); @@ -1013,12 +1015,23 @@ int transport_set_option(struct transport *transport, return 1; } -void transport_set_verbosity(struct transport *transport, int verbosity) +void transport_set_verbosity(struct transport *transport, int verbosity, + int force_progress) { if (verbosity >= 2) transport->verbose = verbosity <= 3 ? verbosity : 3; if (verbosity < 0) transport->verbose = -1; + + /** + * Rules used to determine whether to report progress (processing aborts + * when a rule is satisfied): + * + * 1. Report progress, if force_progress is 1 (ie. --progress). + * 2. Don't report progress, if verbosity < 0 (ie. -q/--quiet ). + * 3. Report progress if isatty(2) is 1. + **/ + transport->progress = force_progress || (verbosity >= 0 && isatty(2)); } int transport_push(struct transport *transport, -- cgit v1.2.3 From 60cfeb8e95d859bf250804c7981e8481e297c3b6 Mon Sep 17 00:00:00 2001 From: Larry D'Anna Date: Fri, 26 Feb 2010 23:52:14 -0500 Subject: git-push: send "To " messages to the standard output in --porcelain mode git-push prints the line "To " before above each of the ref status lines. In --porcelain mode, these "To " lines go to the standard error, but the ref status lines go to the standard output. This makes it difficult for the process reading standard output to know which ref status lines correspond to which remote. This patch sends the "To " lines to the the standard output instead. Signed-off-by: Larry D'Anna Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 3846aacb47..fb653c654a 100644 --- a/transport.c +++ b/transport.c @@ -675,7 +675,7 @@ static void print_ok_ref_status(struct ref *ref, int porcelain) static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain) { if (!count) - fprintf(stderr, "To %s\n", dest); + fprintf(porcelain ? stdout : stderr, "To %s\n", dest); switch(ref->status) { case REF_STATUS_NONE: -- cgit v1.2.3 From 77555854be6e7fbce07c9ded30ea859b54699be0 Mon Sep 17 00:00:00 2001 From: Larry D'Anna Date: Fri, 26 Feb 2010 23:52:15 -0500 Subject: git-push: make git push --porcelain print "Done" The script calling git push --porcelain --dry-run can see clearly from the output if an update was rejected. However, it will probably need to distinguish this condition from the push failing for other reasons, such as the remote not being reachable. This patch modifies git push --porcelain to print "Done" after the rest of its output unless any errors have occurred. For the purpose of the "Done" line, knowing a ref will be rejected in a --dry-run does not count as an error. Actual rejections in non --dry-run pushes do count as errors. Signed-off-by: Larry D'Anna Acked-by: Tay Ray Chuan Signed-off-by: Junio C Hamano --- transport.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index fb653c654a..260350b5a6 100644 --- a/transport.c +++ b/transport.c @@ -791,6 +791,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE); args.quiet = !!(flags & TRANSPORT_PUSH_QUIET); args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); + args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN); ret = send_pack(&args, data->fd, data->conn, remote_refs, &data->extra_have); @@ -1035,7 +1036,7 @@ int transport_push(struct transport *transport, int quiet = flags & TRANSPORT_PUSH_QUIET; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; - int ret, err; + int push_ret, ret, err; if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; @@ -1051,10 +1052,9 @@ int transport_push(struct transport *transport, flags & TRANSPORT_PUSH_MIRROR, flags & TRANSPORT_PUSH_FORCE); - ret = transport->push_refs(transport, remote_refs, flags); + push_ret = transport->push_refs(transport, remote_refs, flags); err = push_had_errors(remote_refs); - - ret |= err; + ret = push_ret | err; if (!quiet || err) print_push_status(transport->url, remote_refs, @@ -1070,8 +1070,11 @@ int transport_push(struct transport *transport, update_tracking_ref(transport->remote, ref, verbose); } - if (!quiet && !ret && !refs_pushed(remote_refs)) + if (porcelain && !push_ret) + puts("Done"); + else if (!quiet && !ret && !refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); + return ret; } return 1; -- cgit v1.2.3 From 638794cde08bb785410a92d293969949a1f5a846 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 23 May 2010 05:17:55 -0400 Subject: make url-related functions reusable The is_url function and url percent-decoding functions were static, but are generally useful. Let's make them available to other parts of the code. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- transport.c | 51 ++------------------------------------------------- 1 file changed, 2 insertions(+), 49 deletions(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 8ce39364a1..4dba6f8815 100644 --- a/transport.c +++ b/transport.c @@ -9,6 +9,7 @@ #include "dir.h" #include "refs.h" #include "branch.h" +#include "url.h" /* rsync support */ @@ -871,54 +872,6 @@ static int is_file(const char *url) return S_ISREG(buf.st_mode); } -static int isurlschemechar(int first_flag, int ch) -{ - /* - * The set of valid URL schemes, as per STD66 (RFC3986) is - * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check - * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version - * of check used '[A-Za-z0-9]+' so not to break any remote - * helpers. - */ - int alphanumeric, special; - alphanumeric = ch > 0 && isalnum(ch); - special = ch == '+' || ch == '-' || ch == '.'; - return alphanumeric || (!first_flag && special); -} - -static int is_url(const char *url) -{ - const char *url2, *first_slash; - - if (!url) - return 0; - url2 = url; - first_slash = strchr(url, '/'); - - /* Input with no slash at all or slash first can't be URL. */ - if (!first_slash || first_slash == url) - return 0; - /* Character before must be : and next must be /. */ - if (first_slash[-1] != ':' || first_slash[1] != '/') - return 0; - /* There must be something before the :// */ - if (first_slash == url + 1) - return 0; - /* - * Check all characters up to first slash - 1. Only alphanum - * is allowed. - */ - url2 = url; - while (url2 < first_slash - 1) { - if (!isurlschemechar(url2 == url, (unsigned char)*url2)) - return 0; - url2++; - } - - /* Valid enough. */ - return 1; -} - static int external_specification_len(const char *url) { return strchr(url, ':') - url; @@ -946,7 +899,7 @@ struct transport *transport_get(struct remote *remote, const char *url) if (url) { const char *p = url; - while (isurlschemechar(p == url, *p)) + while (is_urlschemechar(p == url, *p)) p++; if (!prefixcmp(p, "::")) helper = xstrndup(url, p - url); -- cgit v1.2.3 From d7c411b71d727600d2f031fec9723873ae93c1c7 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 17 Oct 2010 02:37:03 +0800 Subject: push: pass --progress down to git-pack-objects When pushing via builtin transports (like file://, git://), the underlying transport helper (in this case, git-pack-objects) did not get the --progress option, even if it was passed to git push. Fix this, and update the tests to reflect this. Note that according to the git-pack-objects documentation, we can safely apply the usual --progress semantics for the transport commands like clone and fetch (and for pushing over other smart transports). Reported-by: Chase Brammer Helped-by: Jonathan Nieder Signed-off-by: Jeff King Signed-off-by: Tay Ray Chuan Reviewed-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- transport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 4dba6f8815..0078660611 100644 --- a/transport.c +++ b/transport.c @@ -789,6 +789,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re args.use_thin_pack = data->options.thin; args.verbose = (transport->verbose > 0); args.quiet = (transport->verbose < 0); + args.progress = transport->progress; args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN); args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN); -- cgit v1.2.3 From 36cfda15527d4eb50c84256307e3cb46578f975e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 11 Mar 2011 11:32:53 -0800 Subject: refs_from_alternate: helper to use refs from alternates The receiving end of "git push" advertises the objects that the repository itself does not use, but are at the tips of refs in other repositories whose object databases are used as alternates for it. This helps it avoid having to receive (and the pusher having to send) objects that are already available to the receiving repository via the alternates mechanism. Tweak the helper function that implements this feature, and move it to transport.[ch] for future reuse by other programs. The additional test demonstrates how this optimization is helping "git push", and "git fetch" is ignorant about it. Signed-off-by: Junio C Hamano Acked-by: Shawn O. Pearce --- transport.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 0078660611..3dfbc6a79c 100644 --- a/transport.c +++ b/transport.c @@ -1189,3 +1189,37 @@ char *transport_anonymize_url(const char *url) literal_copy: return xstrdup(url); } + +int refs_from_alternate_cb(struct alternate_object_database *e, void *cb) +{ + char *other; + size_t len; + struct remote *remote; + struct transport *transport; + const struct ref *extra; + alternate_ref_fn *ref_fn = cb; + + e->name[-1] = '\0'; + other = xstrdup(make_absolute_path(e->base)); + e->name[-1] = '/'; + len = strlen(other); + + while (other[len-1] == '/') + other[--len] = '\0'; + if (len < 8 || memcmp(other + len - 8, "/objects", 8)) + return 0; + /* Is this a git repository with refs? */ + memcpy(other + len - 8, "/refs", 6); + if (!is_directory(other)) + return 0; + other[len - 8] = '\0'; + remote = remote_get(other); + transport = transport_get(remote, other); + for (extra = transport_get_remote_refs(transport); + extra; + extra = extra->next) + ref_fn(extra, NULL); + transport_disconnect(transport); + free(other); + return 0; +} -- cgit v1.2.3 From c2e86addb86689306b992065328ec52aa2479658 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 22 Mar 2011 00:51:05 -0700 Subject: Fix sparse warnings Fix warnings from 'make check'. - These files don't include 'builtin.h' causing sparse to complain that cmd_* isn't declared: builtin/clone.c:364, builtin/fetch-pack.c:797, builtin/fmt-merge-msg.c:34, builtin/hash-object.c:78, builtin/merge-index.c:69, builtin/merge-recursive.c:22 builtin/merge-tree.c:341, builtin/mktag.c:156, builtin/notes.c:426 builtin/notes.c:822, builtin/pack-redundant.c:596, builtin/pack-refs.c:10, builtin/patch-id.c:60, builtin/patch-id.c:149, builtin/remote.c:1512, builtin/remote-ext.c:240, builtin/remote-fd.c:53, builtin/reset.c:236, builtin/send-pack.c:384, builtin/unpack-file.c:25, builtin/var.c:75 - These files have symbols which should be marked static since they're only file scope: submodule.c:12, diff.c:631, replace_object.c:92, submodule.c:13, submodule.c:14, trace.c:78, transport.c:195, transport-helper.c:79, unpack-trees.c:19, url.c:3, url.c:18, url.c:104, url.c:117, url.c:123, url.c:129, url.c:136, thread-utils.c:21, thread-utils.c:48 - These files redeclare symbols to be different types: builtin/index-pack.c:210, parse-options.c:564, parse-options.c:571, usage.c:49, usage.c:58, usage.c:63, usage.c:72 - These files use a literal integer 0 when they really should use a NULL pointer: daemon.c:663, fast-import.c:2942, imap-send.c:1072, notes-merge.c:362 While we're in the area, clean up some unused #includes in builtin files (mostly exec_cmd.h). Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 0078660611..f1c07816e0 100644 --- a/transport.c +++ b/transport.c @@ -192,7 +192,7 @@ static const char *rsync_url(const char *url) static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) { struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT; - struct ref dummy = {0}, *tail = &dummy; + struct ref dummy = {NULL}, *tail = &dummy; struct child_process rsync; const char *args[5]; int temp_dir_len; -- cgit v1.2.3 From 5dd564895e84eacfc728183fb5a9215665ff59a3 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Thu, 26 May 2011 15:58:16 +0200 Subject: remove tests of always-false condition * fsck.c (fsck_error_function): Don't test obj->sha1 == 0. It can never be true, since that sha1 member is an array. * transport.c (set_upstreams): Likewise for ref->new_sha1. Signed-off-by: Jim Meyering Signed-off-by: Junio C Hamano --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'transport.c') diff --git a/transport.c b/transport.c index 0078660611..26d4e5234a 100644 --- a/transport.c +++ b/transport.c @@ -156,7 +156,7 @@ static void set_upstreams(struct transport *transport, struct ref *refs, continue; if (!ref->peer_ref) continue; - if (!ref->new_sha1 || is_null_sha1(ref->new_sha1)) + if (is_null_sha1(ref->new_sha1)) continue; /* Follow symbolic refs (mainly for HEAD). */ -- cgit v1.2.3