Skip to content

Commit 5817da0

Browse files
MadCodergitster
authored andcommitted
git-blame: migrate to incremental parse-option [1/2]
This step merely moves the parser to an incremental version, still using parse_revisions. Signed-off-by: Pierre Habouzit <madcoder@debian.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 02e5422 commit 5817da0

File tree

1 file changed

+118
-102
lines changed

1 file changed

+118
-102
lines changed

builtin-blame.c

Lines changed: 118 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,16 @@
1818
#include "cache-tree.h"
1919
#include "path-list.h"
2020
#include "mailmap.h"
21+
#include "parse-options.h"
2122

22-
static char blame_usage[] =
23-
"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
24-
" -c Use the same output mode as git-annotate (Default: off)\n"
25-
" -b Show blank SHA-1 for boundary commits (Default: off)\n"
26-
" -l Show long commit SHA1 (Default: off)\n"
27-
" --root Do not treat root commits as boundaries (Default: off)\n"
28-
" -t Show raw timestamp (Default: off)\n"
29-
" -f, --show-name Show original filename (Default: auto)\n"
30-
" -n, --show-number Show original linenumber (Default: off)\n"
31-
" -s Suppress author name and timestamp (Default: off)\n"
32-
" -p, --porcelain Show in a format designed for machine consumption\n"
33-
" -w Ignore whitespace differences\n"
34-
" -L n,m Process only line range n,m, counting from 1\n"
35-
" -M, -C Find line movements within and across files\n"
36-
" --incremental Show blame entries as we find them, incrementally\n"
37-
" --contents file Use <file>'s contents as the final image\n"
38-
" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";
23+
static char blame_usage[] = "git-blame [options] [rev-opts] [rev] [--] file";
24+
25+
static const char *blame_opt_usage[] = {
26+
blame_usage,
27+
"",
28+
"[rev-opts] are documented in git-rev-parse(1)",
29+
NULL
30+
};
3931

4032
static int longest_file;
4133
static int longest_author;
@@ -2219,105 +2211,130 @@ static const char *prepare_initial(struct scoreboard *sb)
22192211
return final_commit_name;
22202212
}
22212213

