t0008: avoid SIGPIPE race condition on fifo
[git.git] / t / t0008-ignores.sh
blobc29342d6bcd005ecc0eaee0ad5e17f65cdf45c3d
1 #!/bin/sh
3 test_description=check-ignore
5 . ./test-lib.sh
7 init_vars () {
8 global_excludes="$(pwd)/global-excludes"
11 enable_global_excludes () {
12 init_vars &&
13 git config core.excludesfile "$global_excludes"
16 expect_in () {
17 dest="$HOME/expected-$1" text="$2"
18 if test -z "$text"
19 then
20 >"$dest" # avoid newline
21 else
22 echo "$text" >"$dest"
26 expect () {
27 expect_in stdout "$1"
30 expect_from_stdin () {
31 cat >"$HOME/expected-stdout"
34 test_stderr () {
35 expected="$1"
36 expect_in stderr "$1" &&
37 test_cmp "$HOME/expected-stderr" "$HOME/stderr"
40 stderr_contains () {
41 regexp="$1"
42 if grep "$regexp" "$HOME/stderr"
43 then
44 return 0
45 else
46 echo "didn't find /$regexp/ in $HOME/stderr"
47 cat "$HOME/stderr"
48 return 1
52 stderr_empty_on_success () {
53 expect_code="$1"
54 if test $expect_code = 0
55 then
56 test_stderr ""
57 else
58 # If we expect failure then stderr might or might not be empty
59 # due to --quiet - the caller can check its contents
60 return 0
64 test_check_ignore () {
65 args="$1" expect_code="${2:-0}" global_args="$3"
67 init_vars &&
68 rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
69 echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
70 >"$HOME/cmd" &&
71 echo "$expect_code" >"$HOME/expected-exit-code" &&
72 test_expect_code "$expect_code" \
73 git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
74 >"$HOME/stdout" 2>"$HOME/stderr" &&
75 test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
76 stderr_empty_on_success "$expect_code"
79 # Runs the same code with 4 different levels of output verbosity:
81 # 1. with -q / --quiet
82 # 2. with default verbosity
83 # 3. with -v / --verbose
84 # 4. with -v / --verbose, *and* -n / --non-matching
86 # expecting success each time. Takes advantage of the fact that
87 # check-ignore --verbose output is the same as normal output except
88 # for the extra first column.
90 # Arguments:
91 # - (optional) prereqs for this test, e.g. 'SYMLINKS'
92 # - test name
93 # - output to expect from the fourth verbosity mode (the output
94 # from the other verbosity modes is automatically inferred
95 # from this value)
96 # - code to run (should invoke test_check_ignore)
97 test_expect_success_multi () {
98 prereq=
99 if test $# -eq 4
100 then
101 prereq=$1
102 shift
104 testname="$1" expect_all="$2" code="$3"
106 expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
107 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
109 test_expect_success $prereq "$testname" '
110 expect "$expect" &&
111 eval "$code"
114 # --quiet is only valid when a single pattern is passed
115 if test $( echo "$expect_all" | wc -l ) = 1
116 then
117 for quiet_opt in '-q' '--quiet'
119 test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
120 expect '' &&
121 $code
123 done
124 quiet_opt=
127 for verbose_opt in '-v' '--verbose'
129 for non_matching_opt in '' ' -n' ' --non-matching'
131 if test -n "$non_matching_opt"
132 then
133 my_expect="$expect_all"
134 else
135 my_expect="$expect_verbose"
138 test_code="
139 expect '$my_expect' &&
140 $code
142 opts="$verbose_opt$non_matching_opt"
143 test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
144 done
145 done
146 verbose_opt=
147 non_matching_opt=
150 test_expect_success 'setup' '
151 init_vars &&
152 mkdir -p a/b/ignored-dir a/submodule b &&
153 if test_have_prereq SYMLINKS
154 then
155 ln -s b a/symlink
156 fi &&
158 cd a/submodule &&
159 git init &&
160 echo a >a &&
161 git add a &&
162 git commit -m"commit in submodule"
163 ) &&
164 git add a/submodule &&
165 cat <<-\EOF >.gitignore &&
167 ignored-*
168 top-level-dir/
170 for dir in . a
172 : >$dir/not-ignored &&
173 : >$dir/ignored-and-untracked &&
174 : >$dir/ignored-but-in-index
175 done &&
176 git add -f ignored-but-in-index a/ignored-but-in-index &&
177 cat <<-\EOF >a/.gitignore &&
178 two*
179 *three
181 cat <<-\EOF >a/b/.gitignore &&
182 four
183 five
184 # this comment should affect the line numbers
186 ignored-dir/
187 # and so should this blank line:
189 !on*
190 !two
192 echo "seven" >a/b/ignored-dir/.gitignore &&
193 test -n "$HOME" &&
194 cat <<-\EOF >"$global_excludes" &&
195 globalone
196 !globaltwo
197 globalthree
199 cat <<-\EOF >>.git/info/exclude
200 per-repo
204 ############################################################################
206 # test invalid inputs
208 test_expect_success_multi '. corner-case' ':: .' '
209 test_check_ignore . 1
212 test_expect_success_multi 'empty command line' '' '
213 test_check_ignore "" 128 &&
214 stderr_contains "fatal: no path specified"
217 test_expect_success_multi '--stdin with empty STDIN' '' '
218 test_check_ignore "--stdin" 1 </dev/null &&
219 test_stderr ""
222 test_expect_success '-q with multiple args' '
223 expect "" &&
224 test_check_ignore "-q one two" 128 &&
225 stderr_contains "fatal: --quiet is only valid with a single pathname"
228 test_expect_success '--quiet with multiple args' '
229 expect "" &&
230 test_check_ignore "--quiet one two" 128 &&
231 stderr_contains "fatal: --quiet is only valid with a single pathname"
234 for verbose_opt in '-v' '--verbose'
236 for quiet_opt in '-q' '--quiet'
238 test_expect_success "$quiet_opt $verbose_opt" "
239 expect '' &&
240 test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
241 stderr_contains 'fatal: cannot have both --quiet and --verbose'
243 done
244 done
246 test_expect_success '--quiet with multiple args' '
247 expect "" &&
248 test_check_ignore "--quiet one two" 128 &&
249 stderr_contains "fatal: --quiet is only valid with a single pathname"
252 test_expect_success_multi 'erroneous use of --' '' '
253 test_check_ignore "--" 128 &&
254 stderr_contains "fatal: no path specified"
257 test_expect_success_multi '--stdin with superfluous arg' '' '
258 test_check_ignore "--stdin foo" 128 &&
259 stderr_contains "fatal: cannot specify pathnames with --stdin"
262 test_expect_success_multi '--stdin -z with superfluous arg' '' '
263 test_check_ignore "--stdin -z foo" 128 &&
264 stderr_contains "fatal: cannot specify pathnames with --stdin"
267 test_expect_success_multi '-z without --stdin' '' '
268 test_check_ignore "-z" 128 &&
269 stderr_contains "fatal: -z only makes sense with --stdin"
272 test_expect_success_multi '-z without --stdin and superfluous arg' '' '
273 test_check_ignore "-z foo" 128 &&
274 stderr_contains "fatal: -z only makes sense with --stdin"
277 test_expect_success_multi 'needs work tree' '' '
279 cd .git &&
280 test_check_ignore "foo" 128
281 ) &&
282 stderr_contains "fatal: This operation must be run in a work tree"
285 ############################################################################
287 # test standard ignores
289 # First make sure that the presence of a file in the working tree
290 # does not impact results, but that the presence of a file in the
291 # index does.
293 for subdir in '' 'a/'
295 if test -z "$subdir"
296 then
297 where="at top-level"
298 else
299 where="in subdir $subdir"
302 test_expect_success_multi "non-existent file $where not ignored" \
303 ":: ${subdir}non-existent" \
304 "test_check_ignore '${subdir}non-existent' 1"
306 test_expect_success_multi "non-existent file $where ignored" \
307 ".gitignore:1:one ${subdir}one" \
308 "test_check_ignore '${subdir}one'"
310 test_expect_success_multi "existing untracked file $where not ignored" \
311 ":: ${subdir}not-ignored" \
312 "test_check_ignore '${subdir}not-ignored' 1"
314 test_expect_success_multi "existing tracked file $where not ignored" \
315 ":: ${subdir}ignored-but-in-index" \
316 "test_check_ignore '${subdir}ignored-but-in-index' 1"
318 test_expect_success_multi "existing untracked file $where ignored" \
319 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
320 "test_check_ignore '${subdir}ignored-and-untracked'"
322 test_expect_success_multi "mix of file types $where" \
323 ":: ${subdir}non-existent
324 .gitignore:1:one ${subdir}one
325 :: ${subdir}not-ignored
326 :: ${subdir}ignored-but-in-index
327 .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
328 "test_check_ignore '
329 ${subdir}non-existent
330 ${subdir}one
331 ${subdir}not-ignored
332 ${subdir}ignored-but-in-index
333 ${subdir}ignored-and-untracked'
335 done
337 # Having established the above, from now on we mostly test against
338 # files which do not exist in the working tree or index.
340 test_expect_success 'sub-directory local ignore' '
341 expect "a/3-three" &&
342 test_check_ignore "a/3-three a/three-not-this-one"
345 test_expect_success 'sub-directory local ignore with --verbose' '
346 expect "a/.gitignore:2:*three a/3-three" &&
347 test_check_ignore "--verbose a/3-three a/three-not-this-one"
350 test_expect_success 'local ignore inside a sub-directory' '
351 expect "3-three" &&
353 cd a &&
354 test_check_ignore "3-three three-not-this-one"
357 test_expect_success 'local ignore inside a sub-directory with --verbose' '
358 expect "a/.gitignore:2:*three 3-three" &&
360 cd a &&
361 test_check_ignore "--verbose 3-three three-not-this-one"
365 test_expect_success_multi 'nested include' \
366 'a/b/.gitignore:8:!on* a/b/one' '
367 test_check_ignore "a/b/one"
370 ############################################################################
372 # test ignored sub-directories
374 test_expect_success_multi 'ignored sub-directory' \
375 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' '
376 test_check_ignore "a/b/ignored-dir"
379 test_expect_success 'multiple files inside ignored sub-directory' '
380 expect_from_stdin <<-\EOF &&
381 a/b/ignored-dir/foo
382 a/b/ignored-dir/twoooo
383 a/b/ignored-dir/seven
385 test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
388 test_expect_success 'multiple files inside ignored sub-directory with -v' '
389 expect_from_stdin <<-\EOF &&
390 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo
391 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo
392 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven
394 test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
397 test_expect_success 'cd to ignored sub-directory' '
398 expect_from_stdin <<-\EOF &&
400 twoooo
401 ../one
402 seven
403 ../../one
406 cd a/b/ignored-dir &&
407 test_check_ignore "foo twoooo ../one seven ../../one"
411 test_expect_success 'cd to ignored sub-directory with -v' '
412 expect_from_stdin <<-\EOF &&
413 a/b/.gitignore:5:ignored-dir/ foo
414 a/b/.gitignore:5:ignored-dir/ twoooo
415 a/b/.gitignore:8:!on* ../one
416 a/b/.gitignore:5:ignored-dir/ seven
417 .gitignore:1:one ../../one
420 cd a/b/ignored-dir &&
421 test_check_ignore "-v foo twoooo ../one seven ../../one"
425 ############################################################################
427 # test handling of symlinks
429 test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
430 test_check_ignore "a/symlink" 1
433 test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
434 test_check_ignore "a/symlink/foo" 128 &&
435 test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
438 test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
440 cd a &&
441 test_check_ignore "symlink/foo" 128
442 ) &&
443 test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
446 ############################################################################
448 # test handling of submodules
450 test_expect_success_multi 'submodule' '' '
451 test_check_ignore "a/submodule/one" 128 &&
452 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
455 test_expect_success_multi 'submodule from subdirectory' '' '
457 cd a &&
458 test_check_ignore "submodule/one" 128
459 ) &&
460 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
463 ############################################################################
465 # test handling of global ignore files
467 test_expect_success 'global ignore not yet enabled' '
468 expect_from_stdin <<-\EOF &&
469 .git/info/exclude:7:per-repo per-repo
470 a/.gitignore:2:*three a/globalthree
471 .git/info/exclude:7:per-repo a/per-repo
473 test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
476 test_expect_success 'global ignore' '
477 enable_global_excludes &&
478 expect_from_stdin <<-\EOF &&
479 globalone
480 per-repo
481 globalthree
482 a/globalthree
483 a/per-repo
484 globaltwo
486 test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
489 test_expect_success 'global ignore with -v' '
490 enable_global_excludes &&
491 expect_from_stdin <<-EOF &&
492 $global_excludes:1:globalone globalone
493 .git/info/exclude:7:per-repo per-repo
494 $global_excludes:3:globalthree globalthree
495 a/.gitignore:2:*three a/globalthree
496 .git/info/exclude:7:per-repo a/per-repo
497 $global_excludes:2:!globaltwo globaltwo
499 test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
502 ############################################################################
504 # test --stdin
506 cat <<-\EOF >stdin
508 not-ignored
509 a/one
510 a/not-ignored
511 a/b/on
512 a/b/one
513 a/b/one one
514 "a/b/one two"
515 "a/b/one\"three"
516 a/b/not-ignored
517 a/b/two
518 a/b/twooo
519 globaltwo
520 a/globaltwo
521 a/b/globaltwo
522 b/globaltwo
524 cat <<-\EOF >expected-default
526 a/one
527 a/b/on
528 a/b/one
529 a/b/one one
530 a/b/one two
531 "a/b/one\"three"
532 a/b/two
533 a/b/twooo
534 globaltwo
535 a/globaltwo
536 a/b/globaltwo
537 b/globaltwo
539 cat <<-EOF >expected-verbose
540 .gitignore:1:one one
541 .gitignore:1:one a/one
542 a/b/.gitignore:8:!on* a/b/on
543 a/b/.gitignore:8:!on* a/b/one
544 a/b/.gitignore:8:!on* a/b/one one
545 a/b/.gitignore:8:!on* a/b/one two
546 a/b/.gitignore:8:!on* "a/b/one\"three"
547 a/b/.gitignore:9:!two a/b/two
548 a/.gitignore:1:two* a/b/twooo
549 $global_excludes:2:!globaltwo globaltwo
550 $global_excludes:2:!globaltwo a/globaltwo
551 $global_excludes:2:!globaltwo a/b/globaltwo
552 $global_excludes:2:!globaltwo b/globaltwo
555 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
556 tr "\n" "\0" >stdin0
557 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
558 tr "\n" "\0" >expected-default0
559 sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
560 tr ":\t\n" "\0" >expected-verbose0
562 test_expect_success '--stdin' '
563 expect_from_stdin <expected-default &&
564 test_check_ignore "--stdin" <stdin
567 test_expect_success '--stdin -q' '
568 expect "" &&
569 test_check_ignore "-q --stdin" <stdin
572 test_expect_success '--stdin -v' '
573 expect_from_stdin <expected-verbose &&
574 test_check_ignore "-v --stdin" <stdin
577 for opts in '--stdin -z' '-z --stdin'
579 test_expect_success "$opts" "
580 expect_from_stdin <expected-default0 &&
581 test_check_ignore '$opts' <stdin0
584 test_expect_success "$opts -q" "
585 expect "" &&
586 test_check_ignore '-q $opts' <stdin0
589 test_expect_success "$opts -v" "
590 expect_from_stdin <expected-verbose0 &&
591 test_check_ignore '-v $opts' <stdin0
593 done
595 cat <<-\EOF >stdin
596 ../one
597 ../not-ignored
599 not-ignored
600 b/on
601 b/one
602 b/one one
603 "b/one two"
604 "b/one\"three"
605 b/two
606 b/not-ignored
607 b/twooo
608 ../globaltwo
609 globaltwo
610 b/globaltwo
611 ../b/globaltwo
612 c/not-ignored
614 # N.B. we deliberately end STDIN with a non-matching pattern in order
615 # to test that the exit code indicates that one or more of the
616 # provided paths is ignored - in other words, that it represents an
617 # aggregation of all the results, not just the final result.
619 cat <<-EOF >expected-all
620 .gitignore:1:one ../one
621 :: ../not-ignored
622 .gitignore:1:one one
623 :: not-ignored
624 a/b/.gitignore:8:!on* b/on
625 a/b/.gitignore:8:!on* b/one
626 a/b/.gitignore:8:!on* b/one one
627 a/b/.gitignore:8:!on* b/one two
628 a/b/.gitignore:8:!on* "b/one\"three"
629 a/b/.gitignore:9:!two b/two
630 :: b/not-ignored
631 a/.gitignore:1:two* b/twooo
632 $global_excludes:2:!globaltwo ../globaltwo
633 $global_excludes:2:!globaltwo globaltwo
634 $global_excludes:2:!globaltwo b/globaltwo
635 $global_excludes:2:!globaltwo ../b/globaltwo
636 :: c/not-ignored
638 grep -v '^:: ' expected-all >expected-verbose
639 sed -e 's/.* //' expected-verbose >expected-default
641 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
642 tr "\n" "\0" >stdin0
643 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
644 tr "\n" "\0" >expected-default0
645 sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
646 tr ":\t\n" "\0" >expected-verbose0
648 test_expect_success '--stdin from subdirectory' '
649 expect_from_stdin <expected-default &&
651 cd a &&
652 test_check_ignore "--stdin" <../stdin
656 test_expect_success '--stdin from subdirectory with -v' '
657 expect_from_stdin <expected-verbose &&
659 cd a &&
660 test_check_ignore "--stdin -v" <../stdin
664 test_expect_success '--stdin from subdirectory with -v -n' '
665 expect_from_stdin <expected-all &&
667 cd a &&
668 test_check_ignore "--stdin -v -n" <../stdin
672 for opts in '--stdin -z' '-z --stdin'
674 test_expect_success "$opts from subdirectory" '
675 expect_from_stdin <expected-default0 &&
677 cd a &&
678 test_check_ignore "'"$opts"'" <../stdin0
682 test_expect_success "$opts from subdirectory with -v" '
683 expect_from_stdin <expected-verbose0 &&
685 cd a &&
686 test_check_ignore "'"$opts"' -v" <../stdin0
689 done
691 test_expect_success PIPE 'streaming support for --stdin' '
692 mkfifo in out &&
693 (git check-ignore -n -v --stdin <in >out &) &&
695 # We cannot just "echo >in" because check-ignore would get EOF
696 # after echo exited; instead we open the descriptor in our
697 # shell, and then echo to the fd. We make sure to close it at
698 # the end, so that the subprocess does get EOF and dies
699 # properly.
701 # Similarly, we must keep "out" open so that check-ignore does
702 # not ever get SIGPIPE trying to write to us. Not only would that
703 # produce incorrect results, but then there would be no writer on the
704 # other end of the pipe, and we would potentially block forever trying
705 # to open it.
706 exec 9>in &&
707 exec 8<out &&
708 test_when_finished "exec 9>&-" &&
709 test_when_finished "exec 8<&-" &&
710 echo >&9 one &&
711 read response <&8 &&
712 echo "$response" | grep "^\.gitignore:1:one one" &&
713 echo >&9 two &&
714 read response <&8 &&
715 echo "$response" | grep "^:: two"
718 test_done