Allow helper to map private ref names into normal names
authorDaniel Barkalow <barkalow@iabervon.org>
Wed, 18 Nov 2009 01:42:28 +0000 (02:42 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Nov 2009 05:45:44 +0000 (21:45 -0800)
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 <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-remote-helpers.txt
remote.c
remote.h
transport-helper.c

index e9aa67e757ac777f10a684258366002dd932ada8..d6c5268d38cab106920f473bdb944d905bdab768 100644 (file)
@@ -46,7 +46,11 @@ Supported if the helper has the "fetch" capability.
 'import' <name>::
        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
 -------------------
 
index 09bb79c22c00a0fe3234218136ba1a6e970078cc..1f7870d107371af9dd4db1fb6e2e777138d682b3 100644 (file)
--- 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;
index ac0ce2ff9cb1e787bbb231d2b5d9e9d2cfb2777d..cdc3b5b159351b550f7136594e0d9f930177e576 100644 (file)
--- 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);
 
index 82caaaead6666eecaceedfbaa486dae4901a80a5..da8185a98150fddf692c9ead76097acbe7b9b41c 100644 (file)
@@ -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;
 }