[RFC PATCH 5/5] ref-filter: add docs for new options

2018-11-08 Thread Olga Telezhnaya
Add documentation for formatting options objectsize:disk
and deltabase.

Signed-off-by: Olga Telezhnaia 
---
 Documentation/git-for-each-ref.txt | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-for-each-ref.txt 
b/Documentation/git-for-each-ref.txt
index 901faef1bfdce..22d2ff88110cd 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -128,13 +128,18 @@ objecttype::
 
 objectsize::
The size of the object (the same as 'git cat-file -s' reports).
-
+   Append `:disk` to get the size, in bytes, that the object takes up on
+   disk. See the note about on-disk sizes in the `CAVEATS` section below.
 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=`, where the minimum length is MINIMUM_ABBREV. The
length may be exceeded to ensure unique object names.
+deltabase::
+   If the object is stored as a delta on-disk, this expands to the 40-hex
+   sha1 of the delta base object. Otherwise, expands to the null sha1
+   (40 zeroes). See `CAVEATS` section below.
 
 upstream::
The name of a local ref which can be considered ``upstream''
@@ -361,6 +366,20 @@ This prints the authorname, if present.
 git for-each-ref --format="%(refname)%(if)%(authorname)%(then) Authored by: 
%(authorname)%(end)"
 
 
+CAVEATS
+---
+
+Note that the sizes of objects on disk are reported accurately, but care
+should be taken in drawing conclusions about which refs or objects are
+responsible for disk usage. The size of a packed non-delta object may be
+much larger than the size of objects which delta against it, but the
+choice of which object is the base and which is the delta is arbitrary
+and is subject to change during a repack.
+
+Note also that multiple copies of an object may be present in the object
+database; in this case, it is undefined which copy's size or delta base
+will be reported.
+
 SEE ALSO
 
 linkgit:git-show-ref[1]

--
https://github.com/git/git/pull/552


[RFC PATCH 1/5] ref-filter: add objectsize:disk option

2018-11-08 Thread Olga Telezhnaya
Add new formatting option objectsize:disk to know
exact size that object takes up on disk.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 26 +-
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 0c45ed9d94a4b..8ba1a4e72f2c3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -231,12 +231,18 @@ static int objecttype_atom_parser(const struct ref_format 
*format, struct used_a
 static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
  const char *arg, struct strbuf *err)
 {
-   if (arg)
-   return strbuf_addf_ret(err, -1, _("%%(objectsize) does not take 
arguments"));
-   if (*atom->name == '*')
-   oi_deref.info.sizep = _deref.size;
-   else
-   oi.info.sizep = 
+   if (!arg) {
+   if (*atom->name == '*')
+   oi_deref.info.sizep = _deref.size;
+   else
+   oi.info.sizep = 
+   } else if (!strcmp(arg, "disk")) {
+   if (*atom->name == '*')
+   oi_deref.info.disk_sizep = _deref.disk_size;
+   else
+   oi.info.disk_sizep = _size;
+   } else
+   return strbuf_addf_ret(err, -1, _("unrecognized %%(objectsize) 
argument: %s"), arg);
return 0;
 }
 
@@ -876,11 +882,13 @@ static void grab_common_values(struct atom_value *val, 
int deref, struct expand_
name++;
if (!strcmp(name, "objecttype"))
v->s = xstrdup(type_name(oi->type));
-   else if (!strcmp(name, "objectsize")) {
+   else if (!strcmp(name, "objectsize:disk")) {
+   v->value = oi->disk_size;
+   v->s = xstrfmt("%lld", (long long)oi->disk_size);
+   } else if (!strcmp(name, "objectsize")) {
v->value = oi->size;
v->s = xstrfmt("%lu", oi->size);
-   }
-   else if (deref)
+   } else if (deref)
grab_objectname(name, >oid, v, _atom[i]);
}
 }

--
https://github.com/git/git/pull/552


[RFC PATCH 3/5] ref-filter: add deltabase option

2018-11-08 Thread Olga Telezhnaya
Add new formatting option: deltabase.
If the object is stored as a delta on-disk, this expands
to the 40-hex sha1 of the delta base object.
Otherwise, expands to the null sha1 (40 zeroes).
We have same option in cat-file command.
Hopefully, in the end I will remove formatting code from
cat-file and reuse formatting parts from ref-filter.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8ba1a4e72f2c3..3cfe01a039f8b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -246,6 +246,18 @@ static int objectsize_atom_parser(const struct ref_format 
*format, struct used_a
return 0;
 }
 
+static int deltabase_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.delta_base_sha1 = oi_deref.delta_base_oid.hash;
+   else
+   oi.info.delta_base_sha1 = oi.delta_base_oid.hash;
+   return 0;
+}
+
 static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
const char *arg, struct strbuf *err)
 {
@@ -437,6 +449,7 @@ static struct {
{ "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
{ "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
{ "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
+   { "deltabase", SOURCE_OTHER, FIELD_STR, deltabase_atom_parser },
{ "tree", SOURCE_OBJ },
{ "parent", SOURCE_OBJ },
{ "numparent", SOURCE_OBJ, FIELD_ULONG },
@@ -888,7 +901,9 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct expand_
} else if (!strcmp(name, "objectsize")) {
v->value = oi->size;
v->s = xstrfmt("%lu", oi->size);
-   } else if (deref)
+   } else if (!strcmp(name, "deltabase"))
+   v->s = xstrdup(oid_to_hex(>delta_base_oid));
+   else if (deref)
grab_objectname(name, >oid, v, _atom[i]);
}
 }

--
https://github.com/git/git/pull/552


[RFC PATCH 2/5] ref-filter: add tests for objectsize:disk

2018-11-08 Thread Olga Telezhnaya
Test new formatting atom.

Signed-off-by: Olga Telezhnaia 
---
 t/t6300-for-each-ref.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 97bfbee6e8d69..097fdf21fe196 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -83,6 +83,7 @@ test_atom head push:strip=1 remotes/myfork/master
 test_atom head push:strip=-1 master
 test_atom head objecttype commit
 test_atom head objectsize 171
+test_atom head objectsize:disk 138
 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)
@@ -124,6 +125,8 @@ test_atom tag upstream ''
 test_atom tag push ''
 test_atom tag objecttype tag
 test_atom tag objectsize 154
+test_atom tag objectsize:disk 138
+test_atom tag '*objectsize:disk' 138
 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)

--
https://github.com/git/git/pull/552


[RFC PATCH 4/5] ref-filter: add tests for deltabase

2018-11-08 Thread Olga Telezhnaya
Test new formatting option deltabase.

Signed-off-by: Olga Telezhnaia 
---
 t/t6300-for-each-ref.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 097fdf21fe196..0ffd63071392e 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -84,6 +84,7 @@ test_atom head push:strip=-1 master
 test_atom head objecttype commit
 test_atom head objectsize 171
 test_atom head objectsize:disk 138
+test_atom head deltabase 
 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)
@@ -127,6 +128,8 @@ test_atom tag objecttype tag
 test_atom tag objectsize 154
 test_atom tag objectsize:disk 138
 test_atom tag '*objectsize:disk' 138
+test_atom tag deltabase 
+test_atom tag '*deltabase' 
 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)

--
https://github.com/git/git/pull/552


[PATCH v2 3/3] ref-filter: free item->value and item->value->s

2018-10-18 Thread Olga Telezhnaya
Release item->value.
Initialize item->value->s dynamically and then release its resources.
Release some local variables.

Final goal of this patch is to reduce number of memory leaks.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 96 +---
 1 file changed, 54 insertions(+), 42 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 70f1d13ab3beb..ca52ee4608c2a 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -875,7 +875,7 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct expand_
if (deref)
name++;
if (!strcmp(name, "objecttype"))
-   v->s = type_name(oi->type);
+   v->s = xstrdup(type_name(oi->type));
else if (!strcmp(name, "objectsize")) {
v->value = oi->size;
v->s = xstrfmt("%lu", oi->size);
@@ -899,9 +899,9 @@ static void grab_tag_values(struct atom_value *val, int 
deref, struct object *ob
if (deref)
name++;
if (!strcmp(name, "tag"))
-   v->s = tag->tag;
+   v->s = xstrdup(tag->tag);
else if (!strcmp(name, "type") && tag->tagged)
-   v->s = type_name(tag->tagged->type);
+   v->s = xstrdup(type_name(tag->tagged->type));
else if (!strcmp(name, "object") && tag->tagged)
v->s = xstrdup(oid_to_hex(>tagged->oid));
}
@@ -1032,7 +1032,7 @@ static void grab_date(const char *buf, struct atom_value 
*v, const char *atomnam
v->value = timestamp;
return;
  bad:
-   v->s = "";
+   v->s = xstrdup("");
v->value = 0;
 }
 
@@ -1227,7 +1227,7 @@ static void fill_missing_values(struct atom_value *val)
for (i = 0; i < used_atom_cnt; i++) {
struct atom_value *v = [i];
if (v->s == NULL)
-   v->s = "";
+   v->s = xstrdup("");
}
 }
 
@@ -1273,7 +1273,8 @@ static inline char *copy_advance(char *dst, const char 
*src)
 static const char *lstrip_ref_components(const char *refname, int len)
 {
long remaining = len;
-   const char *start = refname;
+   const char *start = xstrdup(refname);
+   const char *to_free = start;
 
if (len < 0) {
int i;
@@ -1294,20 +1295,24 @@ static const char *lstrip_ref_components(const char 
*refname, int len)
while (remaining > 0) {
switch (*start++) {
case '\0':
-   return "";
+   free((char *)to_free);
+   return xstrdup("");
case '/':
remaining--;
break;
}
}
 
+   start = xstrdup(start);
+   free((char *)to_free);
return start;
 }
 
 static const char *rstrip_ref_components(const char *refname, int len)
 {
long remaining = len;
-   char *start = xstrdup(refname);
+   const char *start = xstrdup(refname);
+   const char *to_free = start;
 
if (len < 0) {
int i;
@@ -1327,9 +1332,10 @@ static const char *rstrip_ref_components(const char 
*refname, int len)
 
while (remaining-- > 0) {
char *p = strrchr(start, '/');
-   if (p == NULL)
-   return "";
-   else
+   if (p == NULL) {
+   free((char *)to_free);
+   return xstrdup("");
+   } else
p[0] = '\0';
}
return start;
@@ -1344,7 +1350,7 @@ static const char *show_ref(struct refname_atom *atom, 
const char *refname)
else if (atom->option == R_RSTRIP)
return rstrip_ref_components(refname, atom->rstrip);
else
-   return refname;
+   return xstrdup(refname);
 }
 
 static void fill_remote_ref_details(struct used_atom *atom, const char 
*refname,
@@ -1358,7 +1364,7 @@ static void fill_remote_ref_details(struct used_atom 
*atom, const char *refname,
   NULL, AHEAD_BEHIND_FULL) < 0) {
*s = xstrdup(msgs.gone);
} else if (!num_ours && !num_theirs)
-   *s = "";
+   *s = xstrdup("");
else if (!num_ours)
*s = xstrfmt(msgs.behind, num_theirs);
else if (!num_theirs)
@@ -1373,36 +1379,31 @@ static void fill_remote_ref_details(struct used_atom 
*atom, const char *refname,
}
} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, _ours, _theirs,
-  NULL, AHEAD_BEHIND_FULL) < 0)
+  NULL, 

[PATCH v2 1/3] ref-filter: free memory from used_atom

2018-10-18 Thread Olga Telezhnaya
Release memory from used_atom variable for reducing number of memory
leaks.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index e1bcb4ca8a197..70f1d13ab3beb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1996,6 +1996,10 @@ void ref_array_clear(struct ref_array *array)
 {
int i;
 
+   for (i = 0; i < used_atom_cnt; i++)
+   free((char *)used_atom[i].name);
+   FREE_AND_NULL(used_atom);
+   used_atom_cnt = 0;
for (i = 0; i < array->nr; i++)
free_array_item(array->items[i]);
FREE_AND_NULL(array->items);

--
https://github.com/git/git/pull/538


[PATCH v2 2/3] ls-remote: release memory instead of UNLEAK

2018-10-18 Thread Olga Telezhnaya
Use ref_array_clear() to release memory instead of UNLEAK macros.

Signed-off-by: Olga Telezhnaia 
---
 builtin/ls-remote.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 1a25df7ee15b4..6a0cdec30d2d7 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -151,6 +151,6 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
}
 
UNLEAK(sorting);
-   UNLEAK(ref_array);
+   ref_array_clear(_array);
return status;
 }

--
https://github.com/git/git/pull/538


[PATCH 2/3] ls-remote: release memory instead of UNLEAK

2018-10-09 Thread Olga Telezhnaya
Use ref_array_clear() to release memory instead of UNLEAK macros.

Signed-off-by: Olga Telezhnaia 
---
 builtin/ls-remote.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 1a25df7ee15b4..6a0cdec30d2d7 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -151,6 +151,6 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
}
 
UNLEAK(sorting);
-   UNLEAK(ref_array);
+   ref_array_clear(_array);
return status;
 }

--
https://github.com/git/git/pull/538


[PATCH 3/3] ref-filter: free item->value and item->value->s

2018-10-09 Thread Olga Telezhnaya
Release item->value.
Initialize item->value->s dynamically and then release its resources.
Release some local variables.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 95 +---
 1 file changed, 53 insertions(+), 42 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 1b71d08a43a84..4d42c777a9b50 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -875,7 +875,7 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct expand_
if (deref)
name++;
if (!strcmp(name, "objecttype"))
-   v->s = type_name(oi->type);
+   v->s = xstrdup(type_name(oi->type));
else if (!strcmp(name, "objectsize")) {
v->value = oi->size;
v->s = xstrfmt("%lu", oi->size);
@@ -899,9 +899,9 @@ static void grab_tag_values(struct atom_value *val, int 
deref, struct object *ob
if (deref)
name++;
if (!strcmp(name, "tag"))
-   v->s = tag->tag;
+   v->s = xstrdup(tag->tag);
else if (!strcmp(name, "type") && tag->tagged)
-   v->s = type_name(tag->tagged->type);
+   v->s = xstrdup(type_name(tag->tagged->type));
else if (!strcmp(name, "object") && tag->tagged)
v->s = xstrdup(oid_to_hex(>tagged->oid));
}
@@ -1032,7 +1032,7 @@ static void grab_date(const char *buf, struct atom_value 
*v, const char *atomnam
v->value = timestamp;
return;
  bad:
-   v->s = "";
+   v->s = xstrdup("");
v->value = 0;
 }
 
@@ -1227,7 +1227,7 @@ static void fill_missing_values(struct atom_value *val)
for (i = 0; i < used_atom_cnt; i++) {
struct atom_value *v = [i];
if (v->s == NULL)
-   v->s = "";
+   v->s = xstrdup("");
}
 }
 
@@ -1273,7 +1273,8 @@ static inline char *copy_advance(char *dst, const char 
*src)
 static const char *lstrip_ref_components(const char *refname, int len)
 {
long remaining = len;
-   const char *start = refname;
+   const char *start = xstrdup(refname);
+   const char *to_free = start;
 
if (len < 0) {
int i;
@@ -1294,20 +1295,24 @@ static const char *lstrip_ref_components(const char 
*refname, int len)
while (remaining > 0) {
switch (*start++) {
case '\0':
-   return "";
+   free((char *)to_free);
+   return xstrdup("");
case '/':
remaining--;
break;
}
}
 
+   start = xstrdup(start);
+   free((char *)to_free);
return start;
 }
 
 static const char *rstrip_ref_components(const char *refname, int len)
 {
long remaining = len;
-   char *start = xstrdup(refname);
+   const char *start = xstrdup(refname);
+   const char *to_free = start;
 
if (len < 0) {
int i;
@@ -1327,9 +1332,10 @@ static const char *rstrip_ref_components(const char 
*refname, int len)
 
while (remaining-- > 0) {
char *p = strrchr(start, '/');
-   if (p == NULL)
-   return "";
-   else
+   if (p == NULL) {
+   free((char *)to_free);
+   return xstrdup("");
+   } else
p[0] = '\0';
}
return start;
@@ -1344,7 +1350,7 @@ static const char *show_ref(struct refname_atom *atom, 
const char *refname)
else if (atom->option == R_RSTRIP)
return rstrip_ref_components(refname, atom->rstrip);
else
-   return refname;
+   return xstrdup(refname);
 }
 
 static void fill_remote_ref_details(struct used_atom *atom, const char 
*refname,
@@ -1358,7 +1364,7 @@ static void fill_remote_ref_details(struct used_atom 
*atom, const char *refname,
   NULL, AHEAD_BEHIND_FULL) < 0) {
*s = xstrdup(msgs.gone);
} else if (!num_ours && !num_theirs)
-   *s = "";
+   *s = xstrdup("");
else if (!num_ours)
*s = xstrfmt(msgs.behind, num_theirs);
else if (!num_theirs)
@@ -1373,36 +1379,31 @@ static void fill_remote_ref_details(struct used_atom 
*atom, const char *refname,
}
} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, _ours, _theirs,
-  NULL, AHEAD_BEHIND_FULL) < 0)
+  NULL, AHEAD_BEHIND_FULL) < 0) {
+   *s = xstrdup("");
  

[PATCH 1/3] ref-filter: free memory from used_atom

2018-10-09 Thread Olga Telezhnaya
Release memory from used_atom variable.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index e1bcb4ca8a197..1b71d08a43a84 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1996,6 +1996,9 @@ void ref_array_clear(struct ref_array *array)
 {
int i;
 
+   for (i = 0; i < used_atom_cnt; i++)
+   free((char *)used_atom[i].name);
+   free(used_atom);
for (i = 0; i < array->nr; i++)
free_array_item(array->items[i]);
FREE_AND_NULL(array->items);

--
https://github.com/git/git/pull/538


[PATCH v3 5/5] ref-filter: use oid_object_info() to get object

2018-07-17 Thread Olga Telezhnaya
Use oid_object_info_extended() to get object info instead of
read_object_file().
It will help to handle some requests faster (e.g., we do not need to
parse whole object if we need to know %(objectsize)).
It could also help us to add new atoms such as %(objectsize:disk)
and %(deltabase).

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 120 +++
 1 file changed, 87 insertions(+), 33 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 2b401a17c4689..112955f006648 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -61,6 +61,17 @@ struct refname_atom {
int lstrip, rstrip;
 };
 
+static struct expand_data {
+   struct object_id oid;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   struct object_id delta_base_oid;
+   void *content;
+
+   struct object_info info;
+} oi, oi_deref;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -202,6 +213,30 @@ static int remote_ref_atom_parser(const struct ref_format 
*format, struct used_a
return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.typep = _deref.type;
+   else
+   oi.info.typep = 
+   return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objectsize) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.sizep = _deref.size;
+   else
+   oi.info.sizep = 
+   return 0;
+}
+
 static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
const char *arg, struct strbuf *err)
 {
@@ -388,8 +423,8 @@ static struct {
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
{ "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
-   { "objecttype", SOURCE_OTHER },
-   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
{ "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
{ "tree", SOURCE_OBJ },
{ "parent", SOURCE_OBJ },
@@ -502,6 +537,12 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
used_atom[at].name = xmemdupz(atom, ep - atom);
used_atom[at].type = valid_atom[i].cmp_type;
used_atom[at].source = valid_atom[i].source;
+   if (used_atom[at].source == SOURCE_OBJ) {
+   if (*atom == '*')
+   oi_deref.info.contentp = _deref.content;
+   else
+   oi.info.contentp = 
+   }
if (arg) {
arg = used_atom[at].name + (arg - atom) + 1;
if (!*arg) {
@@ -817,7 +858,7 @@ static int grab_objectname(const char *name, const struct 
object_id *oid,
 }
 
 /* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct 
object *obj, void *buf, unsigned long sz)
+static void grab_common_values(struct atom_value *val, int deref, struct 
expand_data *oi)
 {
int i;
 
@@ -829,13 +870,13 @@ static void grab_common_values(struct atom_value *val, 
int deref, struct object
if (deref)
name++;
if (!strcmp(name, "objecttype"))
-   v->s = type_name(obj->type);
+   v->s = type_name(oi->type);
else if (!strcmp(name, "objectsize")) {
-   v->value = sz;
-   v->s = xstrfmt("%lu", sz);
+   v->value = oi->size;
+   v->s = xstrfmt("%lu", oi->size);
}
else if (deref)
-   grab_objectname(name, >oid, v, _atom[i]);
+   grab_objectname(name, >oid, v, _atom[i]);
}
 }
 
@@ -1194,7 +1235,6 @@ static void fill_missing_values(struct atom_value *val)
  */
 static void grab_values(struct atom_value *val, int deref, struct object *obj, 
void *buf, unsigned long sz)
 {
-   grab_common_values(val, deref, obj, buf, sz);
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj, buf, sz);
@@ -1418,29 +1458,36 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static int get_object(struct ref_array_item 

[PATCH v3 3/5] ref-filter: initialize eaten variable

2018-07-17 Thread Olga Telezhnaya
Initialize variable `eaten` before its using. We may initialize it in
parse_object_buffer(), but there are cases when we do not reach this
invocation.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 27733ef013bed..8db7ca95b12c0 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1439,7 +1439,8 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 static int get_object(struct ref_array_item *ref, const struct object_id *oid,
   int deref, struct object **obj, struct strbuf *err)
 {
-   int eaten;
+   /* parse_object_buffer() will set eaten to 0 if free() will be needed */
+   int eaten = 1;
int ret = 0;
unsigned long size;
void *buf = get_obj(oid, obj, , );

--
https://github.com/git/git/pull/520


[PATCH v3 1/5] ref-filter: add info_source to valid_atom

2018-07-17 Thread Olga Telezhnaya
Add the source of object data to prevent parsing of unneeded data.
The goal is to improve performance by avoiding calling expensive
functions when we don't need the information they provide
or when we could get it by using a cheaper function.

It is stored in valid_atoms because it depends on the atoms we are
interested in.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 82 +++-
 1 file changed, 43 insertions(+), 39 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index fa3685d91f046..8611c24fd57d1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -41,6 +41,7 @@ void setup_ref_filter_porcelain_msg(void)
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
+typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;
 
 struct align {
align_type position;
@@ -73,6 +74,7 @@ struct refname_atom {
 static struct used_atom {
const char *name;
cmp_type type;
+   info_source source;
union {
char color[COLOR_MAXLEN];
struct align align;
@@ -380,49 +382,50 @@ static int head_atom_parser(const struct ref_format 
*format, struct used_atom *a
 
 static struct {
const char *name;
+   info_source source;
cmp_type cmp_type;
int (*parser)(const struct ref_format *format, struct used_atom *atom,
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
-   { "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
-   { "objectname", FIELD_STR, objectname_atom_parser },
-   { "tree" },
-   { "parent" },
-   { "numparent", FIELD_ULONG },
-   { "object" },
-   { "type" },
-   { "tag" },
-   { "author" },
-   { "authorname" },
-   { "authoremail" },
-   { "authordate", FIELD_TIME },
-   { "committer" },
-   { "committername" },
-   { "committeremail" },
-   { "committerdate", FIELD_TIME },
-   { "tagger" },
-   { "taggername" },
-   { "taggeremail" },
-   { "taggerdate", FIELD_TIME },
-   { "creator" },
-   { "creatordate", FIELD_TIME },
-   { "subject", FIELD_STR, subject_atom_parser },
-   { "body", FIELD_STR, body_atom_parser },
-   { "trailers", FIELD_STR, trailers_atom_parser },
-   { "contents", FIELD_STR, contents_atom_parser },
-   { "upstream", FIELD_STR, remote_ref_atom_parser },
-   { "push", FIELD_STR, remote_ref_atom_parser },
-   { "symref", FIELD_STR, refname_atom_parser },
-   { "flag" },
-   { "HEAD", FIELD_STR, head_atom_parser },
-   { "color", FIELD_STR, color_atom_parser },
-   { "align", FIELD_STR, align_atom_parser },
-   { "end" },
-   { "if", FIELD_STR, if_atom_parser },
-   { "then" },
-   { "else" },
+   { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "objecttype", SOURCE_OTHER },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
+   { "tree", SOURCE_OBJ },
+   { "parent", SOURCE_OBJ },
+   { "numparent", SOURCE_OBJ, FIELD_ULONG },
+   { "object", SOURCE_OBJ },
+   { "type", SOURCE_OBJ },
+   { "tag", SOURCE_OBJ },
+   { "author", SOURCE_OBJ },
+   { "authorname", SOURCE_OBJ },
+   { "authoremail", SOURCE_OBJ },
+   { "authordate", SOURCE_OBJ, FIELD_TIME },
+   { "committer", SOURCE_OBJ },
+   { "committername", SOURCE_OBJ },
+   { "committeremail", SOURCE_OBJ },
+   { "committerdate", SOURCE_OBJ, FIELD_TIME },
+   { "tagger", SOURCE_OBJ },
+   { "taggername", SOURCE_OBJ },
+   { "taggeremail", SOURCE_OBJ },
+   { "taggerdate", SOURCE_OBJ, FIELD_TIME },
+   { "creator", SOURCE_OBJ },
+   { "creatordate", SOURCE_OBJ, FIELD_TIME },
+   { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
+   { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
+   { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
+   { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+   { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "flag", SOURCE_NONE },
+   { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
+   { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+   { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
+   { "end", SOURCE_NONE },
+   { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
+   { "then", SOURCE_NONE },
+   { "else", SOURCE_NONE },
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
@@ -498,6 +501,7 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
REALLOC_ARRAY(used_atom, 

[PATCH v3 4/5] ref-filter: merge get_obj and get_object

2018-07-17 Thread Olga Telezhnaya
Inline get_obj(): it would be easier to edit the code
without this split.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 36 +++-
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8db7ca95b12c0..2b401a17c4689 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -797,24 +797,6 @@ int verify_ref_format(struct ref_format *format)
return 0;
 }
 
-/*
- * Given an object name, read the object data and size, and return a
- * "struct object".  If the object data we are returning is also borrowed
- * by the "struct object" representation, set *eaten as well---it is a
- * signal from parse_object_buffer to us not to free the buffer.
- */
-static void *get_obj(const struct object_id *oid, struct object **obj, 
unsigned long *sz, int *eaten)
-{
-   enum object_type type;
-   void *buf = read_object_file(oid, , sz);
-
-   if (buf)
-   *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
-   else
-   *obj = NULL;
-   return buf;
-}
-
 static int grab_objectname(const char *name, const struct object_id *oid,
   struct atom_value *v, struct used_atom *atom)
 {
@@ -1437,21 +1419,25 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 }
 
 static int get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj, struct strbuf *err)
+ int deref, struct object **obj, struct strbuf *err)
 {
/* parse_object_buffer() will set eaten to 0 if free() will be needed */
int eaten = 1;
int ret = 0;
unsigned long size;
-   void *buf = get_obj(oid, obj, , );
+   enum object_type type;
+   void *buf = read_object_file(oid, , );
if (!buf)
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
  oid_to_hex(oid), ref->refname);
-   else if (!*obj)
-   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on 
%s for %s"),
- oid_to_hex(oid), ref->refname);
-   else
-   grab_values(ref->value, deref, *obj, buf, size);
+   else {
+   *obj = parse_object_buffer(oid, type, size, buf, );
+   if (!*obj)
+   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer 
failed on %s for %s"),
+ oid_to_hex(oid), ref->refname);
+   else
+   grab_values(ref->value, deref, *obj, buf, size);
+   }
if (!eaten)
free(buf);
return ret;

--
https://github.com/git/git/pull/520


[PATCH v3 2/5] ref-filter: fill empty fields with empty values

2018-07-17 Thread Olga Telezhnaya
Atoms like "align" or "end" do not have string representation.
Earlier we had to go and parse whole object with a hope that we
could fill their string representations. It's easier to fill them
with an empty string before we start to work with whole object.

It is important to mention that we fill only these atoms that must
contain nothing. So, if we could not fill the atom because, for example,
the object is missing, we leave it with NULL.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8611c24fd57d1..27733ef013bed 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
+   v->s = "";
/* only local branches may have an upstream */
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
@@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (atom->u.remote_ref.push) {
const char *branch_name;
+   v->s = "";
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
continue;
@@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (starts_with(name, "align")) {
v->handler = align_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "end")) {
v->handler = end_atom_handler;
+   v->s = "";
continue;
} else if (starts_with(name, "if")) {
const char *s;
-
+   v->s = "";
if (skip_prefix(name, "if:", ))
v->s = xstrdup(s);
v->handler = if_atom_handler;
continue;
} else if (!strcmp(name, "then")) {
v->handler = then_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "else")) {
v->handler = else_atom_handler;
+   v->s = "";
continue;
} else
continue;

--
https://github.com/git/git/pull/520


[PATCH v2 4/4] ref-filter: use oid_object_info() to get object

2018-07-13 Thread Olga Telezhnaya
Use oid_object_info_extended() to get object info instead of
read_object_file().
It will help to handle some requests faster (e.g., we do not need to
parse whole object if we need to know %(objectsize)).
It could also help us to add new atoms such as %(objectsize:disk)
and %(deltabase).

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 123 ++-
 1 file changed, 89 insertions(+), 34 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f04169f0ea0e3..112955f006648 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -61,6 +61,17 @@ struct refname_atom {
int lstrip, rstrip;
 };
 
+static struct expand_data {
+   struct object_id oid;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   struct object_id delta_base_oid;
+   void *content;
+
+   struct object_info info;
+} oi, oi_deref;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -202,6 +213,30 @@ static int remote_ref_atom_parser(const struct ref_format 
*format, struct used_a
return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.typep = _deref.type;
+   else
+   oi.info.typep = 
+   return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objectsize) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.sizep = _deref.size;
+   else
+   oi.info.sizep = 
+   return 0;
+}
+
 static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
const char *arg, struct strbuf *err)
 {
@@ -388,8 +423,8 @@ static struct {
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
{ "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
-   { "objecttype", SOURCE_OTHER },
-   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
{ "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
{ "tree", SOURCE_OBJ },
{ "parent", SOURCE_OBJ },
@@ -502,6 +537,12 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
used_atom[at].name = xmemdupz(atom, ep - atom);
used_atom[at].type = valid_atom[i].cmp_type;
used_atom[at].source = valid_atom[i].source;
+   if (used_atom[at].source == SOURCE_OBJ) {
+   if (*atom == '*')
+   oi_deref.info.contentp = _deref.content;
+   else
+   oi.info.contentp = 
+   }
if (arg) {
arg = used_atom[at].name + (arg - atom) + 1;
if (!*arg) {
@@ -817,7 +858,7 @@ static int grab_objectname(const char *name, const struct 
object_id *oid,
 }
 
 /* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct 
object *obj, void *buf, unsigned long sz)
+static void grab_common_values(struct atom_value *val, int deref, struct 
expand_data *oi)
 {
int i;
 
@@ -829,13 +870,13 @@ static void grab_common_values(struct atom_value *val, 
int deref, struct object
if (deref)
name++;
if (!strcmp(name, "objecttype"))
-   v->s = type_name(obj->type);
+   v->s = type_name(oi->type);
else if (!strcmp(name, "objectsize")) {
-   v->value = sz;
-   v->s = xstrfmt("%lu", sz);
+   v->value = oi->size;
+   v->s = xstrfmt("%lu", oi->size);
}
else if (deref)
-   grab_objectname(name, >oid, v, _atom[i]);
+   grab_objectname(name, >oid, v, _atom[i]);
}
 }
 
@@ -1194,7 +1235,6 @@ static void fill_missing_values(struct atom_value *val)
  */
 static void grab_values(struct atom_value *val, int deref, struct object *obj, 
void *buf, unsigned long sz)
 {
-   grab_common_values(val, deref, obj, buf, sz);
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj, buf, sz);
@@ -1418,28 +1458,36 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static int get_object(struct ref_array_item 

[PATCH v2 1/4] ref-filter: add info_source to valid_atom

2018-07-13 Thread Olga Telezhnaya
Add the source of object data to prevent parsing of unneeded data.
The goal is to improve performance by avoiding calling expensive
functions when we don't need the information they provide
or when we could get it by using a cheaper function.

It is stored in valid_atoms because it depends on the atoms we are
interested in.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 82 +++-
 1 file changed, 43 insertions(+), 39 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index fa3685d91f046..8611c24fd57d1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -41,6 +41,7 @@ void setup_ref_filter_porcelain_msg(void)
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
+typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;
 
 struct align {
align_type position;
@@ -73,6 +74,7 @@ struct refname_atom {
 static struct used_atom {
const char *name;
cmp_type type;
+   info_source source;
union {
char color[COLOR_MAXLEN];
struct align align;
@@ -380,49 +382,50 @@ static int head_atom_parser(const struct ref_format 
*format, struct used_atom *a
 
 static struct {
const char *name;
+   info_source source;
cmp_type cmp_type;
int (*parser)(const struct ref_format *format, struct used_atom *atom,
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
-   { "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
-   { "objectname", FIELD_STR, objectname_atom_parser },
-   { "tree" },
-   { "parent" },
-   { "numparent", FIELD_ULONG },
-   { "object" },
-   { "type" },
-   { "tag" },
-   { "author" },
-   { "authorname" },
-   { "authoremail" },
-   { "authordate", FIELD_TIME },
-   { "committer" },
-   { "committername" },
-   { "committeremail" },
-   { "committerdate", FIELD_TIME },
-   { "tagger" },
-   { "taggername" },
-   { "taggeremail" },
-   { "taggerdate", FIELD_TIME },
-   { "creator" },
-   { "creatordate", FIELD_TIME },
-   { "subject", FIELD_STR, subject_atom_parser },
-   { "body", FIELD_STR, body_atom_parser },
-   { "trailers", FIELD_STR, trailers_atom_parser },
-   { "contents", FIELD_STR, contents_atom_parser },
-   { "upstream", FIELD_STR, remote_ref_atom_parser },
-   { "push", FIELD_STR, remote_ref_atom_parser },
-   { "symref", FIELD_STR, refname_atom_parser },
-   { "flag" },
-   { "HEAD", FIELD_STR, head_atom_parser },
-   { "color", FIELD_STR, color_atom_parser },
-   { "align", FIELD_STR, align_atom_parser },
-   { "end" },
-   { "if", FIELD_STR, if_atom_parser },
-   { "then" },
-   { "else" },
+   { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "objecttype", SOURCE_OTHER },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
+   { "tree", SOURCE_OBJ },
+   { "parent", SOURCE_OBJ },
+   { "numparent", SOURCE_OBJ, FIELD_ULONG },
+   { "object", SOURCE_OBJ },
+   { "type", SOURCE_OBJ },
+   { "tag", SOURCE_OBJ },
+   { "author", SOURCE_OBJ },
+   { "authorname", SOURCE_OBJ },
+   { "authoremail", SOURCE_OBJ },
+   { "authordate", SOURCE_OBJ, FIELD_TIME },
+   { "committer", SOURCE_OBJ },
+   { "committername", SOURCE_OBJ },
+   { "committeremail", SOURCE_OBJ },
+   { "committerdate", SOURCE_OBJ, FIELD_TIME },
+   { "tagger", SOURCE_OBJ },
+   { "taggername", SOURCE_OBJ },
+   { "taggeremail", SOURCE_OBJ },
+   { "taggerdate", SOURCE_OBJ, FIELD_TIME },
+   { "creator", SOURCE_OBJ },
+   { "creatordate", SOURCE_OBJ, FIELD_TIME },
+   { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
+   { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
+   { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
+   { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+   { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "flag", SOURCE_NONE },
+   { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
+   { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+   { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
+   { "end", SOURCE_NONE },
+   { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
+   { "then", SOURCE_NONE },
+   { "else", SOURCE_NONE },
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
@@ -498,6 +501,7 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
REALLOC_ARRAY(used_atom, 

[PATCH v2 3/4] ref-filter: merge get_obj and get_object

2018-07-13 Thread Olga Telezhnaya
Inline get_obj(): it would be easier to edit the code
without this split.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 36 +++-
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 27733ef013bed..f04169f0ea0e3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -797,24 +797,6 @@ int verify_ref_format(struct ref_format *format)
return 0;
 }
 
-/*
- * Given an object name, read the object data and size, and return a
- * "struct object".  If the object data we are returning is also borrowed
- * by the "struct object" representation, set *eaten as well---it is a
- * signal from parse_object_buffer to us not to free the buffer.
- */
-static void *get_obj(const struct object_id *oid, struct object **obj, 
unsigned long *sz, int *eaten)
-{
-   enum object_type type;
-   void *buf = read_object_file(oid, , sz);
-
-   if (buf)
-   *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
-   else
-   *obj = NULL;
-   return buf;
-}
-
 static int grab_objectname(const char *name, const struct object_id *oid,
   struct atom_value *v, struct used_atom *atom)
 {
@@ -1437,20 +1419,24 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 }
 
 static int get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj, struct strbuf *err)
+ int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
int ret = 0;
unsigned long size;
-   void *buf = get_obj(oid, obj, , );
+   enum object_type type;
+   void *buf = read_object_file(oid, , );
if (!buf)
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
  oid_to_hex(oid), ref->refname);
-   else if (!*obj)
-   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on 
%s for %s"),
- oid_to_hex(oid), ref->refname);
-   else
-   grab_values(ref->value, deref, *obj, buf, size);
+   else {
+   *obj = parse_object_buffer(oid, type, size, buf, );
+   if (!*obj)
+   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer 
failed on %s for %s"),
+ oid_to_hex(oid), ref->refname);
+   else
+   grab_values(ref->value, deref, *obj, buf, size);
+   }
if (!eaten)
free(buf);
return ret;

--
https://github.com/git/git/pull/520


[PATCH v2 2/4] ref-filter: fill empty fields with empty values

2018-07-13 Thread Olga Telezhnaya
Atoms like "align" or "end" do not have string representation.
Earlier we had to go and parse whole object with a hope that we
could fill their string representations. It's easier to fill them
with an empty string before we start to work with whole object.

It is important to mention that we fill only these atoms that must
contain nothing. So, if we could not fill the atom because, for example,
the object is missing, we leave it with NULL.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8611c24fd57d1..27733ef013bed 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
+   v->s = "";
/* only local branches may have an upstream */
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
@@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (atom->u.remote_ref.push) {
const char *branch_name;
+   v->s = "";
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
continue;
@@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (starts_with(name, "align")) {
v->handler = align_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "end")) {
v->handler = end_atom_handler;
+   v->s = "";
continue;
} else if (starts_with(name, "if")) {
const char *s;
-
+   v->s = "";
if (skip_prefix(name, "if:", ))
v->s = xstrdup(s);
v->handler = if_atom_handler;
continue;
} else if (!strcmp(name, "then")) {
v->handler = then_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "else")) {
v->handler = else_atom_handler;
+   v->s = "";
continue;
} else
continue;

--
https://github.com/git/git/pull/520


[PATCH 4/4] ref-filter: use oid_object_info() to get object

2018-07-09 Thread Olga Telezhnaya
Use oid_object_info_extended() to get object info instead of
read_object_file().
It will help to handle some requests faster (e.g., we do not need to
parse whole object if we need to know %(objectsize)).
It could also help us to add new atoms such as %(objectsize:disk)
and %(deltabase).

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 120 +++
 1 file changed, 87 insertions(+), 33 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f04169f0ea0e3..9bf7de4c561cb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -61,6 +61,17 @@ struct refname_atom {
int lstrip, rstrip;
 };
 
+struct expand_data {
+   struct object_id oid;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   struct object_id delta_base_oid;
+   void *content;
+
+   struct object_info info;
+} oi, oi_deref;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -202,6 +213,30 @@ static int remote_ref_atom_parser(const struct ref_format 
*format, struct used_a
return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.typep = _deref.type;
+   else
+   oi.info.typep = 
+   return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+   if (arg)
+   return strbuf_addf_ret(err, -1, _("%%(objectsize) does not take 
arguments"));
+   if (*atom->name == '*')
+   oi_deref.info.sizep = _deref.size;
+   else
+   oi.info.sizep = 
+   return 0;
+}
+
 static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
const char *arg, struct strbuf *err)
 {
@@ -388,8 +423,8 @@ static struct {
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
{ "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
-   { "objecttype", SOURCE_OTHER },
-   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
{ "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
{ "tree", SOURCE_OBJ },
{ "parent", SOURCE_OBJ },
@@ -502,6 +537,12 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
used_atom[at].name = xmemdupz(atom, ep - atom);
used_atom[at].type = valid_atom[i].cmp_type;
used_atom[at].source = valid_atom[i].source;
+   if (used_atom[at].source == SOURCE_OBJ) {
+   if (*atom == '*')
+   oi_deref.info.contentp = _deref.content;
+   else
+   oi.info.contentp = 
+   }
if (arg) {
arg = used_atom[at].name + (arg - atom) + 1;
if (!*arg) {
@@ -817,7 +858,7 @@ static int grab_objectname(const char *name, const struct 
object_id *oid,
 }
 
 /* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct 
object *obj, void *buf, unsigned long sz)
+static void grab_common_values(struct atom_value *val, int deref, struct 
expand_data *oi)
 {
int i;
 
@@ -829,13 +870,13 @@ static void grab_common_values(struct atom_value *val, 
int deref, struct object
if (deref)
name++;
if (!strcmp(name, "objecttype"))
-   v->s = type_name(obj->type);
+   v->s = type_name(oi->type);
else if (!strcmp(name, "objectsize")) {
-   v->value = sz;
-   v->s = xstrfmt("%lu", sz);
+   v->value = oi->size;
+   v->s = xstrfmt("%lu", oi->size);
}
else if (deref)
-   grab_objectname(name, >oid, v, _atom[i]);
+   grab_objectname(name, >oid, v, _atom[i]);
}
 }
 
@@ -1194,7 +1235,6 @@ static void fill_missing_values(struct atom_value *val)
  */
 static void grab_values(struct atom_value *val, int deref, struct object *obj, 
void *buf, unsigned long sz)
 {
-   grab_common_values(val, deref, obj, buf, sz);
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj, buf, sz);
@@ -1418,28 +1458,35 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static int get_object(struct ref_array_item *ref, 

[PATCH 1/4] ref-filter: add info_source to valid_atom

2018-07-09 Thread Olga Telezhnaya
Add the source of object data to prevent parsing of unneeded data.
The goal is to improve performance by avoiding calling expensive
functions when we don't need the information they provide
or when we could get it by using a cheaper function.

It is stored in valid_atoms because it depends on the atoms we are
interested in.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 82 +++-
 1 file changed, 43 insertions(+), 39 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index fa3685d91f046..8611c24fd57d1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -41,6 +41,7 @@ void setup_ref_filter_porcelain_msg(void)
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
+typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;
 
 struct align {
align_type position;
@@ -73,6 +74,7 @@ struct refname_atom {
 static struct used_atom {
const char *name;
cmp_type type;
+   info_source source;
union {
char color[COLOR_MAXLEN];
struct align align;
@@ -380,49 +382,50 @@ static int head_atom_parser(const struct ref_format 
*format, struct used_atom *a
 
 static struct {
const char *name;
+   info_source source;
cmp_type cmp_type;
int (*parser)(const struct ref_format *format, struct used_atom *atom,
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
-   { "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
-   { "objectname", FIELD_STR, objectname_atom_parser },
-   { "tree" },
-   { "parent" },
-   { "numparent", FIELD_ULONG },
-   { "object" },
-   { "type" },
-   { "tag" },
-   { "author" },
-   { "authorname" },
-   { "authoremail" },
-   { "authordate", FIELD_TIME },
-   { "committer" },
-   { "committername" },
-   { "committeremail" },
-   { "committerdate", FIELD_TIME },
-   { "tagger" },
-   { "taggername" },
-   { "taggeremail" },
-   { "taggerdate", FIELD_TIME },
-   { "creator" },
-   { "creatordate", FIELD_TIME },
-   { "subject", FIELD_STR, subject_atom_parser },
-   { "body", FIELD_STR, body_atom_parser },
-   { "trailers", FIELD_STR, trailers_atom_parser },
-   { "contents", FIELD_STR, contents_atom_parser },
-   { "upstream", FIELD_STR, remote_ref_atom_parser },
-   { "push", FIELD_STR, remote_ref_atom_parser },
-   { "symref", FIELD_STR, refname_atom_parser },
-   { "flag" },
-   { "HEAD", FIELD_STR, head_atom_parser },
-   { "color", FIELD_STR, color_atom_parser },
-   { "align", FIELD_STR, align_atom_parser },
-   { "end" },
-   { "if", FIELD_STR, if_atom_parser },
-   { "then" },
-   { "else" },
+   { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "objecttype", SOURCE_OTHER },
+   { "objectsize", SOURCE_OTHER, FIELD_ULONG },
+   { "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
+   { "tree", SOURCE_OBJ },
+   { "parent", SOURCE_OBJ },
+   { "numparent", SOURCE_OBJ, FIELD_ULONG },
+   { "object", SOURCE_OBJ },
+   { "type", SOURCE_OBJ },
+   { "tag", SOURCE_OBJ },
+   { "author", SOURCE_OBJ },
+   { "authorname", SOURCE_OBJ },
+   { "authoremail", SOURCE_OBJ },
+   { "authordate", SOURCE_OBJ, FIELD_TIME },
+   { "committer", SOURCE_OBJ },
+   { "committername", SOURCE_OBJ },
+   { "committeremail", SOURCE_OBJ },
+   { "committerdate", SOURCE_OBJ, FIELD_TIME },
+   { "tagger", SOURCE_OBJ },
+   { "taggername", SOURCE_OBJ },
+   { "taggeremail", SOURCE_OBJ },
+   { "taggerdate", SOURCE_OBJ, FIELD_TIME },
+   { "creator", SOURCE_OBJ },
+   { "creatordate", SOURCE_OBJ, FIELD_TIME },
+   { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
+   { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
+   { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
+   { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+   { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+   { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+   { "flag", SOURCE_NONE },
+   { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
+   { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+   { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
+   { "end", SOURCE_NONE },
+   { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
+   { "then", SOURCE_NONE },
+   { "else", SOURCE_NONE },
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
@@ -498,6 +501,7 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
REALLOC_ARRAY(used_atom, 

[PATCH 3/4] ref-filter: merge get_obj and get_object

2018-07-09 Thread Olga Telezhnaya
Inline get_obj(): it would be easier to edit the code
without this split.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 36 +++-
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 27733ef013bed..f04169f0ea0e3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -797,24 +797,6 @@ int verify_ref_format(struct ref_format *format)
return 0;
 }
 
-/*
- * Given an object name, read the object data and size, and return a
- * "struct object".  If the object data we are returning is also borrowed
- * by the "struct object" representation, set *eaten as well---it is a
- * signal from parse_object_buffer to us not to free the buffer.
- */
-static void *get_obj(const struct object_id *oid, struct object **obj, 
unsigned long *sz, int *eaten)
-{
-   enum object_type type;
-   void *buf = read_object_file(oid, , sz);
-
-   if (buf)
-   *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
-   else
-   *obj = NULL;
-   return buf;
-}
-
 static int grab_objectname(const char *name, const struct object_id *oid,
   struct atom_value *v, struct used_atom *atom)
 {
@@ -1437,20 +1419,24 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 }
 
 static int get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj, struct strbuf *err)
+ int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
int ret = 0;
unsigned long size;
-   void *buf = get_obj(oid, obj, , );
+   enum object_type type;
+   void *buf = read_object_file(oid, , );
if (!buf)
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
  oid_to_hex(oid), ref->refname);
-   else if (!*obj)
-   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on 
%s for %s"),
- oid_to_hex(oid), ref->refname);
-   else
-   grab_values(ref->value, deref, *obj, buf, size);
+   else {
+   *obj = parse_object_buffer(oid, type, size, buf, );
+   if (!*obj)
+   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer 
failed on %s for %s"),
+ oid_to_hex(oid), ref->refname);
+   else
+   grab_values(ref->value, deref, *obj, buf, size);
+   }
if (!eaten)
free(buf);
return ret;

--
https://github.com/git/git/pull/520


[PATCH 2/4] ref-filter: add empty values to technical fields

2018-07-09 Thread Olga Telezhnaya
Atoms like "align" or "end" do not have string representation.
Earlier we had to go and parse whole object with a hope that we
could fill their string representations. It's easier to fill them
with an empty string before we start to work with whole object.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8611c24fd57d1..27733ef013bed 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
+   v->s = "";
/* only local branches may have an upstream */
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
@@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (atom->u.remote_ref.push) {
const char *branch_name;
+   v->s = "";
if (!skip_prefix(ref->refname, "refs/heads/",
 _name))
continue;
@@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (starts_with(name, "align")) {
v->handler = align_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "end")) {
v->handler = end_atom_handler;
+   v->s = "";
continue;
} else if (starts_with(name, "if")) {
const char *s;
-
+   v->s = "";
if (skip_prefix(name, "if:", ))
v->s = xstrdup(s);
v->handler = if_atom_handler;
continue;
} else if (!strcmp(name, "then")) {
v->handler = then_atom_handler;
+   v->s = "";
continue;
} else if (!strcmp(name, "else")) {
v->handler = else_atom_handler;
+   v->s = "";
continue;
} else
continue;

--
https://github.com/git/git/pull/520


[PATCH RFC v2 1/4] ref-filter: start using oid_object_info

2018-05-18 Thread Olga Telezhnaya
Start using oid_object_info_extended(). So, if info from this function
is enough, we do not need to get and parse whole object (as it was before).
It's good for 3 reasons:
1. Some Git commands potentially will work faster.
2. It's much easier to add support for objectsize:disk and deltabase.
   (I have plans to add this support further)
3. It's easier to move formatting from cat-file command to this logic
   (It pretends to be unified formatting logic in the end)

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 47 +++
 ref-filter.h | 21 +
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 39e2744c949bb..4008351553391 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -100,6 +100,7 @@ static struct used_atom {
} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
+static struct expand_data oi_data;
 
 /*
  * Expand string, append it to strbuf *sb, then return error code ret.
@@ -267,6 +268,22 @@ static int contents_atom_parser(const struct ref_format 
*format, struct used_ato
return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *unused_err)
+{
+   oi_data.use_data = 1;
+   oi_data.info.typep = _data.type;
+   return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *unused_err)
+{
+   oi_data.use_data = 1;
+   oi_data.info.sizep = _data.size;
+   return 0;
+}
+
 static int objectname_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
  const char *arg, struct strbuf *err)
 {
@@ -383,9 +400,9 @@ static struct {
int (*parser)(const struct ref_format *format, struct used_atom *atom,
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
-   { "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
+   { "refname", FIELD_STR, refname_atom_parser },
+   { "objecttype", FIELD_STR, objecttype_atom_parser },
+   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "objectname", FIELD_STR, objectname_atom_parser },
{ "tree" },
{ "parent" },
@@ -1207,7 +1224,8 @@ static void fill_missing_values(struct atom_value *val)
  */
 static void grab_values(struct atom_value *val, int deref, struct object *obj, 
void *buf, unsigned long sz)
 {
-   grab_common_values(val, deref, obj, buf, sz);
+   if (deref || !oi_data.use_data)
+   grab_common_values(val, deref, obj, buf, sz);
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj, buf, sz);
@@ -1536,6 +1554,13 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (!deref && grab_objectname(name, >objectname, v, 
atom)) {
continue;
+   } else if (!deref && !strcmp(name, "objecttype") && 
oi_data.use_data) {
+   v->s = type_name(oi_data.type);
+   continue;
+   } else if (!deref && !strcmp(name, "objectsize") && 
oi_data.use_data) {
+   v->value = oi_data.size;
+   v->s = xstrfmt("%lu", oi_data.size);
+   continue;
} else if (!strcmp(name, "HEAD")) {
if (atom->u.head && !strcmp(ref->refname, atom->u.head))
v->s = "*";
@@ -2156,8 +2181,17 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct 
ref_array_item *a, stru
int (*cmp_fn)(const char *, const char *);
struct strbuf err = STRBUF_INIT;
 
+   oi_data.oid = a->objectname;
+   if (oi_data.use_data &&
+   oid_object_info_extended(_data.oid, _data.info, 
OBJECT_INFO_LOOKUP_REPLACE) < 0)
+   die(_("missing object %s for %s"), oid_to_hex(>objectname), 
a->refname);
if (get_ref_atom_value(a, s->atom, , ))
die("%s", err.buf);
+
+   oi_data.oid = b->objectname;
+   if (oi_data.use_data &&
+   oid_object_info_extended(_data.oid, _data.info, 
OBJECT_INFO_LOOKUP_REPLACE) < 0)
+   die(_("missing object %s for %s"), oid_to_hex(>objectname), 
b->refname);
if (get_ref_atom_value(b, s->atom, , ))
die("%s", err.buf);
strbuf_release();
@@ -2226,6 +2260,11 @@ int format_ref_array_item(struct ref_array_item *info,
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
+   oi_data.oid = info->objectname;
+   if (oi_data.use_data &&
+   oid_object_info_extended(_data.oid, 

[PATCH RFC v2 2/4] ref-filter: add objectsize:disk formatting option

2018-05-18 Thread Olga Telezhnaya
Add %(objectsize:disk) support. It is still not working for deref:
I am thinking how to support it in a more elegant way.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 21 -
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 4008351553391..c00de58455301 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -277,10 +277,15 @@ static int objecttype_atom_parser(const struct ref_format 
*format, struct used_a
 }
 
 static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
- const char *arg, struct strbuf *unused_err)
+ const char *arg, struct strbuf *err)
 {
+   if (!arg)
+   oi_data.info.sizep = _data.size;
+   else if (!strcmp(arg, "disk"))
+   oi_data.info.disk_sizep = _data.disk_size;
+   else
+   return strbuf_addf_ret(err, -1, _("unrecognized %%(objectsize) 
argument: %s"), arg);
oi_data.use_data = 1;
-   oi_data.info.sizep = _data.size;
return 0;
 }
 
@@ -1557,9 +1562,15 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
} else if (!deref && !strcmp(name, "objecttype") && 
oi_data.use_data) {
v->s = type_name(oi_data.type);
continue;
-   } else if (!deref && !strcmp(name, "objectsize") && 
oi_data.use_data) {
-   v->value = oi_data.size;
-   v->s = xstrfmt("%lu", oi_data.size);
+   } else if (!deref && starts_with(name, "objectsize") && 
oi_data.use_data) {
+   if (!strcmp(name, "objectsize")) {
+   v->value = oi_data.size;
+   v->s = xstrfmt("%lu", oi_data.size);
+   } else {
+   /* It can be only objectsize:disk, we checked 
it in parser */
+   v->value = oi_data.disk_size;
+   v->s = xstrfmt("%lu", oi_data.disk_size);
+   }
continue;
} else if (!strcmp(name, "HEAD")) {
if (atom->u.head && !strcmp(ref->refname, atom->u.head))

--
https://github.com/git/git/pull/493


[PATCH RFC v2 3/4] ref-filter: add tests for objectsize:disk

2018-05-18 Thread Olga Telezhnaya
Add tests for %(objectsize:disk) atom.

Signed-off-by: Olga Telezhnaia 
---
 t/t6300-for-each-ref.sh | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 295d1475bde01..570bb606045d7 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -83,6 +83,7 @@ test_atom head push:strip=1 remotes/myfork/master
 test_atom head push:strip=-1 master
 test_atom head objecttype commit
 test_atom head objectsize 171
+test_atom head objectsize:disk 138
 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)
@@ -124,6 +125,7 @@ test_atom tag upstream ''
 test_atom tag push ''
 test_atom tag objecttype tag
 test_atom tag objectsize 154
+test_atom tag objectsize:disk 138
 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)

--
https://github.com/git/git/pull/493


[PATCH RFC v2 4/4] ref-filter: add deltabase formatting option

2018-05-18 Thread Olga Telezhnaya
Add %(deltabase) support. It is still not working for deref:
I am thinking how to support it in a more elegant way.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index c00de58455301..989ccdb356a32 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -276,6 +276,14 @@ static int objecttype_atom_parser(const struct ref_format 
*format, struct used_a
return 0;
 }
 
+static int deltabase_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *unused_err)
+{
+   oi_data.use_data = 1;
+   oi_data.info.delta_base_sha1 = oi_data.delta_base_oid.hash;
+   return 0;
+}
+
 static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
  const char *arg, struct strbuf *err)
 {
@@ -409,6 +417,7 @@ static struct {
{ "objecttype", FIELD_STR, objecttype_atom_parser },
{ "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "objectname", FIELD_STR, objectname_atom_parser },
+   { "deltabase", FIELD_STR, deltabase_atom_parser },
{ "tree" },
{ "parent" },
{ "numparent", FIELD_ULONG },
@@ -1572,6 +1581,9 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
v->s = xstrfmt("%lu", oi_data.disk_size);
}
continue;
+   } else if (!deref && !strcmp(name, "deltabase") && 
oi_data.use_data) {
+   v->s = xstrdup(oid_to_hex(_data.delta_base_oid));
+   continue;
} else if (!strcmp(name, "HEAD")) {
if (atom->u.head && !strcmp(ref->refname, atom->u.head))
v->s = "*";

--
https://github.com/git/git/pull/493


[PATCH RFC] ref-filter: start using oid_object_info

2018-05-14 Thread Olga Telezhnaya
Start using oid_object_info_extended(). So, if info from this function
is enough, we do not need to get and parse whole object (as it was before).
It's good for 3 reasons:
1. Some Git commands potentially will work faster.
2. It's much easier to add support for objectsize:disk and deltabase.
   (I have plans to add this support further)
3. It's easier to move formatting from cat-file command to this logic
   (It pretends to be unified formatting logic in the end)

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 34 +++---
 ref-filter.h | 21 +
 2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 39e2744c949bb..7c4693ed084bb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -100,6 +100,7 @@ static struct used_atom {
} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
+static struct expand_data format_data;
 
 /*
  * Expand string, append it to strbuf *sb, then return error code ret.
@@ -267,6 +268,22 @@ static int contents_atom_parser(const struct ref_format 
*format, struct used_ato
return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *unused_err)
+{
+   format_data.use_data = 1;
+   format_data.info.typep = _data.type;
+   return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *unused_err)
+{
+   format_data.use_data = 1;
+   format_data.info.sizep = _data.size;
+   return 0;
+}
+
 static int objectname_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
  const char *arg, struct strbuf *err)
 {
@@ -383,9 +400,9 @@ static struct {
int (*parser)(const struct ref_format *format, struct used_atom *atom,
  const char *arg, struct strbuf *err);
 } valid_atom[] = {
-   { "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
+   { "refname", FIELD_STR, refname_atom_parser },
+   { "objecttype", FIELD_STR, objecttype_atom_parser },
+   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "objectname", FIELD_STR, objectname_atom_parser },
{ "tree" },
{ "parent" },
@@ -1536,6 +1553,13 @@ static int populate_value(struct ref_array_item *ref, 
struct strbuf *err)
continue;
} else if (!deref && grab_objectname(name, >objectname, v, 
atom)) {
continue;
+   } else if (!deref && !strcmp(name, "objecttype")) {
+   v->s = type_name(format_data.type);
+   continue;
+   } else if (!deref && !strcmp(name, "objectsize")) {
+   v->value = format_data.size;
+   v->s = xstrfmt("%lu", format_data.size);
+   continue;
} else if (!strcmp(name, "HEAD")) {
if (atom->u.head && !strcmp(ref->refname, atom->u.head))
v->s = "*";
@@ -2226,6 +2250,10 @@ int format_ref_array_item(struct ref_array_item *info,
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
+   format_data.oid = info->objectname;
+   if (format_data.use_data && oid_object_info_extended(_data.oid, 
_data.info,
+
OBJECT_INFO_LOOKUP_REPLACE) < 0)
+   return strbuf_addf_ret(error_buf, -1, "format: could not get 
object info");
 
state.quote_style = format->quote_style;
push_stack_element();
diff --git a/ref-filter.h b/ref-filter.h
index 85c8ebc3b904e..857e8c5318a8f 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -85,6 +85,27 @@ struct ref_format {
int need_color_reset_at_eol;
 };
 
+struct expand_data {
+   struct object_id oid;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   struct object_id delta_base_oid;
+
+   /*
+* This object_info is set up to be passed to oid_object_info_extended.
+* It will point to the data elements above, so you can retrieve
+* the response from there.
+*/
+   struct object_info info;
+
+   /*
+* This flag will be true if the requested format and options
+* require us to call oid_object_info_extended.
+*/
+   unsigned use_data : 1;
+};
+
 #define REF_FORMAT_INIT { NULL, 0, -1 }
 
 /*  Macros for checking --merged and --no-merged options */

--
https://github.com/git/git/pull/493


[PATCH v6 1/6] ref-filter: add shortcut to work with strbufs

2018-03-29 Thread Olga Telezhnaya
Add function strbuf_addf_ret() that helps to save a few lines of code.
Function expands fmt with placeholders, append resulting message
to strbuf *sb, and return error code ret.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..0c8d1589cf316 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,6 +101,19 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
+/*
+ * Expand string, append it to strbuf *sb, then return error code ret.
+ * Allow to save few lines of code.
+ */
+static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
+{
+   va_list ap;
+   va_start(ap, fmt);
+   strbuf_vaddf(sb, fmt, ap);
+   va_end(ap);
+   return ret;
+}
+
 static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
 {
if (!color_value)

--
https://github.com/git/git/pull/466


[PATCH v6 4/6] ref-filter: change parsing function error handling

2018-03-29 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parse_ref_filter_atom() by adding
strbuf parameter for error message.
The function returns the position in the used_atom[] array
(as before) for the given atom, or -1 to signal an error.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 32 
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index a18c86961f08c..93fa6b4e5e63d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -410,7 +410,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -420,7 +421,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
if (*sp == '*' && sp < ep)
sp++; /* deref */
if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   return strbuf_addf_ret(err, -1, _("malformed field name: %.*s"),
+  (int)(ep-atom), atom);
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
@@ -446,7 +448,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
}
 
if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"),
+  (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -728,17 +731,21 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, sp + 2, ep, );
+   if (at < 0)
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2157,13 +2164,17 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
+   if (pos < 0) {
+   pop_stack_element();
+   return -1;
+   }
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf)) {
pop_stack_element();
return -1;
@@ -,7 +2233,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res = parse_ref_filter_atom(, atom, end, );
+   if (res < 0)
+   die("%s", err.buf);
+   strbuf_release();
+   return res;
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/466


[PATCH v6 2/6] ref-filter: start adding strbufs with errors

2018-03-29 Thread Olga Telezhnaya
This is a first step in removing die() calls from ref-filter
formatting logic, so that it could be used by other commands
that do not want to die during formatting process.
die() calls related to bugs in code will not be touched in this patch.

Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and adjusts
its callers. While at it, reduce the scope of the out-variable.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 17 -
 ref-filter.h |  7 ---
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6d0cea9d4bcc4..c21e5a04a0177 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 0c8d1589cf316..9833709dbefe3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2131,9 +2131,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2161,19 +2162,25 @@ void format_ref_array_item(struct ref_array_item *info,
resetv.s = GIT_COLOR_RESET;
append_atom(, );
}
-   if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   if (state.stack->prev) {
+   pop_stack_element();
+   return strbuf_addf_ret(error_buf, -1, _("format: %%(end) atom 
missing"));
+   }
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to 

[PATCH v6 3/6] ref-filter: add return value && strbuf to handlers

2018-03-29 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of handlers by adding return value
and strbuf parameter for errors.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 51 +++
 1 file changed, 35 insertions(+), 16 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 9833709dbefe3..a18c86961f08c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -400,7 +400,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -494,7 +495,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *unused_err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -506,6 +508,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -540,7 +543,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -548,6 +552,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -585,7 +590,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -597,6 +603,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -609,7 +616,8 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
struct ref_formatting_stack *cur = state->stack;
struct if_then_else *if_then_else = NULL;
@@ -617,11 +625,11 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
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"));
+   return strbuf_addf_ret(err, -1, _("format: %%(then) atom used 
without an %%(if) atom"));
if (if_then_else->then_atom_seen)
-   die(_("format: %%(then) atom used more than once"));
+   return strbuf_addf_ret(err, -1, _("format: %%(then) atom used 
more than once"));
if (if_then_else->else_atom_seen)
-   die(_("format: %%(then) atom used after %%(else)"));
+   return strbuf_addf_ret(err, -1, _("format: %%(then) atom used 
after %%(else)"));
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -637,9 +645,11 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(>output);
+   return 0;
 }
 

[PATCH v6 6/6] ref-filter: libify get_ref_atom_value()

2018-03-29 Thread Olga Telezhnaya
Finish removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of get_ref_atom_value() and underlying functions
by adding return value and strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 54 ++
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 3f85ef64267d9..3bc65e49358ee 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1427,28 +1427,30 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static void get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj)
+static int get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
+   int ret = 0;
unsigned long size;
void *buf = get_obj(oid, obj, , );
if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(oid), ref->refname);
-   if (!*obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(oid), ref->refname);
-
-   grab_values(ref->value, deref, *obj, buf, size);
+   ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
+ oid_to_hex(oid), ref->refname);
+   else if (!*obj)
+   ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on 
%s for %s"),
+ oid_to_hex(oid), ref->refname);
+   else
+   grab_values(ref->value, deref, *obj, buf, size);
if (!eaten)
free(buf);
+   return ret;
 }
 
 /*
  * Parse the object referred by ref, and grab needed value.
  */
-static void populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 {
struct object *obj;
int i;
@@ -1570,16 +1572,17 @@ static void populate_value(struct ref_array_item *ref)
break;
}
if (used_atom_cnt <= i)
-   return;
+   return 0;
 
-   get_object(ref, >objectname, 0, );
+   if (get_object(ref, >objectname, 0, , err))
+   return -1;
 
/*
 * If there is no atom that wants to know about tagged
 * object, we are done.
 */
if (!need_tagged || (obj->type != OBJ_TAG))
-   return;
+   return 0;
 
/*
 * If it is a tag object, see if we use a value that derefs
@@ -1593,20 +1596,23 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   get_object(ref, tagged, 1, );
+   return get_object(ref, tagged, 1, , err);
 }
 
 /*
  * Given a ref, return the value for the atom.  This lazily gets value
  * out of the object by calling populate value.
  */
-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
+static int get_ref_atom_value(struct ref_array_item *ref, int atom,
+ struct atom_value **v, struct strbuf *err)
 {
if (!ref->value) {
-   populate_value(ref);
+   if (populate_value(ref, err))
+   return -1;
fill_missing_values(ref->value);
}
*v = >value[atom];
+   return 0;
 }
 
 /*
@@ -2130,9 +2136,13 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct 
ref_array_item *a, stru
int cmp;
cmp_type cmp_type = used_atom[s->atom].type;
int (*cmp_fn)(const char *, const char *);
+   struct strbuf err = STRBUF_INIT;
 
-   get_ref_atom_value(a, s->atom, );
-   get_ref_atom_value(b, s->atom, );
+   if (get_ref_atom_value(a, s->atom, , ))
+   die("%s", err.buf);
+   if (get_ref_atom_value(b, s->atom, , ))
+   die("%s", err.buf);
+   strbuf_release();
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
if (s->version)
cmp = versioncmp(va->s, vb->s);
@@ -2210,12 +2220,8 @@ int format_ref_array_item(struct ref_array_item *info,
if (cp < sp)
append_literal(cp, sp, );
pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
-   if (pos < 0) {
-   pop_stack_element();
-   return -1;
-   }
-   get_ref_atom_value(info, pos, );
-   if (atomv->handler(atomv, , error_buf)) {
+   if (pos < 0 || 

[PATCH v6 5/6] ref-filter: add return value to parsers

2018-03-29 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parsers by adding return value and
strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 138 ++-
 1 file changed, 89 insertions(+), 49 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 93fa6b4e5e63d..3f85ef64267d9 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -114,22 +114,25 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, 
const char *fmt, ...)
return ret;
 }
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
if (!color_value)
-   die(_("expected format: %%(color:)"));
+   return strbuf_addf_ret(err, -1, _("expected format: 
%%(color:)"));
if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   return strbuf_addf_ret(err, -1, _("unrecognized color: 
%%(color:%s)"),
+  color_value);
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -139,16 +142,18 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   return strbuf_addf_ret(err, -1, _("Integer value 
expected refname:lstrip=%s"), arg);
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
+   return strbuf_addf_ret(err, -1, _("Integer value 
expected refname:rstrip=%s"), arg);
} else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) 
argument: %s"), name, arg);
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -158,9 +163,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -183,29 +187,38 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err)) 
{
+   string_list_clear(, 0);
+   return -1;
+   }
}
}
 
string_list_clear(, 0);
+   return 0;
 }
 
-static void body_atom_parser(const struct ref_format *format, struct used_atom 
*atom, const char *arg)
+static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+   const char *arg, struct 

[PATCH v5 4/6] ref-filter: change parsing function error handling

2018-03-21 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parse_ref_filter_atom() by adding
strbuf parameter for error message.
The function returns the position in the used_atom[] array
(as before) for the given atom, or -1 to signal an error.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 30 ++
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f79c8c477f1dc..ca38728b4c998 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -397,7 +397,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -407,7 +408,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
if (*sp == '*' && sp < ep)
sp++; /* deref */
if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   return strbuf_error(err, -1, _("malformed field name: %.*s"),
+   (int)(ep-atom), atom);
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
@@ -433,7 +435,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
}
 
if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   return strbuf_error(err, -1, _("unknown field name: %.*s"),
+   (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -715,17 +718,21 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, sp + 2, ep, );
+   if (at < 0)
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2144,13 +2151,15 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
+   if (pos < 0)
+   return -1;
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf))
return -1;
}
@@ -2203,7 +2212,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res = parse_ref_filter_atom(, atom, end, );
+   if (res < 0)
+   die("%s", err.buf);
+   strbuf_release();
+   return res;
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/466


[PATCH v5 2/6] ref-filter: start adding strbufs with errors

2018-03-21 Thread Olga Telezhnaya
This is a first step in removing die() calls from ref-filter
formatting logic, so that it could be used by other commands
that do not want to die during formatting process.
die() calls related to bugs in code will not be touched in this patch.

Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and adjusts
its callers. While at it, reduce the scope of the out-variable.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 13 +
 ref-filter.h |  7 ---
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6d0cea9d4bcc4..c21e5a04a0177 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..2c3fb2f003708 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2118,9 +2118,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2149,18 +2150,22 @@ void format_ref_array_item(struct ref_array_item *info,
append_atom(, );
}
if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   return strbuf_error(error_buf, -1, _("format: %%(end) atom 
missing"));
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to the list */

--
https://github.com/git/git/pull/466


[PATCH v5 1/6] strbuf: add shortcut to work with error messages

2018-03-21 Thread Olga Telezhnaya
Add function strbuf_error() that helps to save few lines of code.
Function expands fmt with placeholders, append resulting error message
to strbuf *err, and return error code ret.

Signed-off-by: Olga Telezhnaia 
---
 strbuf.h | 13 +
 1 file changed, 13 insertions(+)

diff --git a/strbuf.h b/strbuf.h
index e6cae5f4398c8..fa66d4835f1a7 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -620,4 +620,17 @@ char *xstrvfmt(const char *fmt, va_list ap);
 __attribute__((format (printf, 1, 2)))
 char *xstrfmt(const char *fmt, ...);
 
+/*
+ * Expand error message, append it to strbuf *err, then return error code ret.
+ * Allow to save few lines of code.
+ */
+static inline int strbuf_error(struct strbuf *err, int ret, const char *fmt, 
...)
+{
+   va_list ap;
+   va_start(ap, fmt);
+   strbuf_vaddf(err, fmt, ap);
+   va_end(ap);
+   return ret;
+}
+
 #endif /* STRBUF_H */

--
https://github.com/git/git/pull/466


[PATCH v5 5/6] ref-filter: add return value to parsers

2018-03-21 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parsers by adding return value and
strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 112 ---
 1 file changed, 68 insertions(+), 44 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index ca38728b4c998..0ef7386b5fd20 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,22 +101,25 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
if (!color_value)
-   die(_("expected format: %%(color:)"));
+   return strbuf_error(err, -1, _("expected format: 
%%(color:)"));
if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   return strbuf_error(err, -1, _("unrecognized color: 
%%(color:%s)"),
+   color_value);
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -126,16 +129,18 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   return strbuf_error(err, -1, _("Integer value expected 
refname:lstrip=%s"), arg);
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
+   return strbuf_error(err, -1, _("Integer value expected 
refname:rstrip=%s"), arg);
} else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   return strbuf_error(err, -1, _("unrecognized %%(%s) argument: 
%s"), name, arg);
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -145,9 +150,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -170,29 +174,36 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err))
+   return -1;
}
}
 
string_list_clear(, 0);
+   return 0;
 }
 
-static void body_atom_parser(const struct ref_format *format, struct used_atom 
*atom, const char *arg)
+static int body_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+   const char *arg, struct strbuf *err)
 {
if (arg)
-   die(_("%%(body) does not take arguments"));
+   

[PATCH v5 6/6] ref-filter: libify get_ref_atom_value()

2018-03-21 Thread Olga Telezhnaya
Finish removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of get_ref_atom_value() and underlying functions
by adding return value and strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 49 ++---
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 0ef7386b5fd20..52bb84398dc8d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1398,28 +1398,30 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static void get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj)
+static int get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
+   int ret = 0;
unsigned long size;
void *buf = get_obj(oid, obj, , );
if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(oid), ref->refname);
-   if (!*obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(oid), ref->refname);
-
-   grab_values(ref->value, deref, *obj, buf, size);
+   ret = strbuf_error(err, -1, _("missing object %s for %s"),
+  oid_to_hex(oid), ref->refname);
+   else if (!*obj)
+   ret = strbuf_error(err, -1, _("parse_object_buffer failed on %s 
for %s"),
+  oid_to_hex(oid), ref->refname);
+   else
+   grab_values(ref->value, deref, *obj, buf, size);
if (!eaten)
free(buf);
+   return ret;
 }
 
 /*
  * Parse the object referred by ref, and grab needed value.
  */
-static void populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 {
struct object *obj;
int i;
@@ -1541,16 +1543,17 @@ static void populate_value(struct ref_array_item *ref)
break;
}
if (used_atom_cnt <= i)
-   return;
+   return 0;
 
-   get_object(ref, >objectname, 0, );
+   if (get_object(ref, >objectname, 0, , err))
+   return -1;
 
/*
 * If there is no atom that wants to know about tagged
 * object, we are done.
 */
if (!need_tagged || (obj->type != OBJ_TAG))
-   return;
+   return 0;
 
/*
 * If it is a tag object, see if we use a value that derefs
@@ -1564,20 +1567,23 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   get_object(ref, tagged, 1, );
+   return get_object(ref, tagged, 1, , err);
 }
 
 /*
  * Given a ref, return the value for the atom.  This lazily gets value
  * out of the object by calling populate value.
  */
-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
+static int get_ref_atom_value(struct ref_array_item *ref, int atom,
+ struct atom_value **v, struct strbuf *err)
 {
if (!ref->value) {
-   populate_value(ref);
+   if (populate_value(ref, err))
+   return -1;
fill_missing_values(ref->value);
}
*v = >value[atom];
+   return 0;
 }
 
 /*
@@ -2101,9 +2107,13 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct 
ref_array_item *a, stru
int cmp;
cmp_type cmp_type = used_atom[s->atom].type;
int (*cmp_fn)(const char *, const char *);
+   struct strbuf err = STRBUF_INIT;
 
-   get_ref_atom_value(a, s->atom, );
-   get_ref_atom_value(b, s->atom, );
+   if (get_ref_atom_value(a, s->atom, , ))
+   die("%s", err.buf);
+   if (get_ref_atom_value(b, s->atom, , ))
+   die("%s", err.buf);
+   strbuf_release();
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
if (s->version)
cmp = versioncmp(va->s, vb->s);
@@ -2183,7 +2193,8 @@ int format_ref_array_item(struct ref_array_item *info,
pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
if (pos < 0)
return -1;
-   get_ref_atom_value(info, pos, );
+   if (get_ref_atom_value(info, pos, , error_buf))
+   return -1;
if (atomv->handler(atomv, , error_buf))
return -1;
}

--
https://github.com/git/git/pull/466


[PATCH v5 3/6] ref-filter: add return value && strbuf to handlers

2018-03-21 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of handlers by adding return value
and strbuf parameter for errors.
Return value equals 0 upon success and -1 upon failure.
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 47 +++
 1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 2c3fb2f003708..f79c8c477f1dc 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -387,7 +387,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -481,7 +482,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *unused_err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -493,6 +495,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -527,7 +530,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -535,6 +539,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -572,7 +577,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -584,6 +590,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -596,7 +603,8 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
struct ref_formatting_stack *cur = state->stack;
struct if_then_else *if_then_else = NULL;
@@ -604,11 +612,11 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
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"));
+   return strbuf_error(err, -1, _("format: %%(then) atom used 
without an %%(if) atom"));
if (if_then_else->then_atom_seen)
-   die(_("format: %%(then) atom used more than once"));
+   return strbuf_error(err, -1, _("format: %%(then) atom used more 
than once"));
if (if_then_else->else_atom_seen)
-   die(_("format: %%(then) atom used after %%(else)"));
+   return strbuf_error(err, -1, _("format: %%(then) atom used 
after %%(else)"));
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -624,9 +632,11 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(>output);
+   return 0;
 }
 
-static void 

[PATCH v4 4/5] ref-filter: add return value to parsers

2018-03-20 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parsers by adding return value and
strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure (there
could be more error codes further if necessary).
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 177 +++
 1 file changed, 118 insertions(+), 59 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 2313a33f0baa4..b90cec1056954 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,22 +101,28 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
-   if (!color_value)
-   die(_("expected format: %%(color:)"));
-   if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   if (!color_value) {
+   strbuf_addstr(err, _("expected format: %(color:)"));
+   return -1;
+   }
+   if (color_parse(color_value, atom->u.color) < 0) {
+   strbuf_addf(err, _("unrecognized color: %%(color:%s)"), 
color_value);
+   return -1;
+   }
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -125,17 +131,25 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
else if (skip_prefix(arg, "lstrip=", ) ||
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
-   if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   if (strtol_i(arg, 10, >lstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:lstrip=%s"), arg);
+   return -1;
+   }
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
-   if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
-   } else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   if (strtol_i(arg, 10, >rstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:rstrip=%s"), arg);
+   return -1;
+   }
+   } else {
+   strbuf_addf(err, _("unrecognized %%(%s) argument: %s"), name, 
arg);
+   return -1;
+   }
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -145,9 +159,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -170,29 +183,40 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err))
+   return -1;
 

[PATCH v4 2/5] ref-filter: add return value && strbuf to handlers

2018-03-20 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of handlers by adding return value
and strbuf parameter for errors.
Return value equals 0 upon success and -1 upon failure (there could be
more error codes further if necessary). Upon failure, error message is
appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 71 
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 54fae00bdd410..d120360104806 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -387,7 +387,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -481,7 +482,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *unused_err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -493,6 +495,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -527,7 +530,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -535,6 +539,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -572,7 +577,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -584,6 +590,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -596,19 +603,24 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
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 (!if_then_else) {
+   strbuf_addstr(err, _("format: %(then) atom used without an 
%(if) atom"));
+   return -1;
+   } else if (if_then_else->then_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used more than 
once"));
+   return -1;
+   } else if (if_then_else->else_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used after 
%(else)"));
+   return -1;
+   }
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -624,34 +636,44 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len 

[PATCH v4 5/5] ref-filter: get_ref_atom_value() error handling

2018-03-20 Thread Olga Telezhnaya
Finish removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of get_ref_atom_value() and underlying functions
by adding return value and strbuf parameter for error message.
Return value equals 0 upon success and -1 upon failure (there
could be more error codes further if necessary).
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 55 ---
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index b90cec1056954..85f971663a4aa 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1445,28 +1445,36 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static void get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj)
+static int get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
unsigned long size;
void *buf = get_obj(oid, obj, , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(oid), ref->refname);
-   if (!*obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(oid), ref->refname);
-
+   if (!buf) {
+   strbuf_addf(err, _("missing object %s for %s"), oid_to_hex(oid),
+   ref->refname);
+   if (!eaten)
+   free(buf);
+   return -1;
+   }
+   if (!*obj) {
+   strbuf_addf(err, _("parse_object_buffer failed on %s for %s"),
+   oid_to_hex(oid), ref->refname);
+   if (!eaten)
+   free(buf);
+   return -1;
+   }
grab_values(ref->value, deref, *obj, buf, size);
if (!eaten)
free(buf);
+   return 0;
 }
 
 /*
  * Parse the object referred by ref, and grab needed value.
  */
-static void populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 {
struct object *obj;
int i;
@@ -1588,16 +1596,17 @@ static void populate_value(struct ref_array_item *ref)
break;
}
if (used_atom_cnt <= i)
-   return;
+   return 0;
 
-   get_object(ref, >objectname, 0, );
+   if (get_object(ref, >objectname, 0, , err))
+   return -1;
 
/*
 * If there is no atom that wants to know about tagged
 * object, we are done.
 */
if (!need_tagged || (obj->type != OBJ_TAG))
-   return;
+   return 0;
 
/*
 * If it is a tag object, see if we use a value that derefs
@@ -1611,20 +1620,23 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   get_object(ref, tagged, 1, );
+   return get_object(ref, tagged, 1, , err);
 }
 
 /*
  * Given a ref, return the value for the atom.  This lazily gets value
  * out of the object by calling populate value.
  */
-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
+static int get_ref_atom_value(struct ref_array_item *ref, int atom,
+ struct atom_value **v, struct strbuf *err)
 {
if (!ref->value) {
-   populate_value(ref);
+   if (populate_value(ref, err))
+   return -1;
fill_missing_values(ref->value);
}
*v = >value[atom];
+   return 0;
 }
 
 /*
@@ -2148,9 +2160,13 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct 
ref_array_item *a, stru
int cmp;
cmp_type cmp_type = used_atom[s->atom].type;
int (*cmp_fn)(const char *, const char *);
+   struct strbuf err = STRBUF_INIT;
 
-   get_ref_atom_value(a, s->atom, );
-   get_ref_atom_value(b, s->atom, );
+   if (get_ref_atom_value(a, s->atom, , ))
+   die("%s", err.buf);
+   if (get_ref_atom_value(b, s->atom, , ))
+   die("%s", err.buf);
+   strbuf_release();
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
if (s->version)
cmp = versioncmp(va->s, vb->s);
@@ -2230,7 +2246,8 @@ int format_ref_array_item(struct ref_array_item *info,
pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
if (pos < 0)
return -1;
-   get_ref_atom_value(info, pos, );
+   if (get_ref_atom_value(info, pos, , error_buf))
+   return -1;

[PATCH v4 1/5] ref-filter: start adding strbufs with errors

2018-03-20 Thread Olga Telezhnaya
This is a first step in removing die() calls from ref-filter
formatting logic, so that it could be used by other commands
that do not want to die during formatting process.
die() calls related to bugs in code will not be touched in this patch.

Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and adjusts
its callers. While at it, reduce the scope of the out-variable.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 17 -
 ref-filter.h |  7 ---
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6d0cea9d4bcc4..c21e5a04a0177 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..54fae00bdd410 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2118,9 +2118,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2148,19 +2149,25 @@ void format_ref_array_item(struct ref_array_item *info,
resetv.s = GIT_COLOR_RESET;
append_atom(, );
}
-   if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   if (state.stack->prev) {
+   strbuf_addstr(error_buf, _("format: %(end) atom missing"));
+   return -1;
+   }
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to the list */

--

[PATCH v4 3/5] ref-filter: change parsing function error handling

2018-03-20 Thread Olga Telezhnaya
Continue removing die() calls from ref-filter formatting logic,
so that it could be used by other commands.

Change the signature of parse_ref_filter_atom() by adding
strbuf parameter for error message.
The function returns the position in the used_atom[] array
(as before) for the given atom, or -1 to signal an error (there
could be more negative error codes further if necessary).
Upon failure, error message is appended to the strbuf.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 36 ++--
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index d120360104806..2313a33f0baa4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -397,7 +397,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -406,8 +407,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
sp = atom;
if (*sp == '*' && sp < ep)
sp++; /* deref */
-   if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   if (ep <= sp) {
+   strbuf_addf(err, _("malformed field name: %.*s"), 
(int)(ep-atom), atom);
+   return -1;
+   }
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
@@ -432,8 +435,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   if (ARRAY_SIZE(valid_atom) <= i) {
+   strbuf_addf(err, _("unknown field name: %.*s"), (int)(ep-atom), 
atom);
+   return -1;
+   }
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -725,17 +730,21 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, sp + 2, ep, );
+   if (at < 0)
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2154,13 +2163,15 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
+   if (pos < 0)
+   return -1;
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf))
return -1;
}
@@ -2215,7 +2226,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res = parse_ref_filter_atom(, atom, end, );
+   if (res < 0)
+   die("%s", err.buf);
+   strbuf_release();
+   return res;
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/466


[PATCH v3 4/5] ref-filter: add return value to parsers

2018-03-19 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parsers by adding return value and
strbuf parameter for error message.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 177 +++
 1 file changed, 118 insertions(+), 59 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 2313a33f0baa4..b90cec1056954 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,22 +101,28 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
-   if (!color_value)
-   die(_("expected format: %%(color:)"));
-   if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   if (!color_value) {
+   strbuf_addstr(err, _("expected format: %(color:)"));
+   return -1;
+   }
+   if (color_parse(color_value, atom->u.color) < 0) {
+   strbuf_addf(err, _("unrecognized color: %%(color:%s)"), 
color_value);
+   return -1;
+   }
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -125,17 +131,25 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
else if (skip_prefix(arg, "lstrip=", ) ||
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
-   if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   if (strtol_i(arg, 10, >lstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:lstrip=%s"), arg);
+   return -1;
+   }
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
-   if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
-   } else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   if (strtol_i(arg, 10, >rstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:rstrip=%s"), arg);
+   return -1;
+   }
+   } else {
+   strbuf_addf(err, _("unrecognized %%(%s) argument: %s"), name, 
arg);
+   return -1;
+   }
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -145,9 +159,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -170,29 +183,40 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err))
+   return -1;
}
}
 
string_list_clear(, 0);
+   return 0;
 }
 
-static void body_atom_parser(const struct ref_format *format, struct used_atom 
*atom, const char 

[PATCH v3 2/5] ref-filter: add return value && strbuf to handlers

2018-03-19 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of handlers by adding return value
and strbuf parameter for errors.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 71 
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 54fae00bdd410..d120360104806 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -387,7 +387,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -481,7 +482,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *unused_err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -493,6 +495,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -527,7 +530,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -535,6 +539,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -572,7 +577,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -584,6 +590,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -596,19 +603,24 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
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 (!if_then_else) {
+   strbuf_addstr(err, _("format: %(then) atom used without an 
%(if) atom"));
+   return -1;
+   } else if (if_then_else->then_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used more than 
once"));
+   return -1;
+   } else if (if_then_else->else_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used after 
%(else)"));
+   return -1;
+   }
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -624,34 +636,44 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(>output);
+   return 0;
 }
 
-static void 

[PATCH v3 3/5] ref-filter: change parsing function error handling

2018-03-19 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parse_ref_filter_atom() by adding
strbuf parameter for error message.
Return value means the same except negative values: they indicate
errors (previous version could return only non-negative value).

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 36 ++--
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index d120360104806..2313a33f0baa4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -397,7 +397,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -406,8 +407,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
sp = atom;
if (*sp == '*' && sp < ep)
sp++; /* deref */
-   if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   if (ep <= sp) {
+   strbuf_addf(err, _("malformed field name: %.*s"), 
(int)(ep-atom), atom);
+   return -1;
+   }
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
@@ -432,8 +435,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   if (ARRAY_SIZE(valid_atom) <= i) {
+   strbuf_addf(err, _("unknown field name: %.*s"), (int)(ep-atom), 
atom);
+   return -1;
+   }
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -725,17 +730,21 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, sp + 2, ep, );
+   if (at < 0)
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2154,13 +2163,15 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
+   if (pos < 0)
+   return -1;
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf))
return -1;
}
@@ -2215,7 +2226,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res = parse_ref_filter_atom(, atom, end, );
+   if (res < 0)
+   die("%s", err.buf);
+   strbuf_release();
+   return res;
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/466


[PATCH v3 5/5] ref-filter: get_ref_atom_value() error handling

2018-03-19 Thread Olga Telezhnaya
Finish removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of get_ref_atom_value() and underlying functions
by adding return value and strbuf parameter for error message.

Some die() calls are left; all of them are not for users, but for
Git developers.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 55 ---
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index b90cec1056954..85f971663a4aa 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1445,28 +1445,36 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
-static void get_object(struct ref_array_item *ref, const struct object_id *oid,
-  int deref, struct object **obj)
+static int get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj, struct strbuf *err)
 {
int eaten;
unsigned long size;
void *buf = get_obj(oid, obj, , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(oid), ref->refname);
-   if (!*obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(oid), ref->refname);
-
+   if (!buf) {
+   strbuf_addf(err, _("missing object %s for %s"), oid_to_hex(oid),
+   ref->refname);
+   if (!eaten)
+   free(buf);
+   return -1;
+   }
+   if (!*obj) {
+   strbuf_addf(err, _("parse_object_buffer failed on %s for %s"),
+   oid_to_hex(oid), ref->refname);
+   if (!eaten)
+   free(buf);
+   return -1;
+   }
grab_values(ref->value, deref, *obj, buf, size);
if (!eaten)
free(buf);
+   return 0;
 }
 
 /*
  * Parse the object referred by ref, and grab needed value.
  */
-static void populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 {
struct object *obj;
int i;
@@ -1588,16 +1596,17 @@ static void populate_value(struct ref_array_item *ref)
break;
}
if (used_atom_cnt <= i)
-   return;
+   return 0;
 
-   get_object(ref, >objectname, 0, );
+   if (get_object(ref, >objectname, 0, , err))
+   return -1;
 
/*
 * If there is no atom that wants to know about tagged
 * object, we are done.
 */
if (!need_tagged || (obj->type != OBJ_TAG))
-   return;
+   return 0;
 
/*
 * If it is a tag object, see if we use a value that derefs
@@ -1611,20 +1620,23 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   get_object(ref, tagged, 1, );
+   return get_object(ref, tagged, 1, , err);
 }
 
 /*
  * Given a ref, return the value for the atom.  This lazily gets value
  * out of the object by calling populate value.
  */
-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
+static int get_ref_atom_value(struct ref_array_item *ref, int atom,
+ struct atom_value **v, struct strbuf *err)
 {
if (!ref->value) {
-   populate_value(ref);
+   if (populate_value(ref, err))
+   return -1;
fill_missing_values(ref->value);
}
*v = >value[atom];
+   return 0;
 }
 
 /*
@@ -2148,9 +2160,13 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct 
ref_array_item *a, stru
int cmp;
cmp_type cmp_type = used_atom[s->atom].type;
int (*cmp_fn)(const char *, const char *);
+   struct strbuf err = STRBUF_INIT;
 
-   get_ref_atom_value(a, s->atom, );
-   get_ref_atom_value(b, s->atom, );
+   if (get_ref_atom_value(a, s->atom, , ))
+   die("%s", err.buf);
+   if (get_ref_atom_value(b, s->atom, , ))
+   die("%s", err.buf);
+   strbuf_release();
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
if (s->version)
cmp = versioncmp(va->s, vb->s);
@@ -2230,7 +2246,8 @@ int format_ref_array_item(struct ref_array_item *info,
pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
if (pos < 0)
return -1;
-   get_ref_atom_value(info, pos, );
+   if (get_ref_atom_value(info, pos, , error_buf))
+   return -1;
if (atomv->handler(atomv, , error_buf))
return -1;
}

--

[PATCH v3 1/5] ref-filter: start adding strbufs with errors

2018-03-19 Thread Olga Telezhnaya
This is a first step in removing any printing from
ref-filter formatting logic, so that it could be more general.
Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and adjusts
its callers. While at it, reduce the scope of the out-variable.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 17 -
 ref-filter.h |  7 ---
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 6d0cea9d4bcc4..c21e5a04a0177 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..54fae00bdd410 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2118,9 +2118,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2148,19 +2149,25 @@ void format_ref_array_item(struct ref_array_item *info,
resetv.s = GIT_COLOR_RESET;
append_atom(, );
}
-   if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   if (state.stack->prev) {
+   strbuf_addstr(error_buf, _("format: %(end) atom missing"));
+   return -1;
+   }
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to the list */

--
https://github.com/git/git/pull/466


[PATCH v2 4/5] ref-filter: add return value to parsers

2018-03-14 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parsers by adding return value and
strbuf parameter for error message.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 177 +++
 1 file changed, 118 insertions(+), 59 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index dd83ef326511d..62ea4adcd0ff1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,22 +101,28 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
-   if (!color_value)
-   die(_("expected format: %%(color:)"));
-   if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   if (!color_value) {
+   strbuf_addstr(err, _("expected format: %(color:)"));
+   return -1;
+   }
+   if (color_parse(color_value, atom->u.color) < 0) {
+   strbuf_addf(err, _("unrecognized color: %%(color:%s)"), 
color_value);
+   return -1;
+   }
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -125,17 +131,25 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
else if (skip_prefix(arg, "lstrip=", ) ||
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
-   if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   if (strtol_i(arg, 10, >lstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:lstrip=%s"), arg);
+   return -1;
+   }
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
-   if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
-   } else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   if (strtol_i(arg, 10, >rstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:rstrip=%s"), arg);
+   return -1;
+   }
+   } else {
+   strbuf_addf(err, _("unrecognized %%(%s) argument: %s"), name, 
arg);
+   return -1;
+   }
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -145,9 +159,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -170,29 +183,40 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err))
+   return -1;
}
}
 
string_list_clear(, 0);
+   return 0;
 }
 
-static void body_atom_parser(const struct ref_format *format, struct used_atom 
*atom, const char 

[PATCH v2 2/5] ref-filter: add return value && strbuf to handlers

2018-03-14 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of handlers by adding return value
and strbuf parameter for errors.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 71 
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 54fae00bdd410..d120360104806 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -387,7 +387,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -481,7 +482,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *unused_err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -493,6 +495,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -527,7 +530,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -535,6 +539,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -572,7 +577,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *unused_err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -584,6 +590,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -596,19 +603,24 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
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 (!if_then_else) {
+   strbuf_addstr(err, _("format: %(then) atom used without an 
%(if) atom"));
+   return -1;
+   } else if (if_then_else->then_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used more than 
once"));
+   return -1;
+   } else if (if_then_else->else_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used after 
%(else)"));
+   return -1;
+   }
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -624,34 +636,44 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(>output);
+   return 0;
 }
 
-static void 

[PATCH v2 1/5] ref-filter: start adding strbufs with errors

2018-03-14 Thread Olga Telezhnaya
This is a first step in removing any printing from
ref-filter formatting logic, so that it could be more general.
Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and adjusts
its callers. While at it, reduce the scope of the out-variable.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 17 -
 ref-filter.h |  7 ---
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 8dcc2ed058be6..f86709ca42d5e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..54fae00bdd410 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2118,9 +2118,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2148,19 +2149,25 @@ void format_ref_array_item(struct ref_array_item *info,
resetv.s = GIT_COLOR_RESET;
append_atom(, );
}
-   if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   if (state.stack->prev) {
+   strbuf_addstr(error_buf, _("format: %(end) atom missing"));
+   return -1;
+   }
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to the list */

--
https://github.com/git/git/pull/466


[PATCH v2 5/5] ref-filter: get_ref_atom_value() error handling

2018-03-14 Thread Olga Telezhnaya
Finish removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of get_ref_atom_value() and underlying functions
by adding return value and strbuf parameter for error message.

It's important to mention that grab_objectname() returned 1 if
it gets objectname atom and 0 otherwise. Now this logic changed:
we return 0 if we have no error, -1 otherwise. If someone needs to
know whether it's objectname atom or not, he/she could use
starts_with() function. It duplicates this checking but it does not
sound like a really big overhead.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 109 +--
 1 file changed, 69 insertions(+), 40 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 62ea4adcd0ff1..3f0c3924273d5 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -831,26 +831,27 @@ static void *get_obj(const struct object_id *oid, struct 
object **obj, unsigned
 }
 
 static int grab_objectname(const char *name, const unsigned char *sha1,
-  struct atom_value *v, struct used_atom *atom)
+  struct atom_value *v, struct used_atom *atom,
+  struct strbuf *err)
 {
if (starts_with(name, "objectname")) {
if (atom->u.objectname.option == O_SHORT) {
v->s = xstrdup(find_unique_abbrev(sha1, 
DEFAULT_ABBREV));
-   return 1;
} 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");
+   } else {
+   strbuf_addstr(err, "BUG: unknown %(objectname) option");
+   return -1;
+   }
}
return 0;
 }
 
 /* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct 
object *obj, void *buf, unsigned long sz)
+static int grab_common_values(struct atom_value *val, int deref, struct object 
*obj,
+ void *buf, unsigned long sz, struct strbuf *err)
 {
int i;
 
@@ -868,8 +869,10 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct object
v->s = xstrfmt("%lu", sz);
}
else if (deref)
-   grab_objectname(name, obj->oid.hash, v, _atom[i]);
+   if (grab_objectname(name, obj->oid.hash, v, 
_atom[i], err))
+   return -1;
}
+   return 0;
 }
 
 /* See grab_values */
@@ -1225,9 +1228,11 @@ static void fill_missing_values(struct atom_value *val)
  * pointed at by the ref itself; otherwise it is the object the
  * ref (which is a tag) refers to.
  */
-static void grab_values(struct atom_value *val, int deref, struct object *obj, 
void *buf, unsigned long sz)
+static int grab_values(struct atom_value *val, int deref, struct object *obj,
+  void *buf, unsigned long sz, struct strbuf *err)
 {
-   grab_common_values(val, deref, obj, buf, sz);
+   if (grab_common_values(val, deref, obj, buf, sz, err))
+   return -1;
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj, buf, sz);
@@ -1247,8 +1252,10 @@ static void grab_values(struct atom_value *val, int 
deref, struct object *obj, v
/* grab_blob_values(val, deref, obj, buf, sz); */
break;
default:
-   die("Eh?  Object of type %d?", obj->type);
+   strbuf_addf(err, "Eh?  Object of type %d?", obj->type);
+   return -1;
}
+   return 0;
 }
 
 static inline char *copy_advance(char *dst, const char *src)
@@ -1335,8 +1342,9 @@ static const char *show_ref(struct refname_atom *atom, 
const char *refname)
return refname;
 }
 
-static void fill_remote_ref_details(struct used_atom *atom, const char 
*refname,
-   struct branch *branch, const char **s)
+static int fill_remote_ref_details(struct used_atom *atom, const char *refname,
+  struct branch *branch, const char **s,
+  struct strbuf *err)
 {
int num_ours, num_theirs;
if (atom->u.remote_ref.option == RR_REF)
@@ -1362,7 +1370,7 @@ static void fill_remote_ref_details(struct used_atom 
*atom, const char *refname,
} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, _ours, _theirs,
   NULL, AHEAD_BEHIND_FULL) < 0)
-  

[PATCH v2 3/5] ref-filter: change parsing function error handling

2018-03-14 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parse_ref_filter_atom() by changing return value,
adding previous return value to function parameter and also adding
strbuf parameter for error message.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 43 ++-
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index d120360104806..dd83ef326511d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -397,7 +397,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep, int *res,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -406,14 +407,18 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
sp = atom;
if (*sp == '*' && sp < ep)
sp++; /* deref */
-   if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   if (ep <= sp) {
+   strbuf_addf(err, _("malformed field name: %.*s"), 
(int)(ep-atom), atom);
+   return -1;
+   }
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
int len = strlen(used_atom[i].name);
-   if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
-   return i;
+   if (len == ep - atom && !memcmp(used_atom[i].name, atom, len)) {
+   *res = i;
+   return 0;
+   }
}
 
/*
@@ -432,8 +437,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   if (ARRAY_SIZE(valid_atom) <= i) {
+   strbuf_addf(err, _("unknown field name: %.*s"), (int)(ep-atom), 
atom);
+   return -1;
+   }
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -458,7 +465,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   return at;
+   *res = at;
+   return 0;
 }
 
 static void quote_formatting(struct strbuf *s, const char *str, int 
quote_style)
@@ -725,17 +733,20 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   if (parse_ref_filter_atom(format, sp + 2, ep, , ))
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2154,13 +2165,14 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   if (parse_ref_filter_atom(format, sp + 2, ep, , error_buf))
+   return -1;
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf))
return -1;
}
@@ -2215,7 +2227,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res;
+   if (parse_ref_filter_atom(, atom, end, , ))
+   die("%s", err.buf);
+   strbuf_release();
+   return res;
 }
 
 /*  If no sorting option is given, use refname to sort as 

[RFC 4/4] ref-filter: add return value to parsers

2018-03-13 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parsers by adding return value and
strbuf parameter for error message.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 177 +++
 1 file changed, 118 insertions(+), 59 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index e146215bf1e64..06eb95e7c2c07 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,22 +101,28 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 
-static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
+static int color_atom_parser(const struct ref_format *format, struct used_atom 
*atom,
+const char *color_value, struct strbuf *err)
 {
-   if (!color_value)
-   die(_("expected format: %%(color:)"));
-   if (color_parse(color_value, atom->u.color) < 0)
-   die(_("unrecognized color: %%(color:%s)"), color_value);
+   if (!color_value) {
+   strbuf_addstr(err, _("expected format: %(color:)"));
+   return -1;
+   }
+   if (color_parse(color_value, atom->u.color) < 0) {
+   strbuf_addf(err, _("unrecognized color: %%(color:%s)"), 
color_value);
+   return -1;
+   }
/*
 * We check this after we've parsed the color, which lets us complain
 * about syntactically bogus color names even if they won't be used.
 */
if (!want_color(format->use_color))
color_parse("", atom->u.color);
+   return 0;
 }
 
-static void refname_atom_parser_internal(struct refname_atom *atom,
-const char *arg, const char *name)
+static int refname_atom_parser_internal(struct refname_atom *atom, const char 
*arg,
+const char *name, struct strbuf *err)
 {
if (!arg)
atom->option = R_NORMAL;
@@ -125,17 +131,25 @@ static void refname_atom_parser_internal(struct 
refname_atom *atom,
else if (skip_prefix(arg, "lstrip=", ) ||
 skip_prefix(arg, "strip=", )) {
atom->option = R_LSTRIP;
-   if (strtol_i(arg, 10, >lstrip))
-   die(_("Integer value expected refname:lstrip=%s"), arg);
+   if (strtol_i(arg, 10, >lstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:lstrip=%s"), arg);
+   return -1;
+   }
} else if (skip_prefix(arg, "rstrip=", )) {
atom->option = R_RSTRIP;
-   if (strtol_i(arg, 10, >rstrip))
-   die(_("Integer value expected refname:rstrip=%s"), arg);
-   } else
-   die(_("unrecognized %%(%s) argument: %s"), name, arg);
+   if (strtol_i(arg, 10, >rstrip)) {
+   strbuf_addf(err, _("Integer value expected 
refname:rstrip=%s"), arg);
+   return -1;
+   }
+   } else {
+   strbuf_addf(err, _("unrecognized %%(%s) argument: %s"), name, 
arg);
+   return -1;
+   }
+   return 0;
 }
 
-static void remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+static int remote_ref_atom_parser(const struct ref_format *format, struct 
used_atom *atom,
+ const char *arg, struct strbuf *err)
 {
struct string_list params = STRING_LIST_INIT_DUP;
int i;
@@ -145,9 +159,8 @@ static void remote_ref_atom_parser(const struct ref_format 
*format, struct used_
 
if (!arg) {
atom->u.remote_ref.option = RR_REF;
-   refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
-   return;
+   return refname_atom_parser_internal(>u.remote_ref.refname,
+   arg, atom->name, err);
}
 
atom->u.remote_ref.nobracket = 0;
@@ -170,29 +183,40 @@ static void remote_ref_atom_parser(const struct 
ref_format *format, struct used_
atom->u.remote_ref.push_remote = 1;
} else {
atom->u.remote_ref.option = RR_REF;
-   
refname_atom_parser_internal(>u.remote_ref.refname,
-arg, atom->name);
+   if 
(refname_atom_parser_internal(>u.remote_ref.refname,
+arg, atom->name, err))
+   return -1;
}
}
 
string_list_clear(, 0);
+   return 0;
 }
 
-static void body_atom_parser(const struct ref_format *format, struct used_atom 
*atom, const char 

[RFC 3/4] ref-filter: change parsing function error handling

2018-03-13 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of parse_ref_filter_atom() by changing return value,
adding previous return value to function parameter and also adding
strbuf parameter for error message.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 45 -
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 07bedc636398c..e146215bf1e64 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -397,7 +397,8 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const char *atom, const char *ep)
+const char *atom, const char *ep, int *res,
+struct strbuf *err)
 {
const char *sp;
const char *arg;
@@ -406,14 +407,18 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
sp = atom;
if (*sp == '*' && sp < ep)
sp++; /* deref */
-   if (ep <= sp)
-   die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
+   if (ep <= sp) {
+   strbuf_addf(err, _("malformed field name: %.*s"), 
(int)(ep-atom), atom);
+   return -1;
+   }
 
/* Do we have the atom already used elsewhere? */
for (i = 0; i < used_atom_cnt; i++) {
int len = strlen(used_atom[i].name);
-   if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
-   return i;
+   if (len == ep - atom && !memcmp(used_atom[i].name, atom, len)) {
+   *res = i;
+   return 0;
+   }
}
 
/*
@@ -432,8 +437,10 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
-   die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
+   if (ARRAY_SIZE(valid_atom) <= i) {
+   strbuf_addf(err, _("unknown field name: %.*s"), (int)(ep-atom), 
atom);
+   return -1;
+   }
 
/* Add it in, including the deref prefix */
at = used_atom_cnt;
@@ -458,7 +465,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   return at;
+   *res = at;
+   return 0;
 }
 
 static void quote_formatting(struct strbuf *s, const char *str, int 
quote_style)
@@ -725,17 +733,20 @@ int verify_ref_format(struct ref_format *format)
 
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   struct strbuf err = STRBUF_INIT;
const char *color, *ep = strchr(sp, ')');
int at;
 
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   if (parse_ref_filter_atom(format, sp + 2, ep, , ))
+   die("%s", err.buf);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   strbuf_release();
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
@@ -2154,15 +2165,18 @@ int format_ref_array_item(struct ref_array_item *info,
 
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
+   struct strbuf err = STRBUF_INIT;
+   int pos;
 
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   if (parse_ref_filter_atom(format, sp + 2, ep, , ))
+   return -1;
+   get_ref_atom_value(info, pos, );
if (atomv->handler(atomv, , error_buf))
return -1;
+   strbuf_release();
}
if (*cp) {
sp = cp + strlen(cp);
@@ -2215,7 +2229,12 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   struct strbuf err = STRBUF_INIT;
+   int res;
+   if (parse_ref_filter_atom(, atom, end, , ))
+   

[RFC 1/4] ref-filter: start adding strbufs with errors

2018-03-13 Thread Olga Telezhnaya
This is a first step in removing any printing from
ref-filter formatting logic, so that it could be more general.
Everything would be the same for show_ref_array_item() users.
But, if you want to deal with errors by your own, you could invoke
format_ref_array_item(). It means that you need to print everything
(the result and errors) on your side.

This commit changes signature of format_ref_array_item() by adding
return value and strbuf parameter for errors, and fixes
its callers.

Signed-off-by: Olga Telezhnaia 
---
 builtin/branch.c |  7 +--
 ref-filter.c | 17 -
 ref-filter.h |  7 ---
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 8dcc2ed058be6..f86709ca42d5e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -391,7 +391,6 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
-   struct strbuf out = STRBUF_INIT;
char *to_free = NULL;
 
/*
@@ -419,7 +418,10 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
ref_array_sort(sorting, );
 
for (i = 0; i < array.nr; i++) {
-   format_ref_array_item(array.items[i], format, );
+   struct strbuf out = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   if (format_ref_array_item(array.items[i], format, , ))
+   die("%s", err.buf);
if (column_active(colopts)) {
assert(!filter->verbose && "--column and --verbose are 
incompatible");
 /* format to a string_list to let print_columns() do 
its job */
@@ -428,6 +430,7 @@ static void print_ref_list(struct ref_filter *filter, 
struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
+   strbuf_release();
strbuf_release();
}
 
diff --git a/ref-filter.c b/ref-filter.c
index 45fc56216aaa8..54fae00bdd410 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2118,9 +2118,10 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
-  struct strbuf *final_buf)
+  struct strbuf *final_buf,
+  struct strbuf *error_buf)
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2148,19 +2149,25 @@ void format_ref_array_item(struct ref_array_item *info,
resetv.s = GIT_COLOR_RESET;
append_atom(, );
}
-   if (state.stack->prev)
-   die(_("format: %%(end) atom missing"));
+   if (state.stack->prev) {
+   strbuf_addstr(error_buf, _("format: %(end) atom missing"));
+   return -1;
+   }
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
 void show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   struct strbuf error_buf = STRBUF_INIT;
 
-   format_ref_array_item(info, format, _buf);
+   if (format_ref_array_item(info, format, _buf, _buf))
+   die("%s", error_buf.buf);
fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   strbuf_release(_buf);
strbuf_release(_buf);
putchar('\n');
 }
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..e13f8e6f8721a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -110,9 +110,10 @@ int verify_ref_format(struct ref_format *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 struct ref_format *format,
-  struct strbuf *final_buf);
+int format_ref_array_item(struct ref_array_item *info,
+ const struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf);
 /*  Print the ref using the given format and quote_style */
 void show_ref_array_item(struct ref_array_item *info, const struct ref_format 
*format);
 /*  Parse a single sort specifier and add it to the list */

--
https://github.com/git/git/pull/466


[RFC 2/4] ref-filter: add return value && strbuf to handlers

2018-03-13 Thread Olga Telezhnaya
Continue removing any printing from ref-filter formatting logic,
so that it could be more general.

Change the signature of handlers by adding return value
and strbuf parameter for errors.

Signed-off-by: Olga Telezhnaia 
---
 ref-filter.c | 71 
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 54fae00bdd410..07bedc636398c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -387,7 +387,8 @@ struct ref_formatting_state {
 
 struct atom_value {
const char *s;
-   void (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state);
+   int (*handler)(struct atom_value *atomv, struct ref_formatting_state 
*state,
+  struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
 };
@@ -481,7 +482,8 @@ static void quote_formatting(struct strbuf *s, const char 
*str, int quote_style)
}
 }
 
-static void append_atom(struct atom_value *v, struct ref_formatting_state 
*state)
+static int append_atom(struct atom_value *v, struct ref_formatting_state 
*state,
+  struct strbuf *err)
 {
/*
 * Quote formatting is only done when the stack has a single
@@ -493,6 +495,7 @@ static void append_atom(struct atom_value *v, struct 
ref_formatting_state *state
quote_formatting(>stack->output, v->s, 
state->quote_style);
else
strbuf_addstr(>stack->output, v->s);
+   return 0;
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -527,7 +530,8 @@ static void end_align_handler(struct ref_formatting_stack 
**stack)
strbuf_release();
 }
 
-static void align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int align_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+ struct strbuf *err)
 {
struct ref_formatting_stack *new_stack;
 
@@ -535,6 +539,7 @@ static void align_atom_handler(struct atom_value *atomv, 
struct ref_formatting_s
new_stack = state->stack;
new_stack->at_end = end_align_handler;
new_stack->at_end_data = >atom->u.align;
+   return 0;
 }
 
 static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -572,7 +577,8 @@ static void if_then_else_handler(struct 
ref_formatting_stack **stack)
free(if_then_else);
 }
 
-static void if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int if_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+  struct strbuf *err)
 {
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(sizeof(struct 
if_then_else), 1);
@@ -584,6 +590,7 @@ static void if_atom_handler(struct atom_value *atomv, 
struct ref_formatting_stat
new_stack = state->stack;
new_stack->at_end = if_then_else_handler;
new_stack->at_end_data = if_then_else;
+   return 0;
 }
 
 static int is_empty(const char *s)
@@ -596,19 +603,24 @@ static int is_empty(const char *s)
return 1;
 }
 
-static void then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state)
+static int then_atom_handler(struct atom_value *atomv, struct 
ref_formatting_state *state,
+struct strbuf *err)
 {
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 (!if_then_else) {
+   strbuf_addstr(err, _("format: %(then) atom used without an 
%(if) atom"));
+   return -1;
+   } else if (if_then_else->then_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used more than 
once"));
+   return -1;
+   } else if (if_then_else->else_atom_seen) {
+   strbuf_addstr(err, _("format: %(then) atom used after 
%(else)"));
+   return -1;
+   }
if_then_else->then_atom_seen = 1;
/*
 * If the 'equals' or 'notequals' attribute is used then
@@ -624,34 +636,44 @@ static void then_atom_handler(struct atom_value *atomv, 
struct ref_formatting_st
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
strbuf_reset(>output);
+   return 0;
 }
 
-static void else_atom_handler(struct atom_value *atomv, 

[PATCH v2 2/2] ref-filter: get rid of goto

2018-02-20 Thread Olga Telezhnaya
Get rid of goto command in ref-filter for better readability.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 83ffd84affe52..35359818a1ebb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1494,11 +1494,11 @@ static void populate_value(struct ref_array_item *ref)
for (i = 0; i < used_atom_cnt; i++) {
struct atom_value *v = >value[i];
if (v->s == NULL)
-   goto need_obj;
+   break;
}
-   return;
+   if (i >= used_atom_cnt)
+   return;
 
- need_obj:
get_object(ref, >objectname, 0, );
 
/*

--
https://github.com/git/git/pull/460


[PATCH v2 1/2] ref-filter: get rid of duplicate code

2018-02-20 Thread Olga Telezhnaya
Make one function from 2 duplicate pieces and invoke it twice.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 45 +
 1 file changed, 21 insertions(+), 24 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f9e25aea7a97e..83ffd84affe52 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1354,15 +1354,31 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
+static void get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj)
+{
+   int eaten;
+   unsigned long size;
+   void *buf = get_obj(oid, obj, , );
+   if (!buf)
+   die(_("missing object %s for %s"),
+   oid_to_hex(oid), ref->refname);
+   if (!*obj)
+   die(_("parse_object_buffer failed on %s for %s"),
+   oid_to_hex(oid), ref->refname);
+
+   grab_values(ref->value, deref, *obj, buf, size);
+   if (!eaten)
+   free(buf);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
 static void populate_value(struct ref_array_item *ref)
 {
-   void *buf;
struct object *obj;
-   int eaten, i;
-   unsigned long size;
+   int i;
const struct object_id *tagged;
 
ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
@@ -1483,17 +1499,7 @@ static void populate_value(struct ref_array_item *ref)
return;
 
  need_obj:
-   buf = get_obj(>objectname, , , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
-   if (!obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
-
-   grab_values(ref->value, 0, obj, buf, size);
-   if (!eaten)
-   free(buf);
+   get_object(ref, >objectname, 0, );
 
/*
 * If there is no atom that wants to know about tagged
@@ -1514,16 +1520,7 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   buf = get_obj(tagged, , , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(tagged), ref->refname);
-   if (!obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(tagged), ref->refname);
-   grab_values(ref->value, 1, obj, buf, size);
-   if (!eaten)
-   free(buf);
+   get_object(ref, tagged, 1, );
 }
 
 /*

--
https://github.com/git/git/pull/460


[PATCH 2/2] ref-filter: get rid of goto

2018-02-20 Thread Olga Telezhnaya
Get rid of goto command in ref-filter for better readability.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 83ffd84affe52..28df6e21fb996 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1494,11 +1494,11 @@ static void populate_value(struct ref_array_item *ref)
for (i = 0; i < used_atom_cnt; i++) {
struct atom_value *v = >value[i];
if (v->s == NULL)
-   goto need_obj;
+   break;
}
-   return;
+   if (used_atom_cnt <= i)
+   return;
 
- need_obj:
get_object(ref, >objectname, 0, );
 
/*

--
https://github.com/git/git/pull/460


[PATCH 1/2] ref-filter: get rid of duplicate code

2018-02-20 Thread Olga Telezhnaya
Make one function from 2 duplicate pieces and invoke it twice.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 45 +
 1 file changed, 21 insertions(+), 24 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f9e25aea7a97e..83ffd84affe52 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1354,15 +1354,31 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
+static void get_object(struct ref_array_item *ref, const struct object_id *oid,
+  int deref, struct object **obj)
+{
+   int eaten;
+   unsigned long size;
+   void *buf = get_obj(oid, obj, , );
+   if (!buf)
+   die(_("missing object %s for %s"),
+   oid_to_hex(oid), ref->refname);
+   if (!*obj)
+   die(_("parse_object_buffer failed on %s for %s"),
+   oid_to_hex(oid), ref->refname);
+
+   grab_values(ref->value, deref, *obj, buf, size);
+   if (!eaten)
+   free(buf);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
 static void populate_value(struct ref_array_item *ref)
 {
-   void *buf;
struct object *obj;
-   int eaten, i;
-   unsigned long size;
+   int i;
const struct object_id *tagged;
 
ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
@@ -1483,17 +1499,7 @@ static void populate_value(struct ref_array_item *ref)
return;
 
  need_obj:
-   buf = get_obj(>objectname, , , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
-   if (!obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
-
-   grab_values(ref->value, 0, obj, buf, size);
-   if (!eaten)
-   free(buf);
+   get_object(ref, >objectname, 0, );
 
/*
 * If there is no atom that wants to know about tagged
@@ -1514,16 +1520,7 @@ static void populate_value(struct ref_array_item *ref)
 * is not consistent with what deref_tag() does
 * which peels the onion to the core.
 */
-   buf = get_obj(tagged, , , );
-   if (!buf)
-   die(_("missing object %s for %s"),
-   oid_to_hex(tagged), ref->refname);
-   if (!obj)
-   die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(tagged), ref->refname);
-   grab_values(ref->value, 1, obj, buf, size);
-   if (!eaten)
-   free(buf);
+   get_object(ref, tagged, 1, );
 }
 
 /*

--
https://github.com/git/git/pull/460


[PATCH v3 13/23] ref-filter: get rid of mark_atom_in_object_info()

2018-02-12 Thread Olga Telezhnaya
Remove mark_atom_in_object_info() and create same logic
in terms of ref-filter style.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 45 +
 1 file changed, 21 insertions(+), 24 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 3f92a27d98b6c..34a54db168265 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -255,13 +255,29 @@ static void objectname_atom_parser(const struct 
ref_format *format, struct used_
 static void objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   ; /* default to normal object size */
+   cat_file_info->info.sizep = _file_info->size;
else if (!strcmp(arg, "disk"))
cat_file_info->info.disk_sizep = _file_info->disk_size;
else
die(_("urecognized %%(objectsize) argument: %s"), arg);
 }
 
+static void objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+{
+   if (!arg)
+   cat_file_info->info.typep = _file_info->type;
+   else
+   die(_("urecognized %%(objecttype) argument: %s"), arg);
+}
+
+static void deltabase_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+{
+   if (!arg)
+   cat_file_info->info.delta_base_sha1 = 
cat_file_info->delta_base_oid.hash;
+   else
+   die(_("urecognized %%(deltabase) argument: %s"), arg);
+}
+
 static void refname_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
refname_atom_parser_internal(>u.refname, arg, atom->name);
@@ -384,10 +400,10 @@ static struct valid_atom {
 
 static struct valid_atom valid_cat_file_atom[] = {
{ "objectname" },
-   { "objecttype" },
+   { "objecttype", FIELD_STR, objecttype_atom_parser },
{ "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "rest" },
-   { "deltabase" },
+   { "deltabase", FIELD_STR, deltabase_atom_parser },
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
@@ -411,25 +427,6 @@ struct atom_value {
struct used_atom *atom;
 };
 
-static int is_atom(const char *atom, const char *s, int slen)
-{
-   int alen = strlen(atom);
-   return alen == slen && !memcmp(atom, s, alen);
-}
-
-static void mark_atom_in_object_info(const char *atom, int len,
-   struct expand_data *data)
-{
-   if (is_atom("objecttype", atom, len))
-   data->info.typep = >type;
-   else if (is_atom("objectsize", atom, len))
-   data->info.sizep = >size;
-   else if (is_atom("rest", atom, len))
-   data->split_on_whitespace = 1;
-   else if (is_atom("deltabase", atom, len))
-   data->info.delta_base_sha1 = data->delta_base_oid.hash;
-}
-
 /*
  * Used to parse format string and sort specifiers
  */
@@ -496,8 +493,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   if (cat_file_info)
-   mark_atom_in_object_info(atom, atom_len, cat_file_info);
+   if (cat_file_info && !strcmp(valid_atom[i].name, "rest"))
+   cat_file_info->split_on_whitespace = 1;
return at;
 }
 

--
https://github.com/git/git/pull/452


[PATCH v3 06/23] cat-file: split expand_atom() into 2 functions

2018-02-12 Thread Olga Telezhnaya
Split expand_atom() into 2 different functions,
mark_atom_in_object_info() prepares variable for further filling,
(new) expand_atom() creates resulting string.
Need that for further reusing of formatting logic from ref-filter.
Both functions will be step-by-step removed by the end of this patch.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 73 --
 1 file changed, 38 insertions(+), 35 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 37d6096d201b5..edb04a96d9bd3 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -182,47 +182,47 @@ static int is_atom(const char *atom, const char *s, int 
slen)
return alen == slen && !memcmp(atom, s, alen);
 }
 
-static void expand_atom(struct strbuf *sb, const char *atom, int len,
-   void *vdata)
+static void mark_atom_in_object_info(const char *atom, int len,
+struct expand_data *data)
 {
-   struct expand_data *data = vdata;
+   if (is_atom("objectname", atom, len))
+   ; /* do nothing */
+   else if (is_atom("objecttype", atom, len))
+   data->info.typep = >type;
+   else if (is_atom("objectsize", atom, len))
+   data->info.sizep = >size;
+   else if (is_atom("objectsize:disk", atom, len))
+   data->info.disk_sizep = >disk_size;
+   else if (is_atom("rest", atom, len))
+   data->split_on_whitespace = 1;
+   else if (is_atom("deltabase", atom, len))
+   data->info.delta_base_sha1 = data->delta_base_oid.hash;
+   else
+   die("unknown format element: %.*s", len, atom);
+}
 
-   if (is_atom("objectname", atom, len)) {
-   if (!data->mark_query)
-   strbuf_addstr(sb, oid_to_hex(>oid));
-   } else if (is_atom("objecttype", atom, len)) {
-   if (data->mark_query)
-   data->info.typep = >type;
-   else
-   strbuf_addstr(sb, typename(data->type));
-   } else if (is_atom("objectsize", atom, len)) {
-   if (data->mark_query)
-   data->info.sizep = >size;
-   else
-   strbuf_addf(sb, "%lu", data->size);
-   } else if (is_atom("objectsize:disk", atom, len)) {
-   if (data->mark_query)
-   data->info.disk_sizep = >disk_size;
-   else
-   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
-   } else if (is_atom("rest", atom, len)) {
-   if (data->mark_query)
-   data->split_on_whitespace = 1;
-   else if (data->rest)
+static void expand_atom(struct strbuf *sb, const char *atom, int len,
+struct expand_data *data)
+{
+   if (is_atom("objectname", atom, len))
+   strbuf_addstr(sb, oid_to_hex(>oid));
+   else if (is_atom("objecttype", atom, len))
+   strbuf_addstr(sb, typename(data->type));
+   else if (is_atom("objectsize", atom, len))
+   strbuf_addf(sb, "%lu", data->size);
+   else if (is_atom("objectsize:disk", atom, len))
+   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
+   else if (is_atom("rest", atom, len)) {
+   if (data->rest)
strbuf_addstr(sb, data->rest);
-   } else if (is_atom("deltabase", atom, len)) {
-   if (data->mark_query)
-   data->info.delta_base_sha1 = data->delta_base_oid.hash;
-   else
-   strbuf_addstr(sb,
- oid_to_hex(>delta_base_oid));
-   } else
-   die("unknown format element: %.*s", len, atom);
+   } else if (is_atom("deltabase", atom, len))
+   strbuf_addstr(sb, oid_to_hex(>delta_base_oid));
 }
 
-static size_t expand_format(struct strbuf *sb, const char *start, void *data)
+static size_t expand_format(struct strbuf *sb, const char *start, void *vdata)
 {
const char *end;
+   struct expand_data *data = vdata;
 
if (*start != '(')
return 0;
@@ -230,7 +230,10 @@ static size_t expand_format(struct strbuf *sb, const char 
*start, void *data)
if (!end)
die("format element '%s' does not end in ')'", start);
 
-   expand_atom(sb, start + 1, end - start - 1, data);
+   if (data->mark_query)
+   mark_atom_in_object_info(start + 1, end - start - 1, data);
+   else
+   expand_atom(sb, start + 1, end - start - 1, data);
 
return end - start + 1;
 }

--
https://github.com/git/git/pull/452


[PATCH v3 22/23] cat-file: tests for new atoms added

2018-02-12 Thread Olga Telezhnaya
Add some tests for new formatting atoms from ref-filter.
Some of new atoms are supported automatically,
some of them are expanded into empty string
(because they are useless for some types of objects),
some of them could be supported later in other patches.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 t/t1006-cat-file.sh | 48 
 1 file changed, 48 insertions(+)

diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index b19f332694620..e72fcaf0e02c5 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -20,6 +20,19 @@ maybe_remove_timestamp () {
 fi
 }
 
+test_atom () {
+name=$1
+sha1=$2
+atoms=$3
+expected=$4
+
+test_expect_success "$name" '
+   echo "$expected" >expect &&
+   echo $sha1 | git cat-file --batch-check="$atoms" >actual &&
+   test_cmp expect actual
+'
+}
+
 run_tests () {
 type=$1
 sha1=$2
@@ -119,6 +132,13 @@ $content"
maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
test_cmp expect actual
 '
+
+for atom in refname parent body trailers upstream push symref flag
+do
+   test_atom "Check %($atom) gives empty output" "$sha1" "%($atom)" ""
+done
+
+test_atom "Check %(HEAD) gives only one space as output" "$sha1" '%(HEAD)' 
' '
 }
 
 hello_content="Hello World"
@@ -140,6 +160,12 @@ test_expect_success '--batch-check without %(rest) 
considers whole line' '
test_cmp expect actual
 '
 
+shortname=`echo $hello_sha1 | sed 's/^.\{0\}\(.\{7\}\).*/\1/'`
+test_atom 'Check format option %(objectname:short) works' "$hello_sha1" 
'%(objectname:short)' "$shortname"
+
+test_atom 'Check format option %(align) is not broken' \
+"$hello_sha1" "%(align:8)%(objecttype)%(end)%(objectname)" "blob
$hello_sha1"
+
 tree_sha1=$(git write-tree)
 tree_size=33
 tree_pretty_content="100644 blob $hello_sha1   hello"
@@ -157,6 +183,17 @@ $commit_message"
 
 run_tests 'commit' $commit_sha1 $commit_size "$commit_content" 
"$commit_content" 1
 
+test_atom "Check format option %(if) is not broken" "$commit_sha1" \
+"%(if)%(author)%(then)%(objectname)%(end)" "$commit_sha1"
+test_atom "Check %(tree) works for commit" "$commit_sha1" "%(tree)" 
"$tree_sha1"
+test_atom "Check %(numparent) works for commit" "$commit_sha1" "%(numparent)" 
"0"
+test_atom "Check %(authorname) works for commit" "$commit_sha1" 
"%(authorname)" "$GIT_AUTHOR_NAME"
+test_atom "Check %(authoremail) works for commit" "$commit_sha1" 
"%(authoremail)" "<$GIT_AUTHOR_EMAIL>"
+test_atom "Check %(committername) works for commit" "$commit_sha1" 
"%(committername)" "$GIT_COMMITTER_NAME"
+test_atom "Check %(committeremail) works for commit" "$commit_sha1" 
"%(committeremail)" "<$GIT_COMMITTER_EMAIL>"
+test_atom "Check %(subject) works for commit" "$commit_sha1" "%(subject)" 
"$commit_message"
+test_atom "Check %(contents) works for commit" "$commit_sha1" "%(contents)" 
"$commit_message"
+
 tag_header_without_timestamp="object $hello_sha1
 type blob
 tag hellotag
@@ -171,6 +208,17 @@ tag_size=$(strlen "$tag_content")
 
 run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
 
+test_atom "Check %(object) works for tag" "$tag_sha1" "%(object)" "$hello_sha1"
+test_atom "Check %(type) works for tag" "$tag_sha1" "%(type)" "blob"
+test_atom "Check %(tag) works for tag" "$tag_sha1" "%(tag)" "hellotag"
+test_atom "Check %(taggername) works for tag" "$tag_sha1" "%(taggername)" 
"$GIT_COMMITTER_NAME"
+test_atom "Check %(taggeremail) works for tag" "$tag_sha1" "%(taggeremail)" 
"<$GIT_COMMITTER_EMAIL>"
+test_atom "Check %(subject) works for tag" "$tag_sha1" "%(subject)" 
"$tag_description"
+test_atom "Check %(contents) works for tag" "$tag_sha1" "%(contents)" 
"$tag_description"
+
+test_atom "Check %(color) gives no additional output" "$sha1" \
+"%(objectname) %(color:green) %(objecttype)" "$sha1  $type"
+
 test_expect_success \
 "Reach a blob from a tag pointing to it" \
 "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""

--
https://github.com/git/git/pull/452


[PATCH v3 23/23] cat-file: update of docs

2018-02-12 Thread Olga Telezhnaya
Update the docs for cat-file command. Some new formatting atoms added
because of reusing ref-filter code.
We do not support cat-file atoms in general formatting logic
(there is just the support for cat-file), that is why some of the atoms
are still explained in cat-file docs.
We need to move these explanations when atoms will be supported
by other commands.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 Documentation/git-cat-file.txt | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index f90f09b03fae5..90639ac21d0e8 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -187,17 +187,8 @@ linkgit:git-rev-parse[1].
 You can specify the information shown for each object by using a custom
 ``. The `` is copied literally to stdout for each
 object, with placeholders of the form `%(atom)` expanded, followed by a
-newline. The available atoms are:
-
-`objectname`::
-   The 40-hex object name of the object.
-
-`objecttype`::
-   The type of the object (the same as `cat-file -t` reports).
-
-`objectsize`::
-   The size, in bytes, of the object (the same as `cat-file -s`
-   reports).
+newline. The available atoms are the same as that of
+linkgit:git-for-each-ref[1], but there are some additional ones:
 
 `objectsize:disk`::
The size, in bytes, that the object takes up on disk. See the

--
https://github.com/git/git/pull/452


[PATCH v3 12/23] cat-file: start reusing populate_value()

2018-02-12 Thread Olga Telezhnaya
Move logic related to getting object info from cat-file to ref-filter.
It will help to reuse whole formatting logic from ref-filter further.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 17 -
 ref-filter.c   | 20 
 ref-filter.h   |  1 +
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 0c362828ad81e..6db57e3533806 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -285,21 +285,12 @@ static void batch_object_write(const char *obj_name, 
struct batch_options *opt,
struct strbuf buf = STRBUF_INIT;
struct ref_array_item item = {0};
 
-   if (!data->skip_object_info &&
-   sha1_object_info_extended(data->oid.hash, >info,
- OBJECT_INFO_LOOKUP_REPLACE) < 0) {
-   printf("%s missing\n",
-  obj_name ? obj_name : oid_to_hex(>oid));
-   fflush(stdout);
-   return;
-   }
-
item.oid = data->oid;
-   item.type = data->type;
-   item.size = data->size;
-   item.disk_size = data->disk_size;
item.rest = data->rest;
-   item.delta_base_oid = >delta_base_oid;
+   item.objectname = obj_name;
+
+   if (populate_value())
+   return;
 
strbuf_expand(, opt->format.format, expand_format, );
strbuf_addch(, '\n');
diff --git a/ref-filter.c b/ref-filter.c
index d09ec1bde6d54..3f92a27d98b6c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1403,6 +1403,23 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
return show_ref(>u.refname, ref->refname);
 }
 
+static int check_and_fill_for_cat(struct ref_array_item *ref)
+{
+   if (!cat_file_info->skip_object_info &&
+   sha1_object_info_extended(ref->oid.hash, _file_info->info,
+ OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+   const char *e = ref->objectname;
+   printf("%s missing\n", e ? e : oid_to_hex(>oid));
+   fflush(stdout);
+   return -1;
+   }
+   ref->type = cat_file_info->type;
+   ref->size = cat_file_info->size;
+   ref->disk_size = cat_file_info->disk_size;
+   ref->delta_base_oid = _file_info->delta_base_oid;
+   return 0;
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  * Return 0 if everything was successful, -1 otherwise.
@@ -1424,6 +1441,9 @@ int populate_value(struct ref_array_item *ref)
ref->symref = "";
}
 
+   if (cat_file_info && check_and_fill_for_cat(ref))
+   return -1;
+
/* Fill in specials first */
for (i = 0; i < used_atom_cnt; i++) {
struct used_atom *atom = _atom[i];
diff --git a/ref-filter.h b/ref-filter.h
index 87b026b8b76d0..5c6e019998716 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -45,6 +45,7 @@ struct ref_array_item {
off_t disk_size;
const char *rest;
struct object_id *delta_base_oid;
+   const char *objectname;
char refname[FLEX_ARRAY];
 };
 

--
https://github.com/git/git/pull/452


[PATCH v3 14/23] ref_filter: add is_atom_used function

2018-02-12 Thread Olga Telezhnaya
Delete all items related to split_on_whitespace from ref-filter
and add new function for handling the logic.
Now cat-file could invoke that function to implementing its logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c |  8 +++-
 ref-filter.c   | 17 +++--
 ref-filter.h   | 10 +++---
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 6db57e3533806..3a49b55a1cc2e 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -382,8 +382,7 @@ static int batch_objects(struct batch_options *opt)
 {
struct strbuf buf = STRBUF_INIT;
struct expand_data data;
-   int save_warning;
-   int retval = 0;
+   int save_warning, is_rest, retval = 0;
 
if (!opt->format.format)
opt->format.format = "%(objectname) %(objecttype) 
%(objectsize)";
@@ -395,8 +394,6 @@ static int batch_objects(struct batch_options *opt)
memset(, 0, sizeof(data));
opt->format.cat_file_data = 
verify_ref_format(>format);
-   if (opt->cmdmode)
-   data.split_on_whitespace = 1;
 
if (opt->all_objects) {
struct object_info empty = OBJECT_INFO_INIT;
@@ -435,9 +432,10 @@ static int batch_objects(struct batch_options *opt)
 */
save_warning = warn_on_object_refname_ambiguity;
warn_on_object_refname_ambiguity = 0;
+   is_rest = opt->cmdmode || is_atom_used(>format, "rest");
 
while (strbuf_getline(, stdin) != EOF) {
-   if (data.split_on_whitespace) {
+   if (is_rest) {
/*
 * Split at first whitespace, tying off the beginning
 * of the string and saving the remainder (or NULL) in
diff --git a/ref-filter.c b/ref-filter.c
index 34a54db168265..4adeea6aad0da 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -493,8 +493,6 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   if (cat_file_info && !strcmp(valid_atom[i].name, "rest"))
-   cat_file_info->split_on_whitespace = 1;
return at;
 }
 
@@ -730,6 +728,21 @@ static const char *find_next(const char *cp)
return NULL;
 }
 
+/* Search for atom in given format. */
+int is_atom_used(const struct ref_format *format, const char *atom)
+{
+   const char *cp, *sp;
+   for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   const char *ep = strchr(sp, ')');
+   int atom_len = ep - sp - 2;
+   sp += 2;
+   if (atom_len == strlen(atom) && !memcmp(sp, atom, atom_len))
+   return 1;
+   cp = ep + 1;
+   }
+   return 0;
+}
+
 /*
  * Make sure the format string is well formed, and parse out
  * the used atoms.
diff --git a/ref-filter.h b/ref-filter.h
index 5c6e019998716..fffc443726e28 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -86,13 +86,6 @@ struct expand_data {
const char *rest;
struct object_id delta_base_oid;
 
-   /*
-* Whether to split the input on whitespace before feeding it to
-* get_sha1; this is decided during the mark_query phase based on
-* whether we have a %(rest) token in our format.
-*/
-   int split_on_whitespace;
-
/*
 * After a mark_query run, this object_info is set up to be
 * passed to sha1_object_info_extended. It will point to the data
@@ -186,4 +179,7 @@ void pretty_print_ref(const char *name, const unsigned char 
*sha1,
 /* Fill the values of request and prepare all data for final string creation */
 int populate_value(struct ref_array_item *ref);
 
+/* Search for atom in given format. */
+int is_atom_used(const struct ref_format *format, const char *atom);
+
 #endif /*  REF_FILTER_H  */

--
https://github.com/git/git/pull/452


[PATCH v3 20/23] ref-filter: unifying formatting of cat-file opts

2018-02-12 Thread Olga Telezhnaya
cat-file options are now filled by general logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 33 -
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 8d104b567eb7c..5781416cf9126 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -824,8 +824,12 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct object
else if (!strcmp(name, "objectsize")) {
v->value = sz;
v->s = xstrfmt("%lu", sz);
-   }
-   else if (deref)
+   } else if (!strcmp(name, "objectsize:disk")) {
+   if (cat_file_info.is_cat_file) {
+   v->value = cat_file_info.disk_size;
+   v->s = xstrfmt("%"PRIuMAX, (uintmax_t)v->value);
+   }
+   } else if (deref)
grab_objectname(name, obj->oid.hash, v, _atom[i]);
}
 }
@@ -1465,21 +1469,7 @@ static int populate_value(struct ref_array_item *ref)
name++;
}
 
-   if (cat_file_info.is_cat_file) {
-   if (starts_with(name, "objectname"))
-   v->s = oid_to_hex(>oid);
-   else if (starts_with(name, "objecttype"))
-   v->s = typename(ref->type);
-   else if (starts_with(name, "objectsize")) {
-   v->s = xstrfmt("%lu", ref->size);
-   } else if (starts_with(name, "objectsize:disk")) {
-   v->s = xstrfmt("%"PRIuMAX, 
(uintmax_t)ref->disk_size);
-   } else if (starts_with(name, "rest"))
-   v->s = ref->rest;
-   else if (starts_with(name, "deltabase"))
-   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
-   continue;
-   } else if (starts_with(name, "refname"))
+   if (starts_with(name, "refname"))
refname = get_refname(atom, ref);
else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
@@ -1535,6 +1525,15 @@ static int populate_value(struct ref_array_item *ref)
else
v->s = " ";
continue;
+   } else if (starts_with(name, "rest")) {
+   v->s = ref->rest ? ref->rest : "";
+   continue;
+   } else if (starts_with(name, "deltabase")) {
+   if (ref->delta_base_oid)
+   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
+   else
+   v->s = "";
+   continue;
} else if (starts_with(name, "align")) {
v->handler = align_atom_handler;
continue;

--
https://github.com/git/git/pull/452


[PATCH v3 17/23] ref-filter: make valid_atom general again

2018-02-12 Thread Olga Telezhnaya
Stop using valid_cat_file_atom, making the code more general.
Further commits will contain some tests, docs and
support of new features.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 34 +-
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index cc70bcf2bb8b1..ee311d51ff81c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -358,8 +358,8 @@ static struct valid_atom {
void (*parser)(const struct ref_format *format, struct used_atom *atom, 
const char *arg);
 } valid_atom[] = {
{ "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
+   { "objecttype", FIELD_STR, objecttype_atom_parser },
+   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "objectname", FIELD_STR, objectname_atom_parser },
{ "tree" },
{ "parent" },
@@ -396,12 +396,6 @@ static struct valid_atom {
{ "if", FIELD_STR, if_atom_parser },
{ "then" },
{ "else" },
-};
-
-static struct valid_atom valid_cat_file_atom[] = {
-   { "objectname" },
-   { "objecttype", FIELD_STR, objecttype_atom_parser },
-   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "rest" },
{ "deltabase", FIELD_STR, deltabase_atom_parser },
 };
@@ -431,7 +425,6 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const struct valid_atom *valid_atom, int 
n_atoms,
 const char *atom, const char *ep)
 {
const char *sp;
@@ -461,13 +454,13 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
atom_len = (arg ? arg : ep) - sp;
 
/* Is the atom a valid one? */
-   for (i = 0; i < n_atoms; i++) {
+   for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
int len = strlen(valid_atom[i].name);
if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
break;
}
 
-   if (n_atoms <= i)
+   if (ARRAY_SIZE(valid_atom) <= i)
die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
@@ -761,15 +754,9 @@ int verify_ref_format(struct ref_format *format)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
 
-   if (cat_file_info.is_cat_file)
-   at = parse_ref_filter_atom(format, valid_cat_file_atom,
-  
ARRAY_SIZE(valid_cat_file_atom), sp + 2, ep);
-   else {
-   at = parse_ref_filter_atom(format, valid_atom,
-  ARRAY_SIZE(valid_atom), sp + 
2, ep);
-   if (skip_prefix(used_atom[at].name, "color:", ))
-   format->need_color_reset_at_eol = 
!!strcmp(color, "reset");
-   }
+   at = parse_ref_filter_atom(format, sp + 2, ep);
+   if (skip_prefix(used_atom[at].name, "color:", ))
+   format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
 
cp = ep + 1;
}
@@ -2231,9 +2218,7 @@ int format_ref_array_item(struct ref_array_item *info,
if (cp < sp)
append_literal(cp, sp, );
if (get_ref_atom_value(info,
-  parse_ref_filter_atom(format, valid_atom,
-
ARRAY_SIZE(valid_atom),
-sp + 2, ep),
+  parse_ref_filter_atom(format, sp + 2, 
ep),
   ))
return -1;
atomv->handler(atomv, );
@@ -2286,8 +2271,7 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, valid_atom,
-ARRAY_SIZE(valid_atom), atom, end);
+   return parse_ref_filter_atom(, atom, end);
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/452


[PATCH v3 04/23] ref-filter: make valid_atom as function parameter

2018-02-12 Thread Olga Telezhnaya
Make valid_atom as a function parameter,
there could be another variable further.
Need that for further reusing of formatting logic in cat-file.c.

We do not need to allow users to pass their own valid_atom variable in
global functions like verify_ref_format() because in the end we want to
have same set of valid atoms for all commands. But, as a first step
of migrating, I create further another version of valid_atom
for cat-file.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 9ed5e66066a7a..5e7ed0f338490 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -325,7 +325,7 @@ static void head_atom_parser(const struct ref_format 
*format, struct used_atom *
atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 }
 
-static struct {
+static struct valid_atom {
const char *name;
cmp_type cmp_type;
void (*parser)(const struct ref_format *format, struct used_atom *atom, 
const char *arg);
@@ -396,6 +396,7 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
+const struct valid_atom *valid_atom, int 
n_atoms,
 const char *atom, const char *ep)
 {
const char *sp;
@@ -425,13 +426,13 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
atom_len = (arg ? arg : ep) - sp;
 
/* Is the atom a valid one? */
-   for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
+   for (i = 0; i < n_atoms; i++) {
int len = strlen(valid_atom[i].name);
if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
+   if (n_atoms <= i)
die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
@@ -708,7 +709,8 @@ int verify_ref_format(struct ref_format *format)
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, valid_atom,
+  ARRAY_SIZE(valid_atom), sp + 2, ep);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
@@ -2145,7 +2147,9 @@ int format_ref_array_item(struct ref_array_item *info,
if (cp < sp)
append_literal(cp, sp, );
if (get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, 
ep),
+  parse_ref_filter_atom(format, valid_atom,
+
ARRAY_SIZE(valid_atom),
+sp + 2, ep),
   ))
return -1;
atomv->handler(atomv, );
@@ -2198,7 +2202,8 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   return parse_ref_filter_atom(, valid_atom,
+ARRAY_SIZE(valid_atom), atom, end);
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/452


[PATCH v3 18/23] cat-file: reuse printing logic from ref-filter

2018-02-12 Thread Olga Telezhnaya
Reuse code from ref-filter to print resulting message.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 51 ---
 ref-filter.c   | 21 +++--
 2 files changed, 23 insertions(+), 49 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 273b4038e3893..21007995c5ac6 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -176,45 +176,6 @@ static int cat_one_file(int opt, const char *exp_type, 
const char *obj_name,
return 0;
 }
 
-static int is_atom(const char *atom, const char *s, int slen)
-{
-   int alen = strlen(atom);
-   return alen == slen && !memcmp(atom, s, alen);
-}
-
-static void expand_atom(struct strbuf *sb, const char *atom, int len,
-struct ref_array_item *item)
-{
-   if (is_atom("objectname", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>oid));
-   else if (is_atom("objecttype", atom, len))
-   strbuf_addstr(sb, typename(item->type));
-   else if (is_atom("objectsize", atom, len))
-   strbuf_addf(sb, "%lu", item->size);
-   else if (is_atom("objectsize:disk", atom, len))
-   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)item->disk_size);
-   else if (is_atom("rest", atom, len)) {
-   if (item->rest)
-   strbuf_addstr(sb, item->rest);
-   } else if (is_atom("deltabase", atom, len))
-   strbuf_addstr(sb, oid_to_hex(item->delta_base_oid));
-}
-
-static size_t expand_format(struct strbuf *sb, const char *start, void *data)
-{
-   const char *end;
-   struct ref_array_item *item = data;
-
-   if (*start != '(')
-   return 0;
-   end = strchr(start + 1, ')');
-   if (!end)
-   die("format element '%s' does not end in ')'", start);
-
-   expand_atom(sb, start + 1, end - start - 1, item);
-   return end - start + 1;
-}
-
 static void batch_write(struct batch_options *opt, const void *data, int len)
 {
if (opt->buffer_output) {
@@ -282,23 +243,19 @@ static void print_object_or_die(struct batch_options 
*opt, struct expand_data *d
 static void batch_object_write(const char *obj_name, struct batch_options *opt,
   struct expand_data *data)
 {
-   struct strbuf buf = STRBUF_INIT;
struct ref_array_item item = {0};
 
item.oid = data->oid;
item.rest = data->rest;
item.objectname = obj_name;
 
-   if (populate_value())
+   if (show_ref_array_item(, >format))
return;
-
-   data->type = item.type;
-   strbuf_expand(, opt->format.format, expand_format, );
-   strbuf_addch(, '\n');
-   batch_write(opt, buf.buf, buf.len);
-   strbuf_release();
+   if (!opt->buffer_output)
+   fflush(stdout);
 
if (opt->print_contents) {
+   data->type = item.type;
print_object_or_die(opt, data);
batch_write(opt, "\n", 1);
}
diff --git a/ref-filter.c b/ref-filter.c
index ee311d51ff81c..eb53b0babdb83 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1465,7 +1465,21 @@ int populate_value(struct ref_array_item *ref)
name++;
}
 
-   if (starts_with(name, "refname"))
+   if (cat_file_info.is_cat_file) {
+   if (starts_with(name, "objectname"))
+   v->s = oid_to_hex(>oid);
+   else if (starts_with(name, "objecttype"))
+   v->s = typename(ref->type);
+   else if (starts_with(name, "objectsize")) {
+   v->s = xstrfmt("%lu", ref->size);
+   } else if (starts_with(name, "objectsize:disk")) {
+   v->s = xstrfmt("%"PRIuMAX, 
(uintmax_t)ref->disk_size);
+   } else if (starts_with(name, "rest"))
+   v->s = ref->rest;
+   else if (starts_with(name, "deltabase"))
+   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
+   continue;
+   } else if (starts_with(name, "refname"))
refname = get_refname(atom, ref);
else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
@@ -2207,6 +2221,7 @@ int format_ref_array_item(struct ref_array_item *info,
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
+   int retval = 0;
 
state.quote_style = format->quote_style;
push_stack_element();
@@ -2223,6 +2238,8 @@ int format_ref_array_item(struct ref_array_item *info,
return -1;

[PATCH v3 05/23] cat-file: move struct expand_data into ref-filter

2018-02-12 Thread Olga Telezhnaya
Need that for further reusing of formatting logic in cat-file.
Have plans to get rid of using expand_data in cat-file at all,
and use it only in ref-filter for collecting, formatting and printing
needed data.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 36 
 ref-filter.h   | 36 
 2 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 98fc5ec069a49..37d6096d201b5 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -176,42 +176,6 @@ static int cat_one_file(int opt, const char *exp_type, 
const char *obj_name,
return 0;
 }
 
-struct expand_data {
-   struct object_id oid;
-   enum object_type type;
-   unsigned long size;
-   off_t disk_size;
-   const char *rest;
-   struct object_id delta_base_oid;
-
-   /*
-* If mark_query is true, we do not expand anything, but rather
-* just mark the object_info with items we wish to query.
-*/
-   int mark_query;
-
-   /*
-* Whether to split the input on whitespace before feeding it to
-* get_sha1; this is decided during the mark_query phase based on
-* whether we have a %(rest) token in our format.
-*/
-   int split_on_whitespace;
-
-   /*
-* After a mark_query run, this object_info is set up to be
-* passed to sha1_object_info_extended. It will point to the data
-* elements above, so you can retrieve the response from there.
-*/
-   struct object_info info;
-
-   /*
-* This flag will be true if the requested batch format and options
-* don't require us to call sha1_object_info, which can then be
-* optimized out.
-*/
-   unsigned skip_object_info : 1;
-};
-
 static int is_atom(const char *atom, const char *s, int slen)
 {
int alen = strlen(atom);
diff --git a/ref-filter.h b/ref-filter.h
index b75c8ac45248e..17f2ac24d2739 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -72,6 +72,42 @@ struct ref_filter {
verbose;
 };
 
+struct expand_data {
+   struct object_id oid;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   const char *rest;
+   struct object_id delta_base_oid;
+
+   /*
+* If mark_query is true, we do not expand anything, but rather
+* just mark the object_info with items we wish to query.
+*/
+   int mark_query;
+
+   /*
+* Whether to split the input on whitespace before feeding it to
+* get_sha1; this is decided during the mark_query phase based on
+* whether we have a %(rest) token in our format.
+*/
+   int split_on_whitespace;
+
+   /*
+* After a mark_query run, this object_info is set up to be
+* passed to sha1_object_info_extended. It will point to the data
+* elements above, so you can retrieve the response from there.
+*/
+   struct object_info info;
+
+   /*
+* This flag will be true if the requested batch format and options
+* don't require us to call sha1_object_info, which can then be
+* optimized out.
+*/
+   unsigned skip_object_info : 1;
+};
+
 struct ref_format {
/*
 * Set these to define the format; make sure you call

--
https://github.com/git/git/pull/452


[PATCH v3 10/23] ref-filter: make populate_value() global

2018-02-12 Thread Olga Telezhnaya
Make function global for further using in cat-file.
In the end of patch series this function becomes internal again,
so this is a part of middle step. cat-file would use more general
functions further.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 2 +-
 ref-filter.h | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 5c75259b1ab8c..4acd391b5dfac 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1407,7 +1407,7 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
  * Parse the object referred by ref, and grab needed value.
  * Return 0 if everything was successful, -1 otherwise.
  */
-static int populate_value(struct ref_array_item *ref)
+int populate_value(struct ref_array_item *ref)
 {
void *buf;
struct object *obj;
diff --git a/ref-filter.h b/ref-filter.h
index 781921d4e0978..e16ea2a990119 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -182,4 +182,7 @@ void setup_ref_filter_porcelain_msg(void);
 void pretty_print_ref(const char *name, const unsigned char *sha1,
  const struct ref_format *format);
 
+/* Fill the values of request and prepare all data for final string creation */
+int populate_value(struct ref_array_item *ref);
+
 #endif /*  REF_FILTER_H  */

--
https://github.com/git/git/pull/452


[PATCH v3 21/23] for-each-ref: tests for new atoms added

2018-02-12 Thread Olga Telezhnaya
Add tests for new formatting atoms: rest, deltabase, objectsize:disk.
rest means nothing and we expand it into empty string.
We need this atom for cat-file command.
Have plans to support deltabase and objectsize:disk further
(as it is done in cat-file), now also expand it to empty string.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 t/t6300-for-each-ref.sh | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index c128dfc579079..eee656a6abba9 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -316,6 +316,24 @@ test_expect_success 'exercise strftime with odd fields' '
test_cmp expected actual
 '
 
+test_expect_success 'Check format %(objectsize:disk) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(objectsize:disk)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
+test_expect_success 'Check format %(rest) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(rest)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
+test_expect_success 'Check format %(deltabase) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(deltabase)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
 cat >expected <<\EOF
 refs/heads/master
 refs/remotes/origin/master

--
https://github.com/git/git/pull/452


[PATCH v3 02/23] ref-filter: add return value to some functions

2018-02-12 Thread Olga Telezhnaya
Add return flag to format_ref_array_item(), show_ref_array_item(),
get_ref_array_info() and populate_value() for further using.
Need it to handle situations when item is broken but we can not invoke
die() because we are in batch mode and all items need to be processed.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 37 -
 ref-filter.h | 14 ++
 2 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index d04295e33448e..9ed5e66066a7a 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1356,8 +1356,9 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 
 /*
  * Parse the object referred by ref, and grab needed value.
+ * Return 0 if everything was successful, -1 otherwise.
  */
-static void populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref)
 {
void *buf;
struct object *obj;
@@ -1482,7 +1483,7 @@ static void populate_value(struct ref_array_item *ref)
}
}
if (used_atom_cnt <= i)
-   return;
+   return 0;
 
buf = get_obj(>objectname, , , );
if (!buf)
@@ -1501,7 +1502,7 @@ static void populate_value(struct ref_array_item *ref)
 * object, we are done.
 */
if (!need_tagged || (obj->type != OBJ_TAG))
-   return;
+   return 0;
 
/*
 * If it is a tag object, see if we use a value that derefs
@@ -1525,19 +1526,24 @@ static void populate_value(struct ref_array_item *ref)
grab_values(ref->value, 1, obj, buf, size);
if (!eaten)
free(buf);
+
+   return 0;
 }
 
 /*
  * Given a ref, return the value for the atom.  This lazily gets value
  * out of the object by calling populate value.
+ * Return 0 if everything was successful, -1 otherwise.
  */
-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
+static int get_ref_atom_value(struct ref_array_item *ref, int atom, struct 
atom_value **v)
 {
+   int retval = 0;
if (!ref->value) {
-   populate_value(ref);
+   retval = populate_value(ref);
fill_missing_values(ref->value);
}
*v = >value[atom];
+   return retval;
 }
 
 /*
@@ -2122,7 +2128,7 @@ static void append_literal(const char *cp, const char 
*ep, struct ref_formatting
}
 }
 
-void format_ref_array_item(struct ref_array_item *info,
+int format_ref_array_item(struct ref_array_item *info,
   const struct ref_format *format,
   struct strbuf *final_buf)
 {
@@ -2138,9 +2144,10 @@ void format_ref_array_item(struct ref_array_item *info,
ep = strchr(sp, ')');
if (cp < sp)
append_literal(cp, sp, );
-   get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, ep),
-  );
+   if (get_ref_atom_value(info,
+  parse_ref_filter_atom(format, sp + 2, 
ep),
+  ))
+   return -1;
atomv->handler(atomv, );
}
if (*cp) {
@@ -2156,17 +2163,21 @@ void format_ref_array_item(struct ref_array_item *info,
die(_("format: %%(end) atom missing"));
strbuf_addbuf(final_buf, >output);
pop_stack_element();
+   return 0;
 }
 
-void show_ref_array_item(struct ref_array_item *info,
+int show_ref_array_item(struct ref_array_item *info,
 const struct ref_format *format)
 {
struct strbuf final_buf = STRBUF_INIT;
+   int retval = format_ref_array_item(info, format, _buf);
 
-   format_ref_array_item(info, format, _buf);
-   fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   if (!retval) {
+   fwrite(final_buf.buf, 1, final_buf.len, stdout);
+   putchar('\n');
+   }
strbuf_release(_buf);
-   putchar('\n');
+   return retval;
 }
 
 void pretty_print_ref(const char *name, const unsigned char *sha1,
diff --git a/ref-filter.h b/ref-filter.h
index 0d98342b34319..b75c8ac45248e 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -109,12 +109,18 @@ void ref_array_clear(struct ref_array *array);
 int verify_ref_format(struct ref_format *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,
+/*
+ * Based on the given format and quote_style, fill the strbuf.
+ * Return 0 if everything was successful, -1 otherwise (and strbuf remains 

[PATCH v3 15/23] cat-file: move skip_object_info into ref-filter

2018-02-12 Thread Olga Telezhnaya
Move logic related to skip_object_info into ref-filter,
so that cat-file does not use that field at all.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 7 +--
 ref-filter.c   | 5 +
 ref-filter.h   | 1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 3a49b55a1cc2e..582679f3dca2c 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -393,14 +393,9 @@ static int batch_objects(struct batch_options *opt)
 */
memset(, 0, sizeof(data));
opt->format.cat_file_data = 
+   opt->format.all_objects = opt->all_objects;
verify_ref_format(>format);
 
-   if (opt->all_objects) {
-   struct object_info empty = OBJECT_INFO_INIT;
-   if (!memcmp(, , sizeof(empty)))
-   data.skip_object_info = 1;
-   }
-
/*
 * If we are printing out the object, then always fill in the type,
 * since we will want to decide whether or not to stream.
diff --git a/ref-filter.c b/ref-filter.c
index 4adeea6aad0da..104cd6aef0102 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -775,6 +775,11 @@ int verify_ref_format(struct ref_format *format)
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
+   if (cat_file_info && format->all_objects) {
+   struct object_info empty = OBJECT_INFO_INIT;
+   if (!memcmp(_file_info->info, , sizeof(empty)))
+   cat_file_info->skip_object_info = 1;
+   }
return 0;
 }
 
diff --git a/ref-filter.h b/ref-filter.h
index fffc443726e28..b1c668c12428b 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -118,6 +118,7 @@ struct ref_format {
 * hopefully would be reduced later.
 */
struct expand_data *cat_file_data;
+   unsigned all_objects : 1;
 };
 
 #define REF_FORMAT_INIT { NULL, 0, -1 }

--
https://github.com/git/git/pull/452


[PATCH v3 11/23] ref-filter: rename field in ref_array_item stuct

2018-02-12 Thread Olga Telezhnaya
Rename objectname field to oid in struct ref_array_item.
Next commit will add objectname field that will contain
string representation of object id.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c |  4 ++--
 ref-filter.c   | 10 +-
 ref-filter.h   |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 5b7bc34f1ec6d..0c362828ad81e 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -186,7 +186,7 @@ static void expand_atom(struct strbuf *sb, const char 
*atom, int len,
 struct ref_array_item *item)
 {
if (is_atom("objectname", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>objectname));
+   strbuf_addstr(sb, oid_to_hex(>oid));
else if (is_atom("objecttype", atom, len))
strbuf_addstr(sb, typename(item->type));
else if (is_atom("objectsize", atom, len))
@@ -294,7 +294,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
return;
}
 
-   item.objectname = data->oid;
+   item.oid = data->oid;
item.type = data->type;
item.size = data->size;
item.disk_size = data->disk_size;
diff --git a/ref-filter.c b/ref-filter.c
index 4acd391b5dfac..d09ec1bde6d54 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1489,7 +1489,7 @@ int populate_value(struct ref_array_item *ref)
v->s = xstrdup(buf + 1);
}
continue;
-   } else if (!deref && grab_objectname(name, 
ref->objectname.hash, v, atom)) {
+   } else if (!deref && grab_objectname(name, ref->oid.hash, v, 
atom)) {
continue;
} else if (!strcmp(name, "HEAD")) {
if (atom->u.head && !strcmp(ref->refname, atom->u.head))
@@ -1534,13 +1534,13 @@ int populate_value(struct ref_array_item *ref)
if (used_atom_cnt <= i)
return 0;
 
-   buf = get_obj(>objectname, , , );
+   buf = get_obj(>oid, , , );
if (!buf)
die(_("missing object %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
+   oid_to_hex(>oid), ref->refname);
if (!obj)
die(_("parse_object_buffer failed on %s for %s"),
-   oid_to_hex(>objectname), ref->refname);
+   oid_to_hex(>oid), ref->refname);
 
grab_values(ref->value, 0, obj, buf, size);
if (!eaten)
@@ -1890,7 +1890,7 @@ static struct ref_array_item *new_ref_array_item(const 
char *refname,
 {
struct ref_array_item *ref;
FLEX_ALLOC_STR(ref, refname, refname);
-   hashcpy(ref->objectname.hash, objectname);
+   hashcpy(ref->oid.hash, objectname);
ref->flag = flag;
 
return ref;
diff --git a/ref-filter.h b/ref-filter.h
index e16ea2a990119..87b026b8b76d0 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -34,7 +34,7 @@ struct ref_sorting {
 };
 
 struct ref_array_item {
-   struct object_id objectname;
+   struct object_id oid;
int flag;
unsigned int kind;
const char *symref;

--
https://github.com/git/git/pull/452


[PATCH v3 09/23] cat-file: start use ref_array_item struct

2018-02-12 Thread Olga Telezhnaya
Moving from using expand_data to ref_array_item structure.
That helps us to reuse functions from ref-filter easier.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 32 
 ref-filter.h   |  5 +
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 67e7790d2f319..5b7bc34f1ec6d 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -183,27 +183,27 @@ static int is_atom(const char *atom, const char *s, int 
slen)
 }
 
 static void expand_atom(struct strbuf *sb, const char *atom, int len,
-struct expand_data *data)
+struct ref_array_item *item)
 {
if (is_atom("objectname", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>oid));
+   strbuf_addstr(sb, oid_to_hex(>objectname));
else if (is_atom("objecttype", atom, len))
-   strbuf_addstr(sb, typename(data->type));
+   strbuf_addstr(sb, typename(item->type));
else if (is_atom("objectsize", atom, len))
-   strbuf_addf(sb, "%lu", data->size);
+   strbuf_addf(sb, "%lu", item->size);
else if (is_atom("objectsize:disk", atom, len))
-   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
+   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)item->disk_size);
else if (is_atom("rest", atom, len)) {
-   if (data->rest)
-   strbuf_addstr(sb, data->rest);
+   if (item->rest)
+   strbuf_addstr(sb, item->rest);
} else if (is_atom("deltabase", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>delta_base_oid));
+   strbuf_addstr(sb, oid_to_hex(item->delta_base_oid));
 }
 
-static size_t expand_format(struct strbuf *sb, const char *start, void *vdata)
+static size_t expand_format(struct strbuf *sb, const char *start, void *data)
 {
const char *end;
-   struct expand_data *data = vdata;
+   struct ref_array_item *item = data;
 
if (*start != '(')
return 0;
@@ -211,7 +211,7 @@ static size_t expand_format(struct strbuf *sb, const char 
*start, void *vdata)
if (!end)
die("format element '%s' does not end in ')'", start);
 
-   expand_atom(sb, start + 1, end - start - 1, data);
+   expand_atom(sb, start + 1, end - start - 1, item);
return end - start + 1;
 }
 
@@ -283,6 +283,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
   struct expand_data *data)
 {
struct strbuf buf = STRBUF_INIT;
+   struct ref_array_item item = {0};
 
if (!data->skip_object_info &&
sha1_object_info_extended(data->oid.hash, >info,
@@ -293,7 +294,14 @@ static void batch_object_write(const char *obj_name, 
struct batch_options *opt,
return;
}
 
-   strbuf_expand(, opt->format.format, expand_format, data);
+   item.objectname = data->oid;
+   item.type = data->type;
+   item.size = data->size;
+   item.disk_size = data->disk_size;
+   item.rest = data->rest;
+   item.delta_base_oid = >delta_base_oid;
+
+   strbuf_expand(, opt->format.format, expand_format, );
strbuf_addch(, '\n');
batch_write(opt, buf.buf, buf.len);
strbuf_release();
diff --git a/ref-filter.h b/ref-filter.h
index 52e07dbe6864a..781921d4e0978 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -40,6 +40,11 @@ struct ref_array_item {
const char *symref;
struct commit *commit;
struct atom_value *value;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   const char *rest;
+   struct object_id *delta_base_oid;
char refname[FLEX_ARRAY];
 };
 

--
https://github.com/git/git/pull/452


[PATCH v3 07/23] cat-file: start migrating formatting to ref-filter

2018-02-12 Thread Olga Telezhnaya
Move mark_atom_in_object_info() from cat-file to ref-filter and
start using it in verify_ref_format().
It also means that we start reusing verify_ref_format() in cat-file.

Start from simple moving of mark_atom_in_object_info(),
it would be removed later by integrating all needed processes into
ref-filter logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 35 +--
 ref-filter.c   | 41 -
 ref-filter.h   | 12 ++--
 3 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index edb04a96d9bd3..67e7790d2f319 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -182,25 +182,6 @@ static int is_atom(const char *atom, const char *s, int 
slen)
return alen == slen && !memcmp(atom, s, alen);
 }
 
-static void mark_atom_in_object_info(const char *atom, int len,
-struct expand_data *data)
-{
-   if (is_atom("objectname", atom, len))
-   ; /* do nothing */
-   else if (is_atom("objecttype", atom, len))
-   data->info.typep = >type;
-   else if (is_atom("objectsize", atom, len))
-   data->info.sizep = >size;
-   else if (is_atom("objectsize:disk", atom, len))
-   data->info.disk_sizep = >disk_size;
-   else if (is_atom("rest", atom, len))
-   data->split_on_whitespace = 1;
-   else if (is_atom("deltabase", atom, len))
-   data->info.delta_base_sha1 = data->delta_base_oid.hash;
-   else
-   die("unknown format element: %.*s", len, atom);
-}
-
 static void expand_atom(struct strbuf *sb, const char *atom, int len,
 struct expand_data *data)
 {
@@ -230,11 +211,7 @@ static size_t expand_format(struct strbuf *sb, const char 
*start, void *vdata)
if (!end)
die("format element '%s' does not end in ')'", start);
 
-   if (data->mark_query)
-   mark_atom_in_object_info(start + 1, end - start - 1, data);
-   else
-   expand_atom(sb, start + 1, end - start - 1, data);
-
+   expand_atom(sb, start + 1, end - start - 1, data);
return end - start + 1;
 }
 
@@ -413,14 +390,12 @@ static int batch_objects(struct batch_options *opt)
opt->format.format = "%(objectname) %(objecttype) 
%(objectsize)";
 
/*
-* Expand once with our special mark_query flag, which will prime the
-* object_info to be handed to sha1_object_info_extended for each
-* object.
+* Call verify_ref_format to prepare object_info to be handed to
+* sha1_object_info_extended for each object.
 */
memset(, 0, sizeof(data));
-   data.mark_query = 1;
-   strbuf_expand(, opt->format.format, expand_format, );
-   data.mark_query = 0;
+   opt->format.cat_file_data = 
+   verify_ref_format(>format);
if (opt->cmdmode)
data.split_on_whitespace = 1;
 
diff --git a/ref-filter.c b/ref-filter.c
index 5e7ed0f338490..ff87e632f463c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -392,6 +392,31 @@ struct atom_value {
struct used_atom *atom;
 };
 
+static int is_atom(const char *atom, const char *s, int slen)
+{
+   int alen = strlen(atom);
+   return alen == slen && !memcmp(atom, s, alen);
+}
+
+static void mark_atom_in_object_info(const char *atom, int len,
+   struct expand_data *data)
+{
+   if (is_atom("objectname", atom, len))
+   ; /* do nothing */
+   else if (is_atom("objecttype", atom, len))
+   data->info.typep = >type;
+   else if (is_atom("objectsize", atom, len))
+   data->info.sizep = >size;
+   else if (is_atom("objectsize:disk", atom, len))
+   data->info.disk_sizep = >disk_size;
+   else if (is_atom("rest", atom, len))
+   data->split_on_whitespace = 1;
+   else if (is_atom("deltabase", atom, len))
+   data->info.delta_base_sha1 = data->delta_base_oid.hash;
+   else
+   die("unknown format element: %.*s", len, atom);
+}
+
 /*
  * Used to parse format string and sort specifiers
  */
@@ -709,12 +734,18 @@ int verify_ref_format(struct ref_format *format)
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, valid_atom,
-  ARRAY_SIZE(valid_atom), sp + 2, ep);
-   cp = ep + 1;
 
-   if (skip_prefix(used_atom[at].name, "color:", ))
-   format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   if 

[PATCH v3 16/23] ref-filter: make cat_file_info independent

2018-02-12 Thread Olga Telezhnaya
Remove connection between expand_data variable
in cat-file and in ref-filter.
It will help further to get rid of using expand_data in cat-file.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c |  3 ++-
 ref-filter.c   | 36 +++-
 ref-filter.h   |  7 ++-
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 582679f3dca2c..273b4038e3893 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -292,6 +292,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
if (populate_value())
return;
 
+   data->type = item.type;
strbuf_expand(, opt->format.format, expand_format, );
strbuf_addch(, '\n');
batch_write(opt, buf.buf, buf.len);
@@ -392,7 +393,7 @@ static int batch_objects(struct batch_options *opt)
 * sha1_object_info_extended for each object.
 */
memset(, 0, sizeof(data));
-   opt->format.cat_file_data = 
+   opt->format.is_cat_file = 1;
opt->format.all_objects = opt->all_objects;
verify_ref_format(>format);
 
diff --git a/ref-filter.c b/ref-filter.c
index 104cd6aef0102..cc70bcf2bb8b1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -100,7 +100,7 @@ static struct used_atom {
} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
-struct expand_data *cat_file_info;
+struct expand_data cat_file_info;
 
 static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
 {
@@ -255,9 +255,9 @@ static void objectname_atom_parser(const struct ref_format 
*format, struct used_
 static void objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.sizep = _file_info->size;
+   cat_file_info.info.sizep = _file_info.size;
else if (!strcmp(arg, "disk"))
-   cat_file_info->info.disk_sizep = _file_info->disk_size;
+   cat_file_info.info.disk_sizep = _file_info.disk_size;
else
die(_("urecognized %%(objectsize) argument: %s"), arg);
 }
@@ -265,7 +265,7 @@ static void objectsize_atom_parser(const struct ref_format 
*format, struct used_
 static void objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.typep = _file_info->type;
+   cat_file_info.info.typep = _file_info.type;
else
die(_("urecognized %%(objecttype) argument: %s"), arg);
 }
@@ -273,7 +273,7 @@ static void objecttype_atom_parser(const struct ref_format 
*format, struct used_
 static void deltabase_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.delta_base_sha1 = 
cat_file_info->delta_base_oid.hash;
+   cat_file_info.info.delta_base_sha1 = 
cat_file_info.delta_base_oid.hash;
else
die(_("urecognized %%(deltabase) argument: %s"), arg);
 }
@@ -751,7 +751,7 @@ int verify_ref_format(struct ref_format *format)
 {
const char *cp, *sp;
 
-   cat_file_info = format->cat_file_data;
+   cat_file_info.is_cat_file = format->is_cat_file;
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
const char *color, *ep = strchr(sp, ')');
@@ -761,7 +761,7 @@ int verify_ref_format(struct ref_format *format)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
 
-   if (format->cat_file_data)
+   if (cat_file_info.is_cat_file)
at = parse_ref_filter_atom(format, valid_cat_file_atom,
   
ARRAY_SIZE(valid_cat_file_atom), sp + 2, ep);
else {
@@ -775,10 +775,10 @@ int verify_ref_format(struct ref_format *format)
}
if (format->need_color_reset_at_eol && !want_color(format->use_color))
format->need_color_reset_at_eol = 0;
-   if (cat_file_info && format->all_objects) {
+   if (cat_file_info.is_cat_file && format->all_objects) {
struct object_info empty = OBJECT_INFO_INIT;
-   if (!memcmp(_file_info->info, , sizeof(empty)))
-   cat_file_info->skip_object_info = 1;
+   if (!memcmp(_file_info.info, , sizeof(empty)))
+   cat_file_info.skip_object_info = 1;
}
return 0;
 }
@@ -1420,18 +1420,20 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 
 static int 

[PATCH v3 19/23] ref-filter: make populate_value() internal again

2018-02-12 Thread Olga Telezhnaya
Remove populate_value() from header file. We needed that
for interim step, now it could be returned back.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 2 +-
 ref-filter.h | 3 ---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index eb53b0babdb83..8d104b567eb7c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1428,7 +1428,7 @@ static int check_and_fill_for_cat(struct ref_array_item 
*ref)
  * Parse the object referred by ref, and grab needed value.
  * Return 0 if everything was successful, -1 otherwise.
  */
-int populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref)
 {
void *buf;
struct object *obj;
diff --git a/ref-filter.h b/ref-filter.h
index 4eaf6d0514502..115d00288fdee 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -174,9 +174,6 @@ void setup_ref_filter_porcelain_msg(void);
 void pretty_print_ref(const char *name, const unsigned char *sha1,
  const struct ref_format *format);
 
-/* Fill the values of request and prepare all data for final string creation */
-int populate_value(struct ref_array_item *ref);
-
 /* Search for atom in given format. */
 int is_atom_used(const struct ref_format *format, const char *atom);
 

--
https://github.com/git/git/pull/452


[PATCH v3 08/23] ref-filter: reuse parse_ref_filter_atom()

2018-02-12 Thread Olga Telezhnaya
Continue migrating formatting logic from cat-file to ref-filter.
Reuse parse_ref_filter_atom() for unifying all processes in ref-filter
and further removing of mark_atom_in_object_info().

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 34 +-
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index ff87e632f463c..5c75259b1ab8c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -100,6 +100,7 @@ static struct used_atom {
} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
+struct expand_data *cat_file_info;
 
 static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
 {
@@ -251,6 +252,16 @@ static void objectname_atom_parser(const struct ref_format 
*format, struct used_
die(_("unrecognized %%(objectname) argument: %s"), arg);
 }
 
+static void objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
+{
+   if (!arg)
+   ; /* default to normal object size */
+   else if (!strcmp(arg, "disk"))
+   cat_file_info->info.disk_sizep = _file_info->disk_size;
+   else
+   die(_("urecognized %%(objectsize) argument: %s"), arg);
+}
+
 static void refname_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
refname_atom_parser_internal(>u.refname, arg, atom->name);
@@ -371,6 +382,14 @@ static struct valid_atom {
{ "else" },
 };
 
+static struct valid_atom valid_cat_file_atom[] = {
+   { "objectname" },
+   { "objecttype" },
+   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
+   { "rest" },
+   { "deltabase" },
+};
+
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
 
 struct ref_formatting_stack {
@@ -401,20 +420,14 @@ static int is_atom(const char *atom, const char *s, int 
slen)
 static void mark_atom_in_object_info(const char *atom, int len,
struct expand_data *data)
 {
-   if (is_atom("objectname", atom, len))
-   ; /* do nothing */
-   else if (is_atom("objecttype", atom, len))
+   if (is_atom("objecttype", atom, len))
data->info.typep = >type;
else if (is_atom("objectsize", atom, len))
data->info.sizep = >size;
-   else if (is_atom("objectsize:disk", atom, len))
-   data->info.disk_sizep = >disk_size;
else if (is_atom("rest", atom, len))
data->split_on_whitespace = 1;
else if (is_atom("deltabase", atom, len))
data->info.delta_base_sha1 = data->delta_base_oid.hash;
-   else
-   die("unknown format element: %.*s", len, atom);
 }
 
 /*
@@ -483,6 +496,8 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
+   if (cat_file_info)
+   mark_atom_in_object_info(atom, atom_len, cat_file_info);
return at;
 }
 
@@ -726,6 +741,7 @@ int verify_ref_format(struct ref_format *format)
 {
const char *cp, *sp;
 
+   cat_file_info = format->cat_file_data;
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
const char *color, *ep = strchr(sp, ')');
@@ -736,8 +752,8 @@ int verify_ref_format(struct ref_format *format)
/* sp points at "%(" and ep points at the closing ")" */
 
if (format->cat_file_data)
-   mark_atom_in_object_info(sp + 2, ep - sp - 2,
-   format->cat_file_data);
+   at = parse_ref_filter_atom(format, valid_cat_file_atom,
+  
ARRAY_SIZE(valid_cat_file_atom), sp + 2, ep);
else {
at = parse_ref_filter_atom(format, valid_atom,
   ARRAY_SIZE(valid_atom), sp + 
2, ep);

--
https://github.com/git/git/pull/452


[PATCH v3 01/23] ref-filter: get rid of goto

2018-02-12 Thread Olga Telezhnaya
Get rid of goto command in ref-filter for better readability.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index f9e25aea7a97e..d04295e33448e 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1477,12 +1477,13 @@ static void populate_value(struct ref_array_item *ref)
 
for (i = 0; i < used_atom_cnt; i++) {
struct atom_value *v = >value[i];
-   if (v->s == NULL)
-   goto need_obj;
+   if (v->s == NULL) {
+   break;
+   }
}
-   return;
+   if (used_atom_cnt <= i)
+   return;
 
- need_obj:
buf = get_obj(>objectname, , , );
if (!buf)
die(_("missing object %s for %s"),

--
https://github.com/git/git/pull/452


[PATCH v3 03/23] cat-file: reuse struct ref_format

2018-02-12 Thread Olga Telezhnaya
Start using ref_format struct instead of simple char*.
Need that for further reusing of formatting logic from ref-filter.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index f5fa4fd75af26..98fc5ec069a49 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -13,15 +13,16 @@
 #include "tree-walk.h"
 #include "sha1-array.h"
 #include "packfile.h"
+#include "ref-filter.h"
 
 struct batch_options {
+   struct ref_format format;
int enabled;
int follow_symlinks;
int print_contents;
int buffer_output;
int all_objects;
int cmdmode; /* may be 'w' or 'c' for --filters or --textconv */
-   const char *format;
 };
 
 static const char *force_path;
@@ -348,7 +349,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
return;
}
 
-   strbuf_expand(, opt->format, expand_format, data);
+   strbuf_expand(, opt->format.format, expand_format, data);
strbuf_addch(, '\n');
batch_write(opt, buf.buf, buf.len);
strbuf_release();
@@ -441,8 +442,8 @@ static int batch_objects(struct batch_options *opt)
int save_warning;
int retval = 0;
 
-   if (!opt->format)
-   opt->format = "%(objectname) %(objecttype) %(objectsize)";
+   if (!opt->format.format)
+   opt->format.format = "%(objectname) %(objecttype) 
%(objectsize)";
 
/*
 * Expand once with our special mark_query flag, which will prime the
@@ -451,7 +452,7 @@ static int batch_objects(struct batch_options *opt)
 */
memset(, 0, sizeof(data));
data.mark_query = 1;
-   strbuf_expand(, opt->format, expand_format, );
+   strbuf_expand(, opt->format.format, expand_format, );
data.mark_query = 0;
if (opt->cmdmode)
data.split_on_whitespace = 1;
@@ -543,7 +544,7 @@ static int batch_option_callback(const struct option *opt,
 
bo->enabled = 1;
bo->print_contents = !strcmp(opt->long_name, "batch");
-   bo->format = arg;
+   bo->format.format = arg;
 
return 0;
 }
@@ -552,7 +553,7 @@ int cmd_cat_file(int argc, const char **argv, const char 
*prefix)
 {
int opt = 0;
const char *exp_type = NULL, *obj_name = NULL;
-   struct batch_options batch = {0};
+   struct batch_options batch = { REF_FORMAT_INIT };
int unknown_type = 0;
 
const struct option options[] = {

--
https://github.com/git/git/pull/452


[PATCH RFC v2 17/25] ref-filter: make cat_file_info independent

2018-02-05 Thread Olga Telezhnaya
Remove connection between expand_data variable
in cat-file and in ref-filter.
It will help further to get rid of using expand_data in cat-file.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c |  2 +-
 ref-filter.c   | 29 +++--
 ref-filter.h   |  1 -
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 37adf626d0e55..5b9869cdb9096 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -292,6 +292,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
if (populate_value())
return;
 
+   data->type = item.type;
strbuf_expand(, opt->format.format, expand_format, );
strbuf_addch(, '\n');
batch_write(opt, buf.buf, buf.len);
@@ -393,7 +394,6 @@ static int batch_objects(struct batch_options *opt)
 * object.
 */
memset(, 0, sizeof(data));
-   opt->format.cat_file_data = 
opt->format.is_cat = 1;
opt->format.all_objects = opt->all_objects;
verify_ref_format(>format);
diff --git a/ref-filter.c b/ref-filter.c
index 7dcd36cd2cddc..a65a90790fd2c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -100,7 +100,7 @@ static struct used_atom {
} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
-struct expand_data *cat_file_info;
+struct expand_data cat_file_info;
 static int is_cat = 0;
 
 static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
@@ -256,9 +256,9 @@ static void objectname_atom_parser(const struct ref_format 
*format, struct used_
 static void objectsize_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.sizep = _file_info->size;
+   cat_file_info.info.sizep = _file_info.size;
else if (!strcmp(arg, "disk"))
-   cat_file_info->info.disk_sizep = _file_info->disk_size;
+   cat_file_info.info.disk_sizep = _file_info.disk_size;
else
die(_("urecognized %%(objectsize) argument: %s"), arg);
 }
@@ -266,7 +266,7 @@ static void objectsize_atom_parser(const struct ref_format 
*format, struct used_
 static void objecttype_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.typep = _file_info->type;
+   cat_file_info.info.typep = _file_info.type;
else
die(_("urecognized %%(objecttype) argument: %s"), arg);
 }
@@ -274,7 +274,7 @@ static void objecttype_atom_parser(const struct ref_format 
*format, struct used_
 static void deltabase_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *arg)
 {
if (!arg)
-   cat_file_info->info.delta_base_sha1 = 
cat_file_info->delta_base_oid.hash;
+   cat_file_info.info.delta_base_sha1 = 
cat_file_info.delta_base_oid.hash;
else
die(_("urecognized %%(deltabase) argument: %s"), arg);
 }
@@ -752,7 +752,6 @@ int verify_ref_format(struct ref_format *format)
 {
const char *cp, *sp;
 
-   cat_file_info = format->cat_file_data;
is_cat = format->is_cat;
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
@@ -779,8 +778,8 @@ int verify_ref_format(struct ref_format *format)
format->need_color_reset_at_eol = 0;
if (is_cat && format->all_objects) {
struct object_info empty = OBJECT_INFO_INIT;
-   if (!memcmp(_file_info->info, , sizeof(empty)))
-   cat_file_info->skip_object_info = 1;
+   if (!memcmp(_file_info.info, , sizeof(empty)))
+   cat_file_info.skip_object_info = 1;
}
return 0;
 }
@@ -1422,18 +1421,20 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
 
 static int check_and_fill_for_cat(struct ref_array_item *ref)
 {
-   if (!cat_file_info->skip_object_info &&
-   sha1_object_info_extended(ref->oid.hash, _file_info->info,
+   if (!cat_file_info.info.typep)
+   cat_file_info.info.typep = _file_info.type;
+   if (!cat_file_info.skip_object_info &&
+   sha1_object_info_extended(ref->oid.hash, _file_info.info,
  OBJECT_INFO_LOOKUP_REPLACE) < 0) {
const char *e = ref->objectname;
printf("%s missing\n", e ? e : oid_to_hex(>oid));
fflush(stdout);
return -1;
}
-   ref->type = cat_file_info->type;
-   ref->size = cat_file_info->size;
-   ref->disk_size = cat_file_info->disk_size;
-   ref->delta_base_oid = 

[PATCH RFC v2 14/25] ref-filter: add is_cat flag

2018-02-05 Thread Olga Telezhnaya
Add is_cat flag, further it helps to get rid of cat_file_data field
in ref_format.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 1 +
 ref-filter.c   | 8 +---
 ref-filter.h   | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 179c955b86bd5..e8e788f41b890 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -395,6 +395,7 @@ static int batch_objects(struct batch_options *opt)
 */
memset(, 0, sizeof(data));
opt->format.cat_file_data = 
+   opt->format.is_cat = 1;
verify_ref_format(>format);
if (opt->cmdmode)
data.split_on_whitespace = 1;
diff --git a/ref-filter.c b/ref-filter.c
index 34a54db168265..91290b62450b3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -101,6 +101,7 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
 struct expand_data *cat_file_info;
+static int is_cat = 0;
 
 static void color_atom_parser(const struct ref_format *format, struct 
used_atom *atom, const char *color_value)
 {
@@ -493,7 +494,7 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   if (cat_file_info && !strcmp(valid_atom[i].name, "rest"))
+   if (is_cat && !strcmp(valid_atom[i].name, "rest"))
cat_file_info->split_on_whitespace = 1;
return at;
 }
@@ -739,6 +740,7 @@ int verify_ref_format(struct ref_format *format)
const char *cp, *sp;
 
cat_file_info = format->cat_file_data;
+   is_cat = format->is_cat;
format->need_color_reset_at_eol = 0;
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
const char *color, *ep = strchr(sp, ')');
@@ -748,7 +750,7 @@ int verify_ref_format(struct ref_format *format)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
 
-   if (format->cat_file_data)
+   if (is_cat)
at = parse_ref_filter_atom(format, valid_cat_file_atom,
   
ARRAY_SIZE(valid_cat_file_atom), sp + 2, ep);
else {
@@ -1438,7 +1440,7 @@ int populate_value(struct ref_array_item *ref)
ref->symref = "";
}
 
-   if (cat_file_info && check_and_fill_for_cat(ref))
+   if (is_cat && check_and_fill_for_cat(ref))
return -1;
 
/* Fill in specials first */
diff --git a/ref-filter.h b/ref-filter.h
index 5c6e019998716..69271e8c39f40 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -125,6 +125,7 @@ struct ref_format {
 * hopefully would be reduced later.
 */
struct expand_data *cat_file_data;
+   int is_cat;
 };
 
 #define REF_FORMAT_INIT { NULL, 0, -1 }

--
https://github.com/git/git/pull/452


[PATCH RFC v2 09/25] cat-file: start use ref_array_item struct

2018-02-05 Thread Olga Telezhnaya
Moving from using expand_data to ref_array_item structure.
That helps us to reuse functions from ref-filter easier.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 32 
 ref-filter.h   |  5 +
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 909412747cbd2..61b7acc79155d 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -183,27 +183,27 @@ static int is_atom(const char *atom, const char *s, int 
slen)
 }
 
 static void expand_atom(struct strbuf *sb, const char *atom, int len,
-struct expand_data *data)
+struct ref_array_item *item)
 {
if (is_atom("objectname", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>oid));
+   strbuf_addstr(sb, oid_to_hex(>objectname));
else if (is_atom("objecttype", atom, len))
-   strbuf_addstr(sb, typename(data->type));
+   strbuf_addstr(sb, typename(item->type));
else if (is_atom("objectsize", atom, len))
-   strbuf_addf(sb, "%lu", data->size);
+   strbuf_addf(sb, "%lu", item->size);
else if (is_atom("objectsize:disk", atom, len))
-   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
+   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)item->disk_size);
else if (is_atom("rest", atom, len)) {
-   if (data->rest)
-   strbuf_addstr(sb, data->rest);
+   if (item->rest)
+   strbuf_addstr(sb, item->rest);
} else if (is_atom("deltabase", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>delta_base_oid));
+   strbuf_addstr(sb, oid_to_hex(item->delta_base_oid));
 }
 
-static size_t expand_format(struct strbuf *sb, const char *start, void *vdata)
+static size_t expand_format(struct strbuf *sb, const char *start, void *data)
 {
const char *end;
-   struct expand_data *data = vdata;
+   struct ref_array_item *item = data;
 
if (*start != '(')
return 0;
@@ -211,7 +211,7 @@ static size_t expand_format(struct strbuf *sb, const char 
*start, void *vdata)
if (!end)
die("format element '%s' does not end in ')'", start);
 
-   expand_atom(sb, start + 1, end - start - 1, data);
+   expand_atom(sb, start + 1, end - start - 1, item);
return end - start + 1;
 }
 
@@ -283,6 +283,7 @@ static void batch_object_write(const char *obj_name, struct 
batch_options *opt,
   struct expand_data *data)
 {
struct strbuf buf = STRBUF_INIT;
+   struct ref_array_item item = {0};
 
if (!data->skip_object_info &&
sha1_object_info_extended(data->oid.hash, >info,
@@ -293,7 +294,14 @@ static void batch_object_write(const char *obj_name, 
struct batch_options *opt,
return;
}
 
-   strbuf_expand(, opt->format.format, expand_format, data);
+   item.objectname = data->oid;
+   item.type = data->type;
+   item.size = data->size;
+   item.disk_size = data->disk_size;
+   item.rest = data->rest;
+   item.delta_base_oid = >delta_base_oid;
+
+   strbuf_expand(, opt->format.format, expand_format, );
strbuf_addch(, '\n');
batch_write(opt, buf.buf, buf.len);
strbuf_release();
diff --git a/ref-filter.h b/ref-filter.h
index 52e07dbe6864a..781921d4e0978 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -40,6 +40,11 @@ struct ref_array_item {
const char *symref;
struct commit *commit;
struct atom_value *value;
+   enum object_type type;
+   unsigned long size;
+   off_t disk_size;
+   const char *rest;
+   struct object_id *delta_base_oid;
char refname[FLEX_ARRAY];
 };
 

--
https://github.com/git/git/pull/452


[PATCH RFC v2 23/25] for-each-ref: tests for new atoms added

2018-02-05 Thread Olga Telezhnaya
Add tests for new formatting atoms: rest, deltabase, objectsize:disk.
rest means nothing and we expand it into empty string.
We need this atom for cat-file command.
Have plans to support deltabase and objectsize:disk further
(as it is done in cat-file), now also expand it to empty string.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 t/t6300-for-each-ref.sh | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index c128dfc579079..eee656a6abba9 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -316,6 +316,24 @@ test_expect_success 'exercise strftime with odd fields' '
test_cmp expected actual
 '
 
+test_expect_success 'Check format %(objectsize:disk) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(objectsize:disk)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
+test_expect_success 'Check format %(rest) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(rest)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
+test_expect_success 'Check format %(deltabase) gives empty output ' '
+   echo >expected &&
+   git for-each-ref --format="%(deltabase)" refs/heads >actual &&
+   test_cmp expected actual
+'
+
 cat >expected <<\EOF
 refs/heads/master
 refs/remotes/origin/master

--
https://github.com/git/git/pull/452


[PATCH RFC v2 07/25] cat-file: start migrating formatting to ref-filter

2018-02-05 Thread Olga Telezhnaya
Move mark_atom_in_object_info() from cat-file to ref-filter and
start using it in verify_ref_format().
It also means that we start reusing verify_ref_format() in cat-file.

Start from simple moving of mark_atom_in_object_info(),
it would be removed later by integrating all needed processes into
ref-filter logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 30 +++---
 ref-filter.c   | 41 -
 ref-filter.h   | 12 ++--
 3 files changed, 45 insertions(+), 38 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index edb04a96d9bd3..909412747cbd2 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -182,25 +182,6 @@ static int is_atom(const char *atom, const char *s, int 
slen)
return alen == slen && !memcmp(atom, s, alen);
 }
 
-static void mark_atom_in_object_info(const char *atom, int len,
-struct expand_data *data)
-{
-   if (is_atom("objectname", atom, len))
-   ; /* do nothing */
-   else if (is_atom("objecttype", atom, len))
-   data->info.typep = >type;
-   else if (is_atom("objectsize", atom, len))
-   data->info.sizep = >size;
-   else if (is_atom("objectsize:disk", atom, len))
-   data->info.disk_sizep = >disk_size;
-   else if (is_atom("rest", atom, len))
-   data->split_on_whitespace = 1;
-   else if (is_atom("deltabase", atom, len))
-   data->info.delta_base_sha1 = data->delta_base_oid.hash;
-   else
-   die("unknown format element: %.*s", len, atom);
-}
-
 static void expand_atom(struct strbuf *sb, const char *atom, int len,
 struct expand_data *data)
 {
@@ -230,11 +211,7 @@ static size_t expand_format(struct strbuf *sb, const char 
*start, void *vdata)
if (!end)
die("format element '%s' does not end in ')'", start);
 
-   if (data->mark_query)
-   mark_atom_in_object_info(start + 1, end - start - 1, data);
-   else
-   expand_atom(sb, start + 1, end - start - 1, data);
-
+   expand_atom(sb, start + 1, end - start - 1, data);
return end - start + 1;
 }
 
@@ -418,9 +395,8 @@ static int batch_objects(struct batch_options *opt)
 * object.
 */
memset(, 0, sizeof(data));
-   data.mark_query = 1;
-   strbuf_expand(, opt->format.format, expand_format, );
-   data.mark_query = 0;
+   opt->format.cat_file_data = 
+   verify_ref_format(>format);
if (opt->cmdmode)
data.split_on_whitespace = 1;
 
diff --git a/ref-filter.c b/ref-filter.c
index 5e7ed0f338490..ff87e632f463c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -392,6 +392,31 @@ struct atom_value {
struct used_atom *atom;
 };
 
+static int is_atom(const char *atom, const char *s, int slen)
+{
+   int alen = strlen(atom);
+   return alen == slen && !memcmp(atom, s, alen);
+}
+
+static void mark_atom_in_object_info(const char *atom, int len,
+   struct expand_data *data)
+{
+   if (is_atom("objectname", atom, len))
+   ; /* do nothing */
+   else if (is_atom("objecttype", atom, len))
+   data->info.typep = >type;
+   else if (is_atom("objectsize", atom, len))
+   data->info.sizep = >size;
+   else if (is_atom("objectsize:disk", atom, len))
+   data->info.disk_sizep = >disk_size;
+   else if (is_atom("rest", atom, len))
+   data->split_on_whitespace = 1;
+   else if (is_atom("deltabase", atom, len))
+   data->info.delta_base_sha1 = data->delta_base_oid.hash;
+   else
+   die("unknown format element: %.*s", len, atom);
+}
+
 /*
  * Used to parse format string and sort specifiers
  */
@@ -709,12 +734,18 @@ int verify_ref_format(struct ref_format *format)
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, valid_atom,
-  ARRAY_SIZE(valid_atom), sp + 2, ep);
-   cp = ep + 1;
 
-   if (skip_prefix(used_atom[at].name, "color:", ))
-   format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
+   if (format->cat_file_data)
+   mark_atom_in_object_info(sp + 2, ep - sp - 2,
+   format->cat_file_data);
+   else {
+   at = parse_ref_filter_atom(format, valid_atom,
+  ARRAY_SIZE(valid_atom), sp + 
2, ep);
+   if 

[PATCH RFC v2 21/25] ref-filter: unifying formatting of cat-file opts

2018-02-05 Thread Olga Telezhnaya
cat-file options are now filled by general logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 31 ++-
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 70c685851466b..aa15dd0b4723e 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -825,8 +825,10 @@ static void grab_common_values(struct atom_value *val, int 
deref, struct object
else if (!strcmp(name, "objectsize")) {
v->value = sz;
v->s = xstrfmt("%lu", sz);
-   }
-   else if (deref)
+   } else if (!strcmp(name, "objectsize:disk")) {
+   v->value = cat_file_info.disk_size;
+   v->s = xstrfmt("%"PRIuMAX, (uintmax_t)v->value);
+   } else if (deref)
grab_objectname(name, obj->oid.hash, v, _atom[i]);
}
 }
@@ -1466,21 +1468,7 @@ static int populate_value(struct ref_array_item *ref)
name++;
}
 
-   if (is_cat) {
-   if (starts_with(name, "objectname"))
-   v->s = oid_to_hex(>oid);
-   else if (starts_with(name, "objecttype"))
-   v->s = typename(ref->type);
-   else if (starts_with(name, "objectsize")) {
-   v->s = xstrfmt("%lu", ref->size);
-   } else if (starts_with(name, "objectsize:disk")) {
-   v->s = xstrfmt("%"PRIuMAX, 
(uintmax_t)ref->disk_size);
-   } else if (starts_with(name, "rest"))
-   v->s = ref->rest;
-   else if (starts_with(name, "deltabase"))
-   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
-   continue;
-   } else if (starts_with(name, "refname"))
+   if (starts_with(name, "refname"))
refname = get_refname(atom, ref);
else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
@@ -1536,6 +1524,15 @@ static int populate_value(struct ref_array_item *ref)
else
v->s = " ";
continue;
+   } else if (starts_with(name, "rest")) {
+   v->s = ref->rest ? ref->rest : "";
+   continue;
+   } else if (starts_with(name, "deltabase")) {
+   if (ref->delta_base_oid)
+   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
+   else
+   v->s = "";
+   continue;
} else if (starts_with(name, "align")) {
v->handler = align_atom_handler;
continue;

--
https://github.com/git/git/pull/452


[PATCH RFC v2 20/25] ref-filter: make populate_value() internal again

2018-02-05 Thread Olga Telezhnaya
Remove populate_value() from header file. We needed that
for interim step, now it could be returned back.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 2 +-
 ref-filter.h | 3 ---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index e34580e8db508..70c685851466b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1429,7 +1429,7 @@ static int check_and_fill_for_cat(struct ref_array_item 
*ref)
  * Parse the object referred by ref, and grab needed value.
  * Return 0 if everything was successful, -1 otherwise.
  */
-int populate_value(struct ref_array_item *ref)
+static int populate_value(struct ref_array_item *ref)
 {
void *buf;
struct object *obj;
diff --git a/ref-filter.h b/ref-filter.h
index 244a27bfc4e12..c0edb17aa404a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -177,9 +177,6 @@ void setup_ref_filter_porcelain_msg(void);
 void pretty_print_ref(const char *name, const unsigned char *sha1,
  const struct ref_format *format);
 
-/* Fill the values of request and prepare all data for final string creation */
-int populate_value(struct ref_array_item *ref);
-
 /* Search for atom in given format. */
 int is_atom_used(const struct ref_format *format, const char *atom);
 

--
https://github.com/git/git/pull/452


[PATCH RFC v2 04/25] ref-filter: make valid_atom as function parameter

2018-02-05 Thread Olga Telezhnaya
Make valid_atom as a function parameter,
there could be another variable further.
Need that for further reusing of formatting logic in cat-file.c.

We do not need to allow users to pass their own valid_atom variable in
global functions like verify_ref_format() because in the end we want to
have same set of valid atoms for all commands. But, as a first step
of migrating, I create further another version of valid_atom
for cat-file.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 9ed5e66066a7a..5e7ed0f338490 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -325,7 +325,7 @@ static void head_atom_parser(const struct ref_format 
*format, struct used_atom *
atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 }
 
-static struct {
+static struct valid_atom {
const char *name;
cmp_type cmp_type;
void (*parser)(const struct ref_format *format, struct used_atom *atom, 
const char *arg);
@@ -396,6 +396,7 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
+const struct valid_atom *valid_atom, int 
n_atoms,
 const char *atom, const char *ep)
 {
const char *sp;
@@ -425,13 +426,13 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
atom_len = (arg ? arg : ep) - sp;
 
/* Is the atom a valid one? */
-   for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
+   for (i = 0; i < n_atoms; i++) {
int len = strlen(valid_atom[i].name);
if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
break;
}
 
-   if (ARRAY_SIZE(valid_atom) <= i)
+   if (n_atoms <= i)
die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
@@ -708,7 +709,8 @@ int verify_ref_format(struct ref_format *format)
if (!ep)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
-   at = parse_ref_filter_atom(format, sp + 2, ep);
+   at = parse_ref_filter_atom(format, valid_atom,
+  ARRAY_SIZE(valid_atom), sp + 2, ep);
cp = ep + 1;
 
if (skip_prefix(used_atom[at].name, "color:", ))
@@ -2145,7 +2147,9 @@ int format_ref_array_item(struct ref_array_item *info,
if (cp < sp)
append_literal(cp, sp, );
if (get_ref_atom_value(info,
-  parse_ref_filter_atom(format, sp + 2, 
ep),
+  parse_ref_filter_atom(format, valid_atom,
+
ARRAY_SIZE(valid_atom),
+sp + 2, ep),
   ))
return -1;
atomv->handler(atomv, );
@@ -2198,7 +2202,8 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, atom, end);
+   return parse_ref_filter_atom(, valid_atom,
+ARRAY_SIZE(valid_atom), atom, end);
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/452


[PATCH RFC v2 15/25] ref_filter: add is_atom_used function

2018-02-05 Thread Olga Telezhnaya
Delete all items related to split_on_whitespace from ref-filter
and add new function for handling the logic.
Now cat-file could invoke that function to implementing its logic.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c |  8 +++-
 ref-filter.c   | 17 +++--
 ref-filter.h   | 10 +++---
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index e8e788f41b890..a55138f1fd1d1 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -382,8 +382,7 @@ static int batch_objects(struct batch_options *opt)
 {
struct strbuf buf = STRBUF_INIT;
struct expand_data data;
-   int save_warning;
-   int retval = 0;
+   int save_warning, is_rest, retval = 0;
 
if (!opt->format.format)
opt->format.format = "%(objectname) %(objecttype) 
%(objectsize)";
@@ -397,8 +396,6 @@ static int batch_objects(struct batch_options *opt)
opt->format.cat_file_data = 
opt->format.is_cat = 1;
verify_ref_format(>format);
-   if (opt->cmdmode)
-   data.split_on_whitespace = 1;
 
if (opt->all_objects) {
struct object_info empty = OBJECT_INFO_INIT;
@@ -437,9 +434,10 @@ static int batch_objects(struct batch_options *opt)
 */
save_warning = warn_on_object_refname_ambiguity;
warn_on_object_refname_ambiguity = 0;
+   is_rest = opt->cmdmode || is_atom_used(>format, "rest");
 
while (strbuf_getline(, stdin) != EOF) {
-   if (data.split_on_whitespace) {
+   if (is_rest) {
/*
 * Split at first whitespace, tying off the beginning
 * of the string and saving the remainder (or NULL) in
diff --git a/ref-filter.c b/ref-filter.c
index 91290b62450b3..bbcd507d179a9 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -494,8 +494,6 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
need_tagged = 1;
if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
-   if (is_cat && !strcmp(valid_atom[i].name, "rest"))
-   cat_file_info->split_on_whitespace = 1;
return at;
 }
 
@@ -731,6 +729,21 @@ static const char *find_next(const char *cp)
return NULL;
 }
 
+/* Search for atom in given format. */
+int is_atom_used(const struct ref_format *format, const char *atom)
+{
+   const char *cp, *sp;
+   for (cp = format->format; *cp && (sp = find_next(cp)); ) {
+   const char *ep = strchr(sp, ')');
+   int atom_len = ep - sp - 2;
+   sp += 2;
+   if (atom_len == strlen(atom) && !memcmp(sp, atom, atom_len))
+   return 1;
+   cp = ep + 1;
+   }
+   return 0;
+}
+
 /*
  * Make sure the format string is well formed, and parse out
  * the used atoms.
diff --git a/ref-filter.h b/ref-filter.h
index 69271e8c39f40..f590e5d694df4 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -86,13 +86,6 @@ struct expand_data {
const char *rest;
struct object_id delta_base_oid;
 
-   /*
-* Whether to split the input on whitespace before feeding it to
-* get_sha1; this is decided during the mark_query phase based on
-* whether we have a %(rest) token in our format.
-*/
-   int split_on_whitespace;
-
/*
 * After a mark_query run, this object_info is set up to be
 * passed to sha1_object_info_extended. It will point to the data
@@ -187,4 +180,7 @@ void pretty_print_ref(const char *name, const unsigned char 
*sha1,
 /* Fill the values of request and prepare all data for final string creation */
 int populate_value(struct ref_array_item *ref);
 
+/* Search for atom in given format. */
+int is_atom_used(const struct ref_format *format, const char *atom);
+
 #endif /*  REF_FILTER_H  */

--
https://github.com/git/git/pull/452


[PATCH RFC v2 19/25] cat-file: reuse printing logic from ref-filter

2018-02-05 Thread Olga Telezhnaya
Reuse code from ref-filter to print resulting message.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 builtin/cat-file.c | 51 ---
 ref-filter.c   | 21 +++--
 2 files changed, 23 insertions(+), 49 deletions(-)

diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 5b9869cdb9096..746b02ff150a7 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -176,45 +176,6 @@ static int cat_one_file(int opt, const char *exp_type, 
const char *obj_name,
return 0;
 }
 
-static int is_atom(const char *atom, const char *s, int slen)
-{
-   int alen = strlen(atom);
-   return alen == slen && !memcmp(atom, s, alen);
-}
-
-static void expand_atom(struct strbuf *sb, const char *atom, int len,
-struct ref_array_item *item)
-{
-   if (is_atom("objectname", atom, len))
-   strbuf_addstr(sb, oid_to_hex(>oid));
-   else if (is_atom("objecttype", atom, len))
-   strbuf_addstr(sb, typename(item->type));
-   else if (is_atom("objectsize", atom, len))
-   strbuf_addf(sb, "%lu", item->size);
-   else if (is_atom("objectsize:disk", atom, len))
-   strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)item->disk_size);
-   else if (is_atom("rest", atom, len)) {
-   if (item->rest)
-   strbuf_addstr(sb, item->rest);
-   } else if (is_atom("deltabase", atom, len))
-   strbuf_addstr(sb, oid_to_hex(item->delta_base_oid));
-}
-
-static size_t expand_format(struct strbuf *sb, const char *start, void *data)
-{
-   const char *end;
-   struct ref_array_item *item = data;
-
-   if (*start != '(')
-   return 0;
-   end = strchr(start + 1, ')');
-   if (!end)
-   die("format element '%s' does not end in ')'", start);
-
-   expand_atom(sb, start + 1, end - start - 1, item);
-   return end - start + 1;
-}
-
 static void batch_write(struct batch_options *opt, const void *data, int len)
 {
if (opt->buffer_output) {
@@ -282,23 +243,19 @@ static void print_object_or_die(struct batch_options 
*opt, struct expand_data *d
 static void batch_object_write(const char *obj_name, struct batch_options *opt,
   struct expand_data *data)
 {
-   struct strbuf buf = STRBUF_INIT;
struct ref_array_item item = {0};
 
item.oid = data->oid;
item.rest = data->rest;
item.objectname = obj_name;
 
-   if (populate_value())
+   if (show_ref_array_item(, >format))
return;
-
-   data->type = item.type;
-   strbuf_expand(, opt->format.format, expand_format, );
-   strbuf_addch(, '\n');
-   batch_write(opt, buf.buf, buf.len);
-   strbuf_release();
+   if (!opt->buffer_output)
+   fflush(stdout);
 
if (opt->print_contents) {
+   data->type = item.type;
print_object_or_die(opt, data);
batch_write(opt, "\n", 1);
}
diff --git a/ref-filter.c b/ref-filter.c
index 3f3583ac515a5..e34580e8db508 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1466,7 +1466,21 @@ int populate_value(struct ref_array_item *ref)
name++;
}
 
-   if (starts_with(name, "refname"))
+   if (is_cat) {
+   if (starts_with(name, "objectname"))
+   v->s = oid_to_hex(>oid);
+   else if (starts_with(name, "objecttype"))
+   v->s = typename(ref->type);
+   else if (starts_with(name, "objectsize")) {
+   v->s = xstrfmt("%lu", ref->size);
+   } else if (starts_with(name, "objectsize:disk")) {
+   v->s = xstrfmt("%"PRIuMAX, 
(uintmax_t)ref->disk_size);
+   } else if (starts_with(name, "rest"))
+   v->s = ref->rest;
+   else if (starts_with(name, "deltabase"))
+   v->s = xstrdup(oid_to_hex(ref->delta_base_oid));
+   continue;
+   } else if (starts_with(name, "refname"))
refname = get_refname(atom, ref);
else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
@@ -2208,6 +,7 @@ int format_ref_array_item(struct ref_array_item *info,
 {
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
+   int retval = 0;
 
state.quote_style = format->quote_style;
push_stack_element();
@@ -2224,6 +2239,8 @@ int format_ref_array_item(struct ref_array_item *info,
return -1;
atomv->handler(atomv, );
}
+   

[PATCH RFC v2 18/25] ref-filter: make valid_atom general again

2018-02-05 Thread Olga Telezhnaya
Stop using valid_cat_file_atom, making the code more general.
Further commits will contain some tests, docs and
support of new features.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 34 +-
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index a65a90790fd2c..3f3583ac515a5 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -359,8 +359,8 @@ static struct valid_atom {
void (*parser)(const struct ref_format *format, struct used_atom *atom, 
const char *arg);
 } valid_atom[] = {
{ "refname" , FIELD_STR, refname_atom_parser },
-   { "objecttype" },
-   { "objectsize", FIELD_ULONG },
+   { "objecttype", FIELD_STR, objecttype_atom_parser },
+   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "objectname", FIELD_STR, objectname_atom_parser },
{ "tree" },
{ "parent" },
@@ -397,12 +397,6 @@ static struct valid_atom {
{ "if", FIELD_STR, if_atom_parser },
{ "then" },
{ "else" },
-};
-
-static struct valid_atom valid_cat_file_atom[] = {
-   { "objectname" },
-   { "objecttype", FIELD_STR, objecttype_atom_parser },
-   { "objectsize", FIELD_ULONG, objectsize_atom_parser },
{ "rest" },
{ "deltabase", FIELD_STR, deltabase_atom_parser },
 };
@@ -432,7 +426,6 @@ struct atom_value {
  * Used to parse format string and sort specifiers
  */
 static int parse_ref_filter_atom(const struct ref_format *format,
-const struct valid_atom *valid_atom, int 
n_atoms,
 const char *atom, const char *ep)
 {
const char *sp;
@@ -462,13 +455,13 @@ static int parse_ref_filter_atom(const struct ref_format 
*format,
atom_len = (arg ? arg : ep) - sp;
 
/* Is the atom a valid one? */
-   for (i = 0; i < n_atoms; i++) {
+   for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
int len = strlen(valid_atom[i].name);
if (len == atom_len && !memcmp(valid_atom[i].name, sp, len))
break;
}
 
-   if (n_atoms <= i)
+   if (ARRAY_SIZE(valid_atom) <= i)
die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
 
/* Add it in, including the deref prefix */
@@ -762,15 +755,9 @@ int verify_ref_format(struct ref_format *format)
return error(_("malformed format string %s"), sp);
/* sp points at "%(" and ep points at the closing ")" */
 
-   if (is_cat)
-   at = parse_ref_filter_atom(format, valid_cat_file_atom,
-  
ARRAY_SIZE(valid_cat_file_atom), sp + 2, ep);
-   else {
-   at = parse_ref_filter_atom(format, valid_atom,
-  ARRAY_SIZE(valid_atom), sp + 
2, ep);
-   if (skip_prefix(used_atom[at].name, "color:", ))
-   format->need_color_reset_at_eol = 
!!strcmp(color, "reset");
-   }
+   at = parse_ref_filter_atom(format, sp + 2, ep);
+   if (skip_prefix(used_atom[at].name, "color:", ))
+   format->need_color_reset_at_eol = !!strcmp(color, 
"reset");
 
cp = ep + 1;
}
@@ -2232,9 +2219,7 @@ int format_ref_array_item(struct ref_array_item *info,
if (cp < sp)
append_literal(cp, sp, );
if (get_ref_atom_value(info,
-  parse_ref_filter_atom(format, valid_atom,
-
ARRAY_SIZE(valid_atom),
-sp + 2, ep),
+  parse_ref_filter_atom(format, sp + 2, 
ep),
   ))
return -1;
atomv->handler(atomv, );
@@ -2287,8 +2272,7 @@ static int parse_sorting_atom(const char *atom)
 */
struct ref_format dummy = REF_FORMAT_INIT;
const char *end = atom + strlen(atom);
-   return parse_ref_filter_atom(, valid_atom,
-ARRAY_SIZE(valid_atom), atom, end);
+   return parse_ref_filter_atom(, atom, end);
 }
 
 /*  If no sorting option is given, use refname to sort as default */

--
https://github.com/git/git/pull/452


[PATCH RFC v2 25/25] cat-file: update of docs

2018-02-05 Thread Olga Telezhnaya
Update the docs for cat-file command. Some new formatting atoms added
because of reusing ref-filter code.
We do not support cat-file atoms in general formatting logic
(there is just the support for cat-file), that is why some of the atoms
are still explained in cat-file docs.
We need to move these explanations when atoms will be supported
by other commands.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 Documentation/git-cat-file.txt | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index f90f09b03fae5..90639ac21d0e8 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -187,17 +187,8 @@ linkgit:git-rev-parse[1].
 You can specify the information shown for each object by using a custom
 ``. The `` is copied literally to stdout for each
 object, with placeholders of the form `%(atom)` expanded, followed by a
-newline. The available atoms are:
-
-`objectname`::
-   The 40-hex object name of the object.
-
-`objecttype`::
-   The type of the object (the same as `cat-file -t` reports).
-
-`objectsize`::
-   The size, in bytes, of the object (the same as `cat-file -s`
-   reports).
+newline. The available atoms are the same as that of
+linkgit:git-for-each-ref[1], but there are some additional ones:
 
 `objectsize:disk`::
The size, in bytes, that the object takes up on disk. See the

--
https://github.com/git/git/pull/452


[PATCH RFC v2 10/25] ref-filter: make populate_value() global

2018-02-05 Thread Olga Telezhnaya
Make function global for further using in cat-file.
In the end of patch series this function becomes internal again,
so this is a part of middle step. cat-file would use more general
functions further.

Signed-off-by: Olga Telezhnaia 
Mentored-by: Christian Couder 
Mentored by: Jeff King 
---
 ref-filter.c | 2 +-
 ref-filter.h | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 5c75259b1ab8c..4acd391b5dfac 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1407,7 +1407,7 @@ static const char *get_refname(struct used_atom *atom, 
struct ref_array_item *re
  * Parse the object referred by ref, and grab needed value.
  * Return 0 if everything was successful, -1 otherwise.
  */
-static int populate_value(struct ref_array_item *ref)
+int populate_value(struct ref_array_item *ref)
 {
void *buf;
struct object *obj;
diff --git a/ref-filter.h b/ref-filter.h
index 781921d4e0978..e16ea2a990119 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -182,4 +182,7 @@ void setup_ref_filter_porcelain_msg(void);
 void pretty_print_ref(const char *name, const unsigned char *sha1,
  const struct ref_format *format);
 
+/* Fill the values of request and prepare all data for final string creation */
+int populate_value(struct ref_array_item *ref);
+
 #endif /*  REF_FILTER_H  */

--
https://github.com/git/git/pull/452


  1   2   >