2214+
static int blame_copy_callback(const struct option *option, const char *arg, int unset)
2215+
{
2216+
int *opt = option->value;
2217+
2218+
/*
2219+
* -C enables copy from removed files;
2220+
* -C -C enables copy from existing files, but only
2221+
* when blaming a new file;
2222+
* -C -C -C enables copy from existing files for
2223+
* everybody
2224+
*/
2225+
if (*opt & PICKAXE_BLAME_COPY_HARDER)
2226+
*opt |= PICKAXE_BLAME_COPY_HARDEST;
2227+
if (*opt & PICKAXE_BLAME_COPY)
2228+
*opt |= PICKAXE_BLAME_COPY_HARDER;
2229+
*opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
2230+
2231+
if (arg)
2232+
blame_copy_score = parse_score(arg);
2233+
return 0;
2234+
}
2235+
2236+
static int blame_move_callback(const struct option *option, const char *arg, int unset)
2237+
{
2238+
int *opt = option->value;
2239+
2240+
*opt |= PICKAXE_BLAME_MOVE;
2241+
2242+
if (arg)
2243+
blame_move_score = parse_score(arg);
2244+
return 0;
2245+
}
2246+
2247+
static int blame_bottomtop_callback(const struct option *option, const char *arg, int unset)
2248+
{
2249+
const char **bottomtop = option->value;
2250+
if (!arg)
2251+
return -1;
2252+
if (*bottomtop)
2253+
die("More than one '-L n,m' option given");
2254+
*bottomtop = arg;
2255+
return 0;
2256+
}
2257+
22222258
int cmd_blame(int argc, const char **argv, const char *prefix)
22232259
{
22242260
struct rev_info revs;
22252261
const char *path;
22262262
struct scoreboard sb;
22272263
struct origin *o;
22282264
struct blame_entry *ent;
2229-
int i, seen_dashdash, unk, opt;
2265+
int i, seen_dashdash, unk;
22302266
long bottom, top, lno;
2231-
int output_option = 0;
2232-
int show_stats = 0;
2233-
const char *revs_file = NULL;
22342267
const char *final_commit_name = NULL;
22352268
enum object_type type;
2236-
const char *bottomtop = NULL;
2237-
const char *contents_from = NULL;
2269+
2270+
static const char *bottomtop = NULL;
2271+
static int output_option = 0, opt = 0;
2272+
static int show_stats = 0;
2273+
static const char *revs_file = NULL;
2274+
static const char *contents_from = NULL;
2275+
static const struct option options[] = {
2276+
OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"),
2277+
OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"),
2278+
OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"),
2279+
OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"),
2280+
OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE),
2281+
OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
2282+
OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
2283+
OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
2284+
OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
2285+
OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
2286+
OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
2287+
OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
2288+
OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
2289+
OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
2290+
OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
2291+
{ OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
2292+
{ OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
2293+
OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
2294+
OPT_END()
2295+
};
2296+
2297+
struct parse_opt_ctx_t ctx;
22382298

22392299
cmd_is_annotate = !strcmp(argv[0], "annotate");
22402300

22412301
git_config(git_blame_config, NULL);
2302+
init_revisions(&revs, NULL);
22422303
save_commit_buffer = 0;
22432304

2244-
opt = 0;
2305+
parse_options_start(&ctx, argc, argv, PARSE_OPT_KEEP_DASHDASH |
2306+
PARSE_OPT_KEEP_ARGV0);
2307+
for (;;) {
2308+
int n;
2309+
2310+
switch (parse_options_step(&ctx, options, blame_opt_usage)) {
2311+
case PARSE_OPT_HELP:
2312+
exit(129);
2313+
case PARSE_OPT_DONE:
2314+
goto parse_done;
2315+
}
2316+
2317+
if (!strcmp(ctx.argv[0], "--reverse")) {
2318+
ctx.argv[0] = "--children";
2319+
reverse = 1;
2320+
}
2321+
n = handle_revision_opt(&revs, ctx.argc, ctx.argv,
2322+
&ctx.cpidx, ctx.out);
2323+
if (n <= 0) {
2324+
error("unknown option `%s'", ctx.argv[0]);
2325+
usage_with_options(blame_opt_usage, options);
2326+
}
2327+
ctx.argv += n;
2328+
ctx.argc -= n;
2329+
}
2330+
parse_done:
2331+
argc = parse_options_end(&ctx);
2332+
22452333
seen_dashdash = 0;
22462334
for (unk = i = 1; i < argc; i++) {
22472335
const char *arg = argv[i];
22482336
if (*arg != '-')
22492337
break;
2250-
else if (!strcmp("-b", arg))
2251-
blank_boundary = 1;
2252-
else if (!strcmp("--root", arg))
2253-
show_root = 1;
2254-
else if (!strcmp("--reverse", arg)) {
2255-
argv[unk++] = "--children";
2256-
reverse = 1;
2257-
}
2258-
else if (!strcmp(arg, "--show-stats"))
2259-
show_stats = 1;
2260-
else if (!strcmp("-c", arg))
2261-
output_option |= OUTPUT_ANNOTATE_COMPAT;
2262-
else if (!strcmp("-t", arg))
2263-
output_option |= OUTPUT_RAW_TIMESTAMP;
2264-
else if (!strcmp("-l", arg))
2265-
output_option |= OUTPUT_LONG_OBJECT_NAME;
2266-
else if (!strcmp("-s", arg))
2267-
output_option |= OUTPUT_NO_AUTHOR;
2268-
else if (!strcmp("-w", arg))
2269-
xdl_opts |= XDF_IGNORE_WHITESPACE;
2270-
else if (!strcmp("-S", arg) && ++i < argc)
2271-
revs_file = argv[i];
2272-
else if (!prefixcmp(arg, "-M")) {
2273-
opt |= PICKAXE_BLAME_MOVE;
2274-
blame_move_score = parse_score(arg+2);
2275-
}
2276-
else if (!prefixcmp(arg, "-C")) {
2277-
/*
2278-
* -C enables copy from removed files;
2279-
* -C -C enables copy from existing files, but only
2280-
* when blaming a new file;
2281-
* -C -C -C enables copy from existing files for
2282-
* everybody
2283-
*/
2284-
if (opt & PICKAXE_BLAME_COPY_HARDER)
2285-
opt |= PICKAXE_BLAME_COPY_HARDEST;
2286-
if (opt & PICKAXE_BLAME_COPY)
2287-
opt |= PICKAXE_BLAME_COPY_HARDER;
2288-
opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
2289-
blame_copy_score = parse_score(arg+2);
2290-
}
2291-
else if (!prefixcmp(arg, "-L")) {
2292-
if (!arg[2]) {
2293-
if (++i >= argc)
2294-
usage(blame_usage);
2295-
arg = argv[i];
2296-
}
2297-
else
2298-
arg += 2;
2299-
if (bottomtop)
2300-
die("More than one '-L n,m' option given");
2301-
bottomtop = arg;
2302-
}
2303-
else if (!strcmp("--contents", arg)) {
2304-
if (++i >= argc)
2305-
usage(blame_usage);
2306-
contents_from = argv[i];
2307-
}
2308-
else if (!strcmp("--incremental", arg))
2309-
incremental = 1;
2310-
else if (!strcmp("--score-debug", arg))
2311-
output_option |= OUTPUT_SHOW_SCORE;
2312-
else if (!strcmp("-f", arg) ||
2313-
!strcmp("--show-name", arg))
2314-
output_option |= OUTPUT_SHOW_NAME;
2315-
else if (!strcmp("-n", arg) ||
2316-
!strcmp("--show-number", arg))
2317-
output_option |= OUTPUT_SHOW_NUMBER;
2318-
else if (!strcmp("-p", arg) ||
2319-
!strcmp("--porcelain", arg))
2320-
output_option |= OUTPUT_PORCELAIN;
23212338
else if (!strcmp("--", arg)) {
23222339
seen_dashdash = 1;
23232340
i++;
@@ -2364,16 +2381,16 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
23642381
if (seen_dashdash) {
23652382
/* (1) */
23662383
if (argc <= i)
2367-
usage(blame_usage);
2384+
usage_with_options(blame_opt_usage, options);
23682385
path = add_prefix(prefix, argv[i]);
23692386
if (i + 1 == argc - 1) {
23702387
if (unk != 1)
2371-
usage(blame_usage);
2388+
usage_with_options(blame_opt_usage, options);
23722389
argv[unk++] = argv[i + 1];
23732390
}
23742391
else if (i + 1 != argc)
23752392
/* garbage at end */
2376-
usage(blame_usage);
2393+
usage_with_options(blame_opt_usage, options);
23772394
}
23782395
else {
23792396
int j;
@@ -2383,15 +2400,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
23832400
if (seen_dashdash) {
23842401
/* (2) */
23852402
if (seen_dashdash + 1 != argc - 1)
2386-
usage(blame_usage);
2403+
usage_with_options(blame_opt_usage, options);
23872404
path = add_prefix(prefix, argv[seen_dashdash + 1]);
23882405
for (j = i; j < seen_dashdash; j++)
23892406
argv[unk++] = argv[j];
23902407
}
23912408
else {
23922409
/* (3) */
23932410
if (argc <= i)
2394-
usage(blame_usage);
2411+
usage_with_options(blame_opt_usage, options);
23952412
path = add_prefix(prefix, argv[i]);
23962413
if (i + 1 == argc - 1) {
23972414
final_commit_name = argv[i + 1];
@@ -2405,7 +2422,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24052422
}
24062423
}
24072424
else if (i != argc - 1)
2408-
usage(blame_usage); /* garbage at end */
2425+
usage_with_options(blame_opt_usage, options);
24092426

24102427
setup_work_tree();
24112428
if (!has_path_in_work_tree(path))
@@ -2424,7 +2441,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24242441
argv[unk++] = "--"; /* terminate the rev name */
24252442
argv[unk] = NULL;
24262443

2427-
init_revisions(&revs, NULL);
24282444
setup_revisions(unk, argv, &revs, NULL);
24292445
memset(&sb, 0, sizeof(sb));
24302446

0 commit comments

Comments
 (0)