Skip to content

Commit 8132f2c

Browse files
committed
Merge branch 'rs/pickaxe-i'
Allow the options -i/--regexp-ignore-case, --pickaxe-regex, and -S to be used together and work as expected to perform a pickaxe search using case-insensitive regular expression matching. * rs/pickaxe-i: pickaxe: simplify kwset loop in contains() pickaxe: call strlen only when necessary in diffcore_pickaxe_count() pickaxe: move pickaxe() after pickaxe_match() pickaxe: merge diffcore_pickaxe_grep() and diffcore_pickaxe_count() into diffcore_pickaxe() pickaxe: honor -i when used with -S and --pickaxe-regex t4209: use helper functions to test --author t4209: use helper functions to test --grep t4209: factor out helper function test_log_icase() t4209: factor out helper function test_log() t4209: set up expectations up front
2 parents 6b869a1 + e4aab50 commit 8132f2c

File tree

2 files changed

+116
-188
lines changed

2 files changed

+116
-188
lines changed

diffcore-pickaxe.c

Lines changed: 52 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -12,47 +12,6 @@ typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
1212
struct diff_options *o,
1313
regex_t *regexp, kwset_t kws);
1414

15-
static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
16-
regex_t *regexp, kwset_t kws, pickaxe_fn fn);
17-
18-
static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
19-
regex_t *regexp, kwset_t kws, pickaxe_fn fn)
20-
{
21-
int i;
22-
struct diff_queue_struct outq;
23-
24-
DIFF_QUEUE_CLEAR(&outq);
25-
26-
if (o->pickaxe_opts & DIFF_PICKAXE_ALL) {
27-
/* Showing the whole changeset if needle exists */
28-
for (i = 0; i < q->nr; i++) {
29-
struct diff_filepair *p = q->queue[i];
30-
if (pickaxe_match(p, o, regexp, kws, fn))
31-
return; /* do not munge the queue */
32-
}
33-
34-
/*
35-
* Otherwise we will clear the whole queue by copying
36-
* the empty outq at the end of this function, but
37-
* first clear the current entries in the queue.
38-
*/
39-
for (i = 0; i < q->nr; i++)
40-
diff_free_filepair(q->queue[i]);
41-
} else {
42-
/* Showing only the filepairs that has the needle */
43-
for (i = 0; i < q->nr; i++) {
44-
struct diff_filepair *p = q->queue[i];
45-
if (pickaxe_match(p, o, regexp, kws, fn))
46-
diff_q(&outq, p);
47-
else
48-
diff_free_filepair(p);
49-
}
50-
}
51-
52-
free(q->queue);
53-
*q = outq;
54-
}
55-
5615
struct diffgrep_cb {
5716
regex_t *regexp;
5817
int hit;
@@ -108,29 +67,6 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
10867
return ecbdata.hit;
10968
}
11069

111-
static void diffcore_pickaxe_grep(struct diff_options *o)
112-
{
113-
int err;
114-
regex_t regex;
115-
int cflags = REG_EXTENDED | REG_NEWLINE;
116-
117-
if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
118-
cflags |= REG_ICASE;
119-
120-
err = regcomp(&regex, o->pickaxe, cflags);
121-
if (err) {
122-
char errbuf[1024];
123-
regerror(err, &regex, errbuf, 1024);
124-
regfree(&regex);
125-
die("invalid regex: %s", errbuf);
126-
}
127-
128-
pickaxe(&diff_queued_diff, o, &regex, NULL, diff_grep);
129-
130-
regfree(&regex);
131-
return;
132-
}
133-
13470
static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
13571
{
13672
unsigned int cnt;
@@ -158,13 +94,10 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
15894
while (sz) {
15995
struct kwsmatch kwsm;
16096
size_t offset = kwsexec(kws, data, sz, &kwsm);
161-
const char *found;
16297
if (offset == -1)
16398
break;
164-
else
165-
found = data + offset;
166-
sz -= found - data + kwsm.size[0];
167-
data = found + kwsm.size[0];
99+
sz -= offset + kwsm.size[0];
100+
data += offset + kwsm.size[0];
168101
cnt++;
169102
}
170103
}
@@ -227,17 +160,57 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
227160
return ret;
228161
}
229162

