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 --- Documentation/config.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/config.txt b/Documentation/config.txt index d1e2120e15..0d9d369ca7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1408,6 +1408,10 @@ remote..tagopt:: Setting this value to \--no-tags disables automatic tag following when fetching from remote +remote..vcs:: + Setting this to a value will cause git to interact with + the remote with the git-remote- helper. + remotes.:: The list of remotes which are fetched by "git remote update ". See linkgit:git-remote[1]. -- cgit v1.3-5-g9baa From e65e91ed4af5ed9c5c810a2cd77b8648a0287e66 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:27 +0100 Subject: Add support for "import" helper command This command, supported if the "import" capability is advertized, allows a helper to support fetching by outputting a git-fast-import stream. If both "fetch" and "import" are advertized, git itself will use "fetch" (although other users may use "import" in this case). Signed-off-by: Daniel Barkalow Signed-off-by: Sverre Rabbelier Signed-off-by: Junio C Hamano --- Documentation/git-remote-helpers.txt | 10 +++++++ transport-helper.c | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'Documentation') diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt index 173ee232f2..e9aa67e757 100644 --- a/Documentation/git-remote-helpers.txt +++ b/Documentation/git-remote-helpers.txt @@ -43,6 +43,13 @@ Commands are given by the caller on the helper's standard input, one per line. + Supported if the helper has the "fetch" capability. +'import' :: + Produces a fast-import stream which imports the current value + of the named ref. It may additionally import other refs as + needed to construct the history efficiently. ++ +Supported if the helper has the "import" capability. + If a fatal error occurs, the program writes the error message to stderr and exits. The caller should expect that a suitable error message has been printed if the child closes the connection without @@ -57,6 +64,9 @@ CAPABILITIES 'fetch':: This helper supports the 'fetch' command. +'import':: + This helper supports the 'import' command. + REF LIST ATTRIBUTES ------------------- diff --git a/transport-helper.c b/transport-helper.c index 53d8f08ee9..82caaaead6 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -11,6 +11,7 @@ struct helper_data const char *name; struct child_process *helper; unsigned fetch : 1; + unsigned import : 1; }; static struct child_process *get_helper(struct transport *transport) @@ -48,6 +49,8 @@ static struct child_process *get_helper(struct transport *transport) break; if (!strcmp(buf.buf, "fetch")) data->fetch = 1; + if (!strcmp(buf.buf, "import")) + data->import = 1; } return data->helper; } @@ -98,6 +101,52 @@ static int fetch_with_fetch(struct transport *transport, return 0; } +static int get_importer(struct transport *transport, struct child_process *fastimport) +{ + struct child_process *helper = get_helper(transport); + memset(fastimport, 0, sizeof(*fastimport)); + fastimport->in = helper->out; + fastimport->argv = xcalloc(5, sizeof(*fastimport->argv)); + fastimport->argv[0] = "fast-import"; + fastimport->argv[1] = "--quiet"; + + fastimport->git_cmd = 1; + return start_command(fastimport); +} + +static int fetch_with_import(struct transport *transport, + int nr_heads, struct ref **to_fetch) +{ + struct child_process fastimport; + struct child_process *helper = get_helper(transport); + int i; + struct ref *posn; + struct strbuf buf = STRBUF_INIT; + + if (get_importer(transport, &fastimport)) + die("Couldn't run fast-import"); + + for (i = 0; i < nr_heads; i++) { + posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + + strbuf_addf(&buf, "import %s\n", posn->name); + write_in_full(helper->in, buf.buf, buf.len); + strbuf_reset(&buf); + } + disconnect_helper(transport); + finish_command(&fastimport); + + for (i = 0; i < nr_heads; i++) { + posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + read_ref(posn->name, posn->old_sha1); + } + return 0; +} + static int fetch(struct transport *transport, int nr_heads, struct ref **to_fetch) { @@ -115,6 +164,9 @@ static int fetch(struct transport *transport, if (data->fetch) return fetch_with_fetch(transport, nr_heads, to_fetch); + if (data->import) + return fetch_with_import(transport, nr_heads, to_fetch); + return -1; } -- cgit v1.3-5-g9baa From 72ff894308d4f6eb9f081167377857f7a3268bca Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:28 +0100 Subject: Allow helper to map private ref names into normal names This allows a helper to say that, when it handles "import refs/heads/topic", the script it outputs will actually write to refs/svn/origin/branches/topic; therefore, transport-helper should read it from the latter location after git-fast-import completes. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Documentation/git-remote-helpers.txt | 16 +++++++++++++++- remote.c | 27 +++++++++++++++++++++++++++ remote.h | 5 +++++ transport-helper.c | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 80 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt index e9aa67e757..d6c5268d38 100644 --- a/Documentation/git-remote-helpers.txt +++ b/Documentation/git-remote-helpers.txt @@ -46,7 +46,11 @@ Supported if the helper has the "fetch" capability. 'import' :: Produces a fast-import stream which imports the current value of the named ref. It may additionally import other refs as - needed to construct the history efficiently. + needed to construct the history efficiently. The script writes + to a helper-specific private namespace. The value of the named + ref should be written to a location in this namespace derived + by applying the refspecs from the "refspec" capability to the + name of the ref. + Supported if the helper has the "import" capability. @@ -67,6 +71,16 @@ CAPABILITIES 'import':: This helper supports the 'import' command. +'refspec' 'spec':: + When using the import command, expect the source ref to have + been written to the destination ref. The earliest applicable + refspec takes precedence. For example + "refs/heads/*:refs/svn/origin/branches/*" means that, after an + "import refs/heads/name", the script has written to + refs/svn/origin/branches/name. If this capability is used at + all, it must cover all refs reported by the list command; if + it is not used, it is effectively "*:*" + REF LIST ATTRIBUTES ------------------- diff --git a/remote.c b/remote.c index 09bb79c22c..1f7870d107 100644 --- a/remote.c +++ b/remote.c @@ -673,6 +673,16 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) return parse_refspec_internal(nr_refspec, refspec, 0, 0); } +void free_refspec(int nr_refspec, struct refspec *refspec) +{ + int i; + for (i = 0; i < nr_refspec; i++) { + free(refspec[i].src); + free(refspec[i].dst); + } + free(refspec); +} + static int valid_remote_nick(const char *name) { if (!name[0] || is_dot_or_dotdot(name)) @@ -811,6 +821,23 @@ static int match_name_with_pattern(const char *key, const char *name, return ret; } +char *apply_refspecs(struct refspec *refspecs, int nr_refspec, + const char *name) +{ + int i; + char *ret = NULL; + for (i = 0; i < nr_refspec; i++) { + struct refspec *refspec = refspecs + i; + if (refspec->pattern) { + if (match_name_with_pattern(refspec->src, name, + refspec->dst, &ret)) + return ret; + } else if (!strcmp(refspec->src, name)) + return strdup(refspec->dst); + } + return NULL; +} + int remote_find_tracking(struct remote *remote, struct refspec *refspec) { int find_src = refspec->src == NULL; diff --git a/remote.h b/remote.h index ac0ce2ff9c..cdc3b5b159 100644 --- a/remote.h +++ b/remote.h @@ -91,6 +91,11 @@ void ref_remove_duplicates(struct ref *ref_map); int valid_fetch_refspec(const char *refspec); struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +void free_refspec(int nr_refspec, struct refspec *refspec); + +char *apply_refspecs(struct refspec *refspecs, int nr_refspec, + const char *name); + int match_refs(struct ref *src, struct ref **dst, int nr_refspec, const char **refspec, int all); diff --git a/transport-helper.c b/transport-helper.c index 82caaaead6..da8185a981 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -5,6 +5,7 @@ #include "commit.h" #include "diff.h" #include "revision.h" +#include "remote.h" struct helper_data { @@ -12,6 +13,9 @@ struct helper_data struct child_process *helper; unsigned fetch : 1; unsigned import : 1; + /* These go from remote name (as in "list") to private name */ + struct refspec *refspecs; + int refspec_nr; }; static struct child_process *get_helper(struct transport *transport) @@ -20,6 +24,9 @@ static struct child_process *get_helper(struct transport *transport) struct strbuf buf = STRBUF_INIT; struct child_process *helper; FILE *file; + const char **refspecs = NULL; + int refspec_nr = 0; + int refspec_alloc = 0; if (data->helper) return data->helper; @@ -51,6 +58,21 @@ static struct child_process *get_helper(struct transport *transport) data->fetch = 1; if (!strcmp(buf.buf, "import")) data->import = 1; + if (!data->refspecs && !prefixcmp(buf.buf, "refspec ")) { + ALLOC_GROW(refspecs, + refspec_nr + 1, + refspec_alloc); + refspecs[refspec_nr++] = strdup(buf.buf + strlen("refspec ")); + } + } + if (refspecs) { + int i; + data->refspec_nr = refspec_nr; + data->refspecs = parse_fetch_refspec(refspec_nr, refspecs); + for (i = 0; i < refspec_nr; i++) { + free((char *)refspecs[i]); + } + free(refspecs); } return data->helper; } @@ -72,6 +94,9 @@ static int disconnect_helper(struct transport *transport) static int release_helper(struct transport *transport) { + struct helper_data *data = transport->data; + free_refspec(data->refspec_nr, data->refspecs); + data->refspecs = NULL; disconnect_helper(transport); free(transport->data); return 0; @@ -119,6 +144,7 @@ static int fetch_with_import(struct transport *transport, { struct child_process fastimport; struct child_process *helper = get_helper(transport); + struct helper_data *data = transport->data; int i; struct ref *posn; struct strbuf buf = STRBUF_INIT; @@ -139,10 +165,16 @@ static int fetch_with_import(struct transport *transport, finish_command(&fastimport); for (i = 0; i < nr_heads; i++) { + char *private; posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; - read_ref(posn->name, posn->old_sha1); + if (data->refspecs) + private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name); + else + private = strdup(posn->name); + read_ref(private, posn->old_sha1); + free(private); } return 0; } -- cgit v1.3-5-g9baa From f8ec916731ef8d81eefc5db61e3405dade65d821 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 18 Nov 2009 02:42:30 +0100 Subject: Allow helpers to report in "list" command that the ref is unchanged Helpers may use a line like "? name unchanged" to specify that there is nothing new at that name, without any git-specific code to determine the correct response. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- Documentation/git-remote-helpers.txt | 4 +++- transport-helper.c | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt index d6c5268d38..f4b6a5aea3 100644 --- a/Documentation/git-remote-helpers.txt +++ b/Documentation/git-remote-helpers.txt @@ -84,7 +84,9 @@ CAPABILITIES REF LIST ATTRIBUTES ------------------- -None are defined yet, but the caller must accept any which are supplied. +'unchanged':: + This ref is unchanged since the last import or fetch, although + the helper cannot necessarily determine what value that produced. Documentation ------------- diff --git a/transport-helper.c b/transport-helper.c index 628a5ca210..c87530e87d 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -206,6 +206,22 @@ static int fetch(struct transport *transport, return -1; } +static int has_attribute(const char *attrs, const char *attr) { + int len; + if (!attrs) + return 0; + + len = strlen(attr); + for (;;) { + const char *space = strchrnul(attrs, ' '); + if (len == space - attrs && !strncmp(attrs, attr, len)) + return 1; + if (!*space) + return 0; + attrs = space + 1; + } +} + static struct ref *get_refs_list(struct transport *transport, int for_push) { struct child_process *helper; @@ -240,6 +256,12 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) (*tail)->symref = xstrdup(buf.buf + 1); else if (buf.buf[0] != '?') get_sha1_hex(buf.buf, (*tail)->old_sha1); + if (eon) { + if (has_attribute(eon + 1, "unchanged")) { + (*tail)->status |= REF_STATUS_UPTODATE; + read_ref((*tail)->name, (*tail)->old_sha1); + } + } tail = &((*tail)->next); } strbuf_release(&buf); -- cgit v1.3-5-g9baa