mirror of
https://github.com/git/git.git
synced 2024-11-28 12:34:08 +08:00
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>
This commit is contained in:
parent
02e542206f
commit
5817da0143
220
builtin-blame.c
220
builtin-blame.c
@ -18,24 +18,16 @@
|
||||
#include "cache-tree.h"
|
||||
#include "path-list.h"
|
||||
#include "mailmap.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static char blame_usage[] =
|
||||
"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"
|
||||
" -c Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -b Show blank SHA-1 for boundary commits (Default: off)\n"
|
||||
" -l Show long commit SHA1 (Default: off)\n"
|
||||
" --root Do not treat root commits as boundaries (Default: off)\n"
|
||||
" -t Show raw timestamp (Default: off)\n"
|
||||
" -f, --show-name Show original filename (Default: auto)\n"
|
||||
" -n, --show-number Show original linenumber (Default: off)\n"
|
||||
" -s Suppress author name and timestamp (Default: off)\n"
|
||||
" -p, --porcelain Show in a format designed for machine consumption\n"
|
||||
" -w Ignore whitespace differences\n"
|
||||
" -L n,m Process only line range n,m, counting from 1\n"
|
||||
" -M, -C Find line movements within and across files\n"
|
||||
" --incremental Show blame entries as we find them, incrementally\n"
|
||||
" --contents file Use <file>'s contents as the final image\n"
|
||||
" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";
|
||||
static char blame_usage[] = "git-blame [options] [rev-opts] [rev] [--] file";
|
||||
|
||||
static const char *blame_opt_usage[] = {
|
||||
blame_usage,
|
||||
"",
|
||||
"[rev-opts] are documented in git-rev-parse(1)",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int longest_file;
|
||||
static int longest_author;
|
||||
@ -2219,6 +2211,50 @@ static const char *prepare_initial(struct scoreboard *sb)
|
||||
return final_commit_name;
|
||||
}
|
||||
|
||||
static int blame_copy_callback(const struct option *option, const char *arg, int unset)
|
||||
{
|
||||
int *opt = option->value;
|
||||
|
||||
/*
|
||||
* -C enables copy from removed files;
|
||||
* -C -C enables copy from existing files, but only
|
||||
* when blaming a new file;
|
||||
* -C -C -C enables copy from existing files for
|
||||
* everybody
|
||||
*/
|
||||
if (*opt & PICKAXE_BLAME_COPY_HARDER)
|
||||
*opt |= PICKAXE_BLAME_COPY_HARDEST;
|
||||
if (*opt & PICKAXE_BLAME_COPY)
|
||||
*opt |= PICKAXE_BLAME_COPY_HARDER;
|
||||
*opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
|
||||
|
||||
if (arg)
|
||||
blame_copy_score = parse_score(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blame_move_callback(const struct option *option, const char *arg, int unset)
|
||||
{
|
||||
int *opt = option->value;
|
||||
|
||||
*opt |= PICKAXE_BLAME_MOVE;
|
||||
|
||||
if (arg)
|
||||
blame_move_score = parse_score(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blame_bottomtop_callback(const struct option *option, const char *arg, int unset)
|
||||
{
|
||||
const char **bottomtop = option->value;
|
||||
if (!arg)
|
||||
return -1;
|
||||
if (*bottomtop)
|
||||
die("More than one '-L n,m' option given");
|
||||
*bottomtop = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info revs;
|
||||
@ -2226,98 +2262,79 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
struct scoreboard sb;
|
||||
struct origin *o;
|
||||
struct blame_entry *ent;
|
||||
int i, seen_dashdash, unk, opt;
|
||||
int i, seen_dashdash, unk;
|
||||
long bottom, top, lno;
|
||||
int output_option = 0;
|
||||
int show_stats = 0;
|
||||
const char *revs_file = NULL;
|
||||
const char *final_commit_name = NULL;
|
||||
enum object_type type;
|
||||
const char *bottomtop = NULL;
|
||||
const char *contents_from = NULL;
|
||||
|
||||
static const char *bottomtop = NULL;
|
||||
static int output_option = 0, opt = 0;
|
||||
static int show_stats = 0;
|
||||
static const char *revs_file = NULL;
|
||||
static const char *contents_from = NULL;
|
||||
static const struct option options[] = {
|
||||
OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"),
|
||||
OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"),
|
||||
OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"),
|
||||
OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"),
|
||||
OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE),
|
||||
OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
|
||||
OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
|
||||
OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
|
||||
OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
|
||||
OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
|
||||
OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
|
||||
OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
|
||||
OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
|
||||
OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
|
||||
OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
|
||||
{ OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
|
||||
{ OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
|
||||
OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
struct parse_opt_ctx_t ctx;
|
||||
|
||||
cmd_is_annotate = !strcmp(argv[0], "annotate");
|
||||
|
||||
git_config(git_blame_config, NULL);
|
||||
init_revisions(&revs, NULL);
|
||||
save_commit_buffer = 0;
|
||||
|
||||
opt = 0;
|
||||
parse_options_start(&ctx, argc, argv, PARSE_OPT_KEEP_DASHDASH |
|
||||
PARSE_OPT_KEEP_ARGV0);
|
||||
for (;;) {
|
||||
int n;
|
||||
|
||||
switch (parse_options_step(&ctx, options, blame_opt_usage)) {
|
||||
case PARSE_OPT_HELP:
|
||||
exit(129);
|
||||
case PARSE_OPT_DONE:
|
||||
goto parse_done;
|
||||
}
|
||||
|
||||
if (!strcmp(ctx.argv[0], "--reverse")) {
|
||||
ctx.argv[0] = "--children";
|
||||
reverse = 1;
|
||||
}
|
||||
n = handle_revision_opt(&revs, ctx.argc, ctx.argv,
|
||||
&ctx.cpidx, ctx.out);
|
||||
if (n <= 0) {
|
||||
error("unknown option `%s'", ctx.argv[0]);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
}
|
||||
ctx.argv += n;
|
||||
ctx.argc -= n;
|
||||
}
|
||||
parse_done:
|
||||
argc = parse_options_end(&ctx);
|
||||
|
||||
seen_dashdash = 0;
|
||||
for (unk = i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (*arg != '-')
|
||||
break;
|
||||
else if (!strcmp("-b", arg))
|
||||
blank_boundary = 1;
|
||||
else if (!strcmp("--root", arg))
|
||||
show_root = 1;
|
||||
else if (!strcmp("--reverse", arg)) {
|
||||
argv[unk++] = "--children";
|
||||
reverse = 1;
|
||||
}
|
||||
else if (!strcmp(arg, "--show-stats"))
|
||||
show_stats = 1;
|
||||
else if (!strcmp("-c", arg))
|
||||
output_option |= OUTPUT_ANNOTATE_COMPAT;
|
||||
else if (!strcmp("-t", arg))
|
||||
output_option |= OUTPUT_RAW_TIMESTAMP;
|
||||
else if (!strcmp("-l", arg))
|
||||
output_option |= OUTPUT_LONG_OBJECT_NAME;
|
||||
else if (!strcmp("-s", arg))
|
||||
output_option |= OUTPUT_NO_AUTHOR;
|
||||
else if (!strcmp("-w", arg))
|
||||
xdl_opts |= XDF_IGNORE_WHITESPACE;
|
||||
else if (!strcmp("-S", arg) && ++i < argc)
|
||||
revs_file = argv[i];
|
||||
else if (!prefixcmp(arg, "-M")) {
|
||||
opt |= PICKAXE_BLAME_MOVE;
|
||||
blame_move_score = parse_score(arg+2);
|
||||
}
|
||||
else if (!prefixcmp(arg, "-C")) {
|
||||
/*
|
||||
* -C enables copy from removed files;
|
||||
* -C -C enables copy from existing files, but only
|
||||
* when blaming a new file;
|
||||
* -C -C -C enables copy from existing files for
|
||||
* everybody
|
||||
*/
|
||||
if (opt & PICKAXE_BLAME_COPY_HARDER)
|
||||
opt |= PICKAXE_BLAME_COPY_HARDEST;
|
||||
if (opt & PICKAXE_BLAME_COPY)
|
||||
opt |= PICKAXE_BLAME_COPY_HARDER;
|
||||
opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
|
||||
blame_copy_score = parse_score(arg+2);
|
||||
}
|
||||
else if (!prefixcmp(arg, "-L")) {
|
||||
if (!arg[2]) {
|
||||
if (++i >= argc)
|
||||
usage(blame_usage);
|
||||
arg = argv[i];
|
||||
}
|
||||
else
|
||||
arg += 2;
|
||||
if (bottomtop)
|
||||
die("More than one '-L n,m' option given");
|
||||
bottomtop = arg;
|
||||
}
|
||||
else if (!strcmp("--contents", arg)) {
|
||||
if (++i >= argc)
|
||||
usage(blame_usage);
|
||||
contents_from = argv[i];
|
||||
}
|
||||
else if (!strcmp("--incremental", arg))
|
||||
incremental = 1;
|
||||
else if (!strcmp("--score-debug", arg))
|
||||
output_option |= OUTPUT_SHOW_SCORE;
|
||||
else if (!strcmp("-f", arg) ||
|
||||
!strcmp("--show-name", arg))
|
||||
output_option |= OUTPUT_SHOW_NAME;
|
||||
else if (!strcmp("-n", arg) ||
|
||||
!strcmp("--show-number", arg))
|
||||
output_option |= OUTPUT_SHOW_NUMBER;
|
||||
else if (!strcmp("-p", arg) ||
|
||||
!strcmp("--porcelain", arg))
|
||||
output_option |= OUTPUT_PORCELAIN;
|
||||
else if (!strcmp("--", arg)) {
|
||||
seen_dashdash = 1;
|
||||
i++;
|
||||
@ -2364,16 +2381,16 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
if (seen_dashdash) {
|
||||
/* (1) */
|
||||
if (argc <= i)
|
||||
usage(blame_usage);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
path = add_prefix(prefix, argv[i]);
|
||||
if (i + 1 == argc - 1) {
|
||||
if (unk != 1)
|
||||
usage(blame_usage);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
argv[unk++] = argv[i + 1];
|
||||
}
|
||||
else if (i + 1 != argc)
|
||||
/* garbage at end */
|
||||
usage(blame_usage);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
}
|
||||
else {
|
||||
int j;
|
||||
@ -2383,7 +2400,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
if (seen_dashdash) {
|
||||
/* (2) */
|
||||
if (seen_dashdash + 1 != argc - 1)
|
||||
usage(blame_usage);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
path = add_prefix(prefix, argv[seen_dashdash + 1]);
|
||||
for (j = i; j < seen_dashdash; j++)
|
||||
argv[unk++] = argv[j];
|
||||
@ -2391,7 +2408,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
else {
|
||||
/* (3) */
|
||||
if (argc <= i)
|
||||
usage(blame_usage);
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
path = add_prefix(prefix, argv[i]);
|
||||
if (i + 1 == argc - 1) {
|
||||
final_commit_name = argv[i + 1];
|
||||
@ -2405,7 +2422,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
else if (i != argc - 1)
|
||||
usage(blame_usage); /* garbage at end */
|
||||
usage_with_options(blame_opt_usage, options);
|
||||
|
||||
setup_work_tree();
|
||||
if (!has_path_in_work_tree(path))
|
||||
@ -2424,7 +2441,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
argv[unk++] = "--"; /* terminate the rev name */
|
||||
argv[unk] = NULL;
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
setup_revisions(unk, argv, &revs, NULL);
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user