|
1 | 1 | #include "git-compat-util.h"
|
2 | 2 | #include "environment.h"
|
3 | 3 | #include "gettext.h"
|
| 4 | +#include "config.h" |
4 | 5 | #include "gpg-interface.h"
|
5 | 6 | #include "hex.h"
|
6 | 7 | #include "parse-options.h"
|
| 8 | +#include "run-command.h" |
7 | 9 | #include "refs.h"
|
8 | 10 | #include "wildmatch.h"
|
9 | 11 | #include "object-name.h"
|
@@ -145,6 +147,7 @@ enum atom_type {
|
145 | 147 | ATOM_TAGGERDATE,
|
146 | 148 | ATOM_CREATOR,
|
147 | 149 | ATOM_CREATORDATE,
|
| 150 | + ATOM_DESCRIBE, |
148 | 151 | ATOM_SUBJECT,
|
149 | 152 | ATOM_BODY,
|
150 | 153 | ATOM_TRAILERS,
|
@@ -219,6 +222,7 @@ static struct used_atom {
|
219 | 222 | enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
|
220 | 223 | S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
|
221 | 224 | } signature;
|
| 225 | + const char **describe_args; |
222 | 226 | struct refname_atom refname;
|
223 | 227 | char *head;
|
224 | 228 | } u;
|
@@ -255,6 +259,110 @@ static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
|
255 | 259 | return -1;
|
256 | 260 | }
|
257 | 261 |
|
| 262 | +/* |
| 263 | + * Parse option of name "candidate" in the option string "to_parse" of |
| 264 | + * the form |
| 265 | + * |
| 266 | + * "candidate1[=val1],candidate2[=val2],candidate3[=val3],..." |
| 267 | + * |
| 268 | + * The remaining part of "to_parse" is stored in "end" (if we are |
| 269 | + * parsing the last candidate, then this is NULL) and the value of |
| 270 | + * the candidate is stored in "valuestart" and its length in "valuelen", |
| 271 | + * that is the portion after "=". Since it is possible for a "candidate" |
| 272 | + * to not have a value, in such cases, "valuestart" is set to point to |
| 273 | + * NULL and "valuelen" to 0. |
| 274 | + * |
| 275 | + * The function returns 1 on success. It returns 0 if we don't find |
| 276 | + * "candidate" in "to_parse" or we find "candidate" but it is followed |
| 277 | + * by more chars (for example, "candidatefoo"), that is, we don't find |
| 278 | + * an exact match. |
| 279 | + * |
| 280 | + * This function only does the above for one "candidate" at a time. So |
| 281 | + * it has to be called each time trying to parse a "candidate" in the |
| 282 | + * option string "to_parse". |
| 283 | + */ |
| 284 | +static int match_atom_arg_value(const char *to_parse, const char *candidate, |
| 285 | + const char **end, const char **valuestart, |
| 286 | + size_t *valuelen) |
| 287 | +{ |
| 288 | + const char *atom; |
| 289 | + |
| 290 | + if (!skip_prefix(to_parse, candidate, &atom)) |
| 291 | + return 0; /* definitely not "candidate" */ |
| 292 | + |
| 293 | + if (*atom == '=') { |
| 294 | + /* we just saw "candidate=" */ |
| 295 | + *valuestart = atom + 1; |
| 296 | + atom = strchrnul(*valuestart, ','); |
| 297 | + *valuelen = atom - *valuestart; |
| 298 | + } else if (*atom != ',' && *atom != '\0') { |
| 299 | + /* key begins with "candidate" but has more chars */ |
| 300 | + return 0; |
| 301 | + } else { |
| 302 | + /* just "candidate" without "=val" */ |
| 303 | + *valuestart = NULL; |
| 304 | + *valuelen = 0; |
| 305 | + } |
| 306 | + |
| 307 | + /* atom points at either the ',' or NUL after this key[=val] */ |
| 308 | + if (*atom == ',') |
| 309 | + atom++; |
| 310 | + else if (*atom) |
| 311 | + BUG("Why is *atom not NULL yet?"); |
| 312 | + |
| 313 | + *end = atom; |
| 314 | + return 1; |
| 315 | +} |
| 316 | + |
| 317 | +/* |
| 318 | + * Parse boolean option of name "candidate" in the option list "to_parse" |
| 319 | + * of the form |
| 320 | + * |
| 321 | + * "candidate1[=bool1],candidate2[=bool2],candidate3[=bool3],..." |
| 322 | + * |
| 323 | + * The remaining part of "to_parse" is stored in "end" (if we are parsing |
| 324 | + * the last candidate, then this is NULL) and the value (if given) is |
| 325 | + * parsed and stored in "val", so "val" always points to either 0 or 1. |
| 326 | + * If the value is not given, then "val" is set to point to 1. |
| 327 | + * |
| 328 | + * The boolean value is parsed using "git_parse_maybe_bool()", so the |
| 329 | + * accepted values are |
| 330 | + * |
| 331 | + * to set true - "1", "yes", "true" |
| 332 | + * to set false - "0", "no", "false" |
| 333 | + * |
| 334 | + * This function returns 1 on success. It returns 0 when we don't find |
| 335 | + * an exact match for "candidate" or when the boolean value given is |
| 336 | + * not valid. |
| 337 | + */ |
| 338 | +static int match_atom_bool_arg(const char *to_parse, const char *candidate, |
| 339 | + const char **end, int *val) |
| 340 | +{ |
| 341 | + const char *argval; |
| 342 | + char *strval; |
| 343 | + size_t arglen; |
| 344 | + int v; |
| 345 | + |
| 346 | + if (!match_atom_arg_value(to_parse, candidate, end, &argval, &arglen)) |
| 347 | + return 0; |
| 348 | + |
| 349 | + if (!argval) { |
| 350 | + *val = 1; |
| 351 | + return 1; |
| 352 | + } |
| 353 | + |
| 354 | + strval = xstrndup(argval, arglen); |
| 355 | + v = git_parse_maybe_bool(strval); |
| 356 | + free(strval); |
| 357 | + |
| 358 | + if (v == -1) |
| 359 | + return 0; |
| 360 | + |
| 361 | + *val = v; |
| 362 | + |
| 363 | + return 1; |
| 364 | +} |
| 365 | + |
258 | 366 | static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
|
259 | 367 | const char *color_value, struct strbuf *err)
|
260 | 368 | {
|
@@ -495,6 +603,87 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
|
495 | 603 | return 0;
|
496 | 604 | }
|
497 | 605 |
|
| 606 | +static int describe_atom_option_parser(struct strvec *args, const char **arg, |
| 607 | + struct strbuf *err) |
| 608 | +{ |
| 609 | + const char *argval; |
| 610 | + size_t arglen = 0; |
| 611 | + int optval = 0; |
| 612 | + |
| 613 | + if (match_atom_bool_arg(*arg, "tags", arg, &optval)) { |
| 614 | + if (!optval) |
| 615 | + strvec_push(args, "--no-tags"); |
| 616 | + else |
| 617 | + strvec_push(args, "--tags"); |
| 618 | + return 1; |
| 619 | + } |
| 620 | + |
| 621 | + if (match_atom_arg_value(*arg, "abbrev", arg, &argval, &arglen)) { |
| 622 | + char *endptr; |
| 623 | + |
| 624 | + if (!arglen) |
| 625 | + return strbuf_addf_ret(err, -1, |
| 626 | + _("argument expected for %s"), |
| 627 | + "describe:abbrev"); |
| 628 | + if (strtol(argval, &endptr, 10) < 0) |
| 629 | + return strbuf_addf_ret(err, -1, |
| 630 | + _("positive value expected %s=%s"), |
| 631 | + "describe:abbrev", argval); |
| 632 | + if (endptr - argval != arglen) |
| 633 | + return strbuf_addf_ret(err, -1, |
| 634 | + _("cannot fully parse %s=%s"), |
| 635 | + "describe:abbrev", argval); |
| 636 | + |
| 637 | + strvec_pushf(args, "--abbrev=%.*s", (int)arglen, argval); |
| 638 | + return 1; |
| 639 | + } |
| 640 | + |
| 641 | + if (match_atom_arg_value(*arg, "match", arg, &argval, &arglen)) { |
| 642 | + if (!arglen) |
| 643 | + return strbuf_addf_ret(err, -1, |
| 644 | + _("value expected %s="), |
| 645 | + "describe:match"); |
| 646 | + |
| 647 | + strvec_pushf(args, "--match=%.*s", (int)arglen, argval); |
| 648 | + return 1; |
| 649 | + } |
| 650 | + |
| 651 | + if (match_atom_arg_value(*arg, "exclude", arg, &argval, &arglen)) { |
| 652 | + if (!arglen) |
| 653 | + return strbuf_addf_ret(err, -1, |
| 654 | + _("value expected %s="), |
| 655 | + "describe:exclude"); |
| 656 | + |
| 657 | + strvec_pushf(args, "--exclude=%.*s", (int)arglen, argval); |
| 658 | + return 1; |
| 659 | + } |
| 660 | + |
| 661 | + return 0; |
| 662 | +} |
| 663 | + |
| 664 | +static int describe_atom_parser(struct ref_format *format UNUSED, |
| 665 | + struct used_atom *atom, |
| 666 | + const char *arg, struct strbuf *err) |
| 667 | +{ |
| 668 | + struct strvec args = STRVEC_INIT; |
| 669 | + |
| 670 | + for (;;) { |
| 671 | + int found = 0; |
| 672 | + const char *bad_arg = arg; |
| 673 | + |
| 674 | + if (!arg || !*arg) |
| 675 | + break; |
| 676 | + |
| 677 | + found = describe_atom_option_parser(&args, &arg, err); |
| 678 | + if (found < 0) |
| 679 | + return found; |
| 680 | + if (!found) |
| 681 | + return err_bad_arg(err, "describe", bad_arg); |
| 682 | + } |
| 683 | + atom->u.describe_args = strvec_detach(&args); |
| 684 | + return 0; |
| 685 | +} |
| 686 | + |
498 | 687 | static int raw_atom_parser(struct ref_format *format UNUSED,
|
499 | 688 | struct used_atom *atom,
|
500 | 689 | const char *arg, struct strbuf *err)
|
@@ -697,6 +886,7 @@ static struct {
|
697 | 886 | [ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
|
698 | 887 | [ATOM_CREATOR] = { "creator", SOURCE_OBJ },
|
699 | 888 | [ATOM_CREATORDATE] = { "creatordate", SOURCE_OBJ, FIELD_TIME },
|
| 889 | + [ATOM_DESCRIBE] = { "describe", SOURCE_OBJ, FIELD_STR, describe_atom_parser }, |
700 | 890 | [ATOM_SUBJECT] = { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
|
701 | 891 | [ATOM_BODY] = { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
|
702 | 892 | [ATOM_TRAILERS] = { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
|
@@ -1603,6 +1793,44 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
|
1603 | 1793 | }
|
1604 | 1794 | }
|
1605 | 1795 |
|
| 1796 | +static void grab_describe_values(struct atom_value *val, int deref, |
| 1797 | + struct object *obj) |
| 1798 | +{ |
| 1799 | + struct commit *commit = (struct commit *)obj; |
| 1800 | + int i; |
| 1801 | + |
| 1802 | + for (i = 0; i < used_atom_cnt; i++) { |
| 1803 | + struct used_atom *atom = &used_atom[i]; |
| 1804 | + enum atom_type type = atom->atom_type; |
| 1805 | + const char *name = atom->name; |
| 1806 | + struct atom_value *v = &val[i]; |
| 1807 | + |
| 1808 | + struct child_process cmd = CHILD_PROCESS_INIT; |
| 1809 | + struct strbuf out = STRBUF_INIT; |
| 1810 | + struct strbuf err = STRBUF_INIT; |
| 1811 | + |
| 1812 | + if (type != ATOM_DESCRIBE) |
| 1813 | + continue; |
| 1814 | + |
| 1815 | + if (!!deref != (*name == '*')) |
| 1816 | + continue; |
| 1817 | + |
| 1818 | + cmd.git_cmd = 1; |
| 1819 | + strvec_push(&cmd.args, "describe"); |
| 1820 | + strvec_pushv(&cmd.args, atom->u.describe_args); |
| 1821 | + strvec_push(&cmd.args, oid_to_hex(&commit->object.oid)); |
| 1822 | + if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) { |
| 1823 | + error(_("failed to run 'describe'")); |
| 1824 | + v->s = xstrdup(""); |
| 1825 | + continue; |
| 1826 | + } |
| 1827 | + strbuf_rtrim(&out); |
| 1828 | + v->s = strbuf_detach(&out, NULL); |
| 1829 | + |
| 1830 | + strbuf_release(&err); |
| 1831 | + } |
| 1832 | +} |
| 1833 | + |
1606 | 1834 | /* See grab_values */
|
1607 | 1835 | static void grab_sub_body_contents(struct atom_value *val, int deref, struct expand_data *data)
|
1608 | 1836 | {
|
@@ -1712,13 +1940,15 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
|
1712 | 1940 | grab_tag_values(val, deref, obj);
|
1713 | 1941 | grab_sub_body_contents(val, deref, data);
|
1714 | 1942 | grab_person("tagger", val, deref, buf);
|
| 1943 | + grab_describe_values(val, deref, obj); |
1715 | 1944 | break;
|
1716 | 1945 | case OBJ_COMMIT:
|
1717 | 1946 | grab_commit_values(val, deref, obj);
|
1718 | 1947 | grab_sub_body_contents(val, deref, data);
|
1719 | 1948 | grab_person("author", val, deref, buf);
|
1720 | 1949 | grab_person("committer", val, deref, buf);
|
1721 | 1950 | grab_signature(val, deref, obj);
|
| 1951 | + grab_describe_values(val, deref, obj); |
1722 | 1952 | break;
|
1723 | 1953 | case OBJ_TREE:
|
1724 | 1954 | /* grab_tree_values(val, deref, obj, buf, sz); */
|
|
0 commit comments