github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/test/testhelpers.sh (about) 1 #!/usr/bin/env bash 2 3 # assert_pointer confirms that the pointer in the repository for $path in the 4 # given $ref matches the given $oid and $size. 5 # 6 # $ assert_pointer "master" "path/to/file" "some-oid" 123 7 assert_pointer() { 8 local ref="$1" 9 local path="$2" 10 local oid="$3" 11 local size="$4" 12 13 gitblob=$(git ls-tree -lrz "$ref" | 14 while read -r -d $'\0' x; do 15 echo $x 16 done | 17 grep "$path" | cut -f 3 -d " ") 18 19 actual=$(git cat-file -p $gitblob) 20 expected=$(pointer $oid $size) 21 22 if [ "$expected" != "$actual" ]; then 23 exit 1 24 fi 25 } 26 27 # assert_local_object confirms that an object file is stored for the given oid & 28 # has the correct size 29 # $ assert_local_object "some-oid" size 30 assert_local_object() { 31 local oid="$1" 32 local size="$2" 33 local cfg=`git lfs env | grep LocalMediaDir` 34 local f="${cfg:14}/${oid:0:2}/${oid:2:2}/$oid" 35 actualsize=$(wc -c <"$f" | tr -d '[[:space:]]') 36 if [ "$size" != "$actualsize" ]; then 37 exit 1 38 fi 39 } 40 41 # refute_local_object confirms that an object file is NOT stored for an oid. 42 # If "$size" is given as the second argument, assert that the file exists _and_ 43 # that it does _not_ the expected size 44 # 45 # $ refute_local_object "some-oid" 46 # $ refute_local_object "some-oid" "123" 47 refute_local_object() { 48 local oid="$1" 49 local size="$2" 50 local cfg=`git lfs env | grep LocalMediaDir` 51 local regex="LocalMediaDir=(\S+)" 52 local f="${cfg:14}/${oid:0:2}/${oid:2:2}/$oid" 53 if [ -e $f ]; then 54 if [ -z "$size" ]; then 55 exit 1 56 fi 57 58 actual_size="$(wc -c < "$f" | awk '{ print $1 }')" 59 if [ "$size" -eq "$actual_size" ]; then 60 echo >&2 "fatal: expected object $oid not to have size: $size" 61 exit 1 62 fi 63 fi 64 } 65 66 # delete_local_object deletes the local storage for an oid 67 # $ delete_local_object "some-oid" 68 delete_local_object() { 69 local oid="$1" 70 local cfg=`git lfs env | grep LocalMediaDir` 71 local f="${cfg:14}/${oid:0:2}/${oid:2:2}/$oid" 72 rm "$f" 73 } 74 75 # corrupt_local_object corrupts the local storage for an oid 76 # $ corrupt_local_object "some-oid" 77 corrupt_local_object() { 78 local oid="$1" 79 local cfg=`git lfs env | grep LocalMediaDir` 80 local f="${cfg:14}/${oid:0:2}/${oid:2:2}/$oid" 81 cp /dev/null "$f" 82 } 83 84 85 # check that the object does not exist in the git lfs server. HTTP log is 86 # written to http.log. JSON output is written to http.json. 87 # 88 # $ refute_server_object "reponame" "oid" 89 refute_server_object() { 90 local reponame="$1" 91 local oid="$2" 92 curl -v "$GITSERVER/$reponame.git/info/lfs/objects/batch" \ 93 -u "user:pass" \ 94 -o http.json \ 95 -d "{\"operation\":\"download\",\"objects\":[{\"oid\":\"$oid\"}]}" \ 96 -H "Accept: application/vnd.git-lfs+json" \ 97 -H "X-Check-Object: 1" \ 98 -H "X-Ignore-Retries: true" 2>&1 | 99 tee http.log 100 101 [ "0" = "$(grep -c "download" http.json)" ] || { 102 cat http.json 103 exit 1 104 } 105 } 106 107 # Delete an object on the lfs server. HTTP log is 108 # written to http.log. JSON output is written to http.json. 109 # 110 # $ delete_server_object "reponame" "oid" 111 delete_server_object() { 112 local reponame="$1" 113 local oid="$2" 114 curl -v "$GITSERVER/$reponame.git/info/lfs/objects/$oid" \ 115 -X DELETE \ 116 -u "user:pass" \ 117 -o http.json \ 118 -H "Accept: application/vnd.git-lfs+json" 2>&1 | 119 tee http.log 120 121 grep "200 OK" http.log 122 } 123 124 # check that the object does exist in the git lfs server. HTTP log is written 125 # to http.log. JSON output is written to http.json. 126 assert_server_object() { 127 local reponame="$1" 128 local oid="$2" 129 local refspec="$3" 130 curl -v "$GITSERVER/$reponame.git/info/lfs/objects/batch" \ 131 -u "user:pass" \ 132 -o http.json \ 133 -d "{\"operation\":\"download\",\"objects\":[{\"oid\":\"$oid\"}],\"ref\":{\"name\":\"$refspec\"}}" \ 134 -H "Accept: application/vnd.git-lfs+json" \ 135 -H "X-Check-Object: 1" \ 136 -H "X-Ignore-Retries: true" 2>&1 | 137 tee http.log 138 grep "200 OK" http.log 139 140 grep "download" http.json || { 141 cat http.json 142 exit 1 143 } 144 } 145 146 # This asserts the lock path and returns the lock ID by parsing the response of 147 # 148 # git lfs lock --json <path> 149 assert_lock() { 150 local log="$1" 151 local path="$2" 152 153 if [ $(grep -c "\"path\":\"$path\"" "$log") -eq 0 ]; then 154 echo "path '$path' not found in:" 155 cat "$log" 156 exit 1 157 fi 158 159 local jsonid=$(grep -oh "\"id\":\"\w\+\"" "$log") 160 echo "${jsonid:3}" | tr -d \"\: 161 } 162 163 # assert that a lock with the given ID exists on the test server 164 assert_server_lock() { 165 local reponame="$1" 166 local id="$2" 167 local refspec="$3" 168 169 curl -v "$GITSERVER/$reponame.git/info/lfs/locks?refspec=$refspec" \ 170 -u "user:pass" \ 171 -o http.json \ 172 -H "Accept:application/vnd.git-lfs+json" 2>&1 | 173 tee http.log 174 175 grep "200 OK" http.log 176 grep "$id" http.json || { 177 cat http.json 178 exit 1 179 } 180 } 181 182 # refute that a lock with the given ID exists on the test server 183 refute_server_lock() { 184 local reponame="$1" 185 local id="$2" 186 local refspec="$3" 187 188 curl -v "$GITSERVER/$reponame.git/info/lfs/locks?refspec=$refspec" \ 189 -u "user:pass" \ 190 -o http.json \ 191 -H "Accept:application/vnd.git-lfs+json" 2>&1 | tee http.log 192 193 grep "200 OK" http.log 194 195 [ $(grep -c "$id" http.json) -eq 0 ] 196 } 197 198 # Assert that .gitattributes contains a given attribute N times 199 assert_attributes_count() { 200 local fileext="$1" 201 local attrib="$2" 202 local count="$3" 203 204 pattern="\(*.\)\?$fileext\(.*\)$attrib" 205 actual=$(grep -e "$pattern" .gitattributes | wc -l) 206 if [ "$(printf "%d" "$actual")" != "$count" ]; then 207 echo "wrong number of $attrib entries for $fileext" 208 echo "expected: $count actual: $actual" 209 cat .gitattributes 210 exit 1 211 fi 212 } 213 214 assert_file_writeable() { 215 ls -l "$1" | grep -e "^-rw" 216 } 217 218 refute_file_writeable() { 219 ls -l "$1" | grep -e "^-r-" 220 } 221 222 git_root() { 223 git rev-parse --show-toplevel 2>/dev/null 224 } 225 226 dot_git_dir() { 227 echo "$(git_root)/.git" 228 } 229 230 assert_hooks() { 231 local git_root="$1" 232 233 if [ -z "$git_root" ]; then 234 echo >&2 "fatal: (assert_hooks) not in git repository" 235 exit 1 236 fi 237 238 [ -x "$git_root/hooks/post-checkout" ] 239 [ -x "$git_root/hooks/post-commit" ] 240 [ -x "$git_root/hooks/post-merge" ] 241 [ -x "$git_root/hooks/pre-push" ] 242 } 243 244 assert_clean_status() { 245 status="$(git status)" 246 echo "$status" | grep "working tree clean" || { 247 echo $status 248 git lfs status 249 } 250 } 251 252 # pointer returns a string Git LFS pointer file. 253 # 254 # $ pointer abc-some-oid 123 <version> 255 # > version ... 256 pointer() { 257 local oid=$1 258 local size=$2 259 local version=${3:-https://git-lfs.github.com/spec/v1} 260 printf "version %s 261 oid sha256:%s 262 size %s 263 " "$version" "$oid" "$size" 264 } 265 266 # wait_for_file simply sleeps until a file exists. 267 # 268 # $ wait_for_file "path/to/upcoming/file" 269 wait_for_file() { 270 local filename="$1" 271 n=0 272 wait_time=1 273 while [ $n -lt 17 ]; do 274 if [ -s $filename ]; then 275 return 0 276 fi 277 278 sleep $wait_time 279 n=`expr $n + 1` 280 if [ $wait_time -lt 4 ]; then 281 wait_time=`expr $wait_time \* 2` 282 fi 283 done 284 285 echo "$filename did not appear after 60 seconds." 286 return 1 287 } 288 289 # setup_remote_repo initializes a bare Git repository that is accessible through 290 # the test Git server. The `pwd` is set to the repository's directory, in case 291 # further commands need to be run. This server is running for every test in a 292 # script/integration run, so every test file should setup its own remote 293 # repository to avoid conflicts. 294 # 295 # $ setup_remote_repo "some-name" 296 # 297 setup_remote_repo() { 298 local reponame="$1" 299 echo "set up remote git repository: $reponame" 300 repodir="$REMOTEDIR/$reponame.git" 301 mkdir -p "$repodir" 302 cd "$repodir" 303 git init --bare 304 git config http.receivepack true 305 git config receive.denyCurrentBranch ignore 306 } 307 308 # creates a bare remote repository for a local clone. Useful to test pushing to 309 # a fresh remote server. 310 # 311 # $ setup_alternate_remote "$reponame-whatever" 312 # $ setup_alternate_remote "$reponame-whatever" "other-remote-name" 313 # 314 setup_alternate_remote() { 315 local newRemoteName=$1 316 local remote=${2:-origin} 317 318 wd=`pwd` 319 320 setup_remote_repo "$newRemoteName" 321 cd $wd 322 git remote rm "$remote" 323 git remote add "$remote" "$GITSERVER/$newRemoteName" 324 } 325 326 # clone_repo clones a repository from the test Git server to the subdirectory 327 # $dir under $TRASHDIR. setup_remote_repo() needs to be run first. Output is 328 # written to clone.log. 329 clone_repo() { 330 cd "$TRASHDIR" 331 332 local reponame="$1" 333 local dir="$2" 334 echo "clone local git repository $reponame to $dir" 335 out=$(git clone "$GITSERVER/$reponame" "$dir" 2>&1) 336 cd "$dir" 337 338 git config credential.helper lfstest 339 echo "$out" > clone.log 340 echo "$out" 341 } 342 343 # clone_repo_url clones a Git repository to the subdirectory $dir under $TRASHDIR. 344 # setup_remote_repo() needs to be run first. Output is written to clone.log. 345 clone_repo_url() { 346 cd "$TRASHDIR" 347 348 local repo="$1" 349 local dir="$2" 350 echo "clone git repository $repo to $dir" 351 out=$(git clone "$repo" "$dir" 2>&1) 352 cd "$dir" 353 354 git config credential.helper lfstest 355 echo "$out" > clone.log 356 echo "$out" 357 } 358 359 # clone_repo_ssl clones a repository from the test Git server to the subdirectory 360 # $dir under $TRASHDIR, using the SSL endpoint. 361 # setup_remote_repo() needs to be run first. Output is written to clone_ssl.log. 362 clone_repo_ssl() { 363 cd "$TRASHDIR" 364 365 local reponame="$1" 366 local dir="$2" 367 echo "clone local git repository $reponame to $dir" 368 out=$(git clone "$SSLGITSERVER/$reponame" "$dir" 2>&1) 369 cd "$dir" 370 371 git config credential.helper lfstest 372 373 echo "$out" > clone_ssl.log 374 echo "$out" 375 } 376 377 # clone_repo_clientcert clones a repository from the test Git server to the subdirectory 378 # $dir under $TRASHDIR, using the client cert endpoint. 379 # setup_remote_repo() needs to be run first. Output is written to clone_client_cert.log. 380 clone_repo_clientcert() { 381 cd "$TRASHDIR" 382 383 local reponame="$1" 384 local dir="$2" 385 echo "clone $CLIENTCERTGITSERVER/$reponame to $dir" 386 set +e 387 out=$(git clone "$CLIENTCERTGITSERVER/$reponame" "$dir" 2>&1) 388 res="${PIPESTATUS[0]}" 389 set -e 390 391 if [ "0" -eq "$res" ]; then 392 cd "$dir" 393 echo "$out" > clone_client_cert.log 394 395 git config credential.helper lfstest 396 exit 0 397 fi 398 399 echo "$out" > clone_client_cert.log 400 if [ $(grep -c "NSInvalidArgumentException" clone_client_cert.log) -gt 0 ]; then 401 echo "client-cert-mac-openssl" > clone_client_cert.log 402 exit 0 403 fi 404 405 exit 1 406 } 407 408 # setup_remote_repo_with_file creates a remote repo, clones it locally, commits 409 # a file tracked by LFS, and pushes it to the remote: 410 # 411 # setup_remote_repo_with_file "reponame" "filename" 412 setup_remote_repo_with_file() { 413 local reponame="$1" 414 local filename="$2" 415 local dirname="$(dirname "$filename")" 416 417 setup_remote_repo "$reponame" 418 clone_repo "$reponame" "clone_$reponame" 419 420 mkdir -p "$dirname" 421 422 git lfs track "$filename" 423 echo "$filename" > "$filename" 424 git add .gitattributes $filename 425 git commit -m "add $filename" | tee commit.log 426 427 grep "master (root-commit)" commit.log 428 grep "2 files changed" commit.log 429 grep "create mode 100644 $filename" commit.log 430 grep "create mode 100644 .gitattributes" commit.log 431 432 git push origin master 2>&1 | tee push.log 433 grep "master -> master" push.log 434 } 435 436 # substring_position returns the position of a substring in a 1-indexed search 437 # space. 438 # 439 # [ "$(substring_position "foo bar baz" "baz")" -eq "9" ] 440 substring_position() { 441 local str="$1" 442 local substr="$2" 443 444 # 1) Print the string... 445 # 2) Remove the substring and everything after it 446 # 3) Count the number of characters (bytes) left, i.e., the offset of the 447 # string we were looking for. 448 449 echo "$str" \ 450 | sed "s/$substr.*$//" \ 451 | wc -c 452 } 453 454 # repo_endpoint returns the LFS endpoint for a given server and repository. 455 # 456 # [ "$GITSERVER/example/repo.git/info/lfs" = "$(repo_endpoint $GITSERVER example-repo)" ] 457 repo_endpoint() { 458 local server="$1" 459 local repo="$2" 460 461 echo "$server/$repo.git/info/lfs" 462 } 463 464 # setup initializes the clean, isolated environment for integration tests. 465 setup() { 466 cd "$ROOTDIR" 467 468 rm -rf "$REMOTEDIR" 469 mkdir "$REMOTEDIR" 470 471 if [ -z "$SKIPCOMPILE" ] && [ -z "$LFS_BIN" ]; then 472 echo "compile git-lfs for $0" 473 script/bootstrap || { 474 return $? 475 } 476 fi 477 478 echo "Git LFS: ${LFS_BIN:-$(which git-lfs)}" 479 git lfs version 480 git version 481 482 if [ -z "$SKIPCOMPILE" ]; then 483 [ $IS_WINDOWS -eq 1 ] && EXT=".exe" 484 for go in test/cmd/*.go; do 485 GO15VENDOREXPERIMENT=1 go build -o "$BINPATH/$(basename $go .go)$EXT" "$go" 486 done 487 if [ -z "$SKIPAPITESTCOMPILE" ]; then 488 # Ensure API test util is built during tests to ensure it stays in sync 489 GO15VENDOREXPERIMENT=1 go build -o "$BINPATH/git-lfs-test-server-api$EXT" "test/git-lfs-test-server-api/main.go" "test/git-lfs-test-server-api/testdownload.go" "test/git-lfs-test-server-api/testupload.go" 490 fi 491 fi 492 493 LFSTEST_URL="$LFS_URL_FILE" LFSTEST_SSL_URL="$LFS_SSL_URL_FILE" LFSTEST_CLIENT_CERT_URL="$LFS_CLIENT_CERT_URL_FILE" LFSTEST_DIR="$REMOTEDIR" LFSTEST_CERT="$LFS_CERT_FILE" LFSTEST_CLIENT_CERT="$LFS_CLIENT_CERT_FILE" LFSTEST_CLIENT_KEY="$LFS_CLIENT_KEY_FILE" lfstest-gitserver > "$REMOTEDIR/gitserver.log" 2>&1 & 494 495 wait_for_file "$LFS_URL_FILE" 496 wait_for_file "$LFS_SSL_URL_FILE" 497 wait_for_file "$LFS_CLIENT_CERT_URL_FILE" 498 wait_for_file "$LFS_CERT_FILE" 499 wait_for_file "$LFS_CLIENT_CERT_FILE" 500 wait_for_file "$LFS_CLIENT_KEY_FILE" 501 502 LFS_CLIENT_CERT_URL=`cat $LFS_CLIENT_CERT_URL_FILE` 503 504 # Set up the initial git config and osx keychain if applicable 505 HOME="$TESTHOME" 506 mkdir "$HOME" 507 git lfs install --skip-repo 508 git config --global credential.usehttppath true 509 git config --global credential.helper lfstest 510 git config --global user.name "Git LFS Tests" 511 git config --global user.email "git-lfs@example.com" 512 git config --global http.sslcainfo "$LFS_CERT_FILE" 513 git config --global http.$LFS_CLIENT_CERT_URL/.sslKey "$LFS_CLIENT_KEY_FILE" 514 git config --global http.$LFS_CLIENT_CERT_URL/.sslCert "$LFS_CLIENT_CERT_FILE" 515 git config --global http.$LFS_CLIENT_CERT_URL/.sslVerify "false" 516 517 ( grep "git-lfs clean" "$REMOTEDIR/home/.gitconfig" > /dev/null && grep "git-lfs filter-process" "$REMOTEDIR/home/.gitconfig" > /dev/null ) || { 518 echo "global git config should be set in $REMOTEDIR/home" 519 ls -al "$REMOTEDIR/home" 520 exit 1 521 } 522 523 # setup the git credential password storage 524 mkdir -p "$CREDSDIR" 525 printf "user:pass" > "$CREDSDIR/127.0.0.1" 526 527 echo 528 echo "HOME: $HOME" 529 echo "TMP: $TMPDIR" 530 echo "CREDS: $CREDSDIR" 531 echo "lfstest-gitserver:" 532 echo " LFSTEST_URL=$LFS_URL_FILE" 533 echo " LFSTEST_SSL_URL=$LFS_SSL_URL_FILE" 534 echo " LFSTEST_CLIENT_CERT_URL=$LFS_CLIENT_CERT_URL_FILE ($LFS_CLIENT_CERT_URL)" 535 echo " LFSTEST_CERT=$LFS_CERT_FILE" 536 echo " LFSTEST_CLIENT_CERT=$LFS_CLIENT_CERT_FILE" 537 echo " LFSTEST_CLIENT_KEY=$LFS_CLIENT_KEY_FILE" 538 echo " LFSTEST_DIR=$REMOTEDIR" 539 echo "GIT:" 540 git config --global --get-regexp "lfs|credential|user" 541 542 echo 543 } 544 545 # shutdown cleans the $TRASHDIR and shuts the test Git server down. 546 shutdown() { 547 # every test/test-*.sh file should cleanup its trashdir 548 [ -z "$KEEPTRASH" ] && rm -rf "$TRASHDIR" 549 550 if [ "$SHUTDOWN_LFS" != "no" ]; then 551 # only cleanup test/remote after script/integration done OR a single 552 # test/test-*.sh file is run manually. 553 if [ -s "$LFS_URL_FILE" ]; then 554 curl -s "$(cat "$LFS_URL_FILE")/shutdown" 555 fi 556 557 [ -z "$KEEPTRASH" ] && rm -rf "$REMOTEDIR" 558 559 # delete entire lfs test root if we created it (double check pattern) 560 if [ -z "$KEEPTRASH" ] && [ "$RM_GIT_LFS_TEST_DIR" = "yes" ] && [[ $GIT_LFS_TEST_DIR == *"$TEMPDIR_PREFIX"* ]]; then 561 rm -rf "$GIT_LFS_TEST_DIR" 562 fi 563 fi 564 } 565 566 ensure_git_version_isnt() { 567 local expectedComparison=$1 568 local version=$2 569 570 local gitVersion=$(git version | cut -d" " -f3) 571 572 set +e 573 compare_version $gitVersion $version 574 result=$? 575 set -e 576 577 if [[ $result == $expectedComparison ]]; then 578 echo "skip: $0 (git version $(comparison_to_operator $expectedComparison) $version)" 579 exit 580 fi 581 } 582 583 VERSION_EQUAL=0 584 VERSION_HIGHER=1 585 VERSION_LOWER=2 586 587 # Compare $1 and $2 and return VERSION_EQUAL / VERSION_LOWER / VERSION_HIGHER 588 compare_version() { 589 if [[ $1 == $2 ]] 590 then 591 return $VERSION_EQUAL 592 fi 593 local IFS=. 594 local i ver1=($1) ver2=($2) 595 # fill empty fields in ver1 with zeros 596 for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) 597 do 598 ver1[i]=0 599 done 600 for ((i=0; i<${#ver1[@]}; i++)) 601 do 602 if [[ -z ${ver2[i]} ]] 603 then 604 # fill empty fields in ver2 with zeros 605 ver2[i]=0 606 fi 607 if ((10#${ver1[i]} > 10#${ver2[i]})) 608 then 609 return $VERSION_HIGHER 610 fi 611 if ((10#${ver1[i]} < 10#${ver2[i]})) 612 then 613 return $VERSION_LOWER 614 fi 615 done 616 return $VERSION_EQUAL 617 } 618 619 comparison_to_operator() { 620 local comparison=$1 621 if [[ $1 == $VERSION_EQUAL ]]; then 622 echo "==" 623 elif [[ $1 == $VERSION_HIGHER ]]; then 624 echo ">" 625 elif [[ $1 == $VERSION_LOWER ]]; then 626 echo "<" 627 else 628 echo "???" 629 fi 630 } 631 632 # Calculate the object ID from the string passed as the argument 633 calc_oid() { 634 printf "$1" | $SHASUM | cut -f 1 -d " " 635 } 636 637 # Calculate the object ID from the file passed as the argument 638 calc_oid_file() { 639 $SHASUM "$1" | cut -f 1 -d " " 640 } 641 642 # Get a date string with an offset 643 # Args: One or more date offsets of the form (regex) "[+-]\d+[dmyHM]" 644 # e.g. +1d = 1 day forward from today 645 # -5y = 5 years before today 646 # Example call: 647 # D=$(get_date +1y +1m -5H) 648 # returns date as string in RFC3339 format ccyy-mm-ddThh:MM:ssZ 649 # note returns in UTC time not local time hence Z and not +/- 650 get_date() { 651 # Wrapped because BSD (inc OSX) & GNU 'date' functions are different 652 # on Windows under Git Bash it's GNU 653 if date --version >/dev/null 2>&1 ; then # GNU 654 ARGS="" 655 for var in "$@" 656 do 657 # GNU offsets are more verbose 658 unit=${var: -1} 659 val=${var:0:${#var}-1} 660 case "$unit" in 661 d) unit="days" ;; 662 m) unit="months" ;; 663 y) unit="years" ;; 664 H) unit="hours" ;; 665 M) unit="minutes" ;; 666 esac 667 ARGS="$ARGS $val $unit" 668 done 669 date -d "$ARGS" -u +%Y-%m-%dT%TZ 670 else # BSD 671 ARGS="" 672 for var in "$@" 673 do 674 ARGS="$ARGS -v$var" 675 done 676 date $ARGS -u +%Y-%m-%dT%TZ 677 fi 678 } 679 680 # Convert potentially MinGW bash paths to native Windows paths 681 # Needed to match generic built paths in test scripts to native paths generated from Go 682 native_path() { 683 local arg=$1 684 if [ $IS_WINDOWS -eq 1 ]; then 685 # Use params form to avoid interpreting any '\' characters 686 printf '%s' "$(cygpath -w $arg)" 687 else 688 printf '%s' "$arg" 689 fi 690 } 691 692 # escape any instance of '\' with '\\' on Windows 693 escape_path() { 694 local unescaped="$1" 695 if [ $IS_WINDOWS -eq 1 ]; then 696 printf '%s' "${unescaped//\\/\\\\}" 697 else 698 printf '%s' "$unescaped" 699 fi 700 } 701 702 # As native_path but escape all backslash characters to "\\" 703 native_path_escaped() { 704 local unescaped=$(native_path "$1") 705 escape_path "$unescaped" 706 } 707 708 cat_end() { 709 if [ $IS_WINDOWS -eq 1 ]; then 710 printf '^M$' 711 else 712 printf '$' 713 fi 714 } 715 716 # Compare 2 lists which are newline-delimited in a string, ignoring ordering and blank lines 717 contains_same_elements() { 718 # Remove blank lines then sort 719 printf '%s' "$1" | grep -v '^$' | sort > a.txt 720 printf '%s' "$2" | grep -v '^$' | sort > b.txt 721 722 set +e 723 diff -u a.txt b.txt 1>&2 724 res=$? 725 set -e 726 rm a.txt b.txt 727 exit $res 728 } 729 730 is_stdin_attached() { 731 test -t0 732 echo $? 733 } 734 735 has_test_dir() { 736 if [ -z "$GIT_LFS_TEST_DIR" ]; then 737 echo "No GIT_LFS_TEST_DIR. Skipping..." 738 exit 0 739 fi 740 }