| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='blob conversion via gitattributes' |
| 4 | |
| 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
| 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | . "$TEST_DIRECTORY"/lib-terminal.sh |
| 10 | |
| 11 | PATH=$PWD:$PATH |
| 12 | TEST_ROOT="$(pwd)" |
| 13 | |
| 14 | write_script <<\EOF "$TEST_ROOT/rot13.sh" |
| 15 | tr \ |
| 16 | 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' \ |
| 17 | 'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' |
| 18 | EOF |
| 19 | |
| 20 | generate_random_characters () { |
| 21 | LEN=$1 |
| 22 | NAME=$2 |
| 23 | test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME" |
| 24 | } |
| 25 | |
| 26 | filter_git () { |
| 27 | rm -f *.log && |
| 28 | git "$@" |
| 29 | } |
| 30 | |
| 31 | # Compare two files and ensure that `clean` and `smudge` respectively are |
| 32 | # called at least once if specified in the `expect` file. The actual |
| 33 | # invocation count is not relevant because their number can vary. |
| 34 | # c.f. https://lore.kernel.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/ |
| 35 | test_cmp_count () { |
| 36 | expect=$1 |
| 37 | actual=$2 |
| 38 | for FILE in "$expect" "$actual" |
| 39 | do |
| 40 | sort "$FILE" | uniq -c | |
| 41 | sed -e "s/^ *[0-9][0-9]*[ ]*IN: /x IN: /" >"$FILE.tmp" |
| 42 | done && |
| 43 | test_cmp "$expect.tmp" "$actual.tmp" && |
| 44 | rm "$expect.tmp" "$actual.tmp" |
| 45 | } |
| 46 | |
| 47 | # Compare two files but exclude all `clean` invocations because Git can |
| 48 | # call `clean` zero or more times. |
| 49 | # c.f. https://lore.kernel.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/ |
| 50 | test_cmp_exclude_clean () { |
| 51 | expect=$1 |
| 52 | actual=$2 |
| 53 | for FILE in "$expect" "$actual" |
| 54 | do |
| 55 | grep -v "IN: clean" "$FILE" >"$FILE.tmp" |
| 56 | done && |
| 57 | test_cmp "$expect.tmp" "$actual.tmp" && |
| 58 | rm "$expect.tmp" "$actual.tmp" |
| 59 | } |
| 60 | |
| 61 | # Check that the contents of two files are equal and that their rot13 version |
| 62 | # is equal to the committed content. |
| 63 | test_cmp_committed_rot13 () { |
| 64 | test_cmp "$1" "$2" && |
| 65 | rot13.sh <"$1" >expected && |
| 66 | git cat-file blob :"$2" >actual && |
| 67 | test_cmp expected actual |
| 68 | } |
| 69 | |
| 70 | test_expect_success setup ' |
| 71 | git config filter.rot13.smudge ./rot13.sh && |
| 72 | git config filter.rot13.clean ./rot13.sh && |
| 73 | |
| 74 | { |
| 75 | echo "*.t filter=rot13" && |
| 76 | echo "*.i ident" |
| 77 | } >.gitattributes && |
| 78 | |
| 79 | { |
| 80 | echo a b c d e f g h i j k l m && |
| 81 | echo n o p q r s t u v w x y z && |
| 82 | echo '\''$Id$'\'' |
| 83 | } >test && |
| 84 | cat test >test.t && |
| 85 | cat test >test.o && |
| 86 | cat test >test.i && |
| 87 | git add test test.t test.i && |
| 88 | rm -f test test.t test.i && |
| 89 | git checkout -- test test.t test.i && |
| 90 | |
| 91 | echo "content-test2" >test2.o && |
| 92 | echo "content-test3 - filename with special characters" >"test3 '\''sq'\'',\$x=.o" |
| 93 | ' |
| 94 | |
| 95 | script='s/^\$Id: \([0-9a-f]*\) \$/\1/p' |
| 96 | |
| 97 | test_expect_success check ' |
| 98 | |
| 99 | test_cmp test.o test && |
| 100 | test_cmp test.o test.t && |
| 101 | |
| 102 | # ident should be stripped in the repository |
| 103 | git diff --raw --exit-code :test :test.i && |
| 104 | id=$(git rev-parse --verify :test) && |
| 105 | embedded=$(sed -ne "$script" test.i) && |
| 106 | test "z$id" = "z$embedded" && |
| 107 | |
| 108 | git cat-file blob :test.t >test.r && |
| 109 | |
| 110 | ./rot13.sh <test.o >test.t && |
| 111 | test_cmp test.r test.t |
| 112 | ' |
| 113 | |
| 114 | # If an expanded ident ever gets into the repository, we want to make sure that |
| 115 | # it is collapsed before being expanded again on checkout |
| 116 | test_expect_success expanded_in_repo ' |
| 117 | cat >expanded-keywords.0 <<-\EOF && |
| 118 | File with expanded keywords |
| 119 | $Id$ |
| 120 | $Id:$ |
| 121 | $Id: 0000000000000000000000000000000000000000 $ |
| 122 | $Id: NoSpaceAtEnd$ |
| 123 | $Id:NoSpaceAtFront $ |
| 124 | $Id:NoSpaceAtEitherEnd$ |
| 125 | $Id: NoTerminatingSymbol |
| 126 | $Id: Foreign Commit With Spaces $ |
| 127 | EOF |
| 128 | |
| 129 | { |
| 130 | cat expanded-keywords.0 && |
| 131 | printf "\$Id: NoTerminatingSymbolAtEOF" |
| 132 | } >expanded-keywords && |
| 133 | cat expanded-keywords >expanded-keywords-crlf && |
| 134 | git add expanded-keywords expanded-keywords-crlf && |
| 135 | git commit -m "File with keywords expanded" && |
| 136 | id=$(git rev-parse --verify :expanded-keywords) && |
| 137 | |
| 138 | cat >expected-output.0 <<-EOF && |
| 139 | File with expanded keywords |
| 140 | \$Id: $id \$ |
| 141 | \$Id: $id \$ |
| 142 | \$Id: $id \$ |
| 143 | \$Id: $id \$ |
| 144 | \$Id: $id \$ |
| 145 | \$Id: $id \$ |
| 146 | \$Id: NoTerminatingSymbol |
| 147 | \$Id: Foreign Commit With Spaces \$ |
| 148 | EOF |
| 149 | { |
| 150 | cat expected-output.0 && |
| 151 | printf "\$Id: NoTerminatingSymbolAtEOF" |
| 152 | } >expected-output && |
| 153 | { |
| 154 | append_cr <expected-output.0 && |
| 155 | printf "\$Id: NoTerminatingSymbolAtEOF" |
| 156 | } >expected-output-crlf && |
| 157 | { |
| 158 | echo "expanded-keywords ident" && |
| 159 | echo "expanded-keywords-crlf ident text eol=crlf" |
| 160 | } >>.gitattributes && |
| 161 | |
| 162 | rm -f expanded-keywords expanded-keywords-crlf && |
| 163 | |
| 164 | git checkout -- expanded-keywords && |
| 165 | test_cmp expected-output expanded-keywords && |
| 166 | |
| 167 | git checkout -- expanded-keywords-crlf && |
| 168 | test_cmp expected-output-crlf expanded-keywords-crlf |
| 169 | ' |
| 170 | |
| 171 | # The use of %f in a filter definition is expanded to the path to |
| 172 | # the filename being smudged or cleaned. It must be shell escaped. |
| 173 | # First, set up some interesting file names and pet them in |
| 174 | # .gitattributes. |
| 175 | test_expect_success 'filter shell-escaped filenames' ' |
| 176 | cat >argc.sh <<-EOF && |
| 177 | #!$SHELL_PATH |
| 178 | cat >/dev/null |
| 179 | echo argc: \$# "\$@" |
| 180 | EOF |
| 181 | normal=name-no-magic && |
| 182 | special="name with '\''sq'\'' and \$x" && |
| 183 | echo some test text >"$normal" && |
| 184 | echo some test text >"$special" && |
| 185 | git add "$normal" "$special" && |
| 186 | git commit -q -m "add files" && |
| 187 | echo "name* filter=argc" >.gitattributes && |
| 188 | |
| 189 | # delete the files and check them out again, using a smudge filter |
| 190 | # that will count the args and echo the command-line back to us |
| 191 | test_config filter.argc.smudge "sh ./argc.sh %f" && |
| 192 | rm "$normal" "$special" && |
| 193 | git checkout -- "$normal" "$special" && |
| 194 | |
| 195 | # make sure argc.sh counted the right number of args |
| 196 | echo "argc: 1 $normal" >expect && |
| 197 | test_cmp expect "$normal" && |
| 198 | echo "argc: 1 $special" >expect && |
| 199 | test_cmp expect "$special" && |
| 200 | |
| 201 | # do the same thing, but with more args in the filter expression |
| 202 | test_config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" && |
| 203 | rm "$normal" "$special" && |
| 204 | git checkout -- "$normal" "$special" && |
| 205 | |
| 206 | # make sure argc.sh counted the right number of args |
| 207 | echo "argc: 2 $normal --my-extra-arg" >expect && |
| 208 | test_cmp expect "$normal" && |
| 209 | echo "argc: 2 $special --my-extra-arg" >expect && |
| 210 | test_cmp expect "$special" && |
| 211 | : |
| 212 | ' |
| 213 | |
| 214 | test_expect_success 'required filter should filter data' ' |
| 215 | test_config filter.required.smudge ./rot13.sh && |
| 216 | test_config filter.required.clean ./rot13.sh && |
| 217 | test_config filter.required.required true && |
| 218 | |
| 219 | echo "*.r filter=required" >.gitattributes && |
| 220 | |
| 221 | cat test.o >test.r && |
| 222 | git add test.r && |
| 223 | |
| 224 | rm -f test.r && |
| 225 | git checkout -- test.r && |
| 226 | test_cmp test.o test.r && |
| 227 | |
| 228 | ./rot13.sh <test.o >expected && |
| 229 | git cat-file blob :test.r >actual && |
| 230 | test_cmp expected actual |
| 231 | ' |
| 232 | |
| 233 | test_expect_success 'required filter smudge failure' ' |
| 234 | test_config filter.failsmudge.smudge false && |
| 235 | test_config filter.failsmudge.clean cat && |
| 236 | test_config filter.failsmudge.required true && |
| 237 | |
| 238 | echo "*.fs filter=failsmudge" >.gitattributes && |
| 239 | |
| 240 | echo test >test.fs && |
| 241 | git add test.fs && |
| 242 | rm -f test.fs && |
| 243 | test_must_fail git checkout -- test.fs |
| 244 | ' |
| 245 | |
| 246 | test_expect_success 'required filter clean failure' ' |
| 247 | test_config filter.failclean.smudge cat && |
| 248 | test_config filter.failclean.clean false && |
| 249 | test_config filter.failclean.required true && |
| 250 | |
| 251 | echo "*.fc filter=failclean" >.gitattributes && |
| 252 | |
| 253 | echo test >test.fc && |
| 254 | test_must_fail git add test.fc |
| 255 | ' |
| 256 | |
| 257 | test_expect_success 'required filter with absent clean field' ' |
| 258 | test_config filter.absentclean.smudge cat && |
| 259 | test_config filter.absentclean.required true && |
| 260 | |
| 261 | echo "*.ac filter=absentclean" >.gitattributes && |
| 262 | |
| 263 | echo test >test.ac && |
| 264 | test_must_fail git add test.ac 2>stderr && |
| 265 | test_grep "fatal: test.ac: clean filter .absentclean. failed" stderr |
| 266 | ' |
| 267 | |
| 268 | test_expect_success 'required filter with absent smudge field' ' |
| 269 | test_config filter.absentsmudge.clean cat && |
| 270 | test_config filter.absentsmudge.required true && |
| 271 | |
| 272 | echo "*.as filter=absentsmudge" >.gitattributes && |
| 273 | |
| 274 | echo test >test.as && |
| 275 | git add test.as && |
| 276 | rm -f test.as && |
| 277 | test_must_fail git checkout -- test.as 2>stderr && |
| 278 | test_grep "fatal: test.as: smudge filter absentsmudge failed" stderr |
| 279 | ' |
| 280 | |
| 281 | test_expect_success 'filtering large input to small output should use little memory' ' |
| 282 | test_config filter.devnull.clean "cat >/dev/null" && |
| 283 | test_config filter.devnull.required true && |
| 284 | test_seq -f "%1048576d" 1 30 >30MB && |
| 285 | echo "30MB filter=devnull" >.gitattributes && |
| 286 | GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB |
| 287 | ' |
| 288 | |
| 289 | test_expect_success 'filter that does not read is fine' ' |
| 290 | test-tool genrandom foo $((128 * 1024 + 1)) >big && |
| 291 | echo "big filter=epipe" >.gitattributes && |
| 292 | test_config filter.epipe.clean "echo xyzzy" && |
| 293 | git add big && |
| 294 | git cat-file blob :big >actual && |
| 295 | echo xyzzy >expect && |
| 296 | test_cmp expect actual |
| 297 | ' |
| 298 | |
| 299 | test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'filter large file' ' |
| 300 | test_config filter.largefile.smudge cat && |
| 301 | test_config filter.largefile.clean cat && |
| 302 | test_seq -f "%1048576d" 1 2048 >2GB && |
| 303 | echo "2GB filter=largefile" >.gitattributes && |
| 304 | git add 2GB 2>err && |
| 305 | test_must_be_empty err && |
| 306 | rm -f 2GB && |
| 307 | git checkout -- 2GB 2>err && |
| 308 | test_must_be_empty err |
| 309 | ' |
| 310 | |
| 311 | test_expect_success "filter: clean empty file" ' |
| 312 | test_config filter.in-repo-header.clean "echo cleaned && cat" && |
| 313 | test_config filter.in-repo-header.smudge "sed 1d" && |
| 314 | |
| 315 | echo "empty-in-worktree filter=in-repo-header" >>.gitattributes && |
| 316 | >empty-in-worktree && |
| 317 | |
| 318 | echo cleaned >expected && |
| 319 | git add empty-in-worktree && |
| 320 | git show :empty-in-worktree >actual && |
| 321 | test_cmp expected actual |
| 322 | ' |
| 323 | |
| 324 | test_expect_success "filter: smudge empty file" ' |
| 325 | test_config filter.empty-in-repo.clean "cat >/dev/null" && |
| 326 | test_config filter.empty-in-repo.smudge "echo smudged && cat" && |
| 327 | |
| 328 | echo "empty-in-repo filter=empty-in-repo" >>.gitattributes && |
| 329 | echo dead data walking >empty-in-repo && |
| 330 | git add empty-in-repo && |
| 331 | |
| 332 | echo smudged >expected && |
| 333 | git checkout-index --prefix=filtered- empty-in-repo && |
| 334 | test_cmp expected filtered-empty-in-repo |
| 335 | ' |
| 336 | |
| 337 | test_expect_success 'disable filter with empty override' ' |
| 338 | test_config_global filter.disable.smudge false && |
| 339 | test_config_global filter.disable.clean false && |
| 340 | test_config filter.disable.smudge false && |
| 341 | test_config filter.disable.clean false && |
| 342 | |
| 343 | echo "*.disable filter=disable" >.gitattributes && |
| 344 | |
| 345 | echo test >test.disable && |
| 346 | git -c filter.disable.clean= add test.disable 2>err && |
| 347 | test_must_be_empty err && |
| 348 | rm -f test.disable && |
| 349 | git -c filter.disable.smudge= checkout -- test.disable 2>err && |
| 350 | test_must_be_empty err |
| 351 | ' |
| 352 | |
| 353 | test_expect_success 'diff does not reuse worktree files that need cleaning' ' |
| 354 | test_config filter.counter.clean "echo . >>count; sed s/^/clean:/" && |
| 355 | echo "file filter=counter" >.gitattributes && |
| 356 | test_commit one file && |
| 357 | test_commit two file && |
| 358 | |
| 359 | >count && |
| 360 | git diff-tree -p HEAD && |
| 361 | test_line_count = 0 count |
| 362 | ' |
| 363 | |
| 364 | test_expect_success 'required process filter should filter data' ' |
| 365 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 366 | test_config_global filter.protocol.required true && |
| 367 | rm -rf repo && |
| 368 | mkdir repo && |
| 369 | ( |
| 370 | cd repo && |
| 371 | git init && |
| 372 | |
| 373 | echo "*.r filter=protocol" >.gitattributes && |
| 374 | git add . && |
| 375 | git commit -m "test commit 1" && |
| 376 | git branch empty-branch && |
| 377 | |
| 378 | cp "$TEST_ROOT/test.o" test.r && |
| 379 | cp "$TEST_ROOT/test2.o" test2.r && |
| 380 | mkdir testsubdir && |
| 381 | cp "$TEST_ROOT/test3 '\''sq'\'',\$x=.o" "testsubdir/test3 '\''sq'\'',\$x=.r" && |
| 382 | >test4-empty.r && |
| 383 | |
| 384 | S=$(test_file_size test.r) && |
| 385 | S2=$(test_file_size test2.r) && |
| 386 | S3=$(test_file_size "testsubdir/test3 '\''sq'\'',\$x=.r") && |
| 387 | M=$(git hash-object test.r) && |
| 388 | M2=$(git hash-object test2.r) && |
| 389 | M3=$(git hash-object "testsubdir/test3 '\''sq'\'',\$x=.r") && |
| 390 | EMPTY=$(git hash-object /dev/null) && |
| 391 | |
| 392 | filter_git add . && |
| 393 | cat >expected.log <<-EOF && |
| 394 | START |
| 395 | init handshake complete |
| 396 | IN: clean test.r $S [OK] -- OUT: $S . [OK] |
| 397 | IN: clean test2.r $S2 [OK] -- OUT: $S2 . [OK] |
| 398 | IN: clean test4-empty.r 0 [OK] -- OUT: 0 [OK] |
| 399 | IN: clean testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK] |
| 400 | STOP |
| 401 | EOF |
| 402 | test_cmp_count expected.log debug.log && |
| 403 | |
| 404 | git commit -m "test commit 2" && |
| 405 | MAIN=$(git rev-parse --verify main) && |
| 406 | META="ref=refs/heads/main treeish=$MAIN" && |
| 407 | rm -f test2.r "testsubdir/test3 '\''sq'\'',\$x=.r" && |
| 408 | |
| 409 | filter_git checkout --quiet --no-progress . && |
| 410 | cat >expected.log <<-EOF && |
| 411 | START |
| 412 | init handshake complete |
| 413 | IN: smudge test2.r blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 414 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 415 | STOP |
| 416 | EOF |
| 417 | test_cmp_exclude_clean expected.log debug.log && |
| 418 | |
| 419 | # Make sure that the file appears dirty, so checkout below has to |
| 420 | # run the configured filter. |
| 421 | touch test.r && |
| 422 | filter_git checkout --quiet --no-progress empty-branch && |
| 423 | cat >expected.log <<-EOF && |
| 424 | START |
| 425 | init handshake complete |
| 426 | IN: clean test.r $S [OK] -- OUT: $S . [OK] |
| 427 | STOP |
| 428 | EOF |
| 429 | test_cmp_exclude_clean expected.log debug.log && |
| 430 | |
| 431 | filter_git checkout --quiet --no-progress main && |
| 432 | cat >expected.log <<-EOF && |
| 433 | START |
| 434 | init handshake complete |
| 435 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 436 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 437 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 438 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 439 | STOP |
| 440 | EOF |
| 441 | test_cmp_exclude_clean expected.log debug.log && |
| 442 | |
| 443 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r && |
| 444 | test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r && |
| 445 | test_cmp_committed_rot13 "$TEST_ROOT/test3 '\''sq'\'',\$x=.o" "testsubdir/test3 '\''sq'\'',\$x=.r" |
| 446 | ) |
| 447 | ' |
| 448 | |
| 449 | test_expect_success 'required process filter should filter data for various subcommands' ' |
| 450 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 451 | test_config_global filter.protocol.required true && |
| 452 | ( |
| 453 | cd repo && |
| 454 | |
| 455 | S=$(test_file_size test.r) && |
| 456 | S2=$(test_file_size test2.r) && |
| 457 | S3=$(test_file_size "testsubdir/test3 '\''sq'\'',\$x=.r") && |
| 458 | M=$(git hash-object test.r) && |
| 459 | M2=$(git hash-object test2.r) && |
| 460 | M3=$(git hash-object "testsubdir/test3 '\''sq'\'',\$x=.r") && |
| 461 | EMPTY=$(git hash-object /dev/null) && |
| 462 | |
| 463 | MAIN=$(git rev-parse --verify main) && |
| 464 | |
| 465 | cp "$TEST_ROOT/test.o" test5.r && |
| 466 | git add test5.r && |
| 467 | git commit -m "test commit 3" && |
| 468 | git checkout empty-branch && |
| 469 | filter_git rebase --onto empty-branch main^^ main && |
| 470 | MAIN2=$(git rev-parse --verify main) && |
| 471 | META="ref=refs/heads/main treeish=$MAIN2" && |
| 472 | cat >expected.log <<-EOF && |
| 473 | START |
| 474 | init handshake complete |
| 475 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 476 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 477 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 478 | IN: smudge test5.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 479 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 480 | STOP |
| 481 | EOF |
| 482 | test_cmp_exclude_clean expected.log debug.log && |
| 483 | |
| 484 | git reset --hard empty-branch && |
| 485 | filter_git reset --hard $MAIN && |
| 486 | META="treeish=$MAIN" && |
| 487 | cat >expected.log <<-EOF && |
| 488 | START |
| 489 | init handshake complete |
| 490 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 491 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 492 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 493 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 494 | STOP |
| 495 | EOF |
| 496 | test_cmp_exclude_clean expected.log debug.log && |
| 497 | |
| 498 | git branch old-main $MAIN && |
| 499 | git reset --hard empty-branch && |
| 500 | filter_git reset --hard old-main && |
| 501 | META="ref=refs/heads/old-main treeish=$MAIN" && |
| 502 | cat >expected.log <<-EOF && |
| 503 | START |
| 504 | init handshake complete |
| 505 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 506 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 507 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 508 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 509 | STOP |
| 510 | EOF |
| 511 | test_cmp_exclude_clean expected.log debug.log && |
| 512 | |
| 513 | git checkout -b merge empty-branch && |
| 514 | git branch -f main $MAIN2 && |
| 515 | filter_git merge main && |
| 516 | META="treeish=$MAIN2" && |
| 517 | cat >expected.log <<-EOF && |
| 518 | START |
| 519 | init handshake complete |
| 520 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 521 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 522 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 523 | IN: smudge test5.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 524 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 525 | STOP |
| 526 | EOF |
| 527 | test_cmp_exclude_clean expected.log debug.log && |
| 528 | |
| 529 | filter_git archive main >/dev/null && |
| 530 | META="ref=refs/heads/main treeish=$MAIN2" && |
| 531 | cat >expected.log <<-EOF && |
| 532 | START |
| 533 | init handshake complete |
| 534 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 535 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 536 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 537 | IN: smudge test5.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 538 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 539 | STOP |
| 540 | EOF |
| 541 | test_cmp_exclude_clean expected.log debug.log && |
| 542 | |
| 543 | TREE="$(git rev-parse $MAIN2^{tree})" && |
| 544 | filter_git archive $TREE >/dev/null && |
| 545 | META="treeish=$TREE" && |
| 546 | cat >expected.log <<-EOF && |
| 547 | START |
| 548 | init handshake complete |
| 549 | IN: smudge test.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 550 | IN: smudge test2.r $META blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 551 | IN: smudge test4-empty.r $META blob=$EMPTY 0 [OK] -- OUT: 0 [OK] |
| 552 | IN: smudge test5.r $META blob=$M $S [OK] -- OUT: $S . [OK] |
| 553 | IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $META blob=$M3 $S3 [OK] -- OUT: $S3 . [OK] |
| 554 | STOP |
| 555 | EOF |
| 556 | test_cmp_exclude_clean expected.log debug.log |
| 557 | ) |
| 558 | ' |
| 559 | |
| 560 | test_expect_success 'required process filter takes precedence' ' |
| 561 | test_config_global filter.protocol.clean false && |
| 562 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean" && |
| 563 | test_config_global filter.protocol.required true && |
| 564 | rm -rf repo && |
| 565 | mkdir repo && |
| 566 | ( |
| 567 | cd repo && |
| 568 | git init && |
| 569 | |
| 570 | echo "*.r filter=protocol" >.gitattributes && |
| 571 | cp "$TEST_ROOT/test.o" test.r && |
| 572 | S=$(test_file_size test.r) && |
| 573 | |
| 574 | # Check that the process filter is invoked here |
| 575 | filter_git add . && |
| 576 | cat >expected.log <<-EOF && |
| 577 | START |
| 578 | init handshake complete |
| 579 | IN: clean test.r $S [OK] -- OUT: $S . [OK] |
| 580 | STOP |
| 581 | EOF |
| 582 | test_cmp_count expected.log debug.log |
| 583 | ) |
| 584 | ' |
| 585 | |
| 586 | test_expect_success 'required process filter should be used only for "clean" operation only' ' |
| 587 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean" && |
| 588 | rm -rf repo && |
| 589 | mkdir repo && |
| 590 | ( |
| 591 | cd repo && |
| 592 | git init && |
| 593 | |
| 594 | echo "*.r filter=protocol" >.gitattributes && |
| 595 | cp "$TEST_ROOT/test.o" test.r && |
| 596 | S=$(test_file_size test.r) && |
| 597 | |
| 598 | filter_git add . && |
| 599 | cat >expected.log <<-EOF && |
| 600 | START |
| 601 | init handshake complete |
| 602 | IN: clean test.r $S [OK] -- OUT: $S . [OK] |
| 603 | STOP |
| 604 | EOF |
| 605 | test_cmp_count expected.log debug.log && |
| 606 | |
| 607 | rm test.r && |
| 608 | |
| 609 | filter_git checkout --quiet --no-progress . && |
| 610 | # If the filter would be used for "smudge", too, we would see |
| 611 | # "IN: smudge test.r 57 [OK] -- OUT: 57 . [OK]" here |
| 612 | cat >expected.log <<-EOF && |
| 613 | START |
| 614 | init handshake complete |
| 615 | STOP |
| 616 | EOF |
| 617 | test_cmp_exclude_clean expected.log debug.log |
| 618 | ) |
| 619 | ' |
| 620 | |
| 621 | test_expect_success 'required process filter should process multiple packets' ' |
| 622 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 623 | test_config_global filter.protocol.required true && |
| 624 | |
| 625 | rm -rf repo && |
| 626 | mkdir repo && |
| 627 | ( |
| 628 | cd repo && |
| 629 | git init && |
| 630 | |
| 631 | # Generate data requiring 1, 2, 3 packets |
| 632 | S=65516 && # PKTLINE_DATA_MAXLEN -> Maximal size of a packet |
| 633 | generate_random_characters $(($S )) 1pkt_1__.file && |
| 634 | generate_random_characters $(($S +1)) 2pkt_1+1.file && |
| 635 | generate_random_characters $(($S*2-1)) 2pkt_2-1.file && |
| 636 | generate_random_characters $(($S*2 )) 2pkt_2__.file && |
| 637 | generate_random_characters $(($S*2+1)) 3pkt_2+1.file && |
| 638 | |
| 639 | for FILE in "$TEST_ROOT"/*.file |
| 640 | do |
| 641 | cp "$FILE" . && |
| 642 | rot13.sh <"$FILE" >"$FILE.rot13" || return 1 |
| 643 | done && |
| 644 | |
| 645 | echo "*.file filter=protocol" >.gitattributes && |
| 646 | filter_git add *.file .gitattributes && |
| 647 | cat >expected.log <<-EOF && |
| 648 | START |
| 649 | init handshake complete |
| 650 | IN: clean 1pkt_1__.file $(($S )) [OK] -- OUT: $(($S )) . [OK] |
| 651 | IN: clean 2pkt_1+1.file $(($S +1)) [OK] -- OUT: $(($S +1)) .. [OK] |
| 652 | IN: clean 2pkt_2-1.file $(($S*2-1)) [OK] -- OUT: $(($S*2-1)) .. [OK] |
| 653 | IN: clean 2pkt_2__.file $(($S*2 )) [OK] -- OUT: $(($S*2 )) .. [OK] |
| 654 | IN: clean 3pkt_2+1.file $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK] |
| 655 | STOP |
| 656 | EOF |
| 657 | test_cmp_count expected.log debug.log && |
| 658 | |
| 659 | M1="blob=$(git hash-object 1pkt_1__.file)" && |
| 660 | M2="blob=$(git hash-object 2pkt_1+1.file)" && |
| 661 | M3="blob=$(git hash-object 2pkt_2-1.file)" && |
| 662 | M4="blob=$(git hash-object 2pkt_2__.file)" && |
| 663 | M5="blob=$(git hash-object 3pkt_2+1.file)" && |
| 664 | rm -f *.file debug.log && |
| 665 | |
| 666 | filter_git checkout --quiet --no-progress -- *.file && |
| 667 | cat >expected.log <<-EOF && |
| 668 | START |
| 669 | init handshake complete |
| 670 | IN: smudge 1pkt_1__.file $M1 $(($S )) [OK] -- OUT: $(($S )) . [OK] |
| 671 | IN: smudge 2pkt_1+1.file $M2 $(($S +1)) [OK] -- OUT: $(($S +1)) .. [OK] |
| 672 | IN: smudge 2pkt_2-1.file $M3 $(($S*2-1)) [OK] -- OUT: $(($S*2-1)) .. [OK] |
| 673 | IN: smudge 2pkt_2__.file $M4 $(($S*2 )) [OK] -- OUT: $(($S*2 )) .. [OK] |
| 674 | IN: smudge 3pkt_2+1.file $M5 $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK] |
| 675 | STOP |
| 676 | EOF |
| 677 | test_cmp_exclude_clean expected.log debug.log && |
| 678 | |
| 679 | for FILE in *.file |
| 680 | do |
| 681 | test_cmp_committed_rot13 "$TEST_ROOT/$FILE" $FILE || return 1 |
| 682 | done |
| 683 | ) |
| 684 | ' |
| 685 | |
| 686 | test_expect_success 'required process filter with clean error should fail' ' |
| 687 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 688 | test_config_global filter.protocol.required true && |
| 689 | rm -rf repo && |
| 690 | mkdir repo && |
| 691 | ( |
| 692 | cd repo && |
| 693 | git init && |
| 694 | |
| 695 | echo "*.r filter=protocol" >.gitattributes && |
| 696 | |
| 697 | cp "$TEST_ROOT/test.o" test.r && |
| 698 | echo "this is going to fail" >clean-write-fail.r && |
| 699 | echo "content-test3-subdir" >test3.r && |
| 700 | |
| 701 | test_must_fail git add . |
| 702 | ) |
| 703 | ' |
| 704 | |
| 705 | test_expect_success 'process filter should restart after unexpected write failure' ' |
| 706 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 707 | rm -rf repo && |
| 708 | mkdir repo && |
| 709 | ( |
| 710 | cd repo && |
| 711 | git init && |
| 712 | |
| 713 | echo "*.r filter=protocol" >.gitattributes && |
| 714 | |
| 715 | cp "$TEST_ROOT/test.o" test.r && |
| 716 | cp "$TEST_ROOT/test2.o" test2.r && |
| 717 | echo "this is going to fail" >smudge-write-fail.o && |
| 718 | cp smudge-write-fail.o smudge-write-fail.r && |
| 719 | |
| 720 | S=$(test_file_size test.r) && |
| 721 | S2=$(test_file_size test2.r) && |
| 722 | SF=$(test_file_size smudge-write-fail.r) && |
| 723 | M=$(git hash-object test.r) && |
| 724 | M2=$(git hash-object test2.r) && |
| 725 | MF=$(git hash-object smudge-write-fail.r) && |
| 726 | rm -f debug.log && |
| 727 | |
| 728 | git add . && |
| 729 | rm -f *.r && |
| 730 | |
| 731 | rm -f debug.log && |
| 732 | git checkout --quiet --no-progress . 2>git-stderr.log && |
| 733 | |
| 734 | test_grep "smudge write error" git-stderr.log && |
| 735 | test_grep "error: external filter" git-stderr.log && |
| 736 | |
| 737 | cat >expected.log <<-EOF && |
| 738 | START |
| 739 | init handshake complete |
| 740 | IN: smudge smudge-write-fail.r blob=$MF $SF [OK] -- [WRITE FAIL] |
| 741 | START |
| 742 | init handshake complete |
| 743 | IN: smudge test.r blob=$M $S [OK] -- OUT: $S . [OK] |
| 744 | IN: smudge test2.r blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 745 | STOP |
| 746 | EOF |
| 747 | test_cmp_exclude_clean expected.log debug.log && |
| 748 | |
| 749 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r && |
| 750 | test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r && |
| 751 | |
| 752 | # Smudge failed |
| 753 | ! test_cmp smudge-write-fail.o smudge-write-fail.r && |
| 754 | rot13.sh <smudge-write-fail.o >expected && |
| 755 | git cat-file blob :smudge-write-fail.r >actual && |
| 756 | test_cmp expected actual |
| 757 | ) |
| 758 | ' |
| 759 | |
| 760 | test_expect_success 'process filter should not be restarted if it signals an error' ' |
| 761 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 762 | rm -rf repo && |
| 763 | mkdir repo && |
| 764 | ( |
| 765 | cd repo && |
| 766 | git init && |
| 767 | |
| 768 | echo "*.r filter=protocol" >.gitattributes && |
| 769 | |
| 770 | cp "$TEST_ROOT/test.o" test.r && |
| 771 | cp "$TEST_ROOT/test2.o" test2.r && |
| 772 | echo "this will cause an error" >error.o && |
| 773 | cp error.o error.r && |
| 774 | |
| 775 | S=$(test_file_size test.r) && |
| 776 | S2=$(test_file_size test2.r) && |
| 777 | SE=$(test_file_size error.r) && |
| 778 | M=$(git hash-object test.r) && |
| 779 | M2=$(git hash-object test2.r) && |
| 780 | ME=$(git hash-object error.r) && |
| 781 | rm -f debug.log && |
| 782 | |
| 783 | git add . && |
| 784 | rm -f *.r && |
| 785 | |
| 786 | filter_git checkout --quiet --no-progress . && |
| 787 | cat >expected.log <<-EOF && |
| 788 | START |
| 789 | init handshake complete |
| 790 | IN: smudge error.r blob=$ME $SE [OK] -- [ERROR] |
| 791 | IN: smudge test.r blob=$M $S [OK] -- OUT: $S . [OK] |
| 792 | IN: smudge test2.r blob=$M2 $S2 [OK] -- OUT: $S2 . [OK] |
| 793 | STOP |
| 794 | EOF |
| 795 | test_cmp_exclude_clean expected.log debug.log && |
| 796 | |
| 797 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r && |
| 798 | test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r && |
| 799 | test_cmp error.o error.r |
| 800 | ) |
| 801 | ' |
| 802 | |
| 803 | test_expect_success 'process filter abort stops processing of all further files' ' |
| 804 | test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" && |
| 805 | rm -rf repo && |
| 806 | mkdir repo && |
| 807 | ( |
| 808 | cd repo && |
| 809 | git init && |
| 810 | |
| 811 | echo "*.r filter=protocol" >.gitattributes && |
| 812 | |
| 813 | cp "$TEST_ROOT/test.o" test.r && |
| 814 | cp "$TEST_ROOT/test2.o" test2.r && |
| 815 | echo "error this blob and all future blobs" >abort.o && |
| 816 | cp abort.o abort.r && |
| 817 | |
| 818 | M="blob=$(git hash-object abort.r)" && |
| 819 | rm -f debug.log && |
| 820 | SA=$(test_file_size abort.r) && |
| 821 | |
| 822 | git add . && |
| 823 | rm -f *.r && |
| 824 | |
| 825 | |
| 826 | # Note: This test assumes that Git filters files in alphabetical |
| 827 | # order ("abort.r" before "test.r"). |
| 828 | filter_git checkout --quiet --no-progress . && |
| 829 | cat >expected.log <<-EOF && |
| 830 | START |
| 831 | init handshake complete |
| 832 | IN: smudge abort.r $M $SA [OK] -- [ABORT] |
| 833 | STOP |
| 834 | EOF |
| 835 | test_cmp_exclude_clean expected.log debug.log && |
| 836 | |
| 837 | test_cmp "$TEST_ROOT/test.o" test.r && |
| 838 | test_cmp "$TEST_ROOT/test2.o" test2.r && |
| 839 | test_cmp abort.o abort.r |
| 840 | ) |
| 841 | ' |
| 842 | |
| 843 | test_expect_success 'invalid process filter must fail (and not hang!)' ' |
| 844 | test_config_global filter.protocol.process cat && |
| 845 | test_config_global filter.protocol.required true && |
| 846 | rm -rf repo && |
| 847 | mkdir repo && |
| 848 | ( |
| 849 | cd repo && |
| 850 | git init && |
| 851 | |
| 852 | echo "*.r filter=protocol" >.gitattributes && |
| 853 | |
| 854 | cp "$TEST_ROOT/test.o" test.r && |
| 855 | test_must_fail git add . 2>git-stderr.log && |
| 856 | test_grep "expected git-filter-server" git-stderr.log |
| 857 | ) |
| 858 | ' |
| 859 | |
| 860 | test_expect_success 'missing process filter with space in path does not die' ' |
| 861 | test_config_global filter.protocol.process "/non existent/tool" && |
| 862 | test_config_global filter.protocol.required true && |
| 863 | rm -rf repo && |
| 864 | mkdir repo && |
| 865 | ( |
| 866 | cd repo && |
| 867 | git init && |
| 868 | |
| 869 | echo "*.r filter=protocol" >.gitattributes && |
| 870 | |
| 871 | cp "$TEST_ROOT/test.o" test.r && |
| 872 | test_must_fail git add . 2>git-stderr.log && |
| 873 | test_grep "clean filter.*protocol.*failed" git-stderr.log |
| 874 | ) |
| 875 | ' |
| 876 | |
| 877 | test_expect_success 'delayed checkout in process filter' ' |
| 878 | test_config_global filter.a.process "test-tool rot13-filter --log=a.log clean smudge delay" && |
| 879 | test_config_global filter.a.required true && |
| 880 | test_config_global filter.b.process "test-tool rot13-filter --log=b.log clean smudge delay" && |
| 881 | test_config_global filter.b.required true && |
| 882 | |
| 883 | rm -rf repo && |
| 884 | mkdir repo && |
| 885 | ( |
| 886 | cd repo && |
| 887 | git init && |
| 888 | echo "*.a filter=a" >.gitattributes && |
| 889 | echo "*.b filter=b" >>.gitattributes && |
| 890 | cp "$TEST_ROOT/test.o" test.a && |
| 891 | cp "$TEST_ROOT/test.o" test-delay10.a && |
| 892 | cp "$TEST_ROOT/test.o" test-delay11.a && |
| 893 | cp "$TEST_ROOT/test.o" test-delay20.a && |
| 894 | cp "$TEST_ROOT/test.o" test-delay10.b && |
| 895 | git add . && |
| 896 | git commit -m "test commit" |
| 897 | ) && |
| 898 | |
| 899 | S=$(test_file_size "$TEST_ROOT/test.o") && |
| 900 | PM="ref=refs/heads/main treeish=$(git -C repo rev-parse --verify main) " && |
| 901 | M="${PM}blob=$(git -C repo rev-parse --verify main:test.a)" && |
| 902 | cat >a.exp <<-EOF && |
| 903 | START |
| 904 | init handshake complete |
| 905 | IN: smudge test.a $M $S [OK] -- OUT: $S . [OK] |
| 906 | IN: smudge test-delay10.a $M $S [OK] -- [DELAYED] |
| 907 | IN: smudge test-delay11.a $M $S [OK] -- [DELAYED] |
| 908 | IN: smudge test-delay20.a $M $S [OK] -- [DELAYED] |
| 909 | IN: list_available_blobs test-delay10.a test-delay11.a [OK] |
| 910 | IN: smudge test-delay10.a $M 0 [OK] -- OUT: $S . [OK] |
| 911 | IN: smudge test-delay11.a $M 0 [OK] -- OUT: $S . [OK] |
| 912 | IN: list_available_blobs test-delay20.a [OK] |
| 913 | IN: smudge test-delay20.a $M 0 [OK] -- OUT: $S . [OK] |
| 914 | IN: list_available_blobs [OK] |
| 915 | STOP |
| 916 | EOF |
| 917 | cat >b.exp <<-EOF && |
| 918 | START |
| 919 | init handshake complete |
| 920 | IN: smudge test-delay10.b $M $S [OK] -- [DELAYED] |
| 921 | IN: list_available_blobs test-delay10.b [OK] |
| 922 | IN: smudge test-delay10.b $M 0 [OK] -- OUT: $S . [OK] |
| 923 | IN: list_available_blobs [OK] |
| 924 | STOP |
| 925 | EOF |
| 926 | |
| 927 | rm -rf repo-cloned && |
| 928 | filter_git clone repo repo-cloned && |
| 929 | test_cmp_count a.exp repo-cloned/a.log && |
| 930 | test_cmp_count b.exp repo-cloned/b.log && |
| 931 | |
| 932 | ( |
| 933 | cd repo-cloned && |
| 934 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.a && |
| 935 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.a && |
| 936 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay11.a && |
| 937 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay20.a && |
| 938 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.b && |
| 939 | |
| 940 | rm *.a *.b && |
| 941 | filter_git checkout . && |
| 942 | # We are not checking out a ref here, so filter out ref metadata. |
| 943 | sed -e "s!$PM!!" ../a.exp >a.exp.filtered && |
| 944 | sed -e "s!$PM!!" ../b.exp >b.exp.filtered && |
| 945 | test_cmp_count a.exp.filtered a.log && |
| 946 | test_cmp_count b.exp.filtered b.log && |
| 947 | |
| 948 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.a && |
| 949 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.a && |
| 950 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay11.a && |
| 951 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay20.a && |
| 952 | test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.b |
| 953 | ) |
| 954 | ' |
| 955 | |
| 956 | test_expect_success 'missing file in delayed checkout' ' |
| 957 | test_config_global filter.bug.process "test-tool rot13-filter --log=bug.log clean smudge delay" && |
| 958 | test_config_global filter.bug.required true && |
| 959 | |
| 960 | rm -rf repo && |
| 961 | mkdir repo && |
| 962 | ( |
| 963 | cd repo && |
| 964 | git init && |
| 965 | echo "*.a filter=bug" >.gitattributes && |
| 966 | cp "$TEST_ROOT/test.o" missing-delay.a && |
| 967 | git add . && |
| 968 | git commit -m "test commit" |
| 969 | ) && |
| 970 | |
| 971 | rm -rf repo-cloned && |
| 972 | test_must_fail git clone repo repo-cloned 2>git-stderr.log && |
| 973 | test_grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log |
| 974 | ' |
| 975 | |
| 976 | test_expect_success 'invalid file in delayed checkout' ' |
| 977 | test_config_global filter.bug.process "test-tool rot13-filter --log=bug.log clean smudge delay" && |
| 978 | test_config_global filter.bug.required true && |
| 979 | |
| 980 | rm -rf repo && |
| 981 | mkdir repo && |
| 982 | ( |
| 983 | cd repo && |
| 984 | git init && |
| 985 | echo "*.a filter=bug" >.gitattributes && |
| 986 | cp "$TEST_ROOT/test.o" invalid-delay.a && |
| 987 | cp "$TEST_ROOT/test.o" unfiltered && |
| 988 | git add . && |
| 989 | git commit -m "test commit" |
| 990 | ) && |
| 991 | |
| 992 | rm -rf repo-cloned && |
| 993 | test_must_fail git clone repo repo-cloned 2>git-stderr.log && |
| 994 | test_grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log |
| 995 | ' |
| 996 | |
| 997 | for mode in 'case' 'utf-8' |
| 998 | do |
| 999 | case "$mode" in |
| 1000 | case) dir='A' symlink='a' mode_prereq='CASE_INSENSITIVE_FS' ;; |
| 1001 | utf-8) |
| 1002 | dir=$(printf "\141\314\210") symlink=$(printf "\303\244") |
| 1003 | mode_prereq='UTF8_NFD_TO_NFC' ;; |
| 1004 | esac |
| 1005 | |
| 1006 | test_expect_success SYMLINKS,$mode_prereq \ |
| 1007 | "delayed checkout with $mode-collision don't write to the wrong place" ' |
| 1008 | test_config_global filter.delay.process \ |
| 1009 | "test-tool rot13-filter --always-delay --log=delayed.log clean smudge delay" && |
| 1010 | test_config_global filter.delay.required true && |
| 1011 | |
| 1012 | git init $mode-collision && |
| 1013 | ( |
| 1014 | cd $mode-collision && |
| 1015 | mkdir target-dir && |
| 1016 | |
| 1017 | empty_oid=$(printf "" | git hash-object -w --stdin) && |
| 1018 | symlink_oid=$(printf "%s" "$PWD/target-dir" | git hash-object -w --stdin) && |
| 1019 | attr_oid=$(echo "$dir/z filter=delay" | git hash-object -w --stdin) && |
| 1020 | |
| 1021 | cat >objs <<-EOF && |
| 1022 | 100644 blob $empty_oid $dir/x |
| 1023 | 100644 blob $empty_oid $dir/y |
| 1024 | 100644 blob $empty_oid $dir/z |
| 1025 | 120000 blob $symlink_oid $symlink |
| 1026 | 100644 blob $attr_oid .gitattributes |
| 1027 | EOF |
| 1028 | |
| 1029 | git update-index --index-info <objs && |
| 1030 | git commit -m "test commit" |
| 1031 | ) && |
| 1032 | |
| 1033 | git clone $mode-collision $mode-collision-cloned && |
| 1034 | # Make sure z was really delayed |
| 1035 | test_grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && |
| 1036 | |
| 1037 | # Should not create $dir/z at $symlink/z |
| 1038 | test_path_is_missing $mode-collision/target-dir/z |
| 1039 | ' |
| 1040 | done |
| 1041 | |
| 1042 | test_expect_success SYMLINKS,CASE_INSENSITIVE_FS \ |
| 1043 | "delayed checkout with submodule collision don't write to the wrong place" ' |
| 1044 | git init collision-with-submodule && |
| 1045 | ( |
| 1046 | cd collision-with-submodule && |
| 1047 | git config filter.delay.process "test-tool rot13-filter --always-delay --log=delayed.log clean smudge delay" && |
| 1048 | git config filter.delay.required true && |
| 1049 | |
| 1050 | # We need Git to treat the submodule "a" and the |
| 1051 | # leading dir "A" as different paths in the index. |
| 1052 | git config --local core.ignoreCase false && |
| 1053 | |
| 1054 | empty_oid=$(printf "" | git hash-object -w --stdin) && |
| 1055 | attr_oid=$(echo "A/B/y filter=delay" | git hash-object -w --stdin) && |
| 1056 | cat >objs <<-EOF && |
| 1057 | 100644 blob $empty_oid A/B/x |
| 1058 | 100644 blob $empty_oid A/B/y |
| 1059 | 100644 blob $attr_oid .gitattributes |
| 1060 | EOF |
| 1061 | git update-index --index-info <objs && |
| 1062 | |
| 1063 | git init a && |
| 1064 | mkdir target-dir && |
| 1065 | symlink_oid=$(printf "%s" "$PWD/target-dir" | git -C a hash-object -w --stdin) && |
| 1066 | echo "120000 blob $symlink_oid b" >objs && |
| 1067 | git -C a update-index --index-info <objs && |
| 1068 | git -C a commit -m sub && |
| 1069 | git submodule add ./a && |
| 1070 | git commit -m super && |
| 1071 | |
| 1072 | git checkout --recurse-submodules . && |
| 1073 | test_grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log && |
| 1074 | test_path_is_missing target-dir/y |
| 1075 | ) |
| 1076 | ' |
| 1077 | |
| 1078 | test_expect_success 'setup for progress tests' ' |
| 1079 | git init progress && |
| 1080 | ( |
| 1081 | cd progress && |
| 1082 | git config filter.delay.process "test-tool rot13-filter --log=delay-progress.log clean smudge delay" && |
| 1083 | git config filter.delay.required true && |
| 1084 | |
| 1085 | echo "*.a filter=delay" >.gitattributes && |
| 1086 | touch test-delay10.a && |
| 1087 | git add . && |
| 1088 | git commit -m files |
| 1089 | ) |
| 1090 | ' |
| 1091 | |
| 1092 | test_delayed_checkout_progress () { |
| 1093 | if test "$1" = "!" |
| 1094 | then |
| 1095 | local expect_progress=N && |
| 1096 | shift |
| 1097 | else |
| 1098 | local expect_progress= |
| 1099 | fi && |
| 1100 | |
| 1101 | if test $# -lt 1 |
| 1102 | then |
| 1103 | BUG "no command given to test_delayed_checkout_progress" |
| 1104 | fi && |
| 1105 | |
| 1106 | ( |
| 1107 | cd progress && |
| 1108 | GIT_PROGRESS_DELAY=0 && |
| 1109 | export GIT_PROGRESS_DELAY && |
| 1110 | rm -f *.a delay-progress.log && |
| 1111 | |
| 1112 | "$@" 2>err && |
| 1113 | grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delay-progress.log && |
| 1114 | if test "$expect_progress" = N |
| 1115 | then |
| 1116 | ! grep "Filtering content" err |
| 1117 | else |
| 1118 | grep "Filtering content" err |
| 1119 | fi |
| 1120 | ) |
| 1121 | } |
| 1122 | |
| 1123 | for mode in pathspec branch |
| 1124 | do |
| 1125 | case "$mode" in |
| 1126 | pathspec) opt='.' ;; |
| 1127 | branch) opt='-f HEAD' ;; |
| 1128 | esac |
| 1129 | |
| 1130 | test_expect_success TTY "delayed checkout shows progress by default on tty ($mode checkout)" ' |
| 1131 | test_delayed_checkout_progress test_terminal git checkout $opt |
| 1132 | ' |
| 1133 | |
| 1134 | test_expect_success "delayed checkout omits progress on non-tty ($mode checkout)" ' |
| 1135 | test_delayed_checkout_progress ! git checkout $opt |
| 1136 | ' |
| 1137 | |
| 1138 | test_expect_success TTY "delayed checkout omits progress with --quiet ($mode checkout)" ' |
| 1139 | test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt |
| 1140 | ' |
| 1141 | |
| 1142 | test_expect_success TTY "delayed checkout honors --[no]-progress ($mode checkout)" ' |
| 1143 | test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt && |
| 1144 | test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt |
| 1145 | ' |
| 1146 | done |
| 1147 | |
| 1148 | test_expect_success 'delayed checkout correctly reports the number of updated entries' ' |
| 1149 | rm -rf repo && |
| 1150 | git init repo && |
| 1151 | ( |
| 1152 | cd repo && |
| 1153 | git config filter.delay.process "test-tool rot13-filter --log=delayed.log clean smudge delay" && |
| 1154 | git config filter.delay.required true && |
| 1155 | |
| 1156 | echo "*.a filter=delay" >.gitattributes && |
| 1157 | echo a >test-delay10.a && |
| 1158 | echo a >test-delay11.a && |
| 1159 | git add . && |
| 1160 | git commit -m files && |
| 1161 | |
| 1162 | rm *.a && |
| 1163 | git checkout . 2>err && |
| 1164 | test_grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delayed.log && |
| 1165 | test_grep "IN: smudge test-delay11.a .* \\[DELAYED\\]" delayed.log && |
| 1166 | test_grep "Updated 2 paths from the index" err |
| 1167 | ) |
| 1168 | ' |
| 1169 | |
| 1170 | test_done |