Re: [PATCH 1/3 v2] Add support for external programs for handling native fetches

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Tue, 28 Jul 2009, Daniel Barkalow wrote:

> transport_get() can call transport_shim_init() to have list and
> fetch-ref operations handled by running a separate program as:

As I commented already, "shim" is a meaningless word in the context of 
Git.  At _least_ call it something like "git-remote-<protocol>".  Even 
"git-fetch-<protocol>" would be better than "shim".

> diff --git a/Documentation/git-shim.txt b/Documentation/git-shim.txt
> new file mode 100644
> index 0000000..dd80c6d
> --- /dev/null
> +++ b/Documentation/git-shim.txt
> @@ -0,0 +1,37 @@
> +git-shim(1)
> +============
> +
> +NAME
> +----
> +git-shim - Helper programs for interoperation with remote git

Actually, this is just one helper program, no?  Why can't it be integrated 
into transport.c?

At the very least, the text so far is misleading.

> +COMMANDS
> +--------
> +
> +Commands are given by the caller on the helper's standard input, one per line.
> +
> +'list'::
> +	Lists the refs, one per line, if the format "<value>
> +	<name>". The value is either a hex sha1 hash or "@<dest>" for
> +	symrefs. After the complete list, outputs a blank line.
> +
> +'fetch' ref::
> +	Fetches the given ref, writing the necessary objects to the
> +	database. Outputs a blank line when the fetch is complete.
> ++

So you allow only 'list' and 'fetch'.  That is very limiting, and you do 
not even foresee a method to ask for the helper's capabilities.  We 
already saw how much pain that caused in the transport protocol, so please 
do not repeat the mistake here.

> diff --git a/transport-shim.c b/transport-shim.c
> new file mode 100644
> index 0000000..2518aba
> --- /dev/null
> +++ b/transport-shim.c
> @@ -0,0 +1,142 @@
> +#include "cache.h"
> +#include "transport.h"
> +
> +#include "run-command.h"
> +#include "commit.h"
> +#include "diff.h"
> +#include "revision.h"
> +
> +struct shim_data
> +{
> +	const char *name;
> +	struct child_process *shim;
> +};
> +
> +static struct child_process *get_shim(struct transport *transport)
> +{
> +	struct shim_data *data = transport->data;
> +	if (!data->shim) {

Why can't the caller check for this?  Would this not make much more sense 
to begin with?

> +static int disconnect_shim(struct transport *transport)
> +{
> +	struct shim_data *data = transport->data;
> +	if (data->shim) {
> +		write(data->shim->in, "\n", 1);
> +		close(data->shim->in);
> +		finish_command(data->shim);
> +		free(data->shim->argv);
> +		free(data->shim);
> +		transport->data = NULL;
> +	}
> +	return 0;
> +}

Why is this function returning anything?

> +static int fetch_refs_via_shim(struct transport *transport,
> +			       int nr_heads, const struct ref **to_fetch)

Do you fetch only the refs, or also their objects?  If the latter, the 
name needs to be adjusted.

> +{
> +	struct child_process *shim;
> +	const struct ref *posn;
> +	struct strbuf buf = STRBUF_INIT;
> +	int i, count;
> +	FILE *file;
> +
> +	count = 0;
> +	for (i = 0; i < nr_heads; i++) {
> +		posn = to_fetch[i];
> +		if (posn->status & REF_STATUS_UPTODATE)
> +			continue;
> +		count++;
> +	}

This would be more readable IMO if it read like this:

	for (count = i = 0; i < nr_heads; i++)
		if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
			count++;

> +	if (count) {
> +		shim = get_shim(transport);

It would be much better to say "if (!count) return 0;" here rather than 
indenting a whole block of code, with no code after that.

> +		for (i = 0; i < nr_heads; i++) {
> +			posn = to_fetch[i];
> +			if (posn->status & REF_STATUS_UPTODATE)
> +				continue;
> +			write(shim->in, "fetch ", 6);
> +			write(shim->in, sha1_to_hex(posn->old_sha1), 40);
> +			write(shim->in, " ", 1);
> +			write(shim->in, posn->name, strlen(posn->name));
> +			write(shim->in, "\n", 1);
> +		}
> +		file = fdopen(shim->out, "r");
> +		while (count) {
> +			if (strbuf_getline(&buf, file, '\n') == EOF)
> +				exit(128); /* child died, message supplied already */
> +
> +			count--;

while (count--)

> +		}
> +	}
> +	return 0;
> +}
> +
> +static struct ref *get_refs_via_shim(struct transport *transport, int for_push)
> +{
> +	struct child_process *shim;
> +	struct ref *ret = NULL;
> +	struct ref **end = &ret;

A better name for this is "tail", as is used at least in many parts of the 
Git source code already.

> +	struct ref *posn;
> +	struct strbuf buf = STRBUF_INIT;
> +	FILE *file;
> +
> +	shim = get_shim(transport);
> +	write(shim->in, "list\n", 5);

What about the return value of this write()?  It can indicate error or 
short write.

> +
> +	file = fdopen(shim->out, "r");

No check for file != NULL?

> +	while (1) {
> +		char *eov;
> +		if (strbuf_getline(&buf, file, '\n') == EOF)
> +			exit(128); /* child died, message supplied already */
> +
> +		if (!*buf.buf)
> +			break;
> +
> +		eov = strchr(buf.buf, ' ');
> +		if (!eov)
> +			die("Malformed response in ref list: %s", buf.buf);
> +		*eov = '\0';
> +		*end = alloc_ref(eov + 1);
> +		if (eov) {

Did we not die 4 lines earlier if eov == NULL?

> +			if (buf.buf[0] == '@')
> +				(*end)->symref = xstrdup(buf.buf + 1);
> +			else
> +				get_sha1_hex(buf.buf, (*end)->old_sha1);

IMHO it is not at all clear what you are doing here.  At least a little 
hint is in order if the code does not explain itself.

> +		}
> +		end = &((*end)->next);
> +		strbuf_reset(&buf);
> +	}
> +	strbuf_release(&buf);
> +
> +	for (posn = ret; posn; posn = posn->next)
> +		resolve_remote_symref(posn, ret);
> +
> +	return ret;
> +}

Ciao,
Dscho

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]