Skip to content

Commit

Permalink
parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN
Browse files Browse the repository at this point in the history
The prefix length is passed from one command to another via the new
magic 'prefix'. The magic is for parse_pathspec's internal use only,
not visible to parse_pathspec's callers.

Prefix length is not preserved across commands when --literal-pathspecs
is specified (no magic is allowed, including 'prefix'). That's OK
because we know all paths are literal. No magic, no special treatment
regarding prefix. (This may be no longer true if we make :(glob)
default)

Other options to preserve the prefix include saving it to env variable
or quoting. Env var way (at least _one_ env var) is not suitable
because the prefix is not the same for all pathspecs. Pathspecs
starting with "../" will eat into the prefix part.

We could also preserve 'prefix' across commands by quoting the prefix
part, then dequoting on receiving. But it may not be 100% accurate, we
may dequote longer than the original prefix part, for example. That
may be good or not, but it's not the purpose.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Nguyễn Thái Ngọc Duy authored and Junio C Hamano committed Jul 15, 2013
1 parent 645a29c commit 233c3e6
Showing 1 changed file with 36 additions and 5 deletions.
41 changes: 36 additions & 5 deletions pathspec.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
const char *elt)
{
unsigned magic = 0, short_magic = 0;
const char *copyfrom = elt;
const char *copyfrom = elt, *long_magic_end = NULL;
char *match;
int i;
int i, pathspec_prefix = -1;

if (elt[0] != ':') {
; /* nothing to do */
Expand All @@ -112,18 +112,29 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
nextat = copyfrom + len;
if (!len)
continue;
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
if (strlen(pathspec_magic[i].name) == len &&
!strncmp(pathspec_magic[i].name, copyfrom, len)) {
magic |= pathspec_magic[i].bit;
break;
}
if (!prefixcmp(copyfrom, "prefix:")) {
char *endptr;
pathspec_prefix = strtol(copyfrom + 7,
&endptr, 10);
if (endptr - copyfrom != len)
die(_("invalid parameter for pathspec magic 'prefix'"));
/* "i" would be wrong, but it does not matter */
break;
}
}
if (ARRAY_SIZE(pathspec_magic) <= i)
die(_("Invalid pathspec magic '%.*s' in '%s'"),
(int) len, copyfrom, elt);
}
if (*copyfrom != ')')
die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
long_magic_end = copyfrom;
copyfrom++;
} else {
/* shorthand */
Expand All @@ -150,7 +161,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
magic |= short_magic;
*p_short_magic = short_magic;

if (magic & PATHSPEC_FROMTOP) {
if (pathspec_prefix >= 0 &&
(prefixlen || (prefix && *prefix)))
die("BUG: 'prefix' magic is supposed to be used at worktree's root");

if (pathspec_prefix >= 0) {
match = xstrdup(copyfrom);
prefixlen = pathspec_prefix;
} else if (magic & PATHSPEC_FROMTOP) {
match = xstrdup(copyfrom);
prefixlen = 0;
} else {
Expand All @@ -165,7 +183,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
*/
if (flags & PATHSPEC_PREFIX_ORIGIN) {
struct strbuf sb = STRBUF_INIT;
strbuf_add(&sb, elt, copyfrom - elt);
const char *start = elt;
if (prefixlen && !limit_pathspec_to_literal()) {
/* Preserve the actual prefix length of each pattern */
if (long_magic_end) {
strbuf_add(&sb, start, long_magic_end - start);
strbuf_addf(&sb, ",prefix:%d", prefixlen);
start = long_magic_end;
} else {
if (*start == ':')
start++;
strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
}
}
strbuf_add(&sb, start, copyfrom - start);
strbuf_addstr(&sb, match);
item->original = strbuf_detach(&sb, NULL);
} else
Expand Down

0 comments on commit 233c3e6

Please sign in to comment.