1
0
mirror of https://github.com/git/git synced 2024-06-30 22:54:27 +00:00

Merge branch 'jc/revision-parse-int' into maint-2.43

The command line parser for the "log" family of commands was too
loose when parsing certain numbers, e.g., silently ignoring the
extra 'q' in "git log -n 1q" without complaining, which has been
tightened up.

* jc/revision-parse-int:
  revision: parse integer arguments to --max-count, --skip, etc., more carefully
This commit is contained in:
Junio C Hamano 2024-02-08 16:22:02 -08:00
commit 4b50f86141
3 changed files with 57 additions and 13 deletions

View File

@ -2223,6 +2223,27 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
add_grep(revs, pattern, GREP_PATTERN_BODY);
}
static int parse_count(const char *arg)
{
int count;
if (strtol_i(arg, 10, &count) < 0)
die("'%s': not an integer", arg);
return count;
}
static timestamp_t parse_age(const char *arg)
{
timestamp_t num;
char *p;
errno = 0;
num = parse_timestamp(arg, &p, 10);
if (errno || *p || p == arg)
die("'%s': not a number of seconds since epoch", arg);
return num;
}
static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
int *unkc, const char **unkv,
const struct setup_revision_opt* opt)
@ -2249,29 +2270,27 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
}
if ((argcount = parse_long_opt("max-count", argv, &optarg))) {
revs->max_count = atoi(optarg);
revs->max_count = parse_count(optarg);
revs->no_walk = 0;
return argcount;
} else if ((argcount = parse_long_opt("skip", argv, &optarg))) {
revs->skip_count = atoi(optarg);
revs->skip_count = parse_count(optarg);
return argcount;
} else if ((*arg == '-') && isdigit(arg[1])) {
/* accept -<digit>, like traditional "head" */
if (strtol_i(arg + 1, 10, &revs->max_count) < 0 ||
revs->max_count < 0)
die("'%s': not a non-negative integer", arg + 1);
revs->max_count = parse_count(arg + 1);
revs->no_walk = 0;
} else if (!strcmp(arg, "-n")) {
if (argc <= 1)
return error("-n requires an argument");
revs->max_count = atoi(argv[1]);
revs->max_count = parse_count(argv[1]);
revs->no_walk = 0;
return 2;
} else if (skip_prefix(arg, "-n", &optarg)) {
revs->max_count = atoi(optarg);
revs->max_count = parse_count(optarg);
revs->no_walk = 0;
} else if ((argcount = parse_long_opt("max-age", argv, &optarg))) {
revs->max_age = atoi(optarg);
revs->max_age = parse_age(optarg);
return argcount;
} else if ((argcount = parse_long_opt("since", argv, &optarg))) {
revs->max_age = approxidate(optarg);
@ -2283,7 +2302,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->max_age = approxidate(optarg);
return argcount;
} else if ((argcount = parse_long_opt("min-age", argv, &optarg))) {
revs->min_age = atoi(optarg);
revs->min_age = parse_age(optarg);
return argcount;
} else if ((argcount = parse_long_opt("before", argv, &optarg))) {
revs->min_age = approxidate(optarg);
@ -2371,11 +2390,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else if (!strcmp(arg, "--no-merges")) {
revs->max_parents = 1;
} else if (skip_prefix(arg, "--min-parents=", &optarg)) {
revs->min_parents = atoi(optarg);
revs->min_parents = parse_count(optarg);
} else if (!strcmp(arg, "--no-min-parents")) {
revs->min_parents = 0;
} else if (skip_prefix(arg, "--max-parents=", &optarg)) {
revs->max_parents = atoi(optarg);
revs->max_parents = parse_count(optarg);
} else if (!strcmp(arg, "--no-max-parents")) {
revs->max_parents = -1;
} else if (!strcmp(arg, "--boundary")) {

View File

@ -18,20 +18,34 @@ test_expect_success 'no options' '
'
test_expect_success '--max-count' '
test_must_fail git rev-list --max-count=1q HEAD 2>error &&
grep "not an integer" error &&
test_stdout_line_count = 0 git rev-list HEAD --max-count=0 &&
test_stdout_line_count = 3 git rev-list HEAD --max-count=3 &&
test_stdout_line_count = 5 git rev-list HEAD --max-count=5 &&
test_stdout_line_count = 5 git rev-list HEAD --max-count=10
test_stdout_line_count = 5 git rev-list HEAD --max-count=10 &&
test_stdout_line_count = 5 git rev-list HEAD --max-count=-1
'
test_expect_success '--max-count all forms' '
test_must_fail git rev-list -1q HEAD 2>error &&
grep "not an integer" error &&
test_must_fail git rev-list --1 HEAD &&
test_must_fail git rev-list -n 1q HEAD 2>error &&
grep "not an integer" error &&
test_stdout_line_count = 1 git rev-list HEAD --max-count=1 &&
test_stdout_line_count = 1 git rev-list HEAD -1 &&
test_stdout_line_count = 1 git rev-list HEAD -n1 &&
test_stdout_line_count = 1 git rev-list HEAD -n 1
test_stdout_line_count = 1 git rev-list HEAD -n 1 &&
test_stdout_line_count = 5 git rev-list HEAD -n -1
'
test_expect_success '--skip' '
test_must_fail git rev-list --skip 1q HEAD 2>error &&
grep "not an integer" error &&
test_stdout_line_count = 5 git rev-list HEAD --skip=0 &&
test_stdout_line_count = 2 git rev-list HEAD --skip=3 &&
test_stdout_line_count = 0 git rev-list HEAD --skip=5 &&

View File

@ -63,6 +63,17 @@ test_expect_success 'setup roots, merges and octopuses' '
git checkout main
'
test_expect_success 'parse --max-parents & --min-parents' '
test_must_fail git rev-list --max-parents=1q HEAD 2>error &&
grep "not an integer" error &&
test_must_fail git rev-list --min-parents=1q HEAD 2>error &&
grep "not an integer" error &&
git rev-list --max-parents=1 --min-parents=1 HEAD &&
git rev-list --max-parents=-1 --min-parents=-1 HEAD
'
test_expect_success 'rev-list roots' '
check_revlist "--max-parents=0" one five