230-
static void diffcore_pickaxe_count(struct diff_options *o)
163+
static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
164+
regex_t *regexp, kwset_t kws, pickaxe_fn fn)
165+
{
166+
int i;
167+
struct diff_queue_struct outq;
168+
169+
DIFF_QUEUE_CLEAR(&outq);
170+
171+
if (o->pickaxe_opts & DIFF_PICKAXE_ALL) {
172+
/* Showing the whole changeset if needle exists */
173+
for (i = 0; i < q->nr; i++) {
174+
struct diff_filepair *p = q->queue[i];
175+
if (pickaxe_match(p, o, regexp, kws, fn))
176+
return; /* do not munge the queue */
177+
}
178+
179+
/*
180+
* Otherwise we will clear the whole queue by copying
181+
* the empty outq at the end of this function, but
182+
* first clear the current entries in the queue.
183+
*/
184+
for (i = 0; i < q->nr; i++)
185+
diff_free_filepair(q->queue[i]);
186+
} else {
187+
/* Showing only the filepairs that has the needle */
188+
for (i = 0; i < q->nr; i++) {
189+
struct diff_filepair *p = q->queue[i];
190+
if (pickaxe_match(p, o, regexp, kws, fn))
191+
diff_q(&outq, p);
192+
else
193+
diff_free_filepair(p);
194+
}
195+
}
196+
197+
free(q->queue);
198+
*q = outq;
199+
}
200+
201+
void diffcore_pickaxe(struct diff_options *o)
231202
{
232203
const char *needle = o->pickaxe;
233204
int opts = o->pickaxe_opts;
234-
unsigned long len = strlen(needle);
235205
regex_t regex, *regexp = NULL;
236206
kwset_t kws = NULL;
237207

238-
if (opts & DIFF_PICKAXE_REGEX) {
208+
if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
239209
int err;
240-
err = regcomp(&regex, needle, REG_EXTENDED | REG_NEWLINE);
210+
int cflags = REG_EXTENDED | REG_NEWLINE;
211+
if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
212+
cflags |= REG_ICASE;
213+
err = regcomp(&regex, needle, cflags);
241214
if (err) {
242215
/* The POSIX.2 people are surely sick */
243216
char errbuf[1024];
@@ -249,24 +222,17 @@ static void diffcore_pickaxe_count(struct diff_options *o)
249222
} else {
250223
kws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)
251224
? tolower_trans_tbl : NULL);
252-
kwsincr(kws, needle, len);
225+
kwsincr(kws, needle, strlen(needle));
253226
kwsprep(kws);
254227
}
255228

256-
pickaxe(&diff_queued_diff, o, regexp, kws, has_changes);
229+
/* Might want to warn when both S and G are on; I don't care... */
230+
pickaxe(&diff_queued_diff, o, regexp, kws,
231+
(opts & DIFF_PICKAXE_KIND_G) ? diff_grep : has_changes);
257232

258-
if (opts & DIFF_PICKAXE_REGEX)
259-
regfree(&regex);
233+
if (regexp)
234+
regfree(regexp);
260235
else
261236
kwsfree(kws);
262237
return;
263238
}
264-
265-
void diffcore_pickaxe(struct diff_options *o)
266-
{
267-
/* Might want to warn when both S and G are on; I don't care... */
268-
if (o->pickaxe_opts & DIFF_PICKAXE_KIND_G)
269-
diffcore_pickaxe_grep(o);
270-
else
271-
diffcore_pickaxe_count(o);
272-
}

t/t4209-log-pickaxe.sh

