From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: kevin@sb.org, "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 2/5] get_sha1: allow custom SHA-1 mapping with $SHA1^{~alias} syntax
Date: Fri, 24 Dec 2010 21:07:46 +0700 [thread overview]
Message-ID: <1293199669-19016-3-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1293199669-19016-1-git-send-email-pclouds@gmail.com>
"alias" is defined in config as sha1.alias. %sha1% and %arg% in the
alias command will be substituted.
The alias command is supposed to return a piece of text that
get_sha1() can consume, preferably straight SHA-1.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 9 ++++
Documentation/revisions.txt | 7 +++
alias.c | 23 +++++++++--
cache.h | 1 +
sha1_name.c | 86 +++++++++++++++++++++++++++++++++++++++++++
t/t1511-rev-parse-caret.sh | 45 ++++++++++++++++++++++
6 files changed, 166 insertions(+), 5 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0f85793..0c4fb66 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -588,6 +588,15 @@ it will be treated as a shell command. For example, defining
executed from the top-level directory of a repository, which may
not necessarily be the current directory.
+sha1.*::
+ Extended SHA-1 syntax aliases. These aliases are similar to alias.*
+ but each will correspond to a '{caret}\{{tilde}alias\}' syntax (see
+ linkgit:gitrevisions[7]). '%sha1%' in the alias command will be
+ substituted with resolved SHA-1 before the caret. If
+ '{caret}\{{tilde}alias:extra\}' syntax is used, '%arg%' in the
+ alias command will be substituted with 'extra'. The command is
+ supposed to return an extended SHA-1 syntax.
+
am.keepcr::
If true, git-am will call git-mailsplit for patches in mbox format
with parameter '--keep-cr'. In this case git-mailsplit will
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 174fa8e..413f91c 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -106,6 +106,13 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
and dereference the tag recursively until a non-tag object is
found.
+* A suffix '{caret}' followed by an SHA-1 alias with a leading
+ '{tilde}', all enclosed in brace pair (e.g.
+ `v0.998{caret}\{{tilde}alias\}`) will invoke the corresponding
+ alias command, specified in config (see linkgit:git-config[1],
+ key 'sha1.*'). The command is supposed to return an extended
+ SHA-1.
+
* A suffix '{caret}' to a revision parameter followed by a brace
pair that contains a text led by a slash (e.g. `HEAD^{/fix nasty bug}`):
this is the same as `:/fix nasty bug` syntax below except that
diff --git a/alias.c b/alias.c
index 6626bb0..29a9903 100644
--- a/alias.c
+++ b/alias.c
@@ -1,12 +1,12 @@
#include "cache.h"
#include "run-command.h"
-static const char *alias_key;
static char *alias_val;
static int alias_lookup_cb(const char *k, const char *v, void *cb)
{
- if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
+ const char *key = cb;
+ if (!strcmp(k, key)) {
if (!v)
return config_error_nonbool(k);
alias_val = xstrdup(v);
@@ -15,14 +15,27 @@ static int alias_lookup_cb(const char *k, const char *v, void *cb)
return 0;
}
-char *alias_lookup(const char *alias)
+static char *generic_alias_lookup(const char *alias, const char *namespase)
{
- alias_key = alias;
+ struct strbuf key = STRBUF_INIT;
+ strbuf_addstr(&key, namespase);
+ strbuf_addstr(&key, alias);
alias_val = NULL;
- git_config(alias_lookup_cb, NULL);
+ git_config(alias_lookup_cb, key.buf);
+ strbuf_release(&key);
return alias_val;
}
+char *alias_lookup(const char *alias)
+{
+ return generic_alias_lookup(alias, "alias.");
+}
+
+char *sha1_alias_lookup(const char *alias)
+{
+ return generic_alias_lookup(alias, "sha1.");
+}
+
#define SPLIT_CMDLINE_BAD_ENDING 1
#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
static const char *split_cmdline_errors[] = {
diff --git a/cache.h b/cache.h
index 20a37ff..56a1b18 100644
--- a/cache.h
+++ b/cache.h
@@ -1120,6 +1120,7 @@ struct alias_param {
};
char *alias_lookup(const char *alias);
+char *sha1_alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
/* Takes a negative value returned by split_cmdline */
const char *split_cmdline_strerror(int cmdline_errno);
diff --git a/sha1_name.c b/sha1_name.c
index c5c59ce..3a98a50 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -529,6 +529,76 @@ struct object *peel_to_type(const char *name, int namelen,
}
}
+/*
+ * Handle $SHA1^{~alias} syntax. Config key sha1.alias will be used.
+ * The following parameters are substituted:
+ *
+ * - %sha1% SHA-1 before ^{~alias}, required
+ * - %arg% extra arguments after colon in SHA1^{~alias:args}
+ *
+ * The alias returns a string, preferabbly SHA-1.
+ */
+static int peel_alias(const char *name, int len, const char *sp,
+ const unsigned char *input_sha1,
+ struct strbuf *result)
+{
+ struct alias_param *params, *param;
+ struct strbuf alias = STRBUF_INIT;
+ struct strbuf cmd = STRBUF_INIT;
+ char *s;
+ int ret, arg_len = 0;
+
+ if (name[len-1] != '}')
+ return -1;
+ len -= sp - name + 1; /* remove $SHA1^{~ and } */
+ if (!len)
+ return error("$SHA1^{~alias} syntax with no alias");
+
+ s = strchr(sp, ':');
+ if (s) {
+ arg_len = (sp + len) - (s + 1);
+ len = s - sp;
+ }
+ strbuf_add(&alias, sp, len);
+ s = sha1_alias_lookup(alias.buf);
+ if (!s) {
+ ret = error("unable to find SHA-1 alias '%s'", alias.buf);
+ goto done;
+ }
+ strbuf_attach(&cmd, s, strlen(s), strlen(s)+1);
+
+ extract_alias_params(cmd.buf, ¶ms);
+ param = lookup_alias_param(params, "%sha1%");
+ if (!param) { /* %sha1% is mandatory */
+ ret = error("%%sha1%% not found in alias '%s'", alias.buf);
+ goto done;
+ }
+ param->value = xstrdup(sha1_to_hex(input_sha1));
+
+ param = lookup_alias_param(params, "%arg%");
+ if (param && arg_len)
+ param->value = xstrndup(sp + len + 1,arg_len);
+ else if (param) {
+ ret = error("Alias '%s' needs arguments", alias.buf);
+ goto done;
+ }
+ else if (arg_len) {
+ ret = error("Arguments are given but alias '%s' does not need them", alias.buf);
+ goto done;
+ }
+
+ expand_alias_params(&cmd, params);
+ free_alias_params(params);
+
+ trace_printf("trace: sha1 alias expansion: %s => %s\n",
+ alias.buf, cmd.buf);
+ ret = get_alias_oneline(alias.buf, cmd.buf, result);
+done:
+ strbuf_release(&alias);
+ strbuf_release(&cmd);
+ return ret;
+}
+
static int peel_onion(const char *name, int len, unsigned char *sha1)
{
unsigned char outer[20];
@@ -566,6 +636,22 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
expected_type = OBJ_NONE;
else if (sp[0] == '/')
expected_type = OBJ_COMMIT;
+ else if (sp[0] == '~') {
+ struct strbuf new_name = STRBUF_INIT;
+
+ if (get_sha1_1(name, sp - name - 2, outer))
+ return -1;
+
+ if (peel_alias(name, len, sp + 1, outer, &new_name))
+ return -1;
+ if (get_sha1_1(new_name.buf, new_name.len, sha1)) {
+ strbuf_release(&new_name);
+ return -1;
+ }
+
+ strbuf_release(&new_name);
+ return 0;
+ }
else
return -1;
diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh
index e043cb7..b99bfa2 100755
--- a/t/t1511-rev-parse-caret.sh
+++ b/t/t1511-rev-parse-caret.sh
@@ -70,4 +70,49 @@ test_expect_success 'ref^{/Initial}' '
test_cmp expected actual
'
+test_expect_success 'ref^{~}' '
+ test_must_fail git rev-parse HEAD^{~}
+'
+
+test_expect_success 'ref^{~non-existent}' '
+ test_must_fail git rev-parse HEAD^{~non-existent}
+'
+
+test_expect_success 'ref^{~simple}' '
+ git config sha1.simple "rev-parse %sha1%" &&
+ test_must_fail git rev-parse master^{~simple:something} &&
+ git rev-parse master^{~simple} >actual &&
+ git rev-parse master >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref^{~external}' '
+ git config sha1.external "!echo %sha1%" &&
+ test_must_fail git rev-parse master^{~external:something} &&
+ git rev-parse master^{~external} >actual &&
+ git rev-parse master >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref^{~witharg:args}' '
+ git config sha1.witharg "!echo %sha1%^{%arg%}" &&
+ test_must_fail git rev-parse master^{~witharg} &&
+ git rev-parse master^{~witharg:tree} >actual &&
+ git rev-parse master^{tree} >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref^{~simple}^{~external}' '
+ git rev-parse master^{~simple}^{~external} >actual &&
+ git rev-parse master >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref^{~mapping}' '
+ git config sha1.mapping "!echo %sha1%^{~simple}" &&
+ git rev-parse master^{~mapping} >actual &&
+ git rev-parse master >expected &&
+ test_cmp expected actual
+'
+
test_done
--
1.7.3.3.476.g10a82
next prev parent reply other threads:[~2010-12-24 14:09 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-24 14:07 [PATCH 0/5] Custom extended SHA-1 syntax Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 1/5] alias: add functions to do param substitution and alias running Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` Nguyễn Thái Ngọc Duy [this message]
2010-12-24 14:07 ` [PATCH 3/5] sha1_name: move interpret_nth_prior_checkout closer to interpret_branch_name Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 4/5] interpret_branch_name: takes @{u} code out and reorder the function Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 5/5] get_sha1: allow custom ref mapping with $ref@{~alias} syntax Nguyễn Thái Ngọc Duy
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=1293199669-19016-3-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=kevin@sb.org \
/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).