1#!/bin/sh
   2#
   3# Copyright (C) 2005 Rene Scharfe
   4#
   5test_description='git archive and git get-tar-commit-id test
   7This test covers the topics of file contents, commit date handling and
   9commit id embedding:
  10  The contents of the repository is compared to the extracted tar
  12  archive.  The repository contains simple text files, symlinks and a
  13  binary file (/bin/sh).  Only paths shorter than 99 characters are
  14  used.
  15  git archive applies the commit date to every file in the archive it
  17  creates.  The test sets the commit date to a specific value and checks
  18  if the tar archive contains that value.
  19  When giving git archive a commit id (in contrast to a tree id) it
  21  embeds this commit id into the tar archive as a comment.  The test
  22  checks the ability of git get-tar-commit-id to figure it out from the
  23  tar file.
  24'
  26. ./test-lib.sh
  28SUBSTFORMAT=%H%n
  30test_lazy_prereq TAR_NEEDS_PAX_FALLBACK '
  32        (
  33                mkdir pax &&
  34                cd pax &&
  35                "$TAR" xf "$TEST_DIRECTORY"/t5000/pax.tar &&
  36                test -f PaxHeaders.1791/file
  37        )
  38'
  39test_lazy_prereq GZIP 'gzip --version'
  41get_pax_header() {
  43        file=$1
  44        header=$2=
  45        while read len rest
  47        do
  48                if test "$len" = $(echo "$len $rest" | wc -c)
  49                then
  50                        case "$rest" in
  51                        $header*)
  52                                echo "${rest#$header}"
  53                                ;;
  54                        esac
  55                fi
  56        done <"$file"
  57}
  58check_tar() {
  60        tarfile=$1.tar
  61        listfile=$1.lst
  62        dir=$1
  63        dir_with_prefix=$dir/$2
  64        test_expect_success ' extract tar archive' '
  66                (mkdir $dir && cd $dir && "$TAR" xf -) <$tarfile
  67        '
  68        test_expect_success TAR_NEEDS_PAX_FALLBACK ' interpret pax headers' '
  70                (
  71                        cd $dir &&
  72                        for header in *.paxheader
  73                        do
  74                                data=${header%.paxheader}.data &&
  75                                if test -h $data || test -e $data
  76                                then
  77                                        path=$(get_pax_header $header path) &&
  78                                        if test -n "$path"
  79                                        then
  80                                                mv "$data" "$path"
  81                                        fi
  82                                fi
  83                        done
  84                )
  85        '
  86        test_expect_success ' validate filenames' '
  88                (cd ${dir_with_prefix}a && find .) | sort >$listfile &&
  89                test_cmp a.lst $listfile
  90        '
  91        test_expect_success ' validate file contents' '
  93                diff -r a ${dir_with_prefix}a
  94        '
  95}
  96test_expect_success \
  98    'populate workdir' \
  99    'mkdir a &&
 100     echo simple textfile >a/a &&
 101     ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
 102     echo long filename >a/four$hundred &&
 103     mkdir a/bin &&
 104     test-tool genrandom "frotz" 500000 >a/bin/sh &&
 105     printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
 106     printf "A not substituted O" >a/substfile2 &&
 107     if test_have_prereq SYMLINKS; then
 108        ln -s a a/l1
 109     else
 110        printf %s a > a/l1
 111     fi &&
 112     (p=long_path_to_a_file && cd a &&
 113      for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
 114      echo text >file_with_long_path) &&
 115     (cd a && find .) | sort >a.lst'
 116test_expect_success \
 118    'add ignored file' \
 119    'echo ignore me >a/ignored &&
 120     echo ignored export-ignore >.git/info/attributes'
 121test_expect_success 'add files to repository' '
 123        git add a &&
 124        GIT_COMMITTER_DATE="2005-05-27 22:00" git commit -m initial
 125'
 126test_expect_success 'setup export-subst' '
 128        echo "substfile?" export-subst >>.git/info/attributes &&
 129        git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
 130                >a/substfile1
 131'
 132test_expect_success \
 134    'create bare clone' \
 135    'git clone --bare . bare.git &&
 136     cp .git/info/attributes bare.git/info/attributes'
 137test_expect_success \
 139    'remove ignored file' \
 140    'rm a/ignored'
 141test_expect_success \
 143    'git archive' \
 144    'git archive HEAD >b.tar'
 145check_tar b
 147test_expect_success 'git archive --prefix=prefix/' '
 149        git archive --prefix=prefix/ HEAD >with_prefix.tar
 150'
 151check_tar with_prefix prefix/
 153test_expect_success 'git-archive --prefix=olde-' '
 155        git archive --prefix=olde- HEAD >with_olde-prefix.tar
 156'
 157check_tar with_olde-prefix olde-
 159test_expect_success 'git archive on large files' '
 161    test_config core.bigfilethreshold 1 &&
 162    git archive HEAD >b3.tar &&
 163    test_cmp_bin b.tar b3.tar
 164'
 165test_expect_success \
 167    'git archive in a bare repo' \
 168    '(cd bare.git && git archive HEAD) >b3.tar'
 169test_expect_success \
 171    'git archive vs. the same in a bare repo' \
 172    'test_cmp_bin b.tar b3.tar'
 173test_expect_success 'git archive with --output' \
 175    'git archive --output=b4.tar HEAD &&
 176    test_cmp_bin b.tar b4.tar'
 177test_expect_success 'git archive --remote' \
 179    'git archive --remote=. HEAD >b5.tar &&
 180    test_cmp_bin b.tar b5.tar'
 181test_expect_success 'git archive --remote with configured remote' '
 183        git config remote.foo.url . &&
 184        (
 185                cd a &&
 186                git archive --remote=foo --output=../b5-nick.tar HEAD
 187        ) &&
 188        test_cmp_bin b.tar b5-nick.tar
 189'
 190test_expect_success \
 192    'validate file modification time' \
 193    'mkdir extract &&
 194     "$TAR" xf b.tar -C extract a/a &&
 195     test-tool chmtime --get extract/a/a >b.mtime &&
 196     echo "1117231200" >expected.mtime &&
 197     test_cmp expected.mtime b.mtime'
 198test_expect_success \
 200    'git get-tar-commit-id' \
 201    'git get-tar-commit-id <b.tar >b.commitid &&
 202     test_cmp .git/$(git symbolic-ref HEAD) b.commitid'
 203test_expect_success 'git archive with --output, override inferred format' '
 205        git archive --format=tar --output=d4.zip HEAD &&
 206        test_cmp_bin b.tar d4.zip
 207'
 208test_expect_success GZIP 'git archive with --output and --remote creates .tgz' '
 210        git archive --output=d5.tgz --remote=. HEAD &&
 211        gzip -d -c <d5.tgz >d5.tar &&
 212        test_cmp_bin b.tar d5.tar
 213'
 214test_expect_success 'git archive --list outside of a git repo' '
 216        nongit git archive --list
 217'
 218test_expect_success 'git archive --remote outside of a git repo' '
 220        git archive HEAD >expect.tar &&
 221        nongit git archive --remote="$PWD" HEAD >actual.tar &&
 222        test_cmp_bin expect.tar actual.tar
 223'
 224test_expect_success 'clients cannot access unreachable commits' '
 226        test_commit unreachable &&
 227        sha1=$(git rev-parse HEAD) &&
 228        git reset --hard HEAD^ &&
 229        git archive $sha1 >remote.tar &&
 230        test_must_fail git archive --remote=. $sha1 >remote.tar
 231'
 232test_expect_success 'upload-archive can allow unreachable commits' '
 234        test_commit unreachable1 &&
 235        sha1=$(git rev-parse HEAD) &&
 236        git reset --hard HEAD^ &&
 237        git archive $sha1 >remote.tar &&
 238        test_config uploadarchive.allowUnreachable true &&
 239        git archive --remote=. $sha1 >remote.tar
 240'
 241test_expect_success 'setup tar filters' '
 243        git config tar.tar.foo.command "tr ab ba" &&
 244        git config tar.bar.command "tr ab ba" &&
 245        git config tar.bar.remote true &&
 246        git config tar.invalid baz
 247'
 248test_expect_success 'archive --list mentions user filter' '
 250        git archive --list >output &&
 251        grep "^tar\.foo\$" output &&
 252        grep "^bar\$" output
 253'
 254test_expect_success 'archive --list shows only enabled remote filters' '
 256        git archive --list --remote=. >output &&
 257        ! grep "^tar\.foo\$" output &&
 258        grep "^bar\$" output
 259'
 260test_expect_success 'invoke tar filter by format' '
 262        git archive --format=tar.foo HEAD >config.tar.foo &&
 263        tr ab ba <config.tar.foo >config.tar &&
 264        test_cmp_bin b.tar config.tar &&
 265        git archive --format=bar HEAD >config.bar &&
 266        tr ab ba <config.bar >config.tar &&
 267        test_cmp_bin b.tar config.tar
 268'
 269test_expect_success 'invoke tar filter by extension' '
 271        git archive -o config-implicit.tar.foo HEAD &&
 272        test_cmp_bin config.tar.foo config-implicit.tar.foo &&
 273        git archive -o config-implicit.bar HEAD &&
 274        test_cmp_bin config.tar.foo config-implicit.bar
 275'
 276test_expect_success 'default output format remains tar' '
 278        git archive -o config-implicit.baz HEAD &&
 279        test_cmp_bin b.tar config-implicit.baz
 280'
 281test_expect_success 'extension matching requires dot' '
 283        git archive -o config-implicittar.foo HEAD &&
 284        test_cmp_bin b.tar config-implicittar.foo
 285'
 286test_expect_success 'only enabled filters are available remotely' '
 288        test_must_fail git archive --remote=. --format=tar.foo HEAD \
 289                >remote.tar.foo &&
 290        git archive --remote=. --format=bar >remote.bar HEAD &&
 291        test_cmp_bin remote.bar config.bar
 292'
 293test_expect_success GZIP 'git archive --format=tgz' '
 295        git archive --format=tgz HEAD >j.tgz
 296'
 297test_expect_success GZIP 'git archive --format=tar.gz' '
 299        git archive --format=tar.gz HEAD >j1.tar.gz &&
 300        test_cmp_bin j.tgz j1.tar.gz
 301'
 302test_expect_success GZIP 'infer tgz from .tgz filename' '
 304        git archive --output=j2.tgz HEAD &&
 305        test_cmp_bin j.tgz j2.tgz
 306'
 307test_expect_success GZIP 'infer tgz from .tar.gz filename' '
 309        git archive --output=j3.tar.gz HEAD &&
 310        test_cmp_bin j.tgz j3.tar.gz
 311'
 312test_expect_success GZIP 'extract tgz file' '
 314        gzip -d -c <j.tgz >j.tar &&
 315        test_cmp_bin b.tar j.tar
 316'
 317test_expect_success GZIP 'remote tar.gz is allowed by default' '
 319        git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
 320        test_cmp_bin j.tgz remote.tar.gz
 321'
 322test_expect_success GZIP 'remote tar.gz can be disabled' '
 324        git config tar.tar.gz.remote false &&
 325        test_must_fail git archive --remote=. --format=tar.gz HEAD \
 326                >remote.tar.gz
 327'
 328test_expect_success 'archive and :(glob)' '
 330        git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual &&
 331        cat >expect <<EOF &&
 332a/
 333a/bin/
 334a/bin/sh
 335EOF
 336        test_cmp expect actual
 337'
 338test_expect_success 'catch non-matching pathspec' '
 340        test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
 341'
 342# Pull the size and date of each entry in a tarfile using the system tar.
 344#
 345# We'll pull out only the year from the date; that avoids any question of
 346# timezones impacting the result (as long as we keep our test times away from a
 347# year boundary; our reference times are all in August).
 348#
 349# The output of tar_info is expected to be "<size> <year>", both in decimal. It
 350# ignores the return value of tar. We have to do this, because some of our test
 351# input is only partial (the real data is 64GB in some cases).
 352tar_info () {
 353        "$TAR" tvf "$1" |
 354        awk '{
 355                split($4, date, "-")
 356                print $3 " " date[1]
 357        }'
 358}
 359# See if our system tar can handle a tar file with huge sizes and dates far in
 361# the future, and that we can actually parse its output.
 362#
 363# The reference file was generated by GNU tar, and the magic time and size are
 364# both octal 01000000000001, which overflows normal ustar fields.
 365test_lazy_prereq TAR_HUGE '
 366        echo "68719476737 4147" >expect &&
 367        tar_info "$TEST_DIRECTORY"/t5000/huge-and-future.tar >actual &&
 368        test_cmp expect actual
 369'
 370test_expect_success LONG_IS_64BIT 'set up repository with huge blob' '
 372        obj_d=19 &&
 373        obj_f=f9c8273ec45a8938e6999cb59b3ff66739902a &&
 374        obj=${obj_d}${obj_f} &&
 375        mkdir -p .git/objects/$obj_d &&
 376        cp "$TEST_DIRECTORY"/t5000/$obj .git/objects/$obj_d/$obj_f &&
 377        rm -f .git/index &&
 378        git update-index --add --cacheinfo 100644,$obj,huge &&
 379        git commit -m huge
 380'
 381# We expect git to die with SIGPIPE here (otherwise we
 383# would generate the whole 64GB).
 384test_expect_success LONG_IS_64BIT 'generate tar with huge size' '
 385        {
 386                git archive HEAD
 387                echo $? >exit-code
 388        } | test_copy_bytes 4096 >huge.tar &&
 389        echo 141 >expect &&
 390        test_cmp expect exit-code
 391'
 392test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '
 394        echo 68719476737 >expect &&
 395        tar_info huge.tar | cut -d" " -f1 >actual &&
 396        test_cmp expect actual
 397'
 398test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '
 400        rm -f .git/index &&
 401        echo content >file &&
 402        git add file &&
 403        GIT_COMMITTER_DATE="@68719476737 +0000" \
 404                git commit -m "tempori parendum"
 405'
 406test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '
 408        git archive HEAD >future.tar
 409'
 410test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '
 412        echo 4147 >expect &&
 413        tar_info future.tar | cut -d" " -f2 >actual &&
 414        test_cmp expect actual
 415'
 416test_done