Lines changed: 64 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3,82 +3,72 @@
33
test_description='log --grep/--author/--regexp-ignore-case/-S/-G'
44
. ./test-lib.sh
55

6+
test_log () {
7+
expect=$1
8+
kind=$2
9+
needle=$3
10+
shift 3
11+
rest=$@
12+
13+
case $kind in
14+
--*)
15+
opt=$kind=$needle
16+
;;
17+
*)
18+
opt=$kind$needle
19+
;;
20+
esac
21+
case $expect in
22+
expect_nomatch)
23+
match=nomatch
24+
;;
25+
*)
26+
match=match
27+
;;
28+
esac
29+
30+
test_expect_success "log $kind${rest:+ $rest} ($match)" "
31+
git log $rest $opt --format=%H >actual &&
32+
test_cmp $expect actual
33+
"
34+
}
35+
36+
# test -i and --regexp-ignore-case and expect both to behave the same way
37+
test_log_icase () {
38+
test_log $@ --regexp-ignore-case
39+
test_log $@ -i
40+
}
41+
642
test_expect_success setup '
43+
>expect_nomatch &&
44+
745
>file &&
846
git add file &&
947
test_tick &&
1048
git commit -m initial &&
49+
git rev-parse --verify HEAD >expect_initial &&
1150
1251
echo Picked >file &&
52+
git add file &&
1353
test_tick &&
14-
git commit -a --author="Another Person <[email protected]>" -m second
15-
'
16-
17-
test_expect_success 'log --grep' '
18-
git log --grep=initial --format=%H >actual &&
19-
git rev-parse --verify HEAD^ >expect &&
20-
test_cmp expect actual
21-
'
22-
23-
test_expect_success 'log --grep --regexp-ignore-case' '
24-
git log --regexp-ignore-case --grep=InItial --format=%H >actual &&
25-
git rev-parse --verify HEAD^ >expect &&
26-
test_cmp expect actual
27-
'
28-
29-
test_expect_success 'log --grep -i' '
30-
git log -i --grep=InItial --format=%H >actual &&
31-
git rev-parse --verify HEAD^ >expect &&
32-
test_cmp expect actual
33-
'
34-
35-
test_expect_success 'log --author --regexp-ignore-case' '
36-
git log --regexp-ignore-case --author=person --format=%H >actual &&
37-
git rev-parse --verify HEAD >expect &&
38-
test_cmp expect actual
39-
'
40-
41-
test_expect_success 'log --author -i' '
42-
git log -i --author=person --format=%H >actual &&
43-
git rev-parse --verify HEAD >expect &&
44-
test_cmp expect actual
45-
'
46-
47-
test_expect_success 'log -G (nomatch)' '
48-
git log -Gpicked --format=%H >actual &&
49-
>expect &&
50-
test_cmp expect actual
51-
'
52-
53-
test_expect_success 'log -G (match)' '
54-
git log -GPicked --format=%H >actual &&
55-
git rev-parse --verify HEAD >expect &&
56-
test_cmp expect actual
57-
'
58-
59-
test_expect_success 'log -G --regexp-ignore-case (nomatch)' '
60-
git log --regexp-ignore-case -Gpickle --format=%H >actual &&
61-
>expect &&
62-
test_cmp expect actual
54+
git commit --author="Another Person <[email protected]>" -m second &&
55+
git rev-parse --verify HEAD >expect_second
6356
'
6457

65-
test_expect_success 'log -G -i (nomatch)' '
66-
git log -i -Gpickle --format=%H >actual &&
67-
>expect &&
68-
test_cmp expect actual
69-
'
58+
test_log expect_initial --grep initial
59+
test_log expect_nomatch --grep InItial
60+
test_log_icase expect_initial --grep InItial
61+
test_log_icase expect_nomatch --grep initail
7062

