Subject: [PATCH v2 09/10] tag.c: implement '--format' option

From: Karthik Nayak <[email-masked]>
Date: Thu, 9 Jul 2015 16:29:46 +0530

Implement the '--format' option provided by 'ref-filter'.
This lets the user list tags as per desired format similar
to the implementation in 'git for-each-ref'.

Add tests and documentation for the same.

Mentored-by: Christian Couder <[email-masked]>
Mentored-by: Matthieu Moy <[email-masked]>
Signed-off-by: Karthik Nayak <[email-masked]>
---
  Documentation/git-tag.txt | 16 +++++++++++++++-
  builtin/tag.c             | 11 +++++++----
  t/t7004-tag.sh            | 16 ++++++++++++++++
  3 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 02fb363..16e396c 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -13,7 +13,8 @@ SYNOPSIS
  	<tagname> [<commit> | <object>]
  'git tag' -d <tagname>...
  'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
-	[--column[=<options>] | --no-column] [--sort=<key>] [<pattern>...]
+	[--column[=<options>] | --no-column] [--sort=<key>] [--format=<format>]
+	[<pattern>...]
  'git tag' -v <tagname>...

  DESCRIPTION
@@ -155,6 +156,19 @@ This option is only applicable when listing tags 
without annotation lines.
  	The object that the new tag will refer to, usually a commit.
  	Defaults to HEAD.

+<format>::
+	A string that interpolates `%(fieldname)` from the
+	object pointed at by a ref being shown.  If `fieldname`
+	is prefixed with an asterisk (`*`) and the ref points
+	at a tag object, the value for the field in the object
+	tag refers is used.  When unspecified, defaults to
+	`%(objectname) SPC %(objecttype) TAB %(refname)`.
+	It also interpolates `%%` to `%`, and `%xx` where `xx`
+	are hex digits interpolates to character with hex code
+	`xx`; for example `%00` interpolates to `\0` (NUL),
+	`%09` to `\t` (TAB) and `%0a` to `\n` (LF).
+	The fields are same as those in `git for-each-ref`.
+

  CONFIGURATION
  -------------
diff --git a/builtin/tag.c b/builtin/tag.c
index 36f8019..601b293 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -30,10 +30,9 @@ static const char * const git_tag_usage[] = {

  static unsigned int colopts;

-static int list_tags(struct ref_filter *filter, struct ref_sorting 
*sorting)
+static int list_tags(struct ref_filter *filter, struct ref_sorting 
*sorting, const char *format)
  {
  	struct ref_array array;
-	char *format;
  	int i;

  	memset(&array, 0, sizeof(array));
@@ -43,7 +42,7 @@ static int list_tags(struct ref_filter *filter, struct 
ref_sorting *sorting)

  	if (filter->lines)
  		format = "%(refname:shortalign=16)";
-	else
+	else if (!format)
  		format = "%(refname:short)";

  	verify_ref_format(format);
@@ -325,6 +324,7 @@ int cmd_tag(int argc, const char **argv, const char 
*prefix)
  	struct strbuf err = STRBUF_INIT;
  	struct ref_filter filter;
  	static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
+	const char *format = NULL;
  	struct option options[] = {
  		OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
  		{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"),
@@ -356,6 +356,7 @@ int cmd_tag(int argc, const char **argv, const char 
*prefix)
  			OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
  			N_("print only tags of the object"), 0, parse_opt_object_name
  		},
+		OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use 
for the output")),
  		OPT_END()
  	};

@@ -395,8 +396,10 @@ int cmd_tag(int argc, const char **argv, const char 
*prefix)
  			copts.padding = 2;
  			run_column_filter(colopts, &copts);
  		}
+		if (format && (filter.lines != -1))
+			die(_("--format and -n are incompatible"));
  		filter.name_patterns = argv;
-		ret = list_tags(&filter, sorting);
+		ret = list_tags(&filter, sorting, format);
  		if (column_active(colopts))
  			stop_column_filter();
  		return ret;
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 51a233f..e8cebb6 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1507,4 +1507,20 @@ EOF"
  	test_cmp expect actual
  '

+test_expect_success '--format cannot be used with -n' '
+	test_must_fail git tag -l -n4 --format="%(refname)"
+'
+
+test_expect_success '--format should list tags as per format given' '
+	cat >expect <<-\EOF &&
+	foo1.10
+	foo1.3
+	foo1.6
+	foo1.6-rc1
+	foo1.6-rc2
+	EOF
+	git tag -l --format="%(refname)" "foo*" >actual &&
+	test_cmp expect actual
+'
+
  test_done
-- 
2.4.5