All of lore.kernel.org
 help / color / mirror / Atom feed
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, &params);
+	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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.