From: Johan Herland <johan@herland.net>
To: git@vger.kernel.org
Cc: johan@herland.net, gitster@pobox.com
Subject: [PATCH 5/7] refs.c: Refactor code for shortening full refnames into shorthand names
Date: Sun, 5 May 2013 01:55:47 +0200 [thread overview]
Message-ID: <1367711749-8812-6-git-send-email-johan@herland.net> (raw)
In-Reply-To: <1367711749-8812-1-git-send-email-johan@herland.net>
shorten_unambiguous_ref() provides the reverse functionality to the
expansion of shorthand names into full refnames, i.e. it takes a full
refname (like "refs/heads/master"), and matches it against a pattern
(like "refs/heads/%.*s") to produce a shorthand name (like "master").
Being the last remaining user of ref_rev_parse_rules list, this patch
converts it to use ref_expand_rules instead. However, as we associated
an expansion function with each expansion rule - to allow for alternative
expansion behavior in the future - we also need to associate a
"shortening" function with each rule, to allow for the reverse operation
to be customized as well.
Therefore, we add a "shorten" function to struct ref_expand_rule, to
encode the shortening of a full refname into a shorthand name. The
relevant rule and the full refname is passed as arguments, and the
resulting shorthand name is returned as an allocated string. If the
refname could not be shortened according to the given rule, NULL is
returned.
The reason for moving the allocation of the shorthand name into the
shortening function, is that one assumes the shortening function itself
will best know exactly how much memory is needed to hold the shorthand
string.
Naturally, we provide a shortening function that encodes the current
textual shortening algorithm - called ref_shorten_txtly() - which is
merely a slight refactoring of the former shorten_ref() function.
This patch removes the only remaining user of ref_rev_parse_rules.
It has now been fully replaced by ref_expand_rules. Hence this patch
also removes ref_rev_parse_rules.
Signed-off-by: Johan Herland <johan@herland.net>
---
refs.c | 110 ++++++++++++++++++++++++++++-------------------------------------
refs.h | 2 ++
2 files changed, 50 insertions(+), 62 deletions(-)
diff --git a/refs.c b/refs.c
index 8b02140..a866489 100644
--- a/refs.c
+++ b/refs.c
@@ -1731,24 +1731,41 @@ static void ref_expand_txtly(const struct ref_expand_rule *rule,
mksnpath(dst, dst_len, rule->pattern, shortname_len, shortname);
}
-const struct ref_expand_rule ref_expand_rules[] = {
- { ref_expand_txtly, "%.*s" },
- { ref_expand_txtly, "refs/%.*s" },
- { ref_expand_txtly, "refs/tags/%.*s" },
- { ref_expand_txtly, "refs/heads/%.*s" },
- { ref_expand_txtly, "refs/remotes/%.*s" },
- { ref_expand_txtly, "refs/remotes/%.*s/HEAD" },
- { NULL, NULL }
-};
+static char *ref_shorten_txtly(const struct ref_expand_rule *rule,
+ const char *refname)
+{
+ /*
+ * rule->pattern must be of the form "[pre]%.*s[post]". Check if
+ * refname starts with "[pre]" and ends with "[post]". If so,
+ * extract the middle part into a newly-allocated buffer, and
+ * return it. Else - if refname does not match rule->pattern -
+ * return NULL.
+ */
+ size_t pre_len, post_start, post_len, match_len;
+ size_t ref_len = strlen(refname);
+ char *sep = strstr(rule->pattern, "%.*s");
+ if (!sep || strstr(sep + 4, "%.*s"))
+ die("invalid pattern in ref_rev_parse_rules_alt: %s", rule->pattern);
+ pre_len = sep - rule->pattern;
+ post_start = pre_len + 4;
+ post_len = strlen(rule->pattern + post_start);
+ if (pre_len + post_len >= ref_len)
+ return NULL; /* refname too short */
+ match_len = ref_len - (pre_len + post_len);
+ if (strncmp(refname, rule->pattern, pre_len) ||
+ strncmp(refname + ref_len - post_len, rule->pattern + post_start, post_len))
+ return NULL; /* refname does not match */
+ return xstrndup(refname + pre_len, match_len);
+}
-static const char *ref_rev_parse_rules[] = {
- "%.*s",
- "refs/%.*s",
- "refs/tags/%.*s",
- "refs/heads/%.*s",
- "refs/remotes/%.*s",
- "refs/remotes/%.*s/HEAD",
- NULL
+const struct ref_expand_rule ref_expand_rules[] = {
+ { ref_expand_txtly, NULL, "%.*s" },
+ { ref_expand_txtly, ref_shorten_txtly, "refs/%.*s" },
+ { ref_expand_txtly, ref_shorten_txtly, "refs/tags/%.*s" },
+ { ref_expand_txtly, ref_shorten_txtly, "refs/heads/%.*s" },
+ { ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s" },
+ { ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s/HEAD" },
+ { NULL, NULL, NULL }
};
int refname_match(const char *abbrev_name, const char *full_name,
@@ -2965,68 +2982,35 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name)
return NULL;
}
-int shorten_ref(const char *refname, const char *pattern, char *short_name)
-{
- /*
- * pattern must be of the form "[pre]%.*s[post]". Check if refname
- * starts with "[pre]" and ends with "[post]". If so, write the
- * middle part into short_name, and return the number of chars
- * written (not counting the added NUL-terminator). Otherwise,
- * if refname does not match pattern, return 0.
- */
- size_t pre_len, post_start, post_len, match_len;
- size_t ref_len = strlen(refname);
- char *sep = strstr(pattern, "%.*s");
- if (!sep || strstr(sep + 4, "%.*s"))
- die("invalid pattern in ref_rev_parse_rules: %s", pattern);
- pre_len = sep - pattern;
- post_start = pre_len + 4;
- post_len = strlen(pattern + post_start);
- if (pre_len + post_len >= ref_len)
- return 0; /* refname too short */
- match_len = ref_len - (pre_len + post_len);
- if (strncmp(refname, pattern, pre_len) ||
- strncmp(refname + ref_len - post_len, pattern + post_start, post_len))
- return 0; /* refname does not match */
- memcpy(short_name, refname + pre_len, match_len);
- short_name[match_len] = '\0';
- return match_len;
-}
-
char *shorten_unambiguous_ref(const char *refname, int strict)
{
int i;
char *short_name;
- /* buffer for scanf result, at most refname must fit */
- short_name = xstrdup(refname);
-
- /* skip first rule, it will always match */
- for (i = ARRAY_SIZE(ref_rev_parse_rules) - 1; i > 0 ; --i) {
+ for (i = ARRAY_SIZE(ref_expand_rules) - 1; i >= 0 ; --i) {
int j;
int rules_to_fail = i;
int short_name_len;
+ const struct ref_expand_rule *p = ref_expand_rules + i;
- if (!ref_rev_parse_rules[i] ||
- !(short_name_len = shorten_ref(refname,
- ref_rev_parse_rules[i],
- short_name)))
+ if (!p->shorten || !(short_name = p->shorten(p, refname)))
continue;
+ short_name_len = strlen(short_name);
/*
* in strict mode, all (except the matched one) rules
* must fail to resolve to a valid non-ambiguous ref
*/
if (strict)
- rules_to_fail = ARRAY_SIZE(ref_rev_parse_rules);
+ rules_to_fail = ARRAY_SIZE(ref_expand_rules);
/*
* check if the short name resolves to a valid ref,
* but use only rules prior to the matched one
*/
for (j = 0; j < rules_to_fail; j++) {
- const char *rule = ref_rev_parse_rules[j];
- char refname[PATH_MAX];
+ const struct ref_expand_rule *q = ref_expand_rules + j;
+ char resolved[PATH_MAX];
/* skip matched rule */
if (i == j)
@@ -3037,10 +3021,12 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
* (with this previous rule) to a valid ref
* read_ref() returns 0 on success
*/
- mksnpath(refname, sizeof(refname),
- rule, short_name_len, short_name);
- if (ref_exists(refname))
- break;
+ if (q->expand) {
+ q->expand(q, resolved, sizeof(resolved),
+ short_name, short_name_len);
+ if (ref_exists(resolved))
+ break;
+ }
}
/*
@@ -3049,9 +3035,9 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
*/
if (j == rules_to_fail)
return short_name;
+ free(short_name);
}
- free(short_name);
return xstrdup(refname);
}
diff --git a/refs.h b/refs.h
index 85710cb..245af6f 100644
--- a/refs.h
+++ b/refs.h
@@ -169,6 +169,8 @@ struct ref_expand_rule {
void (*expand)(const struct ref_expand_rule *rule,
char *dst, size_t dst_len,
const char *shortname, size_t shortname_len);
+ char *(*shorten)(const struct ref_expand_rule *rule,
+ const char *refname);
const char *pattern;
};
extern const struct ref_expand_rule ref_expand_rules[];
--
1.8.1.3.704.g33f7d4f
next prev parent reply other threads:[~2013-05-04 23:56 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-04 23:55 [PATCH 0/7] Make "$remote/$branch" work with unconventional refspecs Johan Herland
2013-05-04 23:55 ` [PATCH 1/7] shorten_unambiguous_ref(): Allow shortening refs/remotes/origin/HEAD to origin Johan Herland
2013-05-05 11:56 ` Bert Wesarg
2013-05-06 17:52 ` Junio C Hamano
2013-05-07 18:49 ` Johan Herland
2013-05-07 18:54 ` [PATCHv2 1/3] t1514: Add tests of shortening refnames in strict/loose mode Johan Herland
2013-05-07 18:54 ` [PATCHv2 2/3] t1514: Demonstrate failure to correctly shorten "refs/remotes/origin/HEAD" Johan Herland
2013-05-07 18:54 ` [PATCHv2 3/3] shorten_unambiguous_ref(): Fix shortening refs/remotes/origin/HEAD to origin Johan Herland
2013-05-07 21:03 ` [PATCH 1/7] shorten_unambiguous_ref(): Allow " Junio C Hamano
2013-05-07 21:31 ` Junio C Hamano
2013-05-07 22:03 ` Johan Herland
2013-05-07 22:06 ` Junio C Hamano
2013-05-07 22:37 ` Johan Herland
2013-05-04 23:55 ` [PATCH 2/7] t7900: Start testing usability of namespaced remote refs Johan Herland
2013-05-07 1:29 ` Junio C Hamano
2013-05-07 21:52 ` Johan Herland
2013-05-07 22:20 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 3/7] t7900: Demonstrate failure to expand "$remote/$branch" according to refspecs Johan Herland
2013-05-07 1:30 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 4/7] refs.c: Refactor rules for expanding shorthand names into full refnames Johan Herland
2013-05-07 1:36 ` Junio C Hamano
2013-05-04 23:55 ` Johan Herland [this message]
2013-05-07 1:44 ` [PATCH 5/7] refs.c: Refactor code for shortening full refnames into shorthand names Junio C Hamano
2013-05-04 23:55 ` [PATCH 6/7] refname_match(): Caller must declare if we're matching local or remote refs Johan Herland
2013-05-07 1:48 ` Junio C Hamano
2013-05-04 23:55 ` [PATCH 7/7] refs.c: Add rules for resolving refs using remote refspecs Johan Herland
2013-05-05 4:28 ` [PATCH 0/7] Make "$remote/$branch" work with unconventional refspecs Junio C Hamano
2013-05-05 9:59 ` Johan Herland
2013-05-05 19:02 ` Junio C Hamano
2013-05-05 22:26 ` Johan Herland
2013-05-05 22:36 ` Junio C Hamano
2013-05-06 1:02 ` Santi Béjar
2013-05-06 1:04 ` Santi Béjar
2013-05-06 17:11 ` Junio C Hamano
2013-05-06 19:17 ` Santi Béjar
2013-05-06 17:06 ` Junio C Hamano
2013-05-06 17:20 ` Junio C Hamano
2013-05-06 23:42 ` Johan Herland
2013-05-07 2:11 ` Junio C Hamano
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=1367711749-8812-6-git-send-email-johan@herland.net \
--to=johan@herland.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.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).