git/t/t5004-archive-corner-cases.sh

209 строки
5.8 KiB
Bash
Исходник Обычный вид История

#!/bin/sh
test_description='test corner cases of git-archive'
. ./test-lib.sh
test_expect_success 'create commit with empty tree' '
git commit --allow-empty -m foo
'
# Make a dir and clean it up afterwards
make_dir() {
mkdir "$1" &&
test_when_finished "rm -rf '$1'"
}
# Check that the dir given in "$1" contains exactly the
# set of paths given as arguments.
check_dir() {
dir=$1; shift
{
echo "$dir" &&
for i in "$@"; do
echo "$dir/$i"
done
} | sort >expect &&
find "$dir" ! -name pax_global_header -print | sort >actual &&
test_cmp expect actual
}
test_lazy_prereq UNZIP_ZIP64_SUPPORT '
"$GIT_UNZIP" -v | grep ZIP64_SUPPORT
'
# bsdtar/libarchive versions before 3.1.3 consider a tar file with a
# global pax header that is not followed by a file record as corrupt.
if "$TAR" tf "$TEST_DIRECTORY"/t5004/empty-with-pax-header.tar >/dev/null 2>&1
then
test_set_prereq HEADER_ONLY_TAR_OK
fi
test_expect_success HEADER_ONLY_TAR_OK 'tar archive of commit with empty tree' '
git archive --format=tar HEAD >empty-with-pax-header.tar &&
make_dir extract &&
"$TAR" xf empty-with-pax-header.tar -C extract &&
check_dir extract
'
test_expect_success 'tar archive of empty tree is empty' '
git archive --format=tar HEAD: >empty.tar &&
t5004: avoid using tar for checking emptiness of archive Test 2 of t5004 checks if a supposedly empty tar archive really contains no files. 24676f02 (t5004: fix issue with empty archive test and bsdtar) removed our commit hash to make it work with bsdtar, but the test still fails on NetBSD and OpenBSD, which use their own tar that considers a tar file containing only NULs as broken. Here's what the different archivers do when asked to create a tar file without entries: $ uname -v NetBSD 6.0.1 (GENERIC) $ gtar --version | head -1 tar (GNU tar) 1.26 $ bsdtar --version bsdtar 2.8.4 - libarchive 2.8.4 $ : >zero.tar $ perl -e 'print "\0" x 10240' >tenk.tar $ sha1 zero.tar tenk.tar SHA1 (zero.tar) = da39a3ee5e6b4b0d3255bfef95601890afd80709 SHA1 (tenk.tar) = 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c $ : | tar cf - -T - | sha1 da39a3ee5e6b4b0d3255bfef95601890afd80709 $ : | gtar cf - -T - | sha1 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c $ : | bsdtar cf - -T - | sha1 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c So NetBSD's native tar creates an empty file, while GNU tar and bsdtar both give us 10KB of NULs -- just like git archive with an empty tree. Now let's see how the archivers handle these two kinds of empty tar files: $ tar tf zero.tar; echo $? tar: Unexpected EOF on archive file 1 $ gtar tf zero.tar; echo $? gtar: This does not look like a tar archive gtar: Exiting with failure status due to previous errors 2 $ bsdtar tf zero.tar; echo $? 0 $ tar tf tenk.tar; echo $? tar: Cannot identify format. Searching... tar: End of archive volume 1 reached tar: Sorry, unable to determine archive format. 1 $ gtar tf tenk.tar; echo $? 0 $ bsdtar tf tenk.tar; echo $? 0 NetBSD's tar complains about both, bsdtar happily accepts any of them and GNU tar doesn't like zero-length archive files. So the safest course of action is to stay with our block-of-NULs format which is compatible with GNU tar and bsdtar, as we can't make NetBSD's native tar happy anyway. We can simplify our test, however, by taking tar out of the picture. Instead of extracting the archive and checking for the non-presence of files, check if the file has a size of 10KB and contains only NULs. This makes t5004 pass on NetBSD and OpenBSD. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-05-09 17:13:47 +04:00
perl -e "print \"\\0\" x 10240" >10knuls.tar &&
test_cmp_bin 10knuls.tar empty.tar
'
test_expect_success 'tar archive of empty tree with prefix' '
git archive --format=tar --prefix=foo/ HEAD >prefix.tar &&
make_dir extract &&
"$TAR" xf prefix.tar -C extract &&
check_dir extract foo
'
test_expect_success UNZIP 'zip archive of empty tree is empty' '
# Detect the exit code produced when our particular flavor of unzip
# sees an empty archive. Infozip will generate a warning and exit with
# code 1. But in the name of sanity, we do not expect other unzip
# implementations to do the same thing (it would be perfectly
# reasonable to exit 0, for example).
#
# This makes our test less rigorous on some platforms (unzip may not
# handle the empty repo at all, making our later check of its exit code
# a no-op). But we cannot do anything reasonable except skip the test
# on such platforms anyway, and this is the moral equivalent.
{
"$GIT_UNZIP" "$TEST_DIRECTORY"/t5004/empty.zip
expect_code=$?
} &&
git archive --format=zip HEAD >empty.zip &&
make_dir extract &&
(
cd extract &&
test_expect_code $expect_code "$GIT_UNZIP" ../empty.zip
) &&
check_dir extract
'
test_expect_success UNZIP 'zip archive of empty tree with prefix' '
# We do not have to play exit-code tricks here, because our
# result should not be empty; it has a directory in it.
git archive --format=zip --prefix=foo/ HEAD >prefix.zip &&
make_dir extract &&
(
cd extract &&
"$GIT_UNZIP" ../prefix.zip
) &&
check_dir extract foo
'
test_expect_success 'archive complains about pathspec on empty tree' '
test_must_fail git archive --format=tar HEAD -- foo >/dev/null
'
test_expect_success 'create a commit with an empty subtree' '
empty_tree=$(git hash-object -t tree /dev/null) &&
root_tree=$(printf "040000 tree $empty_tree\tsub\n" | git mktree)
'
test_expect_success 'archive empty subtree with no pathspec' '
git archive --format=tar $root_tree >subtree-all.tar &&
make_dir extract &&
"$TAR" xf subtree-all.tar -C extract &&
archive: don't add empty directories to archives While git doesn't track empty directories, git archive can be tricked into putting some into archives. One way is to construct an empty tree object, as t5004 does. While that is supported by the object database, it can't be represented in the index and thus it's unlikely to occur in the wild. Another way is using the literal name of a directory in an exclude pathspec -- its contents are are excluded, but the directory stub is included. That's inconsistent: exclude pathspecs containing wildcards don't leave empty directories in the archive. Yet another way is have a few levels of nested subdirectories (e.g. d1/d2/d3/file1) and ignoring the entries at the leaves (e.g. file1). The directories with the ignored content are ignored as well (e.g. d3), but their empty parents are included (e.g. d2). As empty directories are not supported by git, they should also not be written into archives. If an empty directory is really needed then it can be tracked and archived by placing an empty .gitignore file in it. There already is a mechanism in place for suppressing empty directories. When read_tree_recursive() encounters a directory excluded by a pathspec then it enters it anyway because it might contain included entries. It calls the callback function before it is able to decide if the directory is actually needed. For that reason git archive adds directories to a queue and writes entries for them only when it encounters the first child item -- but currently only if pathspecs with wildcards are used. Queue *all* directories, no matter if there even are pathspecs present. This prevents git archive from writing entries for empty directories in all cases. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 01:43:57 +03:00
check_dir extract
'
test_expect_success 'archive empty subtree by direct pathspec' '
git archive --format=tar $root_tree -- sub >subtree-path.tar &&
make_dir extract &&
"$TAR" xf subtree-path.tar -C extract &&
archive: don't add empty directories to archives While git doesn't track empty directories, git archive can be tricked into putting some into archives. One way is to construct an empty tree object, as t5004 does. While that is supported by the object database, it can't be represented in the index and thus it's unlikely to occur in the wild. Another way is using the literal name of a directory in an exclude pathspec -- its contents are are excluded, but the directory stub is included. That's inconsistent: exclude pathspecs containing wildcards don't leave empty directories in the archive. Yet another way is have a few levels of nested subdirectories (e.g. d1/d2/d3/file1) and ignoring the entries at the leaves (e.g. file1). The directories with the ignored content are ignored as well (e.g. d3), but their empty parents are included (e.g. d2). As empty directories are not supported by git, they should also not be written into archives. If an empty directory is really needed then it can be tracked and archived by placing an empty .gitignore file in it. There already is a mechanism in place for suppressing empty directories. When read_tree_recursive() encounters a directory excluded by a pathspec then it enters it anyway because it might contain included entries. It calls the callback function before it is able to decide if the directory is actually needed. For that reason git archive adds directories to a queue and writes entries for them only when it encounters the first child item -- but currently only if pathspecs with wildcards are used. Queue *all* directories, no matter if there even are pathspecs present. This prevents git archive from writing entries for empty directories in all cases. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 01:43:57 +03:00
check_dir extract
'
ZIPINFO=zipinfo
test_lazy_prereq ZIPINFO '
n=$("$ZIPINFO" "$TEST_DIRECTORY"/t5004/empty.zip | sed -n "2s/.* //p")
test "x$n" = "x0"
'
test_expect_success ZIPINFO 'zip archive with many entries' '
# add a directory with 256 files
mkdir 00 &&
for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f
do
for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f
do
: >00/$a$b
done
done &&
git add 00 &&
git commit -m "256 files in 1 directory" &&
# duplicate it to get 65536 files in 256 directories
subtree=$(git write-tree --prefix=00/) &&
for c in 0 1 2 3 4 5 6 7 8 9 a b c d e f
do
for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f
do
echo "040000 tree $subtree $c$d"
done
done >tree &&
tree=$(git mktree <tree) &&
# zip them
git archive -o many.zip $tree &&
# check the number of entries in the ZIP file directory
expr 65536 + 256 >expect &&
"$ZIPINFO" many.zip | head -2 | sed -n "2s/.* //p" >actual &&
test_cmp expect actual
'
test_expect_success EXPENSIVE,UNZIP,UNZIP_ZIP64_SUPPORT \
'zip archive bigger than 4GB' '
# build string containing 65536 characters
s=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef &&
s=$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s &&
s=$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s &&
# create blob with a length of 65536 + 1 bytes
blob=$(echo $s | git hash-object -w --stdin) &&
# create tree containing 65500 entries of that blob
for i in $(test_seq 1 65500)
do
echo "100644 blob $blob $i"
done >tree &&
tree=$(git mktree <tree) &&
# zip it, creating an archive a bit bigger than 4GB
git archive -0 -o many-big.zip $tree &&
"$GIT_UNZIP" -t many-big.zip 9999 65500 &&
"$GIT_UNZIP" -t many-big.zip
'
test_expect_success EXPENSIVE,LONG_IS_64BIT,UNZIP,UNZIP_ZIP64_SUPPORT,ZIPINFO \
'zip archive with files bigger than 4GB' '
# Pack created with:
# dd if=/dev/zero of=file bs=1M count=4100 && git hash-object -w file
mkdir -p .git/objects/pack &&
(
cd .git/objects/pack &&
"$GIT_UNZIP" "$TEST_DIRECTORY"/t5004/big-pack.zip
) &&
blob=754a93d6fada4c6873360e6cb4b209132271ab0e &&
size=$(expr 4100 "*" 1024 "*" 1024) &&
# create a tree containing the file
tree=$(echo "100644 blob $blob big-file" | git mktree) &&
# zip it, creating an archive with a file bigger than 4GB
git archive -o big.zip $tree &&
"$GIT_UNZIP" -t big.zip &&
"$ZIPINFO" big.zip >big.lst &&
grep $size big.lst
'
test_done