@@ -0,0 +1,132 @@+#include"cache.h"+#include"remote.h"+#include"strbuf.h"+#include"walker.h"+#include"http.h"++staticstructref*get_refs(structwalker*walker,constchar*url)+{+inthttp_ret;+char*refs_url;+structstrbufbuffer=STRBUF_INIT;+char*data,*start,*mid;+inti=0;+char*ref_name;+structref*refs=NULL;+structref*ref=NULL;+structref*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){+caseHTTP_OK:+break;+caseHTTP_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");+}+free(refs_url);++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(structref)++strlen(ref_name)+1);+memset(ref,0,sizeof(structref));+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);+}++returnrefs;+}++intmain(intargc,constchar**argv)+{+structremote*remote;+structstrbufbuf=STRBUF_INIT;+constchar*url;+structwalker*walker=NULL;++setup_git_directory();+if(argc<2){+fprintf(stderr,"Remote needed\n");+return1;+}++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);+}elseif(!strcmp(buf.buf,"list")){+structref*refs;+structref*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{+return1;+}+strbuf_reset(&buf);+}while(1);+return0;+}
@@ -352,45 +349,6 @@ static int rsync_transport_push(struct transport *transport,returnresult;}-/* Generic functions for using commit walkers */--#ifndef NO_CURL /* http fetch is the only user */-staticintfetch_objs_via_walker(structtransport*transport,-intnr_objs,conststructref**to_fetch)-{-char*dest=xstrdup(transport->url);-structwalker*walker=transport->data;-char**objs=xmalloc(nr_objs*sizeof(*objs));-inti;--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);-return0;-}-#endif /* NO_CURL */--staticintdisconnect_walker(structtransport*transport)-{-structwalker*walker=transport->data;-if(walker)-walker_free(walker);-return0;-}-#ifndef NO_CURLstaticintcurl_transport_push(structtransport*transport,intrefspec_nr,constchar**refspec,intflags){
@@ -432,96 +390,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, consreturn!!err;}-staticstructref*get_refs_via_curl(structtransport*transport,intfor_push)-{-structstrbufbuffer=STRBUF_INIT;-char*data,*start,*mid;-char*ref_name;-char*refs_url;-inti=0;-inthttp_ret;--structref*refs=NULL;-structref*ref=NULL;-structref*last_ref=NULL;--structwalker*walker;--if(for_push)-returnNULL;--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){-caseHTTP_OK:-break;-caseHTTP_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(structref)+-strlen(ref_name)+1);-memset(ref,0,sizeof(structref));-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);-returnrefs;-}--staticintfetch_objs_via_curl(structtransport*transport,-intnr_objs,conststructref**to_fetch)-{-if(!transport->data)-transport->data=get_http_walker(transport->url,-transport->remote);-returnfetch_objs_via_walker(transport,nr_objs,to_fetch);-}-#endifstructbundle_transport_data{
@@ -950,14 +818,12 @@ struct transport *transport_get(struct remote *remote, const char *url)}elseif(!prefixcmp(url,"http://")||!prefixcmp(url,"https://")||!prefixcmp(url,"ftp://")){+transport_shim_init(ret,"curl");#ifdef NO_CURLerror("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;}elseif(is_local(url)&&is_file(url)){structbundle_transport_data*data=xcalloc(1,sizeof(*data));
If you already start some infrastructure like this, you should go the
whole nine yards and make helper functions in remote.c or transport.c that
help implementing "git-remote-<protocol>" helpers.
I think the basic idea of yours is sound, but all I see is some incomplete
separation between builtin git-fetch/-push and the helper. As it stands,
git-fetch/-push have to be compiled with the exact knowledge what helper
is there, git-fetch/-push are _still_ aware if Git was compiled with http
support (so that it is not possible to just install the helper
afterwards), and the infrastructure forbids any extension of capabilities
in the future.
I think these issues are serious enough to merit a rework.
Thanks,
Dscho
From: Erik Faye-Lund <hidden> Date: 2016-06-15 22:47:07
On Tue, Jul 28, 2009 at 3:19 PM, Johannes
Schindelin[off-list ref] wrote:
If you already start some infrastructure like this, you should go the
whole nine yards and make helper functions in remote.c or transport.c that
help implementing "git-remote-<protocol>" helpers.
You mean helper-helpers? :)
--
Erik "kusma" Faye-Lund
kusmabite@gmail.com
(+47) 986 59 656
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:07
Hi,
On Tue, 28 Jul 2009, Erik Faye-Lund wrote:
On Tue, Jul 28, 2009 at 3:19 PM, Johannes
Schindelin[off-list ref] wrote:
quoted
If you already start some infrastructure like this, you should go the
whole nine yards and make helper functions in remote.c or transport.c
that help implementing "git-remote-<protocol>" helpers.
You mean helper-helpers? :)
Not really... I meant functions that do all the stdin parsing for you,
together with error handling, and only return proper lists of verified
arguments in the appropriate data structure. This functionality is likely
to be needed by all remote helpers, that's why I would prefer to have it
exposed as functions in libgit.a, to be reused by all the helpers.
Of course, this would not help shell scripting such helpers, but you have
to start somewhere. And that somewhere happens to be the http transport.
Ciao,
Dscho
This whole chunk of code is a direct move from transport.c, which is
unfortunately not obvious in the way we represent diffs. I'd prefer to
keep the code the same across the move so that we'd be able to track it if
"git blame" got especially smart.
quoted
+
+ 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");
+ }
+ free(refs_url);
+
+ data = buffer.buf;
+ start = NULL;
+ mid = data;
What does "mid" stand for?
quoted
+ while (i < buffer.len) {
+ if (!start) {
+ start = &data[i];
+ }
If you already start some infrastructure like this, you should go the
whole nine yards and make helper functions in remote.c or transport.c that
help implementing "git-remote-<protocol>" helpers.
I thought of that, but I couldn't think of any helper functions that
wouldn't be harder to use than to not use. In any case, they should be in
a separate file, since they'd only be used by a set of separate programs.
Like I said, identifying the remote helper by anything else than the
protocol is a design catastrophe.
But this helper supports all of the protocols supported by curl, and may
eventually not be the only available helper that supports some of these
protocols. I think it's better to represent this fact by having
transport.c explicitly know when to use this helper, rather than linking
the same executable to git-remote-https, git-remote-http, git-remote-ftp,
etc.
quoted
#ifdef NO_CURL
error("git was compiled without libcurl support.");
Why the heck does this have to be guarded by an #ifdef NO_CURL? It is the
helper's task to say, not transport.c's.
What helper? There is no helper at all if NO_CURL, and:
git: 'remote-curl' is not a git-command. See 'git --help'.
is not a user-friendly message. For now, I'm keeping the existing
behavior.
I think the basic idea of yours is sound, but all I see is some incomplete
separation between builtin git-fetch/-push and the helper. As it stands,
git-fetch/-push have to be compiled with the exact knowledge what helper
is there, git-fetch/-push are _still_ aware if Git was compiled with http
support (so that it is not possible to just install the helper
afterwards), and the infrastructure forbids any extension of capabilities
in the future.
In the long run, I want to have two methods for running an external
helper: one where the installation in some way knows when to run the
helper (either by having code in place or by having helpers with
particular names or something), and one where the user specifies something
explicit. That is, git shouldn't know that a remote with no url but some
"codeline" settings that start with "//" is p4, and the user shouldn't
have to know that git repositories whose urls start with http:// are done
with an external helper, so no one mechanism is sufficient.
It would be nice if git supported querying its environment to see whether
a command is available and printing a message suitted to why it was
looking for it, but that's a separate topic.
-Daniel
*This .sig left intentionally blank*
This whole chunk of code is a direct move from transport.c, which is
unfortunately not obvious in the way we represent diffs. I'd prefer to
keep the code the same across the move so that we'd be able to track it
if "git blame" got especially smart.
... and make review of the current patch -- which is possible right now,
without the need of a super clever git blame -- hard? Do you really think
this is a wise decision?
If you already start some infrastructure like this, you should go the
whole nine yards and make helper functions in remote.c or transport.c that
help implementing "git-remote-<protocol>" helpers.
I thought of that, but I couldn't think of any helper functions that
wouldn't be harder to use than to not use. In any case, they should be in
a separate file, since they'd only be used by a set of separate programs.
So every helper should implement the same parsing of the whole protocol?
I mean, the protocol _lends_ itself to an interface that implements
handlers for the commands sent over the pipe, but with compile time errors
when, say, a parameter type mistake happened.
Like I said, identifying the remote helper by anything else than the
protocol is a design catastrophe.
But this helper supports all of the protocols supported by curl, and may
eventually not be the only available helper that supports some of these
protocols.
Yes, and in the near future my computer may understand what I say, and
guess my thoughts.
Let's stay with the presence, okay?
It is _all_ too easy to hardlink git-remote-http to git-remote-https.
And if you have two different handlers for the same protocol, how should
_Git_ decide which one to take?
No, I firmly believe that this design decision is too short-sighted.
I think it's better to represent this fact by having transport.c
explicitly know when to use this helper, rather than linking the same
executable to git-remote-https, git-remote-http, git-remote-ftp, etc.
You really want to recompile Git whenever somebody writes a new protocol
helper? That's wrong.
quoted
quoted
#ifdef NO_CURL
error("git was compiled without libcurl support.");
Why the heck does this have to be guarded by an #ifdef NO_CURL? It is the
helper's task to say, not transport.c's.
What helper? There is no helper at all if NO_CURL,
Again, you want to _require_ that the helpers and Git are compiled
together. I stand firmly against this idea.
and:
git: 'remote-curl' is not a git-command. See 'git --help'.
is not a user-friendly message.
Oh? You would want to show the user that message? I wouldn't. I would
want to show the user:
No helper found to handle protocol 'https' (i.e. no
git-remote-http was found in the PATH)
I think the basic idea of yours is sound, but all I see is some incomplete
separation between builtin git-fetch/-push and the helper. As it stands,
git-fetch/-push have to be compiled with the exact knowledge what helper
is there, git-fetch/-push are _still_ aware if Git was compiled with http
support (so that it is not possible to just install the helper
afterwards), and the infrastructure forbids any extension of capabilities
in the future.
In the long run, I want to have two methods for running an external
helper: one where the installation in some way knows when to run the
helper (either by having code in place or by having helpers with
particular names or something), and one where the user specifies something
explicit.
I am not sure I like that.
That is, git shouldn't know that a remote with no url but some
"codeline" settings that start with "//" is p4,
What speaks against a URL "p4://..."? That would be _totally_ intuitive
and easy to handle.
and the user shouldn't have to know that git repositories whose urls
start with http:// are done with an external helper, so no one mechanism
is sufficient.
Why on earth should the user need to know that http:// is handled by an
external helper?
Of course, if the user wants to support, say, VSS, it is now easy (well,
the Git part) to provide a simple git-remote-vss helper _and not having to
recompile Git at all_.
It would be nice if git supported querying its environment to see whether
a command is available and printing a message suitted to why it was
looking for it, but that's a separate topic.
We do have such a framework in place already. You even mentioned it. Our
git-help can look in the PATH what is available.
But then, we do not have to do that at all.
We just try to handle the protocol internally. If that is not possible,
we extract the protocol from the URL and try to call a program called
git-remote-<protocol>. We inquire via the capabilities command if that
helper can fetch/push and continue accordingly. If the program could not
be launched, with exit status 127, we know there was no helper and can
tell the user that.
We do not need to do any discovery of the environment at all.
start_command() is all we ever need.
Simple is beautiful,
Dscho