Okay, finally got to it just now. This is entirely untested (because I
don't have anything that uses it), but it compiles and should be correct.
It would be nice to get a clean bill of health on it from valgrind.
If it works, please squash it into my other patch, keep that commit
message, and add my sign-off.
commit 5fdebd88a8e5c2714470c86a2c13ee2c795210cb
Author: Daniel Barkalow <barkalow@iabervon.org>
Date: Wed Nov 11 13:36:36 2009 -0500
Free memory used by remote helper importing refspecs, document
"Allow helper to map private ref names into normal names" was just an
RFD which turned out to be surprisingly correct. This adds the necessary
memory-management and documentation, and generally makes it a suitable
patch.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
index 2c5130f..f4b6a5a 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' <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
-------------------
diff --git a/remote.c b/remote.c
index 09e14a8..1f7870d 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))
diff --git a/remote.h b/remote.h
index c2f920b..f89cb0e 100644
--- a/remote.h
+++ b/remote.h
@@ -91,6 +91,8 @@ 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 *refspecs);
+
char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
const char *name);
diff --git a/transport-helper.c b/transport-helper.c
index 7ea76fd..cea646c 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -72,8 +72,13 @@ static struct child_process *get_helper(struct transport *transport)
}
}
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;
}
@@ -90,6 +95,8 @@ static int disconnect_helper(struct transport *transport)
free(data->helper);
data->helper = NULL;
}
+ free_refspec(data->refspec_nr, data->refspecs);
+ data->refspecs = NULL;
return 0;
}