* [PATCH v5b 00/17] port branch.c to use ref-filter's printing options
@ 2016-04-25 10:52 Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 01/17] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
` (17 more replies)
0 siblings, 18 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 10:52 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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).
v1 can be found here: $(gmane/288342)
v2 can be found here: $(gmane/288863)
v3 can be found here: $(gmane/290299)
v4 can be found here: $(gmane/291106)
Changes in this version (v5b):
1. Added the first patch of the series which was missing in v5.
Changes in v5:
1. Rebased on top of jk/branch-shortening-funny-symrefs ($gmane/291295).
2. Introduced refname_atom_parser_internal() to act as a common ground
for ref-printing atoms. Written by Jeff ($gmane/291497).
3. Ensure that ':dir', 'base', 'strip' is available to all ref-printing
atoms. Written by Jeff.
4. Fix a memory leak which was reported by Stefan ($gmane/291703).
Thanks to Junio, Jeff and Stefan for suggestions on the previous version.
Karthik Nayak (17):
ref-filter: implement %(if), %(then), and %(else) atoms
ref-filter: include reference to 'used_atom' within 'atom_value'
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 refname_atom_parser_internal()
ref-filter: introduce symref_atom_parser() and refname_atom_parser()
ref-filter: make remote_ref_atom_parser() use
refname_atom_parser_internal()
ref-filter: add `:dir` and `:base` options for ref printing atoms
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 | 87 +++++--
builtin/branch.c | 275 +++++++---------------
builtin/tag.c | 2 +
ref-filter.c | 456 +++++++++++++++++++++++++++++++------
ref-filter.h | 7 +
t/t3203-branch-output.sh | 16 +-
t/t6040-tracking-info.sh | 2 +-
t/t6300-for-each-ref.sh | 73 +++++-
t/t6302-for-each-ref-filter.sh | 94 ++++++++
10 files changed, 726 insertions(+), 293 deletions(-)
Interdiff:
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 0954269..4a5e9ea 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -116,21 +116,23 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` in the same way as
- `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). `:track` also prints "[gone]" whenever
- unknown upstream ref is encountered. 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.
+ from the displayed ref. Respects `:short`, `:strip`, `:base`
+ and `:dir` in the same way as `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). `:track`
+ also prints "[gone]" whenever unknown upstream ref is
+ encountered. 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
- for the displayed ref. Respects `:short`, `:track`, and
- `:trackshort` options as `upstream` does. Produces an empty
- string if no `@{push}` ref is configured.
+ The name of a local ref which represents the `@{push}`
+ location for the displayed ref. Respects `:short`, `:strip`,
+ `:track`, `:trackshort`, `:base` and `:dir` options as
+ `upstream` does. Produces an empty string if no `@{push}` ref
+ is configured.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
@@ -165,6 +167,12 @@ if::
the value between the %(if:...) and %(then) atoms with the
given string.
+symref::
+ The ref which the given symbolic ref refers to. If not a
+ symbolic ref, nothing is printed. Respects the `:short`,
+ `:strip`, `:base` and `:dir` options in the same way as
+ `refname` above.
+
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
diff --git a/builtin/branch.c b/builtin/branch.c
index c9a2e5b..6847ac3 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -288,9 +288,11 @@ 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);
- if (it->kind == FILTER_REFS_DETACHED_HEAD)
- w = strlen(get_head_description());
- else
+ if (it->kind == FILTER_REFS_DETACHED_HEAD) {
+ char *head_desc = get_head_description();
+ w = strlen(head_desc);
+ free(head_desc);
+ } else
w = utf8_strwidth(desc);
if (it->kind == FILTER_REFS_REMOTES)
diff --git a/ref-filter.c b/ref-filter.c
index 3435df1..74c4869 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -50,6 +50,11 @@ struct if_then_else {
condition_satisfied : 1;
};
+struct refname_atom {
+ enum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;
+ unsigned int strip;
+};
+
/*
* An atom is a valid field atom listed below, possibly prefixed with
* a "*" to denote deref_tag().
@@ -67,7 +72,8 @@ static struct used_atom {
char color[COLOR_MAXLEN];
struct align align;
struct {
- enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;
+ enum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;
+ struct refname_atom refname;
unsigned int nobracket: 1;
} remote_ref;
struct {
@@ -82,11 +88,7 @@ static struct used_atom {
enum { O_FULL, O_LENGTH, O_SHORT } option;
unsigned int length;
} objectname;
- enum { S_FULL, S_SHORT } symref;
- struct {
- enum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;
- unsigned int strip;
- } refname;
+ struct refname_atom refname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -100,13 +102,34 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)
die(_("unrecognized color: %%(color:%s)"), color_value);
}
+static void refname_atom_parser_internal(struct refname_atom *atom,
+ const char *arg, const char *name)
+{
+ if (!arg)
+ atom->option = R_NORMAL;
+ else if (!strcmp(arg, "short"))
+ atom->option = R_SHORT;
+ else if (skip_prefix(arg, "strip=", &arg)) {
+ atom->option = R_STRIP;
+ if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
+ die(_("positive value expected refname:strip=%s"), arg);
+ } else if (!strcmp(arg, "dir"))
+ atom->option = R_DIR;
+ else if (!strcmp(arg, "base"))
+ atom->option = R_BASE;
+ else
+ die(_("unrecognized %%(%s) argument: %s"), name, arg);
+}
+
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
{
struct string_list params = STRING_LIST_INIT_DUP;
int i;
if (!arg) {
- atom->u.remote_ref.option = RR_NORMAL;
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
return;
}
@@ -116,16 +139,17 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
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"))
+ 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);
+ else {
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
+ }
}
string_list_clear(¶ms, 0);
@@ -170,7 +194,7 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
else if (!strcmp(arg, "short"))
atom->u.objectname.option = O_SHORT;
else if (skip_prefix(arg, "short=", &arg)) {
- atom->u.contents.option = O_LENGTH;
+ atom->u.objectname.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);
@@ -180,6 +204,16 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
+static void symref_atom_parser(struct used_atom *atom, const char *arg)
+{
+ return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
+}
+
+static void refname_atom_parser(struct used_atom *atom, const char *arg)
+{
+ return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
+}
+
static align_type parse_align_position(const char *s)
{
if (!strcmp(s, "right"))
@@ -242,41 +276,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(if) argument: %s"), arg);
}
-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 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 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);
-}
-
static struct {
const char *name;
cmp_type cmp_type;
void (*parser)(struct used_atom *atom, const char *arg);
} valid_atom[] = {
- { "refname", FIELD_STR, refname_atom_parser },
+ { "refname" , FIELD_STR, refname_atom_parser },
{ "objecttype" },
{ "objectsize", FIELD_ULONG },
{ "objectname", FIELD_STR, objectname_atom_parser },
@@ -1098,7 +1103,7 @@ static const char *strip_ref_components(const char *refname, unsigned int len)
while (remaining) {
switch (*start++) {
case '\0':
- die("ref '%s' does not have %ud components to :strip",
+ die(_("ref '%s' does not have %ud components to :strip"),
refname, len);
case '/':
remaining--;
@@ -1108,12 +1113,40 @@ static const char *strip_ref_components(const char *refname, unsigned int len)
return start;
}
+static const char *show_ref(struct refname_atom *atom, const char *refname)
+{
+ if (atom->option == R_SHORT)
+ return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ else if (atom->option == R_STRIP)
+ return strip_ref_components(refname, atom->strip);
+ else if (atom->option == R_BASE) {
+ const char *sp, *ep;
+
pp+ if (skip_prefix(refname, "refs/", &sp)) {
+ ep = strchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ }
+ return "";
+ } else if (atom->option == R_DIR) {
+ const char *sp, *ep;
+
+ sp = refname;
+ ep = strrchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ } else
+ return refname;
+}
+
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.option == RR_SHORTEN)
- *s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ if (atom->u.remote_ref.option == RR_REF)
+ *s = show_ref(&atom->u.remote_ref.refname, refname);
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
@@ -1145,8 +1178,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = ">";
else
*s = "<>";
- } else /* RR_NORMAL */
- *s = refname;
+ } else
+ die("BUG: unhandled RR_* enum");
}
char *get_head_description(void)
@@ -1184,41 +1217,15 @@ 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;
+ return show_ref(&atom->u.refname, 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 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;
+ return show_ref(&atom->u.refname, ref->refname);
}
/*
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 0bd6368..d8edaf2 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -189,7 +189,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
cat >expect <<-\EOF &&
ref-to-branch -> branch-one
- ref-to-remote -> refs/remotes/origin/branch-one
+ ref-to-remote -> origin/branch-one
EOF
git branch >actual.raw &&
grep ref-to <actual.raw >actual &&
@@ -203,6 +203,8 @@ test_expect_success 'git branch --format option' '
Refname is refs/heads/branch-one
Refname is refs/heads/branch-two
Refname is refs/heads/master
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
EOF
git branch --format="Refname is %(refname)" >actual &&
test_cmp expect actual
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 36d32d7..8ff6568 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -57,8 +57,14 @@ 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 upstream:strip=2 origin/master
+test_atom head upstream:dir refs/remotes/origin
+test_atom head upstream:base remotes
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
+test_atom head push:strip=1 remotes/myfork/master
+test_atom head push:dir refs/remotes/myfork
+test_atom head push:base remotes
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -591,4 +597,31 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
test_cmp expected actual
'
+cat >expected <<EOF
+master
+EOF
+
+test_expect_success 'Verify usage of %(symref:strip) atom' '
+ git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+refs/heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:dir) atom' '
+ git for-each-ref --format="%(symref:dir)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:base) atom' '
+ git for-each-ref --format="%(symref:base)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 01/17] ref-filter: implement %(if), %(then), and %(else) atoms
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 02/17] ref-filter: include reference to 'used_atom' within 'atom_value' Karthik Nayak
` (16 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 | 76 +++++++++++++++++++++
3 files changed, 243 insertions(+), 11 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index c52578b..473b6bf 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 70afb44..05935b3 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -328,4 +328,80 @@ 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/annotated-tag
+ No author: refs/tags/doubly-annotated-tag
+ No author: refs/tags/doubly-signed-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
+ annotated-tag: Not Head ref
+ doubly-annotated-tag: Not Head ref
+ doubly-signed-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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 02/17] ref-filter: include reference to 'used_atom' within 'atom_value'
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 01/17] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 03/17] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
` (15 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak
Ensure that each 'atom_value' has a reference to its corresponding
'used_atom'. This let's us use values within 'used_atom' in the
'handler' function.
Hence we can get the %(align) atom's parameters directly from the
'used_atom' therefore removing the necessity of passing %(align) atom's
parameters to 'atom_value'.
This also acts as a preparatory patch for the upcoming patch where we
introduce %(if:equals=) and %(if:notequals=).
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 41e73f0..12e646c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -230,11 +230,9 @@ struct ref_formatting_state {
struct atom_value {
const char *s;
- union {
- struct align align;
- } u;
void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
unsigned long ul; /* used for sorting when not FIELD_STR */
+ struct used_atom *atom;
};
/*
@@ -370,7 +368,7 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
push_stack_element(&state->stack);
new = state->stack;
new->at_end = end_align_handler;
- new->at_end_data = &atomv->u.align;
+ new->at_end_data = &atomv->atom->u.align;
}
static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -1069,6 +1067,7 @@ static void populate_value(struct ref_array_item *ref)
struct branch *branch = NULL;
v->handler = append_atom;
+ v->atom = atom;
if (*name == '*') {
deref = 1;
@@ -1133,7 +1132,6 @@ static void populate_value(struct ref_array_item *ref)
v->s = " ";
continue;
} else if (starts_with(name, "align")) {
- v->u.align = atom->u.align;
v->handler = align_atom_handler;
continue;
} else if (!strcmp(name, "end")) {
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 03/17] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 01/17] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 02/17] ref-filter: include reference to 'used_atom' within 'atom_value' Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 04/17] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
` (14 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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>'.
This is done by introducing 'if_atom_parser()' which parses the given
%(if) atom and then stores the data in used_atom which is later passed
on to the used_atom of the %(then) atom, so that it can do the required
comparisons.
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 | 43 +++++++++++++++++++++++++++++++++-----
t/t6302-for-each-ref-filter.sh | 18 ++++++++++++++++
3 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 473b6bf..3e7db10 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 12e646c..857a8b5 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;
@@ -49,6 +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;
+ struct {
+ const char *if_equals,
+ *not_equals;
+ } if_then_else;
enum { O_FULL, O_SHORT } objectname;
} u;
} *used_atom;
@@ -169,6 +175,19 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
string_list_clear(¶ms, 0);
}
+static void if_atom_parser(struct used_atom *atom, const char *arg)
+{
+ if (!arg)
+ return;
+ else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.if_equals))
+ ;
+ else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.not_equals))
+ ;
+ else
+ die(_("unrecognized %%(if) argument: %s"), arg);
+}
+
+
static struct {
const char *name;
cmp_type cmp_type;
@@ -209,7 +228,7 @@ static struct {
{ "color", FIELD_STR, color_atom_parser },
{ "align", FIELD_STR, align_atom_parser },
{ "end" },
- { "if" },
+ { "if", FIELD_STR, if_atom_parser },
{ "then" },
{ "else" },
};
@@ -410,6 +429,9 @@ 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);
+ if_then_else->if_equals = atomv->atom->u.if_then_else.if_equals;
+ if_then_else->not_equals = atomv->atom->u.if_then_else.not_equals;
+
push_stack_element(&state->stack);
new = state->stack;
new->at_end = if_then_else_handler;
@@ -441,10 +463,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);
}
@@ -1137,7 +1166,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 05935b3..206ad67 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -404,4 +404,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 04/17] ref-filter: modify "%(objectname:short)" to take length
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (2 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 03/17] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 05/17] ref-filter: move get_head_description() from branch.c Karthik Nayak
` (13 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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, the length is 'DEFAULT_ABBREV'. The minimum length is
'MINIMUM_ABBREV'. The length may be exceeded to ensure that the provided
object name is unique.
Add tests and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Helped-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 4 ++++
ref-filter.c | 25 +++++++++++++++++++------
t/t6300-for-each-ref.sh | 10 ++++++++++
3 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 3e7db10..5370fe5 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -107,6 +107,10 @@ objectsize::
objectname::
The object name (aka SHA-1).
For a non-ambiguous abbreviation of the object name append `:short`.
+ For an abbreviation of the object name with desired length append
+ `:short=<length>`, where the minimum length is MINIMUM_ABBREV. The
+ length may be exceeded to ensure unique object names.
+
upstream::
The name of a local ref which can be considered ``upstream''
diff --git a/ref-filter.c b/ref-filter.c
index 857a8b5..7d3af1c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -55,7 +55,10 @@ static struct used_atom {
const char *if_equals,
*not_equals;
} if_then_else;
- 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;
@@ -118,10 +121,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.objectname.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);
}
@@ -591,12 +601,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 05/17] ref-filter: move get_head_description() from branch.c
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (3 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 04/17] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 06/17] ref-filter: introduce format_ref_array_item() Karthik Nayak
` (12 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 0adba62..d467840 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -361,37 +361,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 7d3af1c..fcb3353 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;
@@ -1077,6 +1078,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.
*/
@@ -1116,9 +1148,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 06/17] ref-filter: introduce format_ref_array_item()
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (4 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 05/17] ref-filter: move get_head_description() from branch.c Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 07/17] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
` (11 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 fcb3353..da2b9ee 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1813,10 +1813,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;
@@ -1846,9 +1846,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 07/17] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (5 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 06/17] ref-filter: introduce format_ref_array_item() Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 08/17] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
` (10 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 and
Documentation/git-for-each-ref.txt to reflect this change.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Helped-by : Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 ++-
ref-filter.c | 4 +++-
t/t6300-for-each-ref.sh | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 5370fe5..f1e46a7 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -119,7 +119,8 @@ upstream::
"[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.
+ tracking information associated with it. `:track` also prints
+ "[gone]" whenever unknown upstream ref is encountered.
push::
The name of a local ref which represents the `@{push}` location
diff --git a/ref-filter.c b/ref-filter.c
index da2b9ee..3bb6923 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1049,8 +1049,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 08/17] ref-filter: add support for %(upstream:track,nobracket)
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (6 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 07/17] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 09/17] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
` (9 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 | 8 +++--
ref-filter.c | 67 +++++++++++++++++++++++++-------------
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 51 insertions(+), 26 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index f1e46a7..5c85f27 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -118,9 +118,11 @@ 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. `:track` also prints
- "[gone]" whenever unknown upstream ref is encountered.
+ or "=" (in sync). `:track` also prints "[gone]" whenever
+ unknown upstream ref is encountered. 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 3bb6923..b898bcd 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;
@@ -75,16 +77,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)
@@ -1045,25 +1064,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 09/17] ref-filter: make "%(symref)" atom work with the ':short' modifier
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (7 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 08/17] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 10/17] ref-filter: introduce refname_atom_parser_internal() Karthik Nayak
` (8 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 comparing with valid_atom rather than used_atom.
Add tests for %(symref) and %(symref:short) while we're here.
Helped-by: Junio C Hamano <gitster@pobox.com>
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 b898bcd..083cc27 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -338,7 +338,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 (!strcmp(valid_atom[i].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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 10/17] ref-filter: introduce refname_atom_parser_internal()
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (8 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 09/17] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 11/17] ref-filter: introduce symref_atom_parser() and refname_atom_parser() Karthik Nayak
` (7 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak
Since there are multiple atoms which print refs ('%(refname)',
'%(symref)', '%(push)', '%upstream'), it makes sense to have a common
ground for parsing them. This would allow us to share implementations of
the atom modifiers between these atoms.
Introduce refname_atom_parser_internal() to act as a common parsing
function for ref printing atoms. This would eventually be used to
introduce refname_atom_parser() and symref_atom_parser() and also be
internally used in remote_ref_atom_parser().
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/ref-filter.c b/ref-filter.c
index 083cc27..778fe02 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -30,6 +30,11 @@ struct if_then_else {
condition_satisfied : 1;
};
+struct refname_atom {
+ enum { R_NORMAL, R_SHORT, R_STRIP } option;
+ unsigned int strip;
+};
+
/*
* An atom is a valid field atom listed below, possibly prefixed with
* a "*" to denote deref_tag().
@@ -62,6 +67,7 @@ static struct used_atom {
enum { O_FULL, O_LENGTH, O_SHORT } option;
unsigned int length;
} objectname;
+ struct refname_atom refname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -75,6 +81,21 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)
die(_("unrecognized color: %%(color:%s)"), color_value);
}
+static void refname_atom_parser_internal(struct refname_atom *atom,
+ const char *arg, const char *name)
+{
+ if (!arg)
+ atom->option = R_NORMAL;
+ else if (!strcmp(arg, "short"))
+ atom->option = R_SHORT;
+ else if (skip_prefix(arg, "strip=", &arg)) {
+ atom->option = R_STRIP;
+ if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
+ die(_("positive value expected refname:strip=%s"), arg);
+ } else
+ die(_("unrecognized %%(%s) argument: %s"), name, arg);
+}
+
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
{
struct string_list params = STRING_LIST_INIT_DUP;
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 11/17] ref-filter: introduce symref_atom_parser() and refname_atom_parser()
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (9 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 10/17] ref-filter: introduce refname_atom_parser_internal() Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 12/17] ref-filter: make remote_ref_atom_parser() use refname_atom_parser_internal() Karthik Nayak
` (6 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak
Using refname_atom_parser_internal(), introduce symref_atom_parser() and
refname_atom_parser() which will parse the atoms %(symref) and
%(refname) respectively. Store the parsed information into the
'used_atom' structure based on the modifiers used along with the atoms.
Now the '%(symref)' atom supports the ':strip' atom modifier. Update the
Documentation and tests to reflect this.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 5 +++
ref-filter.c | 78 ++++++++++++++++++++++----------------
t/t6300-for-each-ref.sh | 9 +++++
3 files changed, 59 insertions(+), 33 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 5c85f27..e0c0a12 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -163,6 +163,11 @@ if::
the value between the %(if:...) and %(then) atoms with the
given string.
+symref::
+ The ref which the given symbolic ref refers to. If not a
+ symbolic ref, nothing is printed. Respects the `:short` and
+ `:strip` options in the same way as `refname` above.
+
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 778fe02..933f8ca 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -176,6 +176,16 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
+static void symref_atom_parser(struct used_atom *atom, const char *arg)
+{
+ return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
+}
+
+static void refname_atom_parser(struct used_atom *atom, const char *arg)
+{
+ return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
+}
+
static align_type parse_align_position(const char *s)
{
if (!strcmp(s, "right"))
@@ -244,7 +254,7 @@ static struct {
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 },
@@ -273,7 +283,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 },
@@ -1058,21 +1068,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;
@@ -1081,6 +1086,16 @@ static const char *strip_ref_components(const char *refname, const char *nr_arg)
return start;
}
+static const char *show_ref(struct refname_atom *atom, const char *refname)
+{
+ if (atom->option == R_SHORT)
+ return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ else if (atom->option == R_STRIP)
+ return strip_ref_components(refname, atom->strip);
+ else
+ return refname;
+}
+
static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
struct branch *branch, const char **s)
{
@@ -1153,6 +1168,21 @@ 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
+ return show_ref(&atom->u.refname, 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();
+ return show_ref(&atom->u.refname, ref->refname);
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1181,7 +1211,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;
@@ -1192,12 +1221,10 @@ 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"))
- refname = ref->symref ? ref->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;
/* only local branches may have an upstream */
@@ -1273,21 +1300,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
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index b06ea1c..3d28234 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -589,4 +589,13 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
test_cmp expected actual
'
+cat >expected <<EOF
+master
+EOF
+
+test_expect_success 'Verify usage of %(symref:strip) atom' '
+ git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 12/17] ref-filter: make remote_ref_atom_parser() use refname_atom_parser_internal()
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (10 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 11/17] ref-filter: introduce symref_atom_parser() and refname_atom_parser() Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 13/17] ref-filter: add `:dir` and `:base` options for ref printing atoms Karthik Nayak
` (5 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak
Use the recently introduced refname_atom_parser_internal() within
remote_ref_atom_parser(), this provides a common base for all the ref
printing atoms, allowing %(upstream) and %(push) to also use the
':strip' option.
The atoms '%(push)' and '%(upstream)' will retain the ':track' and
':trackshort' atom modifiers to themselves as they have no meaning in
context to the '%(refname)' and '%(symref)' atoms.
Update the documentation and tests to reflect the same.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 27 ++++++++++++++-------------
ref-filter.c | 26 +++++++++++++++-----------
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index e0c0a12..3eaf770 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -114,21 +114,22 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` in the same way as
- `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). `:track` also prints "[gone]" whenever
- unknown upstream ref is encountered. 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.
+ from the displayed ref. Respects `:short` and `:strip` in the
+ same way as `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). `:track` also prints "[gone]"
+ whenever unknown upstream ref is encountered. 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
- for the displayed ref. Respects `:short`, `:track`, and
- `:trackshort` options as `upstream` does. Produces an empty
- string if no `@{push}` ref is configured.
+ The name of a local ref which represents the `@{push}`
+ location for the displayed ref. Respects `:short`, `:strip`,
+ `:track`, and `:trackshort` options as `upstream`
+ does. Produces an empty string if no `@{push}` ref is
+ configured.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
diff --git a/ref-filter.c b/ref-filter.c
index 933f8ca..3b42aab 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -52,7 +52,8 @@ static struct used_atom {
char color[COLOR_MAXLEN];
struct align align;
struct {
- enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;
+ enum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;
+ struct refname_atom refname;
unsigned int nobracket: 1;
} remote_ref;
struct {
@@ -102,7 +103,9 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
int i;
if (!arg) {
- atom->u.remote_ref.option = RR_NORMAL;
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
return;
}
@@ -112,16 +115,17 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
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"))
+ 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);
+ else {
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
+ }
}
string_list_clear(¶ms, 0);
@@ -1100,8 +1104,8 @@ 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.option == RR_SHORTEN)
- *s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ if (atom->u.remote_ref.option == RR_REF)
+ *s = show_ref(&atom->u.remote_ref.refname, refname);
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
@@ -1133,8 +1137,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = ">";
else
*s = "<>";
- } else /* RR_NORMAL */
- *s = refname;
+ } else
+ die("BUG: unhandled RR_* enum");
}
char *get_head_description(void)
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 3d28234..7ca0a12 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -55,8 +55,10 @@ test_atom head refname:strip=1 heads/master
test_atom head refname:strip=2 master
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
+test_atom head upstream:strip=2 origin/master
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
+test_atom head push:strip=1 remotes/myfork/master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 13/17] ref-filter: add `:dir` and `:base` options for ref printing atoms
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (11 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 12/17] ref-filter: make remote_ref_atom_parser() use refname_atom_parser_internal() Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 14/17] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
` (4 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak
Add the options `:dir` and `:base` to all ref printing ('%(refname)',
'%(symref)', '%(push)' and '%(upstream)') atoms. 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 | 34 +++++++++++++++++++---------------
ref-filter.c | 29 +++++++++++++++++++++++++----
t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++
3 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 3eaf770..4a5e9ea 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`).
@@ -114,22 +116,23 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` and `:strip` in the
- same way as `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). `:track` also prints "[gone]"
- whenever unknown upstream ref is encountered. 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.
+ from the displayed ref. Respects `:short`, `:strip`, `:base`
+ and `:dir` in the same way as `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). `:track`
+ also prints "[gone]" whenever unknown upstream ref is
+ encountered. 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 for the displayed ref. Respects `:short`, `:strip`,
- `:track`, and `:trackshort` options as `upstream`
- does. Produces an empty string if no `@{push}` ref is
- configured.
+ `:track`, `:trackshort`, `:base` and `:dir` options as
+ `upstream` does. Produces an empty string if no `@{push}` ref
+ is configured.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
@@ -166,8 +169,9 @@ if::
symref::
The ref which the given symbolic ref refers to. If not a
- symbolic ref, nothing is printed. Respects the `:short` and
- `:strip` options in the same way as `refname` above.
+ symbolic ref, nothing is printed. Respects the `:short`,
+ `:strip`, `:base` and `:dir` options in the same way as
+ `refname` above.
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 3b42aab..97977a5 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -31,7 +31,7 @@ struct if_then_else {
};
struct refname_atom {
- enum { R_NORMAL, R_SHORT, R_STRIP } option;
+ enum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;
unsigned int strip;
};
@@ -93,7 +93,11 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
atom->option = R_STRIP;
if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
die(_("positive value expected refname:strip=%s"), arg);
- } else
+ } else if (!strcmp(arg, "dir"))
+ atom->option = R_DIR;
+ else if (!strcmp(arg, "base"))
+ atom->option = R_BASE;
+ else
die(_("unrecognized %%(%s) argument: %s"), name, arg);
}
@@ -252,7 +256,6 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(if) argument: %s"), arg);
}
-
static struct {
const char *name;
cmp_type cmp_type;
@@ -1096,7 +1099,25 @@ static const char *show_ref(struct refname_atom *atom, const char *refname)
return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
else if (atom->option == R_STRIP)
return strip_ref_components(refname, atom->strip);
- else
+ else if (atom->option == R_BASE) {
+ const char *sp, *ep;
+
+ if (skip_prefix(refname, "refs/", &sp)) {
+ ep = strchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ }
+ return "";
+ } else if (atom->option == R_DIR) {
+ const char *sp, *ep;
+
+ sp = refname;
+ ep = strrchr(sp, '/');
+ if (!ep)
+ return "";
+ return xstrndup(sp, ep - sp);
+ } else
return refname;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 7ca0a12..8ff6568 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -53,12 +53,18 @@ 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 upstream:strip=2 origin/master
+test_atom head upstream:dir refs/remotes/origin
+test_atom head upstream:base remotes
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
test_atom head push:strip=1 remotes/myfork/master
+test_atom head push:dir refs/remotes/myfork
+test_atom head push:base remotes
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -600,4 +606,22 @@ test_expect_success 'Verify usage of %(symref:strip) atom' '
test_cmp expected actual
'
+cat >expected <<EOF
+refs/heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:dir) atom' '
+ git for-each-ref --format="%(symref:dir)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:base) atom' '
+ git for-each-ref --format="%(symref:base)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 14/17] ref-filter: allow porcelain to translate messages in the output
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (12 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 13/17] ref-filter: add `:dir` and `:base` options for ref printing atoms Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 15/17] branch, tag: use porcelain output Karthik Nayak
` (3 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 97977a5..74c4869 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 {
@@ -1130,15 +1150,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 15/17] branch, tag: use porcelain output
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (13 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 14/17] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 16/17] branch: use ref-filter printing APIs Karthik Nayak
` (2 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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 d467840..ecd7ffc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -632,6 +632,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 528a1ba..3b51be1 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -379,6 +379,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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 16/17] branch: use ref-filter printing APIs
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (14 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 15/17] branch, tag: use porcelain output Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 17/17] branch: implement '--format' option Karthik Nayak
2016-04-25 21:47 ` [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Junio C Hamano
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, 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.
Before this patch, all cross-prefix symrefs weren't shortened. Since
we're using ref-filter APIs, we shorten all symrefs by default. We also
allow the user to change the format if needed with the introduction of
the '--format' option in the next patch.
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 | 234 ++++++++++++++---------------------------------
t/t3203-branch-output.sh | 2 +-
t/t6040-tracking-info.sh | 2 +-
3 files changed, 70 insertions(+), 168 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index ecd7ffc..07068d2 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -36,12 +36,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,
@@ -277,162 +277,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_to_show = "";
- const char *prefix_to_skip = NULL;
- const char *desc = item->refname;
- char *to_free = NULL;
-
- switch (item->kind) {
- case FILTER_REFS_BRANCHES:
- prefix_to_skip = "refs/heads/";
- skip_prefix(desc, prefix_to_skip, &desc);
- if (!filter->detached && !strcmp(desc, head))
- current = 1;
- else
- color = BRANCH_COLOR_LOCAL;
- break;
- case FILTER_REFS_REMOTES:
- prefix_to_skip = "refs/remotes/";
- skip_prefix(desc, prefix_to_skip, &desc);
- color = BRANCH_COLOR_REMOTE;
- prefix_to_show = 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_to_show, 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) {
- const char *symref = item->symref;
- if (prefix_to_skip)
- skip_prefix(symref, prefix_to_skip, &symref);
- strbuf_addf(&out, " -> %s", symref);
- }
- 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;
@@ -443,7 +287,12 @@ 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) {
+ char *head_desc = get_head_description();
+ w = strlen(head_desc);
+ free(head_desc);
+ } else
+ w = utf8_strwidth(desc);
if (it->kind == FILTER_REFS_REMOTES)
w += remote_bonus;
@@ -453,12 +302,52 @@ 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%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ 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,
@@ -470,12 +359,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
@@ -487,10 +378,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/t3203-branch-output.sh b/t/t3203-branch-output.sh
index c6a3ccb..980c732 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -189,7 +189,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
cat >expect <<-\EOF &&
ref-to-branch -> branch-one
- ref-to-remote -> refs/remotes/origin/branch-one
+ ref-to-remote -> origin/branch-one
EOF
git branch >actual.raw &&
grep ref-to <actual.raw >actual &&
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.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v5b 17/17] branch: implement '--format' option
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (15 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 16/17] branch: use ref-filter printing APIs Karthik Nayak
@ 2016-04-25 15:17 ` Karthik Nayak
2016-04-25 21:47 ` [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Junio C Hamano
17 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-25 15:17 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, peff, Karthik Nayak, Karthik Nayak
Implement the '--format' option provided by 'ref-filter'. This lets the
user list branches 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 | 14 ++++++++++++++
3 files changed, 29 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 07068d2..6847ac3 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -28,6 +28,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
};
@@ -340,14 +341,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,
@@ -364,7 +365,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);
/*
@@ -392,7 +394,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)
@@ -491,6 +493,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")),
@@ -531,6 +534,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(),
};
@@ -591,7 +595,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 980c732..d8edaf2 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -196,4 +196,18 @@ test_expect_success 'local-branch symrefs shortened properly' '
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
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
+ EOF
+ git branch --format="Refname is %(refname)" >actual &&
+ test_cmp expect actual
+'
+
test_done
--
2.8.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v5b 00/17] port branch.c to use ref-filter's printing options
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
` (16 preceding siblings ...)
2016-04-25 15:17 ` [PATCH v5b 17/17] branch: implement '--format' option Karthik Nayak
@ 2016-04-25 21:47 ` Junio C Hamano
2016-04-26 18:21 ` Karthik Nayak
17 siblings, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2016-04-25 21:47 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git, jacob.keller, peff
Karthik Nayak <karthik.188@gmail.com> writes:
> 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).
>
> v1 can be found here: $(gmane/288342)
> v2 can be found here: $(gmane/288863)
> v3 can be found here: $(gmane/290299)
> v4 can be found here: $(gmane/291106)
>
> Changes in this version (v5b):
> 1. Added the first patch of the series which was missing in v5.
2. Rebased on top of 'master', which includes
jk/branch-shortening-funny-symrefs.
> Interdiff:
>
> diff --git a/builtin/branch.c b/builtin/branch.c
> index c9a2e5b..6847ac3 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -288,9 +288,11 @@ 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);
> - if (it->kind == FILTER_REFS_DETACHED_HEAD)
> - w = strlen(get_head_description());
> - else
> + if (it->kind == FILTER_REFS_DETACHED_HEAD) {
> + char *head_desc = get_head_description();
> + w = strlen(head_desc);
> + free(head_desc);
> + } else
> w = utf8_strwidth(desc);
Presumably w is computed here to be used later for some kind of
alignment? It is curious why we can assume that head_desc does not
need utf8_strwidth() here.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v5b 00/17] port branch.c to use ref-filter's printing options
2016-04-25 21:47 ` [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Junio C Hamano
@ 2016-04-26 18:21 ` Karthik Nayak
0 siblings, 0 replies; 20+ messages in thread
From: Karthik Nayak @ 2016-04-26 18:21 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git, Jacob Keller, Jeff King
On Tue, Apr 26, 2016 at 3:17 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> 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).
>>
>> v1 can be found here: $(gmane/288342)
>> v2 can be found here: $(gmane/288863)
>> v3 can be found here: $(gmane/290299)
>> v4 can be found here: $(gmane/291106)
>>
>> Changes in this version (v5b):
>> 1. Added the first patch of the series which was missing in v5.
>
> 2. Rebased on top of 'master', which includes
> jk/branch-shortening-funny-symrefs.
>
>> Interdiff:
>>
>> diff --git a/builtin/branch.c b/builtin/branch.c
>> index c9a2e5b..6847ac3 100644
>> --- a/builtin/branch.c
>> +++ b/builtin/branch.c
>> @@ -288,9 +288,11 @@ 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);
>> - if (it->kind == FILTER_REFS_DETACHED_HEAD)
>> - w = strlen(get_head_description());
>> - else
>> + if (it->kind == FILTER_REFS_DETACHED_HEAD) {
>> + char *head_desc = get_head_description();
>> + w = strlen(head_desc);
>> + free(head_desc);
>> + } else
>> w = utf8_strwidth(desc);
>
> Presumably w is computed here to be used later for some kind of
> alignment? It is curious why we can assume that head_desc does not
> need utf8_strwidth() here.
Seems to be a bug, `get_head_description()` is susceptible to be changed
due to translation and hence `utf8_strwidth()` would be a better candidate here
rather than `strlen()`.
Thanks.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2016-04-26 18:21 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-25 10:52 [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 01/17] ref-filter: implement %(if), %(then), and %(else) atoms Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 02/17] ref-filter: include reference to 'used_atom' within 'atom_value' Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 03/17] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>) Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 04/17] ref-filter: modify "%(objectname:short)" to take length Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 05/17] ref-filter: move get_head_description() from branch.c Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 06/17] ref-filter: introduce format_ref_array_item() Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 07/17] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 08/17] ref-filter: add support for %(upstream:track,nobracket) Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 09/17] ref-filter: make "%(symref)" atom work with the ':short' modifier Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 10/17] ref-filter: introduce refname_atom_parser_internal() Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 11/17] ref-filter: introduce symref_atom_parser() and refname_atom_parser() Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 12/17] ref-filter: make remote_ref_atom_parser() use refname_atom_parser_internal() Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 13/17] ref-filter: add `:dir` and `:base` options for ref printing atoms Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 14/17] ref-filter: allow porcelain to translate messages in the output Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 15/17] branch, tag: use porcelain output Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 16/17] branch: use ref-filter printing APIs Karthik Nayak
2016-04-25 15:17 ` [PATCH v5b 17/17] branch: implement '--format' option Karthik Nayak
2016-04-25 21:47 ` [PATCH v5b 00/17] port branch.c to use ref-filter's printing options Junio C Hamano
2016-04-26 18:21 ` Karthik Nayak
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
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 read-only IMAP folder(s) and NNTP newsgroup(s).