ref-filter: truncate atom names in error messages

If you pass a bogus argument to %(refname), you may end up with a message like this: $ git for-each-ref --format='%(refname:foo)' fatal: unrecognized %(refname:foo) argument: foo which is confusing. It should just say: fatal: unrecognized %(refname) argument: foo which is clearer, and is consistent with most other atom parsers. Those other parsers do not have the same problem because they pass the atom name from a string literal in the parser function. But because the parser for %(refname) also handles %(upstream) and %(push), it instead uses atom->name, which includes the arguments. The oid atom parser which handles %(tree), %(parent), etc suffers from the same problem. It seems like the cleanest fix would be for atom->name to be _just_ the name, since there's already a separate "args" field. But since that field is also used for other things, we can't change it easily (e.g., it's how we find things in the used_atoms array, and clearly %(refname) and %(refname:short) are not the same thing). Instead, we'll teach our error_bad_arg() function to stop at the first ":". This is a little hacky, as we're effectively re-parsing the name, but the format is simple enough to do this as a one-liner, and this localizes the change to the error-reporting code. We'll give the same treatment to err_no_arg(). None of its callers use this atom->name trick, but it's worth future-proofing it while we're here. Signed-off-by: Jeff King <peff@peff.net> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 14, 2022 at 11:23 UTC 1955ef10edf3c888dcb237728c81dd6e81df4960
2 files changed +14 -4
ref-filter.c
+8 -4
@@ -230,13 +230,17 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
230
231 static int err_no_arg(struct strbuf *sb, const char *name)
232 {
233 - strbuf_addf(sb, _("%%(%s) does not take arguments"), name);
233 + size_t namelen = strchrnul(name, ':') - name;
234 + strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
235 + (int)namelen, name);
236 return -1;
237 }
238
239 static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
240 {
239 - strbuf_addf(sb, _("unrecognized %%(%s) argument: %s"), name, arg);
241 + size_t namelen = strchrnul(name, ':') - name;
242 + strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
243 + (int)namelen, name, arg);
244 return -1;
245 }
246
@@ -274,7 +278,7 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
278 if (strtol_i(arg, 10, &atom->rstrip))
279 return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
280 } else
277 - return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
281 + return err_bad_arg(err, name, arg);
282 return 0;
283 }
284
@@ -471,7 +475,7 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
475 if (atom->u.oid.length < MINIMUM_ABBREV)
476 atom->u.oid.length = MINIMUM_ABBREV;
477 } else
474 - return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), atom->name, arg);
478 + return err_bad_arg(err, atom->name, arg);
479 return 0;
480 }
481
t/t6300-for-each-ref.sh
+6
@@ -1254,6 +1254,12 @@ test_expect_success 'subject atom rejects unknown arguments' '
1254 test_cmp expect err
1255 '
1256
1257 +test_expect_success 'refname atom rejects unknown arguments' '
1258 + test_must_fail git for-each-ref --format="%(refname:foo)" 2>err &&
1259 + echo "fatal: unrecognized %(refname) argument: foo" >expect &&
1260 + test_cmp expect err
1261 +'
1262 +
1263 test_expect_success 'trailer parsing not fooled by --- line' '
1264 git commit --allow-empty -F - <<-\EOF &&
1265 this is the subject