提交 a27d5bef 编写于 作者: J Junio C Hamano

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
...@@ -189,30 +189,74 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list) ...@@ -189,30 +189,74 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
return compile_pattern_or(list); return compile_pattern_or(list);
} }
void compile_grep_patterns(struct grep_opt *opt) 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_pat *p;
struct grep_expr *header_expr = NULL; struct grep_expr *header_expr;
struct grep_expr *(header_group[GREP_HEADER_FIELD_MAX]);
if (opt->header_list) { enum grep_header_field fld;
p = opt->header_list;
header_expr = compile_pattern_expr(&p); if (!opt->header_list)
if (p) return NULL;
die("incomplete pattern expression: %s", p->pattern); p = opt->header_list;
for (p = opt->header_list; p; p = p->next) { for (p = opt->header_list; p; p = p->next) {
switch (p->token) { if (p->token != GREP_PATTERN_HEAD)
case GREP_PATTERN: /* atom */ die("bug: a non-header pattern in grep header list.");
case GREP_PATTERN_HEAD: if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field)
case GREP_PATTERN_BODY: die("bug: unknown header field %d", p->field);
compile_regexp(p, opt); compile_regexp(p, opt);
break; }
default:
opt->extended = 1; for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++)
break; 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 = prep_header_patterns(opt);
for (p = opt->pattern_list; p; p = p->next) { for (p = opt->pattern_list; p; p = p->next) {
switch (p->token) { switch (p->token) {
case GREP_PATTERN: /* atom */ case GREP_PATTERN: /* atom */
...@@ -231,9 +275,6 @@ void compile_grep_patterns(struct grep_opt *opt) ...@@ -231,9 +275,6 @@ void compile_grep_patterns(struct grep_opt *opt)
else if (!opt->extended) else if (!opt->extended)
return; return;
/* Then bundle them up in an expression.
* A classic recursive descent parser would do.
*/
p = opt->pattern_list; p = opt->pattern_list;
if (p) if (p)
opt->pattern_expression = compile_pattern_expr(&p); opt->pattern_expression = compile_pattern_expr(&p);
...@@ -243,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt) ...@@ -243,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt)
if (!header_expr) if (!header_expr)
return; return;
if (opt->pattern_expression) { 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 {
opt->pattern_expression = header_expr; opt->pattern_expression = header_expr;
} else
opt->pattern_expression = grep_or_expr(opt->pattern_expression,
header_expr);
opt->all_match = 1; opt->all_match = 1;
} }
static void free_pattern_expr(struct grep_expr *x) static void free_pattern_expr(struct grep_expr *x)
{ {
switch (x->node) { switch (x->node) {
case GREP_NODE_TRUE:
case GREP_NODE_ATOM: case GREP_NODE_ATOM:
break; break;
case GREP_NODE_NOT: case GREP_NODE_NOT:
...@@ -487,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, ...@@ -487,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
if (!x) if (!x)
die("Not a valid grep expression"); die("Not a valid grep expression");
switch (x->node) { switch (x->node) {
case GREP_NODE_TRUE:
h = 1;
break;
case GREP_NODE_ATOM: case GREP_NODE_ATOM:
h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
break; break;
......
...@@ -22,6 +22,7 @@ enum grep_header_field { ...@@ -22,6 +22,7 @@ enum grep_header_field {
GREP_HEADER_AUTHOR = 0, GREP_HEADER_AUTHOR = 0,
GREP_HEADER_COMMITTER GREP_HEADER_COMMITTER
}; };
#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
struct grep_pat { struct grep_pat {
struct grep_pat *next; struct grep_pat *next;
...@@ -41,6 +42,7 @@ enum grep_expr_node { ...@@ -41,6 +42,7 @@ enum grep_expr_node {
GREP_NODE_ATOM, GREP_NODE_ATOM,
GREP_NODE_NOT, GREP_NODE_NOT,
GREP_NODE_AND, GREP_NODE_AND,
GREP_NODE_TRUE,
GREP_NODE_OR GREP_NODE_OR
}; };
......
...@@ -324,8 +324,13 @@ test_expect_success 'log grep setup' ' ...@@ -324,8 +324,13 @@ test_expect_success 'log grep setup' '
echo a >>file && echo a >>file &&
test_tick && 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)' ' test_expect_success 'log grep (1)' '
...@@ -372,6 +377,28 @@ test_expect_success 'log --grep --author implicitly uses all-match' ' ...@@ -372,6 +377,28 @@ test_expect_success 'log --grep --author implicitly uses all-match' '
test_cmp expect actual 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' ' test_expect_success 'grep with CE_VALID file' '
git update-index --assume-unchanged t/t && git update-index --assume-unchanged t/t &&
rm t/t && rm t/t &&
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册