* [PATCH 00/15] port branch.c to use ref-filter's printing options
@ 2016-03-06 12:04 Karthik Nayak
2016-03-06 12:04 ` [PATCH 01/15] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
` (14 more replies)
0 siblings, 15 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak
This is part of unification of the commands 'git tag -l, git branch -l
and git for-each-ref'. This ports over branch.c to use ref-filter's
printing options.
Initially posted here: $(gmane/279226). It was decided that this series
would follow up after refactoring ref-filter parsing mechanism, which
is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).
Karthik Nayak (15):
ref-filter: implement %(if), %(then), and %(else) atoms
ref-filter: implement %(if:equals=<string>) and
%(if:notequals=<string>)
ref-filter: modify "%(objectname:short)" to take length
ref-filter: move get_head_description() from branch.c
ref-filter: introduce format_ref_array_item()
ref-filter: make %(upstream:track) prints "[gone]" for invalid
upstreams
ref-filter: add support for %(upstream:track,nobracket)
ref-filter: make "%(symref)" atom work with the ':short' modifier
ref-filter: introduce symref_atom_parser()
ref-filter: introduce refname_atom_parser()
ref-filter: add support for %(refname:dir) and %(refname:base)
ref-filter: allow porcelain to translate messages in the output
branch, tag: use porcelain output
branch: use ref-filter printing APIs
branch: implement '--format' option
Documentation/git-branch.txt | 7 +-
Documentation/git-for-each-ref.txt | 58 ++++-
builtin/branch.c | 267 +++++++----------------
builtin/tag.c | 2 +
ref-filter.c | 428 +++++++++++++++++++++++++++++++------
ref-filter.h | 7 +
t/t3203-branch-output.sh | 11 +
t/t6040-tracking-info.sh | 2 +-
t/t6300-for-each-ref.sh | 40 +++-
t/t6302-for-each-ref-filter.sh | 88 ++++++++
10 files changed, 637 insertions(+), 273 deletions(-)
--
2.7.2
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 01/15] ref-filter: implement %(if), %(then), and %(else) atoms
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
` (13 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Implement %(if), %(then) and %(else) atoms. Used as
%(if)...%(then)...%(end) or %(if)...%(then)...%(else)...%(end). If the
format string between %(if) and %(then) expands to an empty string, or
to only whitespaces, then the whole %(if)...%(end) expands to the string
following %(then). Otherwise, it expands to the string following
%(else), if any. Nesting of this construct is possible.
This is in preparation for porting over `git branch -l` to use
ref-filter APIs for printing.
Add Documentation and tests regarding the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 45 +++++++++++--
ref-filter.c | 133 +++++++++++++++++++++++++++++++++++--
t/t6302-for-each-ref-filter.sh | 70 +++++++++++++++++++
3 files changed, 237 insertions(+), 11 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 012e8f9..d048561 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -141,10 +141,17 @@ align::
"width=" and/or "position=" prefixes may be omitted, and bare
<width> and <position> used instead. For instance,
`%(align:<width>,<position>)`. If the contents length is more
- than the width then no alignment is performed. If used with
- '--quote' everything in between %(align:...) and %(end) is
- quoted, but if nested then only the topmost level performs
- quoting.
+ than the width then no alignment is performed.
+
+if::
+ Used as %(if)...%(then)...(%end) or
+ %(if)...%(then)...%(else)...%(end). If there is an atom with
+ value or string literal after the %(if) then everything after
+ the %(then) is printed, else if the %(else) atom is used, then
+ everything after %(else) is printed. We ignore space when
+ evaluating the string before %(then), this is useful when we
+ use the %(HEAD) atom which prints either "*" or " " and we
+ want to apply the 'if' condition only on the 'HEAD' ref.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
@@ -181,6 +188,20 @@ As a special case for the date-type fields, you may specify a format for
the date by adding `:` followed by date format name (see the
values the `--date` option to linkgit::git-rev-list[1] takes).
+Some atoms like %(align) and %(if) always require a matching %(end).
+We call them "opening atoms" and sometimes denote them as %($open).
+
+When a scripting language specific quoting is in effect (i.e. one of
+`--shell`, `--perl`, `--python`, `--tcl` is used), except for opening
+atoms, replacement from every %(atom) is quoted when and only when it
+appears at the top-level (that is, when it appears outside
+%($open)...%(end)).
+
+When a scripting language specific quoting is in effect, everything
+between a top-level opening atom and its matching %(end) is evaluated
+according to the semantics of the opening atom and its result is
+quoted.
+
EXAMPLES
--------
@@ -268,6 +289,22 @@ eval=`git for-each-ref --shell --format="$fmt" \
eval "$eval"
------------
+
+An example to show the usage of %(if)...%(then)...%(else)...%(end).
+This prefixes the current branch with a star.
+
+------------
+git for-each-ref --format="%(if)%(HEAD)%(then)* %(else) %(end)%(refname:short)" refs/heads/
+------------
+
+
+An example to show the usage of %(if)...%(then)...%(end).
+This prints the authorname, if present.
+
+------------
+git for-each-ref --format="%(refname)%(if)%(authorname)%(then) %(color:red)Authored by: %(authorname)%(end)"
+------------
+
SEE ALSO
--------
linkgit:git-show-ref[1]
diff --git a/ref-filter.c b/ref-filter.c
index bc551a7..41e73f0 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -21,6 +21,12 @@ struct align {
unsigned int width;
};
+struct if_then_else {
+ unsigned int then_atom_seen : 1,
+ else_atom_seen : 1,
+ condition_satisfied : 1;
+};
+
/*
* An atom is a valid field atom listed below, possibly prefixed with
* a "*" to denote deref_tag().
@@ -203,6 +209,9 @@ static struct {
{ "color", FIELD_STR, color_atom_parser },
{ "align", FIELD_STR, align_atom_parser },
{ "end" },
+ { "if" },
+ { "then" },
+ { "else" },
};
#define REF_FORMATTING_STATE_INIT { 0, NULL }
@@ -210,7 +219,7 @@ static struct {
struct ref_formatting_stack {
struct ref_formatting_stack *prev;
struct strbuf output;
- void (*at_end)(struct ref_formatting_stack *stack);
+ void (*at_end)(struct ref_formatting_stack **stack);
void *at_end_data;
};
@@ -343,13 +352,14 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
*stack = prev;
}
-static void end_align_handler(struct ref_formatting_stack *stack)
+static void end_align_handler(struct ref_formatting_stack **stack)
{
- struct align *align = (struct align *)stack->at_end_data;
+ struct ref_formatting_stack *cur = *stack;
+ struct align *align = (struct align *)cur->at_end_data;
struct strbuf s = STRBUF_INIT;
- strbuf_utf8_align(&s, align->position, align->width, stack->output.buf);
- strbuf_swap(&stack->output, &s);
+ strbuf_utf8_align(&s, align->position, align->width, cur->output.buf);
+ strbuf_swap(&cur->output, &s);
strbuf_release(&s);
}
@@ -363,6 +373,103 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
new->at_end_data = &atomv->u.align;
}
+static void if_then_else_handler(struct ref_formatting_stack **stack)
+{
+ struct ref_formatting_stack *cur = *stack;
+ struct ref_formatting_stack *prev = cur->prev;
+ struct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;
+
+ if (!if_then_else->then_atom_seen)
+ die(_("format: %%(if) atom used without a %%(then) atom"));
+
+ if (if_then_else->else_atom_seen) {
+ /*
+ * There is an %(else) atom: we need to drop one state from the
+ * stack, either the %(else) branch if the condition is satisfied, or
+ * the %(then) branch if it isn't.
+ */
+ if (if_then_else->condition_satisfied) {
+ strbuf_reset(&cur->output);
+ pop_stack_element(&cur);
+ } else {
+ strbuf_swap(&cur->output, &prev->output);
+ strbuf_reset(&cur->output);
+ pop_stack_element(&cur);
+ }
+ } else if (!if_then_else->condition_satisfied)
+ /*
+ * No %(else) atom: just drop the %(then) branch if the
+ * condition is not satisfied.
+ */
+ strbuf_reset(&cur->output);
+
+ *stack = cur;
+ free(if_then_else);
+}
+
+static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+ struct ref_formatting_stack *new;
+ struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
+
+ push_stack_element(&state->stack);
+ new = state->stack;
+ new->at_end = if_then_else_handler;
+ new->at_end_data = if_then_else;
+}
+
+static int is_empty(const char *s)
+{
+ while (*s != '\0') {
+ if (!isspace(*s))
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+ struct ref_formatting_stack *cur = state->stack;
+ struct if_then_else *if_then_else = NULL;
+
+ if (cur->at_end == if_then_else_handler)
+ if_then_else = (struct if_then_else *)cur->at_end_data;
+ if (!if_then_else)
+ die(_("format: %%(then) atom used without an %%(if) atom"));
+ if (if_then_else->then_atom_seen)
+ die(_("format: %%(then) atom used more than once"));
+ if (if_then_else->else_atom_seen)
+ die(_("format: %%(then) atom used after %%(else)"));
+ if_then_else->then_atom_seen = 1;
+ /*
+ * If there exists non-empty string between the 'if' and
+ * 'then' atom then the 'if' condition is satisfied.
+ */
+ if (cur->output.len && !is_empty(cur->output.buf))
+ if_then_else->condition_satisfied = 1;
+ strbuf_reset(&cur->output);
+}
+
+static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+ struct ref_formatting_stack *prev = state->stack;
+ struct if_then_else *if_then_else = NULL;
+
+ if (prev->at_end == if_then_else_handler)
+ if_then_else = (struct if_then_else *)prev->at_end_data;
+ if (!if_then_else)
+ die(_("format: %%(else) atom used without an %%(if) atom"));
+ if (!if_then_else->then_atom_seen)
+ die(_("format: %%(else) atom used without a %%(then) atom"));
+ if (if_then_else->else_atom_seen)
+ die(_("format: %%(else) atom used more than once"));
+ if_then_else->else_atom_seen = 1;
+ push_stack_element(&state->stack);
+ state->stack->at_end_data = prev->at_end_data;
+ state->stack->at_end = prev->at_end;
+}
+
static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
{
struct ref_formatting_stack *current = state->stack;
@@ -370,14 +477,17 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
if (!current->at_end)
die(_("format: %%(end) atom used without corresponding atom"));
- current->at_end(current);
+ current->at_end(&state->stack);
+
+ /* Stack may have been popped within at_end(), hence reset the current pointer */
+ current = state->stack;
/*
* Perform quote formatting when the stack element is that of
* a supporting atom. If nested then perform quote formatting
* only on the topmost supporting atom.
*/
- if (!state->stack->prev->prev) {
+ if (!current->prev->prev) {
quote_formatting(&s, current->output.buf, state->quote_style);
strbuf_swap(¤t->output, &s);
}
@@ -1029,6 +1139,15 @@ static void populate_value(struct ref_array_item *ref)
} else if (!strcmp(name, "end")) {
v->handler = end_atom_handler;
continue;
+ } else if (!strcmp(name, "if")) {
+ v->handler = if_atom_handler;
+ continue;
+ } else if (!strcmp(name, "then")) {
+ v->handler = then_atom_handler;
+ continue;
+ } else if (!strcmp(name, "else")) {
+ v->handler = else_atom_handler;
+ continue;
} else
continue;
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index bcf472b..954b12a 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -297,4 +297,74 @@ test_expect_success 'reverse version sort' '
test_cmp expect actual
'
+test_expect_success 'improper usage of %(if), %(then), %(else) and %(end) atoms' '
+ test_must_fail git for-each-ref --format="%(if)" &&
+ test_must_fail git for-each-ref --format="%(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(then) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(else)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(else) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(end)"
+'
+
+test_expect_success 'check %(if)...%(then)...%(end) atoms' '
+ git for-each-ref --format="%(if)%(authorname)%(then)%(authorname): %(refname)%(end)" >actual &&
+ cat >expect <<-\EOF &&
+ A U Thor: refs/heads/master
+ A U Thor: refs/heads/side
+ A U Thor: refs/odd/spot
+
+ A U Thor: refs/tags/foo1.10
+ A U Thor: refs/tags/foo1.3
+ A U Thor: refs/tags/foo1.6
+ A U Thor: refs/tags/four
+ A U Thor: refs/tags/one
+
+ A U Thor: refs/tags/three
+ A U Thor: refs/tags/two
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'check %(if)...%(then)...%(else)...%(end) atoms' '
+ git for-each-ref --format="%(if)%(authorname)%(then)%(authorname)%(else)No author%(end): %(refname)" >actual &&
+ cat >expect <<-\EOF &&
+ A U Thor: refs/heads/master
+ A U Thor: refs/heads/side
+ A U Thor: refs/odd/spot
+ No author: refs/tags/double-tag
+ A U Thor: refs/tags/foo1.10
+ A U Thor: refs/tags/foo1.3
+ A U Thor: refs/tags/foo1.6
+ A U Thor: refs/tags/four
+ A U Thor: refs/tags/one
+ No author: refs/tags/signed-tag
+ A U Thor: refs/tags/three
+ A U Thor: refs/tags/two
+ EOF
+ test_cmp expect actual
+'
+test_expect_success 'ignore spaces in %(if) atom usage' '
+ git for-each-ref --format="%(refname:short): %(if)%(HEAD)%(then)Head ref%(else)Not Head ref%(end)" >actual &&
+ cat >expect <<-\EOF &&
+ master: Head ref
+ side: Not Head ref
+ odd/spot: Not Head ref
+ double-tag: Not Head ref
+ foo1.10: Not Head ref
+ foo1.3: Not Head ref
+ foo1.6: Not Head ref
+ four: Not Head ref
+ one: Not Head ref
+ signed-tag: Not Head ref
+ three: Not Head ref
+ two: Not Head ref
+ EOF
+ test_cmp expect actual
+'
+
test_done
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
2016-03-06 12:04 ` [PATCH 01/15] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-07 22:49 ` Junio C Hamano
2016-03-06 12:04 ` [PATCH 03/15] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
` (12 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Implement %(if:equals=<string>) wherein the if condition is only
satisfied if the value obtained between the %(if:...) and %(then) atom
is the same as the given '<string>'.
Similarly, implement (if:notequals=<string>) wherein the if condition
is only satisfied if the value obtained between the %(if:...) and
%(then) atom is differnt from the given '<string>'.
Add tests and Documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 +++
ref-filter.c | 29 +++++++++++++++++++++++++----
t/t6302-for-each-ref-filter.sh | 18 ++++++++++++++++++
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index d048561..e1b1a66 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -152,6 +152,9 @@ if::
evaluating the string before %(then), this is useful when we
use the %(HEAD) atom which prints either "*" or " " and we
want to apply the 'if' condition only on the 'HEAD' ref.
+ Append ":equals=<string>" or ":notequals=<string>" to compare
+ the value between the %(if:...) and %(then) atoms with the
+ given string.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
diff --git a/ref-filter.c b/ref-filter.c
index 41e73f0..440e270 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -22,6 +22,8 @@ struct align {
};
struct if_then_else {
+ const char *if_equals,
+ *not_equals;
unsigned int then_atom_seen : 1,
else_atom_seen : 1,
condition_satisfied : 1;
@@ -411,6 +413,14 @@ static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
{
struct ref_formatting_stack *new;
struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
+ const char *valp;
+
+ if (skip_prefix(atomv->s, "equals=", &valp))
+ if_then_else->if_equals = valp;
+ else if (skip_prefix(atomv->s, "notequals=", &valp))
+ if_then_else->not_equals = valp;
+ else if (atomv->s[0])
+ die(_("format: unknown format if:%s"), atomv->s);
push_stack_element(&state->stack);
new = state->stack;
@@ -443,10 +453,17 @@ static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_st
die(_("format: %%(then) atom used after %%(else)"));
if_then_else->then_atom_seen = 1;
/*
- * If there exists non-empty string between the 'if' and
- * 'then' atom then the 'if' condition is satisfied.
+ * If the 'equals' or 'notequals' attribute is used then
+ * perform the required comparison. If not, only non-empty
+ * strings satisfy the 'if' condition.
*/
- if (cur->output.len && !is_empty(cur->output.buf))
+ if (if_then_else->if_equals) {
+ if (!strcmp(if_then_else->if_equals, cur->output.buf))
+ if_then_else->condition_satisfied = 1;
+ } else if (if_then_else->not_equals) {
+ if (strcmp(if_then_else->not_equals, cur->output.buf))
+ if_then_else->condition_satisfied = 1;
+ } else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(&cur->output);
}
@@ -1139,7 +1156,11 @@ static void populate_value(struct ref_array_item *ref)
} else if (!strcmp(name, "end")) {
v->handler = end_atom_handler;
continue;
- } else if (!strcmp(name, "if")) {
+ } else if (starts_with(name, "if")) {
+ const char *s;
+
+ if (skip_prefix(name, "if:", &s))
+ v->s = xstrdup(s);
v->handler = if_atom_handler;
continue;
} else if (!strcmp(name, "then")) {
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 954b12a..83716e4 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -367,4 +367,22 @@ test_expect_success 'ignore spaces in %(if) atom usage' '
test_cmp expect actual
'
+test_expect_success 'check %(if:equals=<string>)' '
+ git for-each-ref --format="%(if:equals=master)%(refname:short)%(then)Found master%(else)Not master%(end)" refs/heads/ >actual &&
+ cat >expect <<-\EOF &&
+ Found master
+ Not master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'check %(if:notequals=<string>)' '
+ git for-each-ref --format="%(if:notequals=master)%(refname:short)%(then)Not master%(else)Found master%(end)" refs/heads/ >actual &&
+ cat >expect <<-\EOF &&
+ Found master
+ Not master
+ EOF
+ test_cmp expect actual
+'
+
test_done
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 03/15] ref-filter: modify "%(objectname:short)" to take length
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
2016-03-06 12:04 ` [PATCH 01/15] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
2016-03-06 12:04 ` [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 04/15] ref-filter: move get_head_description() from branch.c Karthik Nayak
` (11 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Add support for %(objectname:short=<length>) which would print the
abbreviated unique objectname of given length. When no length is
specified 7 is used. The minimum length is 'MINIMUM_ABBREV'.
Add tests and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 25 +++++++++++++++++++------
t/t6300-for-each-ref.sh | 10 ++++++++++
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 440e270..2ab90d4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -51,7 +51,10 @@ static struct used_atom {
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option;
unsigned int nlines;
} contents;
- enum { O_FULL, O_SHORT } objectname;
+ struct {
+ enum { O_FULL, O_LENGTH, O_SHORT } option;
+ unsigned int length;
+ } objectname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -114,10 +117,17 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
static void objectname_atom_parser(struct used_atom *atom, const char *arg)
{
if (!arg)
- atom->u.objectname = O_FULL;
+ atom->u.objectname.option = O_FULL;
else if (!strcmp(arg, "short"))
- atom->u.objectname = O_SHORT;
- else
+ atom->u.objectname.option = O_SHORT;
+ else if (skip_prefix(arg, "short=", &arg)) {
+ atom->u.contents.option = O_LENGTH;
+ if (strtoul_ui(arg, 10, &atom->u.objectname.length) ||
+ atom->u.objectname.length == 0)
+ die(_("positive value expected objectname:short=%s"), arg);
+ if (atom->u.objectname.length < MINIMUM_ABBREV)
+ atom->u.objectname.length = MINIMUM_ABBREV;
+ } else
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
@@ -581,12 +591,15 @@ static int grab_objectname(const char *name, const unsigned char *sha1,
struct atom_value *v, struct used_atom *atom)
{
if (starts_with(name, "objectname")) {
- if (atom->u.objectname == O_SHORT) {
+ if (atom->u.objectname.option == O_SHORT) {
v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
return 1;
- } else if (atom->u.objectname == O_FULL) {
+ } else if (atom->u.objectname.option == O_FULL) {
v->s = xstrdup(sha1_to_hex(sha1));
return 1;
+ } else if (atom->u.objectname.option == O_LENGTH) {
+ v->s = xstrdup(find_unique_abbrev(sha1, atom->u.objectname.length));
+ return 1;
} else
die("BUG: unknown %%(objectname) option");
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 19a2823..2be0a3f 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -60,6 +60,8 @@ test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
test_atom head objectname:short $(git rev-parse --short refs/heads/master)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom head tree $(git rev-parse refs/heads/master^{tree})
test_atom head parent ''
test_atom head numparent 0
@@ -99,6 +101,8 @@ test_atom tag objecttype tag
test_atom tag objectsize 154
test_atom tag objectname $(git rev-parse refs/tags/testtag)
test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom tag tree ''
test_atom tag parent ''
test_atom tag numparent ''
@@ -164,6 +168,12 @@ test_expect_success 'Check invalid format specifiers are errors' '
test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
'
+test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
+ test_must_fail git for-each-ref --format="%(objectname:short=0)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=-1)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=foo)"
+'
+
test_date () {
f=$1 &&
committer_date=$2 &&
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 04/15] ref-filter: move get_head_description() from branch.c
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (2 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 03/15] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 05/15] ref-filter: introduce format_ref_array_item() Karthik Nayak
` (10 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Move the implementation of get_head_description() from branch.c to
ref-filter. This gives a description of the HEAD ref if called. This
is used as the refname for the HEAD ref whenever the
FILTER_REFS_DETACHED_HEAD option is used. Make it public because we
need it to calculate the length of the HEAD refs description in
branch.c:calc_maxwidth() when we port branch.c to use ref-filter
APIs.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 31 -------------------------------
ref-filter.c | 38 ++++++++++++++++++++++++++++++++++++--
ref-filter.h | 2 ++
3 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 7b45b6b..460f32f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -355,37 +355,6 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
strbuf_release(&subject);
}
-static char *get_head_description(void)
-{
- struct strbuf desc = STRBUF_INIT;
- struct wt_status_state state;
- memset(&state, 0, sizeof(state));
- wt_status_get_state(&state, 1);
- if (state.rebase_in_progress ||
- state.rebase_interactive_in_progress)
- strbuf_addf(&desc, _("(no branch, rebasing %s)"),
- state.branch);
- else if (state.bisect_in_progress)
- strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
- state.branch);
- else if (state.detached_from) {
- /* TRANSLATORS: make sure these match _("HEAD detached at ")
- and _("HEAD detached from ") in wt-status.c */
- if (state.detached_at)
- strbuf_addf(&desc, _("(HEAD detached at %s)"),
- state.detached_from);
- else
- strbuf_addf(&desc, _("(HEAD detached from %s)"),
- state.detached_from);
- }
- else
- strbuf_addstr(&desc, _("(no branch)"));
- free(state.branch);
- free(state.onto);
- free(state.detached_from);
- return strbuf_detach(&desc, NULL);
-}
-
static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
struct ref_filter *filter, const char *remote_prefix)
{
diff --git a/ref-filter.c b/ref-filter.c
index 2ab90d4..f02344c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -13,6 +13,7 @@
#include "utf8.h"
#include "git-compat-util.h"
#include "version.h"
+#include "wt-status.h"
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
@@ -1067,6 +1068,37 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = refname;
}
+char *get_head_description(void)
+{
+ struct strbuf desc = STRBUF_INIT;
+ struct wt_status_state state;
+ memset(&state, 0, sizeof(state));
+ wt_status_get_state(&state, 1);
+ if (state.rebase_in_progress ||
+ state.rebase_interactive_in_progress)
+ strbuf_addf(&desc, _("(no branch, rebasing %s)"),
+ state.branch);
+ else if (state.bisect_in_progress)
+ strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
+ state.branch);
+ else if (state.detached_from) {
+ /* TRANSLATORS: make sure these match _("HEAD detached at ")
+ and _("HEAD detached from ") in wt-status.c */
+ if (state.detached_at)
+ strbuf_addf(&desc, _("(HEAD detached at %s)"),
+ state.detached_from);
+ else
+ strbuf_addf(&desc, _("(HEAD detached from %s)"),
+ state.detached_from);
+ }
+ else
+ strbuf_addstr(&desc, _("(no branch)"));
+ free(state.branch);
+ free(state.onto);
+ free(state.detached_from);
+ return strbuf_detach(&desc, NULL);
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1105,9 +1137,11 @@ static void populate_value(struct ref_array_item *ref)
name++;
}
- if (starts_with(name, "refname"))
+ if (starts_with(name, "refname")) {
refname = ref->refname;
- else if (starts_with(name, "symref"))
+ if (ref->kind & FILTER_REFS_DETACHED_HEAD)
+ refname = get_head_description();
+ } else if (starts_with(name, "symref"))
refname = ref->symref ? ref->symref : "";
else if (starts_with(name, "upstream")) {
const char *branch_name;
diff --git a/ref-filter.h b/ref-filter.h
index 14d435e..4aea594 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -106,5 +106,7 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
struct ref_sorting *ref_default_sorting(void);
/* Function to parse --merged and --no-merged options */
int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);
+/* Get the current HEAD's description */
+char *get_head_description(void);
#endif /* REF_FILTER_H */
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 05/15] ref-filter: introduce format_ref_array_item()
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (3 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 04/15] ref-filter: move get_head_description() from branch.c Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
` (9 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
To allow column display, we will need to first render the output in a
string list to allow print_columns() to compute the proper size of
each column before starting the actual output. Introduce the function
format_ref_array_item() that does the formatting of a ref_array_item
to an strbuf.
show_ref_array_item() is kept as a convenience wrapper around it which
obtains the strbuf and prints it the standard output.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 16 ++++++++++++----
ref-filter.h | 3 +++
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index f02344c..2896cde 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1803,10 +1803,10 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
}
}
-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
+void format_ref_array_item(struct ref_array_item *info, const char *format,
+ int quote_style, struct strbuf *final_buf)
{
const char *cp, *sp, *ep;
- struct strbuf *final_buf;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
state.quote_style = quote_style;
@@ -1836,9 +1836,17 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
}
if (state.stack->prev)
die(_("format: %%(end) atom missing"));
- final_buf = &state.stack->output;
- fwrite(final_buf->buf, 1, final_buf->len, stdout);
+ strbuf_addbuf(final_buf, &state.stack->output);
pop_stack_element(&state.stack);
+}
+
+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
+{
+ struct strbuf final_buf = STRBUF_INIT;
+
+ format_ref_array_item(info, format, quote_style, &final_buf);
+ fwrite(final_buf.buf, 1, final_buf.len, stdout);
+ strbuf_release(&final_buf);
putchar('\n');
}
diff --git a/ref-filter.h b/ref-filter.h
index 4aea594..0014b92 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -98,6 +98,9 @@ int parse_ref_filter_atom(const char *atom, const char *ep);
int verify_ref_format(const char *format);
/* Sort the given ref_array as per the ref_sorting provided */
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
+/* Based on the given format and quote_style, fill the strbuf */
+void format_ref_array_item(struct ref_array_item *info, const char *format,
+ int quote_style, struct strbuf *final_buf);
/* Print the ref using the given format and quote_style */
void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);
/* Callback function for parsing the sort option */
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (4 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 05/15] ref-filter: introduce format_ref_array_item() Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-08 1:55 ` Jacob Keller
2016-03-06 12:04 ` [PATCH 07/15] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
` (8 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Borrowing from branch.c's implementation print "[gone]" whenever an
unknown upstream ref is encountered instead of just ignoring it.
This makes sure that when branch.c is ported over to using ref-filter
APIs for printing, this feature is not lost.
Make changes to t/t6300-for-each-ref.sh to reflect this change.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 4 +++-
t/t6300-for-each-ref.sh | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 2896cde..c8ba68f 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1039,8 +1039,10 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
else if (atom->u.remote_ref == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
- &num_theirs, NULL))
+ &num_theirs, NULL)) {
+ *s = "[gone]";
return;
+ }
if (!num_ours && !num_theirs)
*s = "";
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 2be0a3f..a92b36f 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -382,7 +382,7 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '
test_expect_success 'Check that :track[short] works when upstream is invalid' '
cat >expected <<-\EOF &&
-
+ [gone]
EOF
test_when_finished "git config branch.master.merge refs/heads/master" &&
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 07/15] ref-filter: add support for %(upstream:track,nobracket)
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (5 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
` (7 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Add support for %(upstream:track,nobracket) which will print the
tracking information without the brackets (i.e. "ahead N, behind M").
This is needed when we port branch.c to use ref-filter's printing APIs.
Add test and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 6 ++--
ref-filter.c | 67 +++++++++++++++++++++++++-------------
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index e1b1a66..0658c3f 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -114,8 +114,10 @@ upstream::
`refname` above. Additionally respects `:track` to show
"[ahead N, behind M]" and `:trackshort` to show the terse
version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
- or "=" (in sync). Has no effect if the ref does not have
- tracking information associated with it.
+ or "=" (in sync). Append `:track,nobracket` to show tracking
+ information without brackets (i.e "ahead N, behind M"). Has
+ no effect if the ref does not have tracking information
+ associated with it.
push::
The name of a local ref which represents the `@{push}` location
diff --git a/ref-filter.c b/ref-filter.c
index c8ba68f..0e6ab75 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -46,8 +46,10 @@ static struct used_atom {
union {
char color[COLOR_MAXLEN];
struct align align;
- enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }
- remote_ref;
+ struct {
+ enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;
+ unsigned int nobracket: 1;
+ } remote_ref;
struct {
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option;
unsigned int nlines;
@@ -71,16 +73,33 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
{
- if (!arg)
- atom->u.remote_ref = RR_NORMAL;
- else if (!strcmp(arg, "short"))
- atom->u.remote_ref = RR_SHORTEN;
- else if (!strcmp(arg, "track"))
- atom->u.remote_ref = RR_TRACK;
- else if (!strcmp(arg, "trackshort"))
- atom->u.remote_ref = RR_TRACKSHORT;
- else
- die(_("unrecognized format: %%(%s)"), atom->name);
+ struct string_list params = STRING_LIST_INIT_DUP;
+ int i;
+
+ if (!arg) {
+ atom->u.remote_ref.option = RR_NORMAL;
+ return;
+ }
+
+ atom->u.remote_ref.nobracket = 0;
+ string_list_split(¶ms, arg, ',', -1);
+
+ for (i = 0; i < params.nr; i++) {
+ const char *s = params.items[i].string;
+
+ if (!strcmp(s, "short"))
+ atom->u.remote_ref.option = RR_SHORTEN;
+ else if (!strcmp(s, "track"))
+ atom->u.remote_ref.option = RR_TRACK;
+ else if (!strcmp(s, "trackshort"))
+ atom->u.remote_ref.option = RR_TRACKSHORT;
+ else if (!strcmp(s, "nobracket"))
+ atom->u.remote_ref.nobracket = 1;
+ else
+ die(_("unrecognized format: %%(%s)"), atom->name);
+ }
+
+ string_list_clear(¶ms, 0);
}
static void body_atom_parser(struct used_atom *atom, const char *arg)
@@ -1035,25 +1054,27 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
struct branch *branch, const char **s)
{
int num_ours, num_theirs;
- if (atom->u.remote_ref == RR_SHORTEN)
+ if (atom->u.remote_ref.option == RR_SHORTEN)
*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
- else if (atom->u.remote_ref == RR_TRACK) {
+ else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
- *s = "[gone]";
- return;
- }
-
- if (!num_ours && !num_theirs)
+ *s = xstrdup("gone");
+ } else if (!num_ours && !num_theirs)
*s = "";
else if (!num_ours)
- *s = xstrfmt("[behind %d]", num_theirs);
+ *s = xstrfmt("behind %d", num_theirs);
else if (!num_theirs)
- *s = xstrfmt("[ahead %d]", num_ours);
+ *s = xstrfmt("ahead %d", num_ours);
else
- *s = xstrfmt("[ahead %d, behind %d]",
+ *s = xstrfmt("ahead %d, behind %d",
num_ours, num_theirs);
- } else if (atom->u.remote_ref == RR_TRACKSHORT) {
+ if (!atom->u.remote_ref.nobracket && *s[0]) {
+ const char *to_free = *s;
+ *s = xstrfmt("[%s]", *s);
+ free((void *)to_free);
+ }
+ } else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL))
return;
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a92b36f..2c5f177 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -372,6 +372,8 @@ test_expect_success 'setup for upstream:track[short]' '
test_atom head upstream:track '[ahead 1]'
test_atom head upstream:trackshort '>'
+test_atom head upstream:track,nobracket 'ahead 1'
+test_atom head upstream:nobracket,track 'ahead 1'
test_atom head push:track '[ahead 1]'
test_atom head push:trackshort '>'
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (6 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 07/15] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-07 23:08 ` Junio C Hamano
2016-03-06 12:04 ` [PATCH 09/15] ref-filter: introduce symref_atom_parser() Karthik Nayak
` (6 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak
The "%(symref)" atom doesn't work when used with the ':short' modifier
because we strictly match only 'symref' for setting the 'need_symref'
indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
Add tests for %(symref) and %(symref:short) while we're here.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 2 +-
t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/ref-filter.c b/ref-filter.c
index 0e6ab75..ab860a3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -323,7 +323,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
valid_atom[i].parser(&used_atom[at], arg);
if (*atom == '*')
need_tagged = 1;
- if (!strcmp(used_atom[at].name, "symref"))
+ if (starts_with(used_atom[at].name, "symref"))
need_symref = 1;
return at;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 2c5f177..b06ea1c 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -38,6 +38,7 @@ test_atom() {
case "$1" in
head) ref=refs/heads/master ;;
tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
*) ref=$1 ;;
esac
printf '%s\n' "$3" >expected
@@ -565,4 +566,27 @@ test_expect_success 'Verify sort with multiple keys' '
refs/tags/bogo refs/tags/master > actual &&
test_cmp expected actual
'
+
+test_expect_success 'Add symbolic ref for the following tests' '
+ git symbolic-ref refs/heads/sym refs/heads/master
+'
+
+cat >expected <<EOF
+refs/heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref) atom' '
+ git for-each-ref --format="%(symref)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref:short) atom' '
+ git for-each-ref --format="%(symref:short)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 09/15] ref-filter: introduce symref_atom_parser()
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (7 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 10/15] ref-filter: introduce refname_atom_parser() Karthik Nayak
` (5 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak
Introduce symref_atom_parser() which will parse the '%(symref)' atom and
store information into the 'used_atom' structure based on the modifiers
used along with the atom.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index ab860a3..59eb280 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -58,6 +58,7 @@ static struct used_atom {
enum { O_FULL, O_LENGTH, O_SHORT } option;
unsigned int length;
} objectname;
+ enum { S_FULL, S_SHORT } symref;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -201,6 +202,16 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
string_list_clear(¶ms, 0);
}
+static void symref_atom_parser(struct used_atom *atom, const char *arg)
+{
+ if (!arg)
+ atom->u.symref = S_FULL;
+ else if (!strcmp(arg, "short"))
+ atom->u.symref = S_SHORT;
+ else
+ die(_("unrecognized %%(symref) argument: %s"), arg);
+}
+
static struct {
const char *name;
cmp_type cmp_type;
@@ -235,7 +246,7 @@ static struct {
{ "contents", FIELD_STR, contents_atom_parser },
{ "upstream", FIELD_STR, remote_ref_atom_parser },
{ "push", FIELD_STR, remote_ref_atom_parser },
- { "symref" },
+ { "symref", FIELD_STR, symref_atom_parser },
{ "flag" },
{ "HEAD" },
{ "color", FIELD_STR, color_atom_parser },
@@ -1122,6 +1133,17 @@ char *get_head_description(void)
return strbuf_detach(&desc, NULL);
}
+static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref)
+{
+ if (!ref->symref)
+ return "";
+ else if (atom->u.symref == S_SHORT)
+ return shorten_unambiguous_ref(ref->symref,
+ warn_ambiguous_refs);
+ else
+ return ref->symref;
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1165,7 +1187,7 @@ static void populate_value(struct ref_array_item *ref)
if (ref->kind & FILTER_REFS_DETACHED_HEAD)
refname = get_head_description();
} else if (starts_with(name, "symref"))
- refname = ref->symref ? ref->symref : "";
+ refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
/* only local branches may have an upstream */
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 10/15] ref-filter: introduce refname_atom_parser()
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (8 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 09/15] ref-filter: introduce symref_atom_parser() Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 11/15] ref-filter: add support for %(refname:dir) and %(refname:base) Karthik Nayak
` (4 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak
Introduce refname_atom_parser() which will parse the '%(refname)' atom
and store information into the 'used_atom' structure based on the
modifiers used along with the atom.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 70 +++++++++++++++++++++++++++++++++---------------------------
1 file changed, 39 insertions(+), 31 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 59eb280..2393800 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -59,6 +59,10 @@ static struct used_atom {
unsigned int length;
} objectname;
enum { S_FULL, S_SHORT } symref;
+ struct {
+ enum { R_NORMAL, R_SHORT, R_STRIP } option;
+ unsigned int strip;
+ } refname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -212,12 +216,27 @@ static void symref_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(symref) argument: %s"), arg);
}
+static void refname_atom_parser(struct used_atom *atom, const char *arg)
+{
+ if (!arg)
+ atom->u.refname.option = R_NORMAL;
+ else if (!strcmp(arg, "short"))
+ atom->u.refname.option = R_SHORT;
+ else if (skip_prefix(arg, "strip=", &arg)) {
+ atom->u.contents.option = R_STRIP;
+ if (strtoul_ui(arg, 10, &atom->u.refname.strip) ||
+ atom->u.refname.strip <= 0)
+ die(_("positive value expected refname:strip=%s"), arg);
+ } else
+ die(_("unrecognized %%(refname) argument: %s"), arg);
+}
+
static struct {
const char *name;
cmp_type cmp_type;
void (*parser)(struct used_atom *atom, const char *arg);
} valid_atom[] = {
- { "refname" },
+ { "refname", FIELD_STR, refname_atom_parser },
{ "objecttype" },
{ "objectsize", FIELD_ULONG },
{ "objectname", FIELD_STR, objectname_atom_parser },
@@ -1038,21 +1057,16 @@ static inline char *copy_advance(char *dst, const char *src)
return dst;
}
-static const char *strip_ref_components(const char *refname, const char *nr_arg)
+static const char *strip_ref_components(const char *refname, unsigned int len)
{
- char *end;
- long nr = strtol(nr_arg, &end, 10);
- long remaining = nr;
+ long remaining = len;
const char *start = refname;
- if (nr < 1 || *end != '\0')
- die(_(":strip= requires a positive integer argument"));
-
while (remaining) {
switch (*start++) {
case '\0':
- die(_("ref '%s' does not have %ld components to :strip"),
- refname, nr);
+ die("ref '%s' does not have %ud components to :strip",
+ refname, len);
case '/':
remaining--;
break;
@@ -1144,6 +1158,18 @@ static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref
return ref->symref;
}
+static const char *get_refname(struct used_atom *atom, struct ref_array_item *ref)
+{
+ if (ref->kind & FILTER_REFS_DETACHED_HEAD)
+ return get_head_description();
+ if (atom->u.refname.option == R_SHORT)
+ return shorten_unambiguous_ref(ref->refname, warn_ambiguous_refs);
+ else if (atom->u.refname.option == R_STRIP)
+ return strip_ref_components(ref->refname, atom->u.refname.strip);
+ else
+ return ref->refname;
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1172,7 +1198,6 @@ static void populate_value(struct ref_array_item *ref)
struct atom_value *v = &ref->value[i];
int deref = 0;
const char *refname;
- const char *formatp;
struct branch *branch = NULL;
v->handler = append_atom;
@@ -1182,11 +1207,9 @@ static void populate_value(struct ref_array_item *ref)
name++;
}
- if (starts_with(name, "refname")) {
- refname = ref->refname;
- if (ref->kind & FILTER_REFS_DETACHED_HEAD)
- refname = get_head_description();
- } else if (starts_with(name, "symref"))
+ if (starts_with(name, "refname"))
+ refname = get_refname(atom, ref);
+ else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
@@ -1264,21 +1287,6 @@ static void populate_value(struct ref_array_item *ref)
} else
continue;
- formatp = strchr(name, ':');
- if (formatp) {
- const char *arg;
-
- formatp++;
- if (!strcmp(formatp, "short"))
- refname = shorten_unambiguous_ref(refname,
- warn_ambiguous_refs);
- else if (skip_prefix(formatp, "strip=", &arg))
- refname = strip_ref_components(refname, arg);
- else
- die(_("unknown %.*s format %s"),
- (int)(formatp - name), name, formatp);
- }
-
if (!deref)
v->s = refname;
else
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 11/15] ref-filter: add support for %(refname:dir) and %(refname:base)
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (9 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 10/15] ref-filter: introduce refname_atom_parser() Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 12/15] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
` (3 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak
Add the options `:dir` and `:base` to the %(refname) atom. The `:dir`
option gives the directory (the part after $GIT_DIR/) of the ref without
the refname. The `:base` option gives the base directory of the given
ref (i.e. the directory following $GIT_DIR/refs/).
Add tests and documentation for the same.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 4 +++-
ref-filter.c | 28 +++++++++++++++++++++++++---
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 0658c3f..193e99e 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -96,7 +96,9 @@ refname::
slash-separated path components from the front of the refname
(e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`.
`<N>` must be a positive integer. If a displayed ref has fewer
- components than `<N>`, the command aborts with an error.
+ components than `<N>`, the command aborts with an error. For the base
+ directory of the ref (i.e. foo in refs/foo/bar/boz) append
+ `:base`. For the entire directory path append `:dir`.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/ref-filter.c b/ref-filter.c
index 2393800..45f9d16 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -60,7 +60,7 @@ static struct used_atom {
} objectname;
enum { S_FULL, S_SHORT } symref;
struct {
- enum { R_NORMAL, R_SHORT, R_STRIP } option;
+ enum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;
unsigned int strip;
} refname;
} u;
@@ -227,7 +227,11 @@ static void refname_atom_parser(struct used_atom *atom, const char *arg)
if (strtoul_ui(arg, 10, &atom->u.refname.strip) ||
atom->u.refname.strip <= 0)
die(_("positive value expected refname:strip=%s"), arg);
- } else
+ } else if (!strcmp(arg, "dir"))
+ atom->u.contents.option = R_DIR;
+ else if (!strcmp(arg, "base"))
+ atom->u.contents.option = R_BASE;
+ else
die(_("unrecognized %%(refname) argument: %s"), arg);
}
@@ -1166,7 +1170,25 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re
return shorten_unambiguous_ref(ref->refname, warn_ambiguous_refs);
else if (atom->u.refname.option == R_STRIP)
return strip_ref_components(ref->refname, atom->u.refname.strip);
- else
+ else if (atom->u.refname.option == R_BASE) {
+ const char *sp, *ep;
+
+ if (skip_prefix(ref->refname, "refs/", &sp)) {
+ ep = strchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ }
+ return "";
+ } else if (atom->u.refname.option == R_DIR) {
+ const char *sp, *ep;
+
+ sp = ref->refname;
+ ep = strrchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ } else
return ref->refname;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index b06ea1c..36d32d7 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -53,6 +53,8 @@ test_atom head refname refs/heads/master
test_atom head refname:short master
test_atom head refname:strip=1 heads/master
test_atom head refname:strip=2 master
+test_atom head refname:dir refs/heads
+test_atom head refname:base heads
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
test_atom head push refs/remotes/myfork/master
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 12/15] ref-filter: allow porcelain to translate messages in the output
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (10 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 11/15] ref-filter: add support for %(refname:dir) and %(refname:base) Karthik Nayak
@ 2016-03-06 12:04 ` Karthik Nayak
2016-03-06 12:05 ` [PATCH 13/15] branch, tag: use porcelain output Karthik Nayak
` (2 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:04 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Introduce setup_ref_filter_porcelain_msg() so that the messages used in
the atom %(upstream:track) can be translated if needed. This is needed
as we port branch.c to use ref-filter's printing API's.
Written-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 28 ++++++++++++++++++++++++----
ref-filter.h | 2 ++
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 45f9d16..76ea7c3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -15,6 +15,26 @@
#include "version.h"
#include "wt-status.h"
+static struct ref_msg {
+ const char *gone;
+ const char *ahead;
+ const char *behind;
+ const char *ahead_behind;
+} msgs = {
+ "gone",
+ "ahead %d",
+ "behind %d",
+ "ahead %d, behind %d"
+};
+
+void setup_ref_filter_porcelain_msg(void)
+{
+ msgs.gone = _("gone");
+ msgs.ahead = _("ahead %d");
+ msgs.behind = _("behind %d");
+ msgs.ahead_behind = _("ahead %d, behind %d");
+}
+
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
struct align {
@@ -1088,15 +1108,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
- *s = xstrdup("gone");
+ *s = xstrdup(msgs.gone);
} else if (!num_ours && !num_theirs)
*s = "";
else if (!num_ours)
- *s = xstrfmt("behind %d", num_theirs);
+ *s = xstrfmt(msgs.behind, num_theirs);
else if (!num_theirs)
- *s = xstrfmt("ahead %d", num_ours);
+ *s = xstrfmt(msgs.ahead, num_ours);
else
- *s = xstrfmt("ahead %d, behind %d",
+ *s = xstrfmt(msgs.ahead_behind,
num_ours, num_theirs);
if (!atom->u.remote_ref.nobracket && *s[0]) {
const char *to_free = *s;
diff --git a/ref-filter.h b/ref-filter.h
index 0014b92..da17145 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -111,5 +111,7 @@ struct ref_sorting *ref_default_sorting(void);
int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);
/* Get the current HEAD's description */
char *get_head_description(void);
+/* Set up translated strings in the output. */
+void setup_ref_filter_porcelain_msg(void);
#endif /* REF_FILTER_H */
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 13/15] branch, tag: use porcelain output
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (11 preceding siblings ...)
2016-03-06 12:04 ` [PATCH 12/15] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
@ 2016-03-06 12:05 ` Karthik Nayak
2016-03-06 12:05 ` [PATCH 14/15] branch: use ref-filter printing APIs Karthik Nayak
2016-03-06 12:05 ` [PATCH 15/15] branch: implement '--format' option Karthik Nayak
14 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:05 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Call ref-filter's setup_ref_filter_porcelain_msg() to enable
translated messages for the %(upstream:tack) atom. Although branch.c
doesn't currently use ref-filter's printing API's, this will ensure
that when it does in the future patches, we do not need to worry about
translation.
Written-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 2 ++
builtin/tag.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/builtin/branch.c b/builtin/branch.c
index 460f32f..8747d82 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -622,6 +622,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_ref_filter_porcelain_msg();
+
memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;
diff --git a/builtin/tag.c b/builtin/tag.c
index 1705c94..82a04ed 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -373,6 +373,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ setup_ref_filter_porcelain_msg();
+
git_config(git_tag_config, sorting_tail);
memset(&opt, 0, sizeof(opt));
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 14/15] branch: use ref-filter printing APIs
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (12 preceding siblings ...)
2016-03-06 12:05 ` [PATCH 13/15] branch, tag: use porcelain output Karthik Nayak
@ 2016-03-06 12:05 ` Karthik Nayak
2016-03-07 23:11 ` Junio C Hamano
2016-03-06 12:05 ` [PATCH 15/15] branch: implement '--format' option Karthik Nayak
14 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:05 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
Port branch.c to use ref-filter APIs for printing. This clears out
most of the code used in branch.c for printing and replaces them with
calls made to the ref-filter library.
Introduce build_format() which gets the format required for printing
of refs. Make amendments to print_ref_list() to reflect these changes.
Change calc_maxwidth() to also account for the length of HEAD ref, by
calling ref-filter:get_head_discription().
Also change the test in t6040 to reflect the changes.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 226 ++++++++++++++---------------------------------
t/t6040-tracking-info.sh | 2 +-
2 files changed, 66 insertions(+), 162 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 8747d82..29cd206 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -35,12 +35,12 @@ static unsigned char head_sha1[20];
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
- GIT_COLOR_RESET,
- GIT_COLOR_NORMAL, /* PLAIN */
- GIT_COLOR_RED, /* REMOTE */
- GIT_COLOR_NORMAL, /* LOCAL */
- GIT_COLOR_GREEN, /* CURRENT */
- GIT_COLOR_BLUE, /* UPSTREAM */
+ "%(color:reset)",
+ "%(color:reset)", /* PLAIN */
+ "%(color:red)", /* REMOTE */
+ "%(color:reset)", /* LOCAL */
+ "%(color:green)", /* CURRENT */
+ "%(color:blue)", /* UPSTREAM */
};
enum color_branch {
BRANCH_COLOR_RESET = 0,
@@ -271,157 +271,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
return(ret);
}
-static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
- int show_upstream_ref)
-{
- int ours, theirs;
- char *ref = NULL;
- struct branch *branch = branch_get(branch_name);
- const char *upstream;
- struct strbuf fancy = STRBUF_INIT;
- int upstream_is_gone = 0;
- int added_decoration = 1;
-
- if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {
- if (!upstream)
- return;
- upstream_is_gone = 1;
- }
-
- if (show_upstream_ref) {
- ref = shorten_unambiguous_ref(upstream, 0);
- if (want_color(branch_use_color))
- strbuf_addf(&fancy, "%s%s%s",
- branch_get_color(BRANCH_COLOR_UPSTREAM),
- ref, branch_get_color(BRANCH_COLOR_RESET));
- else
- strbuf_addstr(&fancy, ref);
- }
-
- if (upstream_is_gone) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours && !theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
- else
- strbuf_addf(stat, _("[behind %d]"), theirs);
-
- } else if (!theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
- else
- strbuf_addf(stat, _("[ahead %d]"), ours);
- } else {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
- fancy.buf, ours, theirs);
- else
- strbuf_addf(stat, _("[ahead %d, behind %d]"),
- ours, theirs);
- }
- strbuf_release(&fancy);
- if (added_decoration)
- strbuf_addch(stat, ' ');
- free(ref);
-}
-
-static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
- struct ref_filter *filter, const char *refname)
-{
- struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
- const char *sub = _(" **** invalid ref ****");
- struct commit *commit = item->commit;
-
- if (!parse_commit(commit)) {
- pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
- sub = subject.buf;
- }
-
- if (item->kind == FILTER_REFS_BRANCHES)
- fill_tracking_info(&stat, refname, filter->verbose > 1);
-
- strbuf_addf(out, " %s %s%s",
- find_unique_abbrev(item->commit->object.oid.hash, filter->abbrev),
- stat.buf, sub);
- strbuf_release(&stat);
- strbuf_release(&subject);
-}
-
-static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
- struct ref_filter *filter, const char *remote_prefix)
-{
- char c;
- int current = 0;
- int color;
- struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
- const char *prefix = "";
- const char *desc = item->refname;
- char *to_free = NULL;
-
- switch (item->kind) {
- case FILTER_REFS_BRANCHES:
- skip_prefix(desc, "refs/heads/", &desc);
- if (!filter->detached && !strcmp(desc, head))
- current = 1;
- else
- color = BRANCH_COLOR_LOCAL;
- break;
- case FILTER_REFS_REMOTES:
- skip_prefix(desc, "refs/remotes/", &desc);
- color = BRANCH_COLOR_REMOTE;
- prefix = remote_prefix;
- break;
- case FILTER_REFS_DETACHED_HEAD:
- desc = to_free = get_head_description();
- current = 1;
- break;
- default:
- color = BRANCH_COLOR_PLAIN;
- break;
- }
-
- c = ' ';
- if (current) {
- c = '*';
- color = BRANCH_COLOR_CURRENT;
- }
-
- strbuf_addf(&name, "%s%s", prefix, desc);
- if (filter->verbose) {
- int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
- strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
- maxwidth + utf8_compensation, name.buf,
- branch_get_color(BRANCH_COLOR_RESET));
- } else
- strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
- name.buf, branch_get_color(BRANCH_COLOR_RESET));
-
- if (item->symref) {
- skip_prefix(item->symref, "refs/remotes/", &desc);
- strbuf_addf(&out, " -> %s", desc);
- }
- else if (filter->verbose)
- /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
- add_verbose_info(&out, item, filter, desc);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- string_list_append(&output, out.buf);
- } else {
- printf("%s\n", out.buf);
- }
- strbuf_release(&name);
- strbuf_release(&out);
- free(to_free);
-}
-
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
{
int i, max = 0;
@@ -432,7 +281,10 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
skip_prefix(it->refname, "refs/heads/", &desc);
skip_prefix(it->refname, "refs/remotes/", &desc);
- w = utf8_strwidth(desc);
+ if (it->kind == FILTER_REFS_DETACHED_HEAD)
+ w = strlen(get_head_description());
+ else
+ w = utf8_strwidth(desc);
if (it->kind == FILTER_REFS_REMOTES)
w += remote_bonus;
@@ -442,12 +294,51 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
return max;
}
+static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
+{
+ struct strbuf fmt = STRBUF_INIT;
+ struct strbuf local = STRBUF_INIT;
+ struct strbuf remote = STRBUF_INIT;
+
+ strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)", branch_get_color(BRANCH_COLOR_CURRENT));
+
+ if (filter->verbose) {
+ strbuf_addf(&local, "%%(align:%d,left)%%(refname:strip=2)%%(end)", maxwidth);
+ strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&local, " %%(objectname:short=7) ");
+
+ if (filter->verbose > 1)
+ strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
+ "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
+ branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
+
+ strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:strip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)"
+ "%%(else) %%(objectname:short=7) %%(contents:subject)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), maxwidth,
+ remote_prefix, branch_get_color(BRANCH_COLOR_RESET));
+ } else {
+ strbuf_addf(&local, "%%(refname:strip=2)%s", branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&remote, "%s%s%%(refname:strip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), remote_prefix, branch_get_color(BRANCH_COLOR_RESET));
+ }
+
+ strbuf_addf(&fmt, "%%(if:notequals=remotes)%%(refname:base)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
+
+ strbuf_release(&local);
+ strbuf_release(&remote);
+ return strbuf_detach(&fmt, NULL);
+}
+
static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
{
int i;
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
+ struct strbuf out = STRBUF_INIT;
+ char *format;
/*
* If we are listing more than just remote branches,
@@ -459,12 +350,14 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
memset(&array, 0, sizeof(array));
- verify_ref_format("%(refname)%(symref)");
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
if (filter->verbose)
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
+ format = build_format(filter, maxwidth, remote_prefix);
+ verify_ref_format(format);
+
/*
* If no sorting parameter is given then we default to sorting
* by 'refname'. This would give us an alphabetically sorted
@@ -476,10 +369,21 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
sorting = ref_default_sorting();
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++)
- format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
+ for (i = 0; i < array.nr; i++) {
+ format_ref_array_item(array.items[i], format, 0, &out);
+ if (column_active(colopts)) {
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+ /* format to a string_list to let print_columns() do its job */
+ string_list_append(&output, out.buf);
+ } else {
+ fwrite(out.buf, 1, out.len, stdout);
+ putchar('\n');
+ }
+ strbuf_release(&out);
+ }
ref_array_clear(&array);
+ free(format);
}
static void rename_branch(const char *oldname, const char *newname, int force)
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 3d5c238..97a0765 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
b2 [ahead 1, behind 1] d
b3 [behind 1] b
b4 [ahead 2] f
-b5 g
+b5 [gone] g
b6 c
EOF
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 15/15] branch: implement '--format' option
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
` (13 preceding siblings ...)
2016-03-06 12:05 ` [PATCH 14/15] branch: use ref-filter printing APIs Karthik Nayak
@ 2016-03-06 12:05 ` Karthik Nayak
2016-03-08 1:58 ` Jacob Keller
14 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-06 12:05 UTC (permalink / raw)
To: git; +Cc: gitster, Karthik Nayak, Karthik Nayak
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 <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-branch.txt | 7 ++++++-
builtin/branch.c | 14 +++++++++-----
t/t3203-branch-output.sh | 12 ++++++++++++
3 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 4a7037f..8af132f 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[--list] [-v [--abbrev=<length> | --no-abbrev]]
[--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]
- [--points-at <object>] [<pattern>...]
+ [--points-at <object>] [--format=<format>] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
'git branch' --unset-upstream [<branchname>]
@@ -246,6 +246,11 @@ start-point is either a local or remote-tracking branch.
--points-at <object>::
Only list branches of the given object.
+--format <format>::
+ A string that interpolates `%(fieldname)` from the object
+ pointed at by a ref being shown. The format is the same as
+ that of linkgit:git-for-each-ref[1].
+
Examples
--------
diff --git a/builtin/branch.c b/builtin/branch.c
index 29cd206..fb05b39 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -27,6 +27,7 @@ static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
N_("git branch [<options>] [-r | -a] [--points-at]"),
+ N_("git branch [<options>] [-r | -a] [--format]"),
NULL
};
@@ -331,14 +332,14 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
return strbuf_detach(&fmt, NULL);
}
-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
{
int i;
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
struct strbuf out = STRBUF_INIT;
- char *format;
+ char *to_free = NULL;
/*
* If we are listing more than just remote branches,
@@ -355,7 +356,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
if (filter->verbose)
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
- format = build_format(filter, maxwidth, remote_prefix);
+ if (!format)
+ format = to_free = build_format(filter, maxwidth, remote_prefix);
verify_ref_format(format);
/*
@@ -383,7 +385,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
}
ref_array_clear(&array);
- free(format);
+ free(to_free);
}
static void rename_branch(const char *oldname, const char *newname, int force)
@@ -483,6 +485,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
enum branch_track track;
struct ref_filter filter;
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
+ const char *format = NULL;
struct option options[] = {
OPT_GROUP(N_("Generic options")),
@@ -523,6 +526,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
N_("print only branches of the object"), 0, parse_opt_object_name
},
+ OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
OPT_END(),
};
@@ -583,7 +587,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
filter.kind |= FILTER_REFS_DETACHED_HEAD;
filter.name_patterns = argv;
- print_ref_list(&filter, sorting);
+ print_ref_list(&filter, sorting, format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
return 0;
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 4261403..c33a3f3 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -184,4 +184,16 @@ test_expect_success 'ambiguous branch/tag not marked' '
test_cmp expect actual
'
+test_expect_success 'git branch --format option' '
+ cat >expect <<-\EOF &&
+ Refname is (HEAD detached from fromtag)
+ Refname is refs/heads/ambiguous
+ Refname is refs/heads/branch-one
+ Refname is refs/heads/branch-two
+ Refname is refs/heads/master
+ EOF
+ git branch --format="Refname is %(refname)" >actual &&
+ test_cmp expect actual
+'
+
test_done
--
2.7.2
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-03-06 12:04 ` [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
@ 2016-03-07 22:49 ` Junio C Hamano
2016-03-08 5:41 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Junio C Hamano @ 2016-03-07 22:49 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git
Karthik Nayak <karthik.188@gmail.com> writes:
> diff --git a/ref-filter.c b/ref-filter.c
> index 41e73f0..440e270 100644
> --- a/ref-filter.c
> +++ b/ref-filter.c
> @@ -22,6 +22,8 @@ struct align {
> };
>
> struct if_then_else {
> + const char *if_equals,
> + *not_equals;
> unsigned int then_atom_seen : 1,
> else_atom_seen : 1,
> condition_satisfied : 1;
> @@ -411,6 +413,14 @@ static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
> {
> struct ref_formatting_stack *new;
> struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
> + const char *valp;
> +
> + if (skip_prefix(atomv->s, "equals=", &valp))
> + if_then_else->if_equals = valp;
> + else if (skip_prefix(atomv->s, "notequals=", &valp))
> + if_then_else->not_equals = valp;
> + else if (atomv->s[0])
> + die(_("format: unknown format if:%s"), atomv->s);
>
> push_stack_element(&state->stack);
> new = state->stack;
The fact that you are pushing stack element here tells me that this
"handler" is run once for each 'ref' that we prepare output for
(i.e. unlike the helper functions called "parser" that are called
only once while preparing used_atom[] array).
It somehow feels that this goes against the overall design you did
in the earlier topic to pre-parse as much as possible when you
prepare the used_atom array and avoid parsing at the runtime. Am I
misreading the patch?
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-06 12:04 ` [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
@ 2016-03-07 23:08 ` Junio C Hamano
2016-03-08 1:56 ` Jacob Keller
0 siblings, 1 reply; 30+ messages in thread
From: Junio C Hamano @ 2016-03-07 23:08 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git
Karthik Nayak <karthik.188@gmail.com> writes:
> The "%(symref)" atom doesn't work when used with the ':short' modifier
> because we strictly match only 'symref' for setting the 'need_symref'
> indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
Does that mean you also accept %(symrefgarbage) without complaining?
>
> Add tests for %(symref) and %(symref:short) while we're here.
>
> Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
> ---
> ref-filter.c | 2 +-
> t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++
> 2 files changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/ref-filter.c b/ref-filter.c
> index 0e6ab75..ab860a3 100644
> --- a/ref-filter.c
> +++ b/ref-filter.c
> @@ -323,7 +323,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
> valid_atom[i].parser(&used_atom[at], arg);
> if (*atom == '*')
> need_tagged = 1;
> - if (!strcmp(used_atom[at].name, "symref"))
> + if (starts_with(used_atom[at].name, "symref"))
> need_symref = 1;
> return at;
> }
> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
> index 2c5f177..b06ea1c 100755
> --- a/t/t6300-for-each-ref.sh
> +++ b/t/t6300-for-each-ref.sh
> @@ -38,6 +38,7 @@ test_atom() {
> case "$1" in
> head) ref=refs/heads/master ;;
> tag) ref=refs/tags/testtag ;;
> + sym) ref=refs/heads/sym ;;
> *) ref=$1 ;;
> esac
> printf '%s\n' "$3" >expected
> @@ -565,4 +566,27 @@ test_expect_success 'Verify sort with multiple keys' '
> refs/tags/bogo refs/tags/master > actual &&
> test_cmp expected actual
> '
> +
> +test_expect_success 'Add symbolic ref for the following tests' '
> + git symbolic-ref refs/heads/sym refs/heads/master
> +'
> +
> +cat >expected <<EOF
> +refs/heads/master
> +EOF
> +
> +test_expect_success 'Verify usage of %(symref) atom' '
> + git for-each-ref --format="%(symref)" refs/heads/sym > actual &&
> + test_cmp expected actual
> +'
> +
> +cat >expected <<EOF
> +heads/master
> +EOF
> +
> +test_expect_success 'Verify usage of %(symref:short) atom' '
> + git for-each-ref --format="%(symref:short)" refs/heads/sym > actual &&
> + test_cmp expected actual
> +'
> +
> test_done
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 14/15] branch: use ref-filter printing APIs
2016-03-06 12:05 ` [PATCH 14/15] branch: use ref-filter printing APIs Karthik Nayak
@ 2016-03-07 23:11 ` Junio C Hamano
0 siblings, 0 replies; 30+ messages in thread
From: Junio C Hamano @ 2016-03-07 23:11 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git
Karthik Nayak <karthik.188@gmail.com> writes:
> Port branch.c to use ref-filter APIs for printing. This clears out
> most of the code used in branch.c for printing and replaces them with
> calls made to the ref-filter library.
>
> Introduce build_format() which gets the format required for printing
> of refs. Make amendments to print_ref_list() to reflect these changes.
>
> Change calc_maxwidth() to also account for the length of HEAD ref, by
> calling ref-filter:get_head_discription().
>
> Also change the test in t6040 to reflect the changes.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
> ---
> builtin/branch.c | 226 ++++++++++++++---------------------------------
> t/t6040-tracking-info.sh | 2 +-
> 2 files changed, 66 insertions(+), 162 deletions(-)
Nice reduction of the code ;-)
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams
2016-03-06 12:04 ` [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
@ 2016-03-08 1:55 ` Jacob Keller
2016-03-08 6:10 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Jacob Keller @ 2016-03-08 1:55 UTC (permalink / raw)
To: Karthik Nayak; +Cc: Git mailing list, Junio C Hamano
On Sun, Mar 6, 2016 at 4:04 AM, Karthik Nayak <karthik.188@gmail.com> wrote:
> Borrowing from branch.c's implementation print "[gone]" whenever an
> unknown upstream ref is encountered instead of just ignoring it.
>
> This makes sure that when branch.c is ported over to using ref-filter
> APIs for printing, this feature is not lost.
>
> Make changes to t/t6300-for-each-ref.sh to reflect this change.
>
Shouldn't this be documented as well?
Thanks,
Jake
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-07 23:08 ` Junio C Hamano
@ 2016-03-08 1:56 ` Jacob Keller
2016-03-08 6:21 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Jacob Keller @ 2016-03-08 1:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Karthik Nayak, Git mailing list
On Mon, Mar 7, 2016 at 3:08 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> The "%(symref)" atom doesn't work when used with the ':short' modifier
>> because we strictly match only 'symref' for setting the 'need_symref'
>> indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
>
> Does that mean you also accept %(symrefgarbage) without complaining?
>
>
Looks like patch 9 fixes this by introducing symref_atom_parser.
Regards,
Jake
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 15/15] branch: implement '--format' option
2016-03-06 12:05 ` [PATCH 15/15] branch: implement '--format' option Karthik Nayak
@ 2016-03-08 1:58 ` Jacob Keller
2016-03-15 16:38 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Jacob Keller @ 2016-03-08 1:58 UTC (permalink / raw)
To: Karthik Nayak; +Cc: Git mailing list, Junio C Hamano
On Sun, Mar 6, 2016 at 4:05 AM, Karthik Nayak <karthik.188@gmail.com> wrote:
> 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'.
>
s/tags/branches/ maybe?
Thanks,
Jake
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-03-07 22:49 ` Junio C Hamano
@ 2016-03-08 5:41 ` Karthik Nayak
2016-03-08 6:04 ` Junio C Hamano
0 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-08 5:41 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git
On Tue, Mar 8, 2016 at 4:19 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> diff --git a/ref-filter.c b/ref-filter.c
>> index 41e73f0..440e270 100644
>> --- a/ref-filter.c
>> +++ b/ref-filter.c
>> @@ -22,6 +22,8 @@ struct align {
>> };
>>
>> struct if_then_else {
>> + const char *if_equals,
>> + *not_equals;
>> unsigned int then_atom_seen : 1,
>> else_atom_seen : 1,
>> condition_satisfied : 1;
>> @@ -411,6 +413,14 @@ static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
>> {
>> struct ref_formatting_stack *new;
>> struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
>> + const char *valp;
>> +
>> + if (skip_prefix(atomv->s, "equals=", &valp))
>> + if_then_else->if_equals = valp;
>> + else if (skip_prefix(atomv->s, "notequals=", &valp))
>> + if_then_else->not_equals = valp;
>> + else if (atomv->s[0])
>> + die(_("format: unknown format if:%s"), atomv->s);
>>
>> push_stack_element(&state->stack);
>> new = state->stack;
>
> The fact that you are pushing stack element here tells me that this
> "handler" is run once for each 'ref' that we prepare output for
> (i.e. unlike the helper functions called "parser" that are called
> only once while preparing used_atom[] array).
>
> It somehow feels that this goes against the overall design you did
> in the earlier topic to pre-parse as much as possible when you
> prepare the used_atom array and avoid parsing at the runtime. Am I
> misreading the patch?
You're correct, the "handler" functions run once for each "ref". But WRT
to the %(if)...%(then)...%(else)...%(end) atoms, it needs to be. Because
each outcome of these atoms depend on the current outcome of the fields
used between then WRT to the current ref.
Although we could somehow go about parsing the "equals=" / " notequals="
part of the %(if) atom beforehand to ensure that we do not end up repeating
that each time for every atom.
This could be done by parsing the %(if) atom before hand, probably with a
if_atom_parser, storing the "equals=" / " notequals=" value into used_atom[i]
and providing this used_atom[i] to the if_atom_handler. This would require
extending the prototype of the 'handler' functions to also pass used_atom[i].
Which seems like a good thing, considering that this may enable future 'handler'
functions to follow the same route and parse whatever can be parsed beforehand.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-03-08 5:41 ` Karthik Nayak
@ 2016-03-08 6:04 ` Junio C Hamano
2016-03-08 6:09 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Junio C Hamano @ 2016-03-08 6:04 UTC (permalink / raw)
To: Karthik Nayak; +Cc: Git
On Mon, Mar 7, 2016 at 9:41 PM, Karthik Nayak <karthik.188@gmail.com> wrote:
>
> You're correct, the "handler" functions run once for each "ref". But WRT
> to the %(if)...%(then)...%(else)...%(end) atoms, it needs to be. Because
> each outcome of these atoms depend on the current outcome of the fields
> used between then WRT to the current ref.
Yeah, there is no argument against that part at all. My comment was purely
about preparsing the if_equals field. All other fields are preparsed in *parse()
helper functions and it looked strange that only these two are scanned in the
handle() function every time it is evaluated for each ref, only to yield the
same result.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-03-08 6:04 ` Junio C Hamano
@ 2016-03-08 6:09 ` Karthik Nayak
0 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-08 6:09 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git
On Tue, Mar 8, 2016 at 11:34 AM, Junio C Hamano <gitster@pobox.com> wrote:
> On Mon, Mar 7, 2016 at 9:41 PM, Karthik Nayak <karthik.188@gmail.com> wrote:
>>
>> You're correct, the "handler" functions run once for each "ref". But WRT
>> to the %(if)...%(then)...%(else)...%(end) atoms, it needs to be. Because
>> each outcome of these atoms depend on the current outcome of the fields
>> used between then WRT to the current ref.
>
> Yeah, there is no argument against that part at all. My comment was purely
> about preparsing the if_equals field. All other fields are preparsed in *parse()
> helper functions and it looked strange that only these two are scanned in the
> handle() function every time it is evaluated for each ref, only to yield the
> same result.
True, I definitely agree, will fix that in the next iteration, thanks.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams
2016-03-08 1:55 ` Jacob Keller
@ 2016-03-08 6:10 ` Karthik Nayak
0 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-08 6:10 UTC (permalink / raw)
To: Jacob Keller; +Cc: Git mailing list, Junio C Hamano
On Tue, Mar 8, 2016 at 7:25 AM, Jacob Keller <jacob.keller@gmail.com> wrote:
> On Sun, Mar 6, 2016 at 4:04 AM, Karthik Nayak <karthik.188@gmail.com> wrote:
>> Borrowing from branch.c's implementation print "[gone]" whenever an
>> unknown upstream ref is encountered instead of just ignoring it.
>>
>> This makes sure that when branch.c is ported over to using ref-filter
>> APIs for printing, this feature is not lost.
>>
>> Make changes to t/t6300-for-each-ref.sh to reflect this change.
>>
>
> Shouldn't this be documented as well?
>
> Thanks,
> Jake
Definitely! will add that in. Thanks.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-08 1:56 ` Jacob Keller
@ 2016-03-08 6:21 ` Karthik Nayak
2016-03-08 20:19 ` Junio C Hamano
0 siblings, 1 reply; 30+ messages in thread
From: Karthik Nayak @ 2016-03-08 6:21 UTC (permalink / raw)
To: Jacob Keller; +Cc: Junio C Hamano, Git mailing list
On Tue, Mar 8, 2016 at 7:26 AM, Jacob Keller <jacob.keller@gmail.com> wrote:
> On Mon, Mar 7, 2016 at 3:08 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> Karthik Nayak <karthik.188@gmail.com> writes:
>>
>>> The "%(symref)" atom doesn't work when used with the ':short' modifier
>>> because we strictly match only 'symref' for setting the 'need_symref'
>>> indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
>>
>> Does that mean you also accept %(symrefgarbage) without complaining?
>>
>>
>
> Looks like patch 9 fixes this by introducing symref_atom_parser.
>
There are two ways this kinda errors can occur:
1. %(symrefgarbage) : This is handled by parse_ref_filter_atom() which would
print a "fatal: unknown field name: symrefgarbage".
2. %(symref:garbage): This is handled by populate_value() which would print
a "fatal: unknown symref: format garbage".
Either ways we do not need to worry about this as existing code would handle
it. Also like Jacob mentioned Patch 09 would ensure this error checking would
happen within symref_atom_parser().
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-08 6:21 ` Karthik Nayak
@ 2016-03-08 20:19 ` Junio C Hamano
2016-03-09 11:17 ` Karthik Nayak
0 siblings, 1 reply; 30+ messages in thread
From: Junio C Hamano @ 2016-03-08 20:19 UTC (permalink / raw)
To: Karthik Nayak; +Cc: Jacob Keller, Git mailing list
Karthik Nayak <karthik.188@gmail.com> writes:
> On Tue, Mar 8, 2016 at 7:26 AM, Jacob Keller <jacob.keller@gmail.com> wrote:
>> On Mon, Mar 7, 2016 at 3:08 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>> Karthik Nayak <karthik.188@gmail.com> writes:
>>>
>>>> The "%(symref)" atom doesn't work when used with the ':short' modifier
>>>> because we strictly match only 'symref' for setting the 'need_symref'
>>>> indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
>>>
>>> Does that mean you also accept %(symrefgarbage) without complaining?
>>>
>>>
>>
>> Looks like patch 9 fixes this by introducing symref_atom_parser.
>>
>
> There are two ways this kinda errors can occur:
> 1. %(symrefgarbage) : This is handled by parse_ref_filter_atom() which would
> print a "fatal: unknown field name: symrefgarbage".
> 2. %(symref:garbage): This is handled by populate_value() which would print
> a "fatal: unknown symref: format garbage".
>
> Either ways we do not need to worry about this as existing code would handle
> it. Also like Jacob mentioned Patch 09 would ensure this error checking would
> happen within symref_atom_parser().
You forgot to mention that there is 3., which is that you just
closed the door for a new valid_atom[] that begins with substring
"symref" which does not need to flip need_symref on, I think.
You can check valid_atom[i].name with strcmp() to achieve what you
are trying to do here, instead of checking used_atom[at].name, and I
think that would be a cleaner way to avoid all three problems.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-03-08 20:19 ` Junio C Hamano
@ 2016-03-09 11:17 ` Karthik Nayak
0 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-09 11:17 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jacob Keller, Git mailing list
On Wed, Mar 9, 2016 at 1:49 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> On Tue, Mar 8, 2016 at 7:26 AM, Jacob Keller <jacob.keller@gmail.com> wrote:
>>> On Mon, Mar 7, 2016 at 3:08 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>>> Karthik Nayak <karthik.188@gmail.com> writes:
>>>>
>>>>> The "%(symref)" atom doesn't work when used with the ':short' modifier
>>>>> because we strictly match only 'symref' for setting the 'need_symref'
>>>>> indicator. Fix this by using 'starts_with()' rather than 'strcmp()'.
>>>>
>>>> Does that mean you also accept %(symrefgarbage) without complaining?
>>>>
>>>>
>>>
>>> Looks like patch 9 fixes this by introducing symref_atom_parser.
>>>
>>
>> There are two ways this kinda errors can occur:
>> 1. %(symrefgarbage) : This is handled by parse_ref_filter_atom() which would
>> print a "fatal: unknown field name: symrefgarbage".
>> 2. %(symref:garbage): This is handled by populate_value() which would print
>> a "fatal: unknown symref: format garbage".
>>
>> Either ways we do not need to worry about this as existing code would handle
>> it. Also like Jacob mentioned Patch 09 would ensure this error checking would
>> happen within symref_atom_parser().
>
> You forgot to mention that there is 3., which is that you just
> closed the door for a new valid_atom[] that begins with substring
> "symref" which does not need to flip need_symref on, I think.
>
> You can check valid_atom[i].name with strcmp() to achieve what you
> are trying to do here, instead of checking used_atom[at].name, and I
> think that would be a cleaner way to avoid all three problems.
That's actually a very good point, will incorporate that, thanks!
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 15/15] branch: implement '--format' option
2016-03-08 1:58 ` Jacob Keller
@ 2016-03-15 16:38 ` Karthik Nayak
0 siblings, 0 replies; 30+ messages in thread
From: Karthik Nayak @ 2016-03-15 16:38 UTC (permalink / raw)
To: Jacob Keller; +Cc: Git mailing list, Junio C Hamano
On Tue, Mar 8, 2016 at 7:28 AM, Jacob Keller <jacob.keller@gmail.com> wrote:
> On Sun, Mar 6, 2016 at 4:05 AM, Karthik Nayak <karthik.188@gmail.com> wrote:
>> 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'.
>>
>
> s/tags/branches/ maybe?
>
> Thanks,
> Jake
Copy-Paste error, will fix. Thank you.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2016-03-15 16:38 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-06 12:04 [PATCH 00/15] port branch.c to use ref-filter's printing options Karthik Nayak
2016-03-06 12:04 ` [PATCH 01/15] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
2016-03-06 12:04 ` [PATCH 02/15] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
2016-03-07 22:49 ` Junio C Hamano
2016-03-08 5:41 ` Karthik Nayak
2016-03-08 6:04 ` Junio C Hamano
2016-03-08 6:09 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 03/15] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
2016-03-06 12:04 ` [PATCH 04/15] ref-filter: move get_head_description() from branch.c Karthik Nayak
2016-03-06 12:04 ` [PATCH 05/15] ref-filter: introduce format_ref_array_item() Karthik Nayak
2016-03-06 12:04 ` [PATCH 06/15] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
2016-03-08 1:55 ` Jacob Keller
2016-03-08 6:10 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 07/15] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
2016-03-06 12:04 ` [PATCH 08/15] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
2016-03-07 23:08 ` Junio C Hamano
2016-03-08 1:56 ` Jacob Keller
2016-03-08 6:21 ` Karthik Nayak
2016-03-08 20:19 ` Junio C Hamano
2016-03-09 11:17 ` Karthik Nayak
2016-03-06 12:04 ` [PATCH 09/15] ref-filter: introduce symref_atom_parser() Karthik Nayak
2016-03-06 12:04 ` [PATCH 10/15] ref-filter: introduce refname_atom_parser() Karthik Nayak
2016-03-06 12:04 ` [PATCH 11/15] ref-filter: add support for %(refname:dir) and %(refname:base) Karthik Nayak
2016-03-06 12:04 ` [PATCH 12/15] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
2016-03-06 12:05 ` [PATCH 13/15] branch, tag: use porcelain output Karthik Nayak
2016-03-06 12:05 ` [PATCH 14/15] branch: use ref-filter printing APIs Karthik Nayak
2016-03-07 23:11 ` Junio C Hamano
2016-03-06 12:05 ` [PATCH 15/15] branch: implement '--format' option Karthik Nayak
2016-03-08 1:58 ` Jacob Keller
2016-03-15 16:38 ` Karthik Nayak
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).