mirror of
https://github.com/git/git.git
synced 2025-03-24 03:29:47 +00:00
Merge branch 'jc/grep-header-all-match-fix'
* jc/grep-header-all-match-fix: log --author: take union of multiple "author" requests grep: move logic to compile header pattern into a separate helper
This commit is contained in:
commit
a27d5bef56
104
grep.c
104
grep.c
@ -189,29 +189,73 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
|
||||
return compile_pattern_or(list);
|
||||
}
|
||||
|
||||
static struct grep_expr *grep_true_expr(void)
|
||||
{
|
||||
struct grep_expr *z = xcalloc(1, sizeof(*z));
|
||||
z->node = GREP_NODE_TRUE;
|
||||
return z;
|
||||
}
|
||||
|
||||
static struct grep_expr *grep_or_expr(struct grep_expr *left, struct grep_expr *right)
|
||||
{
|
||||
struct grep_expr *z = xcalloc(1, sizeof(*z));
|
||||
z->node = GREP_NODE_OR;
|
||||
z->u.binary.left = left;
|
||||
z->u.binary.right = right;
|
||||
return z;
|
||||
}
|
||||
|
||||
static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *header_expr;
|
||||
struct grep_expr *(header_group[GREP_HEADER_FIELD_MAX]);
|
||||
enum grep_header_field fld;
|
||||
|
||||
if (!opt->header_list)
|
||||
return NULL;
|
||||
p = opt->header_list;
|
||||
for (p = opt->header_list; p; p = p->next) {
|
||||
if (p->token != GREP_PATTERN_HEAD)
|
||||
die("bug: a non-header pattern in grep header list.");
|
||||
if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field)
|
||||
die("bug: unknown header field %d", p->field);
|
||||
compile_regexp(p, opt);
|
||||
}
|
||||
|
||||
for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++)
|
||||
header_group[fld] = NULL;
|
||||
|
||||
for (p = opt->header_list; p; p = p->next) {
|
||||
struct grep_expr *h;
|
||||
struct grep_pat *pp = p;
|
||||
|
||||
h = compile_pattern_atom(&pp);
|
||||
if (!h || pp != p->next)
|
||||
die("bug: malformed header expr");
|
||||
if (!header_group[p->field]) {
|
||||
header_group[p->field] = h;
|
||||
continue;
|
||||
}
|
||||
header_group[p->field] = grep_or_expr(h, header_group[p->field]);
|
||||
}
|
||||
|
||||
header_expr = NULL;
|
||||
|
||||
for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) {
|
||||
if (!header_group[fld])
|
||||
continue;
|
||||
if (!header_expr)
|
||||
header_expr = grep_true_expr();
|
||||
header_expr = grep_or_expr(header_group[fld], header_expr);
|
||||
}
|
||||
return header_expr;
|
||||
}
|
||||
|
||||
void compile_grep_patterns(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *header_expr = NULL;
|
||||
|
||||
if (opt->header_list) {
|
||||
p = opt->header_list;
|
||||
header_expr = compile_pattern_expr(&p);
|
||||
if (p)
|
||||
die("incomplete pattern expression: %s", p->pattern);
|
||||
for (p = opt->header_list; p; p = p->next) {
|
||||
switch (p->token) {
|
||||
case GREP_PATTERN: /* atom */
|
||||
case GREP_PATTERN_HEAD:
|
||||
case GREP_PATTERN_BODY:
|
||||
compile_regexp(p, opt);
|
||||
break;
|
||||
default:
|
||||
opt->extended = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
struct grep_expr *header_expr = prep_header_patterns(opt);
|
||||
|
||||
for (p = opt->pattern_list; p; p = p->next) {
|
||||
switch (p->token) {
|
||||
@ -231,9 +275,6 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
else if (!opt->extended)
|
||||
return;
|
||||
|
||||
/* Then bundle them up in an expression.
|
||||
* A classic recursive descent parser would do.
|
||||
*/
|
||||
p = opt->pattern_list;
|
||||
if (p)
|
||||
opt->pattern_expression = compile_pattern_expr(&p);
|
||||
@ -243,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
if (!header_expr)
|
||||
return;
|
||||
|
||||
if (opt->pattern_expression) {
|
||||
struct grep_expr *z;
|
||||
z = xcalloc(1, sizeof(*z));
|
||||
z->node = GREP_NODE_OR;
|
||||
z->u.binary.left = opt->pattern_expression;
|
||||
z->u.binary.right = header_expr;
|
||||
opt->pattern_expression = z;
|
||||
} else {
|
||||
if (!opt->pattern_expression)
|
||||
opt->pattern_expression = header_expr;
|
||||
}
|
||||
else
|
||||
opt->pattern_expression = grep_or_expr(opt->pattern_expression,
|
||||
header_expr);
|
||||
opt->all_match = 1;
|
||||
}
|
||||
|
||||
static void free_pattern_expr(struct grep_expr *x)
|
||||
{
|
||||
switch (x->node) {
|
||||
case GREP_NODE_TRUE:
|
||||
case GREP_NODE_ATOM:
|
||||
break;
|
||||
case GREP_NODE_NOT:
|
||||
@ -487,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
|
||||
if (!x)
|
||||
die("Not a valid grep expression");
|
||||
switch (x->node) {
|
||||
case GREP_NODE_TRUE:
|
||||
h = 1;
|
||||
break;
|
||||
case GREP_NODE_ATOM:
|
||||
h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
|
||||
break;
|
||||
|
2
grep.h
2
grep.h
@ -22,6 +22,7 @@ enum grep_header_field {
|
||||
GREP_HEADER_AUTHOR = 0,
|
||||
GREP_HEADER_COMMITTER
|
||||
};
|
||||
#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
|
||||
|
||||
struct grep_pat {
|
||||
struct grep_pat *next;
|
||||
@ -41,6 +42,7 @@ enum grep_expr_node {
|
||||
GREP_NODE_ATOM,
|
||||
GREP_NODE_NOT,
|
||||
GREP_NODE_AND,
|
||||
GREP_NODE_TRUE,
|
||||
GREP_NODE_OR
|
||||
};
|
||||
|
||||
|
@ -324,8 +324,13 @@ test_expect_success 'log grep setup' '
|
||||
|
||||
echo a >>file &&
|
||||
test_tick &&
|
||||
git commit -a -m "third"
|
||||
git commit -a -m "third" &&
|
||||
|
||||
echo a >>file &&
|
||||
test_tick &&
|
||||
GIT_AUTHOR_NAME="Night Fall" \
|
||||
GIT_AUTHOR_EMAIL="nitfol@frobozz.com" \
|
||||
git commit -a -m "fourth"
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (1)' '
|
||||
@ -372,6 +377,28 @@ test_expect_success 'log --grep --author implicitly uses all-match' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log with multiple --author uses union' '
|
||||
git log --author="Thor" --author="Aster" --format=%s >actual &&
|
||||
{
|
||||
echo third && echo second && echo initial
|
||||
} >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log with --grep and multiple --author uses all-match' '
|
||||
git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
|
||||
{
|
||||
echo third && echo initial
|
||||
} >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log with --grep and multiple --author uses all-match' '
|
||||
git log --author="Thor" --author="Night" --grep=q --format=%s >actual &&
|
||||
>expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'grep with CE_VALID file' '
|
||||
git update-index --assume-unchanged t/t &&
|
||||
rm t/t &&
|
||||
|
Loading…
x
Reference in New Issue
Block a user