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 <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Daniel Barkalow 2009-11-18 02:42:28 +01:00 коммит произвёл Junio C Hamano
Родитель e65e91ed4a
Коммит 72ff894308
4 изменённых файлов: 80 добавлений и 2 удалений

Просмотреть файл

@ -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
-------------------

Просмотреть файл

@ -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;

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
}