From: Johan Herland <johan@herland.net>
To: git@vger.kernel.org
Cc: johan@herland.net, gitster@pobox.com, jrnieder@gmail.com
Subject: [PATCHv2 05/10] refs.c: Add support for expanding/shortening refs in refs/peers/*
Date: Sat, 11 May 2013 18:21:15 +0200 [thread overview]
Message-ID: <1368289280-30337-6-git-send-email-johan@herland.net> (raw)
In-Reply-To: <1368289280-30337-1-git-send-email-johan@herland.net>
This patch adds the following patterns for expanding/shortening refs:
"refs/peers/%*"
"refs/peers/%1/tags/%*"
"refs/peers/%1/heads/%*"
These allow shorthand names like "origin/master" to expand to refs in
the refs/peers/* hierarchy (in this case, the likely expansion would be
by the middle rule above, resulting in "refs/peers/origin/heads/master").
To accomplish this, we have added the new "%1" wildcard which shall
expand into the first component (i.e. up to the first '/') of the given
shorthand. The other wildcard ("%*") shall then expand into the remainder
of the shorthand (i.e. following the first '/').
Correspondingly, when shortening according to a pattern with "%1", a
single component (not including any '/' character) shall be extracted
from that point in the given refname, and shall be added to the resulting
shorthand, with a trailing '/'. Then, when hitting the "%*", the
remainder of the given refname (modulo a trailing match in the pattern)
shall be extracted and appended to the portion previously extracted by
the "%1" wildcard.
The need to split the "$remote/$ref" into its $remote and $ref parts is
the reason why multi-level remote names will no longer work (and hence
were disallowed in the previous patch). A testcase demonstrating how
multi-level remote names fail is therefore included in this patch.
Signed-off-by: Johan Herland <johan@herland.net>
---
refs.c | 101 +++++++++++++++++++++----
t/t7900-working-with-namespaced-remote-refs.sh | 4 +-
t/t7901-multi-level-remote-name-failure.sh | 20 +++++
3 files changed, 107 insertions(+), 18 deletions(-)
create mode 100755 t/t7901-multi-level-remote-name-failure.sh
diff --git a/refs.c b/refs.c
index ab5e120..188a9eb 100644
--- a/refs.c
+++ b/refs.c
@@ -1789,7 +1789,10 @@ static const char *refname_patterns[] = {
"refs/tags/%*",
"refs/heads/%*",
"refs/remotes/%*",
- "refs/remotes/%*/HEAD"
+ "refs/remotes/%*/HEAD",
+ "refs/peers/%*",
+ "refs/peers/%1/tags/%*",
+ "refs/peers/%1/heads/%*"
};
struct wildcard_data {
@@ -1806,6 +1809,15 @@ static size_t refname_expand_helper(struct strbuf *sb, const char *placeholder,
strbuf_add(sb, cb->s, cb->len);
cb->done = 1;
return 1;
+ } else if (*placeholder == '1' && !cb->done) {
+ const char *p = memchr(cb->s, '/', cb->len);
+ size_t copy_len = p ? p - cb->s : cb->len;
+ strbuf_add(sb, cb->s, copy_len);
+ if (copy_len < cb->len && cb->s[copy_len] == '/')
+ copy_len++;
+ cb->s += copy_len;
+ cb->len -= copy_len;
+ return 1;
}
return 0;
}
@@ -1821,6 +1833,46 @@ static int refname_expand(struct strbuf *dst, const char *pattern,
return !cbdata.done;
}
+static int handle_fragment(struct strbuf *dst, struct strbuf *fragment,
+ int first, int last,
+ const char *refname, size_t refname_len)
+{
+ const char *ref = refname, *p;
+ size_t ref_len = refname_len, trail_len;
+ if (!first) {
+ /* extract wildcard according to wildcard char */
+ switch (fragment->buf[0]) {
+ case '1':
+ /* extract up to next '/' from refname */
+ p = memchr(ref, '/', ref_len);
+ if (!p)
+ return -1;
+ strbuf_add(dst, ref, p - ref);
+ strbuf_addch(dst, '/');
+ ref_len -= p - ref;
+ ref += p - ref;
+ break;
+ case '*':
+ /* extract all up to matching trailer */
+ assert(last);
+ trail_len = fragment->len - 1;
+ if (trail_len > ref_len)
+ return -1;
+ strbuf_add(dst, ref, ref_len - trail_len);
+ ref += ref_len - trail_len;
+ ref_len -= ref_len - trail_len;
+ break;
+ }
+ }
+
+ /* match rest of fragment verbatim */
+ p = fragment->buf + (first ? 0 : 1); /* skip wildcard character */
+ trail_len = fragment->len - ((first ? 0 : 1) + (last ? 0 : 1));
+ if (trail_len > ref_len || memcmp(ref, p, trail_len))
+ return -1;
+ return (ref - refname) + trail_len;
+}
+
static int refname_shorten(struct strbuf *dst, const char *pattern,
const char *refname, size_t refname_len)
{
@@ -1830,26 +1882,43 @@ static int refname_shorten(struct strbuf *dst, const char *pattern,
* Return 0 on success (positive match, wildcard-matching portion
* copied into dst), and non-zero on failure (no match, dst empty).
*/
- const char *match_end;
- struct strbuf **fragments = strbuf_split_str(pattern, '%', 2);
- struct strbuf *prefix = fragments[0], *suffix = fragments[1];
- assert(!fragments[2]);
- assert(prefix->len && prefix->buf[prefix->len - 1] == '%');
- assert(suffix->len && suffix->buf[0] == '*');
+ struct strbuf **fragments = strbuf_split_str(pattern, '%', 0);
+ struct strbuf **it;
+ int first = 1, last, ret = 1;
strbuf_reset(dst);
- match_end = refname + refname_len - (suffix->len - 1);
- if (refname_len <= (prefix->len - 1) + (suffix->len - 1) ||
- memcmp(prefix->buf, refname, prefix->len - 1) ||
- memcmp(suffix->buf + 1, match_end, suffix->len - 1)) {
- strbuf_list_free(fragments);
- return 1; /* refname does not match pattern */
+ for (it = fragments; *it; it++) {
+ int consumed;
+ struct strbuf *cur = *it;
+ last = *(it + 1) == NULL;
+
+ /* all but last ends with '%' */
+ assert(last || cur->buf[cur->len - 1] == '%');
+ /* all but first starts with '*' or '1' */
+ assert(first || cur->buf[0] == '*' || cur->buf[0] == '1');
+ /* only last starts with '*' */
+ assert((cur->buf[0] == '*' && last) ||
+ (cur->buf[0] != '*' && !last));
+
+ consumed = handle_fragment(dst, cur, first, last,
+ refname, refname_len);
+ if (consumed < 0)
+ goto cleanup;
+ else {
+ refname += consumed;
+ refname_len -= consumed;
+ }
+
+ first = 0;
}
+ if (refname_len == 0)
+ ret = 0;
- refname += prefix->len - 1;
- strbuf_add(dst, refname, match_end - refname);
+cleanup:
+ if (ret)
+ strbuf_reset(dst);
strbuf_list_free(fragments);
- return 0;
+ return ret;
}
int refname_match(const char *abbrev_name, const char *full_name)
diff --git a/t/t7900-working-with-namespaced-remote-refs.sh b/t/t7900-working-with-namespaced-remote-refs.sh
index 109e9b8..33266e0 100755
--- a/t/t7900-working-with-namespaced-remote-refs.sh
+++ b/t/t7900-working-with-namespaced-remote-refs.sh
@@ -83,7 +83,7 @@ test_expect_success 'enter client repo' '
cd client
'
-test_expect_failure 'short-hand notation expands correctly for remote-tracking branches' '
+test_expect_success 'short-hand notation expands correctly for remote-tracking branches' '
echo refs/peers/origin/heads/master >expect &&
git rev-parse --symbolic-full-name refs/peers/origin/heads/master >actual &&
test_cmp expect actual &&
@@ -95,7 +95,7 @@ test_expect_failure 'short-hand notation expands correctly for remote-tracking b
test_cmp expect actual
'
-test_expect_failure 'remote-tracking branches are shortened correctly' '
+test_expect_success 'remote-tracking branches are shortened correctly' '
echo origin/master >expect &&
git rev-parse --abbrev-ref refs/peers/origin/heads/master >actual &&
test_cmp expect actual &&
diff --git a/t/t7901-multi-level-remote-name-failure.sh b/t/t7901-multi-level-remote-name-failure.sh
new file mode 100755
index 0000000..8d2a617
--- /dev/null
+++ b/t/t7901-multi-level-remote-name-failure.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='Show why multi-level remote names can no longer be used'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit a &&
+ git config remote.multi/level.url . &&
+ git config remote.multi/level.fetch "+refs/heads/*:refs/peers/multi/level/heads/*" &&
+ git fetch multi/level
+'
+
+test_expect_failure 'Fail to use shorthand notation: "$remote/$branch"' '
+ git rev-parse --verify a >expect &&
+ git rev-parse --verify multi/level/master >actual &&
+ test_cmp expect actual
+'
+
+test_done
--
1.8.1.3.704.g33f7d4f
next prev parent reply other threads:[~2013-05-11 16:22 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-11 16:21 [PATCHv2 00/10] Prepare for alternative remote-tracking branch location Johan Herland
2013-05-11 16:21 ` [PATCHv2 01/10] t7900: Start testing usability of namespaced remote refs Johan Herland
2013-05-11 16:21 ` [PATCHv2 02/10] t7900: Demonstrate failure to expand "$peer/$branch" according to refspecs Johan Herland
2013-05-11 16:21 ` [PATCHv2 03/10] refs.c: Refactor code for mapping between shorthand names and full refnames Johan Herland
2013-05-13 4:56 ` Junio C Hamano
2013-05-13 6:31 ` Johan Herland
2013-05-13 6:45 ` Junio C Hamano
2013-05-13 20:34 ` Junio C Hamano
2013-05-14 14:24 ` Johan Herland
2013-05-14 17:50 ` Junio C Hamano
2013-05-15 6:45 ` Michael Haggerty
2013-05-15 7:39 ` Johan Herland
2013-05-15 13:53 ` Johan Herland
2013-05-15 15:14 ` Junio C Hamano
2013-05-15 19:49 ` Eric Wong
2013-05-11 16:21 ` [PATCHv2 04/10] remote: Reject remote names containing '/' Johan Herland
2013-05-13 4:48 ` Eric Sunshine
2013-05-13 6:32 ` Johan Herland
2013-05-13 4:54 ` Junio C Hamano
2013-05-13 6:53 ` Johan Herland
2013-05-16 9:48 ` Ramkumar Ramachandra
2013-05-16 11:17 ` Johan Herland
2013-05-16 12:14 ` Ramkumar Ramachandra
2013-05-11 16:21 ` Johan Herland [this message]
2013-05-11 16:21 ` [PATCHv2 06/10] t7900: Test git branch -r/-a output w/remote-tracking branches in refs/peers/* Johan Herland
2013-05-11 16:21 ` [PATCHv2 07/10] t3203: Add testcase for fix in 1603ade81352a526ccb206f41ff81ecbc855df2d Johan Herland
2013-05-11 16:21 ` [PATCHv2 08/10] builtin/branch.c: Refactor ref_item.name and .dest into strbufs Johan Herland
2013-05-11 16:21 ` [PATCHv2 09/10] builtin/branch.c: Refactor "remotes/" prepending to remote-tracking branches Johan Herland
2013-05-11 16:21 ` [PATCHv2 10/10] branch: Fix display of remote branches in refs/peers/* Johan Herland
2013-05-13 5:19 ` Eric Sunshine
2013-05-13 6:55 ` Johan Herland
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1368289280-30337-6-git-send-email-johan@herland.net \
--to=johan@herland.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).