71-
test_expect_success 'log -G --regexp-ignore-case (match)' '
72-
git log --regexp-ignore-case -Gpicked --format=%H >actual &&
73-
git rev-parse --verify HEAD >expect &&
74-
test_cmp expect actual
75-
'
63+
test_log expect_second --author Person
64+
test_log expect_nomatch --author person
65+
test_log_icase expect_second --author person
66+
test_log_icase expect_nomatch --author spreon
7667

77-
test_expect_success 'log -G -i (match)' '
78-
git log -i -Gpicked --format=%H >actual &&
79-
git rev-parse --verify HEAD >expect &&
80-
test_cmp expect actual
81-
'
68+
test_log expect_nomatch -G picked
69+
test_log expect_second -G Picked
70+
test_log_icase expect_nomatch -G pickle
71+
test_log_icase expect_second -G picked
8272

8373
test_expect_success 'log -G --textconv (missing textconv tool)' '
8474
echo "* diff=test" >.gitattributes &&
@@ -89,46 +79,19 @@ test_expect_success 'log -G --textconv (missing textconv tool)' '
8979
test_expect_success 'log -G --no-textconv (missing textconv tool)' '
9080
echo "* diff=test" >.gitattributes &&
9181
git -c diff.test.textconv=missing log -Gfoo --no-textconv >actual &&
92-
>expect &&
93-
test_cmp expect actual &&
82+
test_cmp expect_nomatch actual &&
9483
rm .gitattributes
9584
'
9685

97-
test_expect_success 'log -S (nomatch)' '
98-
git log -Spicked --format=%H >actual &&
99-
>expect &&
100-
test_cmp expect actual
101-
'
102-
103-
test_expect_success 'log -S (match)' '
104-
git log -SPicked --format=%H >actual &&
105-
git rev-parse --verify HEAD >expect &&
106-
test_cmp expect actual
107-
'
108-
109-
test_expect_success 'log -S --regexp-ignore-case (match)' '
110-
git log --regexp-ignore-case -Spicked --format=%H >actual &&
111-
git rev-parse --verify HEAD >expect &&
112-
test_cmp expect actual
113-
'
114-
115-
test_expect_success 'log -S -i (match)' '
116-
git log -i -Spicked --format=%H >actual &&
117-
git rev-parse --verify HEAD >expect &&
118-
test_cmp expect actual
119-
'
120-
121-
test_expect_success 'log -S --regexp-ignore-case (nomatch)' '
122-
git log --regexp-ignore-case -Spickle --format=%H >actual &&
123-
>expect &&
124-
test_cmp expect actual
125-
'
86+
test_log expect_nomatch -S picked
87+
test_log expect_second -S Picked
88+
test_log_icase expect_second -S picked
89+
test_log_icase expect_nomatch -S pickle
12690

127-
test_expect_success 'log -S -i (nomatch)' '
128-
git log -i -Spickle --format=%H >actual &&
129-
>expect &&
130-
test_cmp expect actual
131-
'
91+
test_log expect_nomatch -S p.cked --pickaxe-regex
92+
test_log expect_second -S P.cked --pickaxe-regex
93+
test_log_icase expect_second -S p.cked --pickaxe-regex
94+
test_log_icase expect_nomatch -S p.ckle --pickaxe-regex
13295

13396
test_expect_success 'log -S --textconv (missing textconv tool)' '
13497
echo "* diff=test" >.gitattributes &&
@@ -139,8 +102,7 @@ test_expect_success 'log -S --textconv (missing textconv tool)' '
139102
test_expect_success 'log -S --no-textconv (missing textconv tool)' '
140103
echo "* diff=test" >.gitattributes &&
141104
git -c diff.test.textconv=missing log -Sfoo --no-textconv >actual &&
142-
>expect &&
143-
test_cmp expect actual &&
105+
test_cmp expect_nomatch actual &&
144106
rm .gitattributes
145107
'
146108

0 commit comments

Comments
 (0)