Merge branch 'ab/config-based-hooks-base' into seen
[git] / t / t5000-tar-tree.sh
1 #!/bin/sh
2 #
3 # Copyright (C) 2005 Rene Scharfe
4 #
5
6 test_description='git archive and git get-tar-commit-id test
7
8 This test covers the topics of file contents, commit date handling and
9 commit id embedding:
10
11   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
16   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
20   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
25 '
26
27 . ./test-lib.sh
28
29 SUBSTFORMAT=%H%n
30
31 test_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 '
39
40 test_lazy_prereq GZIP 'gzip --version'
41
42 get_pax_header() {
43         file=$1
44         header=$2=
45
46         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 }
58
59 check_tar() {
60         tarfile=$1.tar
61         listfile=$1.lst
62         dir=$1
63         dir_with_prefix=$dir/$2
64
65         test_expect_success ' extract tar archive' '
66                 (mkdir $dir && cd $dir && "$TAR" xf -) <$tarfile
67         '
68
69         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
87         test_expect_success ' validate filenames' '
88                 (cd ${dir_with_prefix}a && find .) | sort >$listfile &&
89                 test_cmp a.lst $listfile
90         '
91
92         test_expect_success ' validate file contents' '
93                 diff -r a ${dir_with_prefix}a
94         '
95 }
96
97 check_added() {
98         dir=$1
99         path_in_fs=$2
100         path_in_archive=$3
101
102         test_expect_success " validate extra file $path_in_archive" '
103                 diff -r $path_in_fs $dir/$path_in_archive
104         '
105 }
106
107 test_expect_success 'setup' '
108         test_oid_cache <<-EOF
109         obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a
110         obj sha256:3c666f798798601571f5cec0adb57ce4aba8546875e7693177e0535f34d2c49b
111         EOF
112 '
113
114 test_expect_success 'populate workdir' '
115         mkdir a &&
116         echo simple textfile >a/a &&
117         ten=0123456789 &&
118         hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" &&
119         echo long filename >"a/four$hundred" &&
120         mkdir a/bin &&
121         test-tool genrandom "frotz" 500000 >a/bin/sh &&
122         printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
123         printf "A not substituted O" >a/substfile2 &&
124         if test_have_prereq SYMLINKS
125         then
126                 ln -s a a/l1
127         else
128                 printf %s a >a/l1
129         fi &&
130         (
131                 p=long_path_to_a_file &&
132                 cd a &&
133                 for depth in 1 2 3 4 5
134                 do
135                         mkdir $p &&
136                         cd $p
137                 done &&
138                 echo text >file_with_long_path
139         ) &&
140         (cd a && find .) | sort >a.lst
141 '
142
143 test_expect_success \
144     'add ignored file' \
145     'echo ignore me >a/ignored &&
146      echo ignored export-ignore >.git/info/attributes'
147
148 test_expect_success 'add files to repository' '
149         git add a &&
150         GIT_COMMITTER_DATE="2005-05-27 22:00" git commit -m initial
151 '
152
153 test_expect_success 'setup export-subst' '
154         echo "substfile?" export-subst >>.git/info/attributes &&
155         git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
156                 >a/substfile1
157 '
158
159 test_expect_success 'create bare clone' '
160         git clone --bare . bare.git &&
161         cp .git/info/attributes bare.git/info/attributes
162 '
163
164 test_expect_success 'remove ignored file' '
165         rm a/ignored
166 '
167
168 test_expect_success 'git archive' '
169         git archive HEAD >b.tar
170 '
171
172 check_tar b
173
174 test_expect_success 'git archive --prefix=prefix/' '
175         git archive --prefix=prefix/ HEAD >with_prefix.tar
176 '
177
178 check_tar with_prefix prefix/
179
180 test_expect_success 'git-archive --prefix=olde-' '
181         git archive --prefix=olde- HEAD >with_olde-prefix.tar
182 '
183
184 check_tar with_olde-prefix olde-
185
186 test_expect_success 'git archive --add-file' '
187         echo untracked >untracked &&
188         git archive --add-file=untracked HEAD >with_untracked.tar
189 '
190
191 check_tar with_untracked
192 check_added with_untracked untracked untracked
193
194 test_expect_success 'git archive --add-file twice' '
195         echo untracked >untracked &&
196         git archive --prefix=one/ --add-file=untracked \
197                 --prefix=two/ --add-file=untracked \
198                 --prefix= HEAD >with_untracked2.tar
199 '
200
201 check_tar with_untracked2
202 check_added with_untracked2 untracked one/untracked
203 check_added with_untracked2 untracked two/untracked
204
205 test_expect_success 'git archive on large files' '
206         test_config core.bigfilethreshold 1 &&
207         git archive HEAD >b3.tar &&
208         test_cmp_bin b.tar b3.tar
209 '
210
211 test_expect_success 'git archive in a bare repo' '
212         git --git-dir bare.git archive HEAD >b3.tar
213 '
214
215 test_expect_success 'git archive vs. the same in a bare repo' '
216         test_cmp_bin b.tar b3.tar
217 '
218
219 test_expect_success 'git archive with --output' '
220         git archive --output=b4.tar HEAD &&
221         test_cmp_bin b.tar b4.tar
222 '
223
224 test_expect_success 'git archive --remote' '
225         git archive --remote=. HEAD >b5.tar &&
226         test_cmp_bin b.tar b5.tar
227 '
228
229 test_expect_success 'git archive --remote with configured remote' '
230         git config remote.foo.url . &&
231         (
232                 cd a &&
233                 git archive --remote=foo --output=../b5-nick.tar HEAD
234         ) &&
235         test_cmp_bin b.tar b5-nick.tar
236 '
237
238 test_expect_success 'validate file modification time' '
239         mkdir extract &&
240         "$TAR" xf b.tar -C extract a/a &&
241         test-tool chmtime --get extract/a/a >b.mtime &&
242         echo "1117231200" >expected.mtime &&
243         test_cmp expected.mtime b.mtime
244 '
245
246 test_expect_success 'git get-tar-commit-id' '
247         git get-tar-commit-id <b.tar >actual &&
248         git rev-parse HEAD >expect &&
249         test_cmp expect actual
250 '
251
252 test_expect_success 'git archive with --output, override inferred format' '
253         git archive --format=tar --output=d4.zip HEAD &&
254         test_cmp_bin b.tar d4.zip
255 '
256
257 test_expect_success GZIP 'git archive with --output and --remote creates .tgz' '
258         git archive --output=d5.tgz --remote=. HEAD &&
259         gzip -d -c <d5.tgz >d5.tar &&
260         test_cmp_bin b.tar d5.tar
261 '
262
263 test_expect_success 'git archive --list outside of a git repo' '
264         nongit git archive --list
265 '
266
267 test_expect_success 'git archive --remote outside of a git repo' '
268         git archive HEAD >expect.tar &&
269         nongit git archive --remote="$PWD" HEAD >actual.tar &&
270         test_cmp_bin expect.tar actual.tar
271 '
272
273 test_expect_success 'clients cannot access unreachable commits' '
274         test_commit unreachable &&
275         sha1=$(git rev-parse HEAD) &&
276         git reset --hard HEAD^ &&
277         git archive $sha1 >remote.tar &&
278         test_must_fail git archive --remote=. $sha1 >remote.tar
279 '
280
281 test_expect_success 'upload-archive can allow unreachable commits' '
282         test_commit unreachable1 &&
283         sha1=$(git rev-parse HEAD) &&
284         git reset --hard HEAD^ &&
285         git archive $sha1 >remote.tar &&
286         test_config uploadarchive.allowUnreachable true &&
287         git archive --remote=. $sha1 >remote.tar
288 '
289
290 test_expect_success 'setup tar filters' '
291         git config tar.tar.foo.command "tr ab ba" &&
292         git config tar.bar.command "tr ab ba" &&
293         git config tar.bar.remote true &&
294         git config tar.invalid baz
295 '
296
297 test_expect_success 'archive --list mentions user filter' '
298         git archive --list >output &&
299         grep "^tar\.foo\$" output &&
300         grep "^bar\$" output
301 '
302
303 test_expect_success 'archive --list shows only enabled remote filters' '
304         git archive --list --remote=. >output &&
305         ! grep "^tar\.foo\$" output &&
306         grep "^bar\$" output
307 '
308
309 test_expect_success 'invoke tar filter by format' '
310         git archive --format=tar.foo HEAD >config.tar.foo &&
311         tr ab ba <config.tar.foo >config.tar &&
312         test_cmp_bin b.tar config.tar &&
313         git archive --format=bar HEAD >config.bar &&
314         tr ab ba <config.bar >config.tar &&
315         test_cmp_bin b.tar config.tar
316 '
317
318 test_expect_success 'invoke tar filter by extension' '
319         git archive -o config-implicit.tar.foo HEAD &&
320         test_cmp_bin config.tar.foo config-implicit.tar.foo &&
321         git archive -o config-implicit.bar HEAD &&
322         test_cmp_bin config.tar.foo config-implicit.bar
323 '
324
325 test_expect_success 'default output format remains tar' '
326         git archive -o config-implicit.baz HEAD &&
327         test_cmp_bin b.tar config-implicit.baz
328 '
329
330 test_expect_success 'extension matching requires dot' '
331         git archive -o config-implicittar.foo HEAD &&
332         test_cmp_bin b.tar config-implicittar.foo
333 '
334
335 test_expect_success 'only enabled filters are available remotely' '
336         test_must_fail git archive --remote=. --format=tar.foo HEAD \
337                 >remote.tar.foo &&
338         git archive --remote=. --format=bar >remote.bar HEAD &&
339         test_cmp_bin remote.bar config.bar
340 '
341
342 test_expect_success GZIP 'git archive --format=tgz' '
343         git archive --format=tgz HEAD >j.tgz
344 '
345
346 test_expect_success GZIP 'git archive --format=tar.gz' '
347         git archive --format=tar.gz HEAD >j1.tar.gz &&
348         test_cmp_bin j.tgz j1.tar.gz
349 '
350
351 test_expect_success GZIP 'infer tgz from .tgz filename' '
352         git archive --output=j2.tgz HEAD &&
353         test_cmp_bin j.tgz j2.tgz
354 '
355
356 test_expect_success GZIP 'infer tgz from .tar.gz filename' '
357         git archive --output=j3.tar.gz HEAD &&
358         test_cmp_bin j.tgz j3.tar.gz
359 '
360
361 test_expect_success GZIP 'extract tgz file' '
362         gzip -d -c <j.tgz >j.tar &&
363         test_cmp_bin b.tar j.tar
364 '
365
366 test_expect_success GZIP 'remote tar.gz is allowed by default' '
367         git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
368         test_cmp_bin j.tgz remote.tar.gz
369 '
370
371 test_expect_success GZIP 'remote tar.gz can be disabled' '
372         git config tar.tar.gz.remote false &&
373         test_must_fail git archive --remote=. --format=tar.gz HEAD \
374                 >remote.tar.gz
375 '
376
377 test_expect_success 'archive and :(glob)' '
378         git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual &&
379         cat >expect <<EOF &&
380 a/
381 a/bin/
382 a/bin/sh
383 EOF
384         test_cmp expect actual
385 '
386
387 test_expect_success 'catch non-matching pathspec' '
388         test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
389 '
390
391 # Pull the size and date of each entry in a tarfile using the system tar.
392 #
393 # We'll pull out only the year from the date; that avoids any question of
394 # timezones impacting the result (as long as we keep our test times away from a
395 # year boundary; our reference times are all in August).
396 #
397 # The output of tar_info is expected to be "<size> <year>", both in decimal. It
398 # ignores the return value of tar. We have to do this, because some of our test
399 # input is only partial (the real data is 64GB in some cases).
400 tar_info () {
401         "$TAR" tvf "$1" |
402         awk '{
403                 split($4, date, "-")
404                 print $3 " " date[1]
405         }'
406 }
407
408 # See if our system tar can handle a tar file with huge sizes and dates far in
409 # the future, and that we can actually parse its output.
410 #
411 # The reference file was generated by GNU tar, and the magic time and size are
412 # both octal 01000000000001, which overflows normal ustar fields.
413 test_lazy_prereq TAR_HUGE '
414         echo "68719476737 4147" >expect &&
415         tar_info "$TEST_DIRECTORY"/t5000/huge-and-future.tar >actual &&
416         test_cmp expect actual
417 '
418
419 test_expect_success LONG_IS_64BIT 'set up repository with huge blob' '
420         obj=$(test_oid obj) &&
421         path=$(test_oid_to_path $obj) &&
422         mkdir -p .git/objects/$(dirname $path) &&
423         cp "$TEST_DIRECTORY"/t5000/huge-object .git/objects/$path &&
424         rm -f .git/index &&
425         git update-index --add --cacheinfo 100644,$obj,huge &&
426         git commit -m huge
427 '
428
429 # We expect git to die with SIGPIPE here (otherwise we
430 # would generate the whole 64GB).
431 test_expect_success LONG_IS_64BIT 'generate tar with huge size' '
432         {
433                 git archive HEAD
434                 echo $? >exit-code
435         } | test_copy_bytes 4096 >huge.tar &&
436         echo 141 >expect &&
437         test_cmp expect exit-code
438 '
439
440 test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '
441         echo 68719476737 >expect &&
442         tar_info huge.tar | cut -d" " -f1 >actual &&
443         test_cmp expect actual
444 '
445
446 test_expect_success TIME_IS_64BIT 'set up repository with far-future (2^34 - 1) commit' '
447         rm -f .git/index &&
448         echo foo >file &&
449         git add file &&
450         GIT_COMMITTER_DATE="@17179869183 +0000" \
451                 git commit -m "tempori parendum"
452 '
453
454 test_expect_success TIME_IS_64BIT 'generate tar with far-future mtime' '
455         git archive HEAD >future.tar
456 '
457
458 test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '
459         echo 2514 >expect &&
460         tar_info future.tar | cut -d" " -f2 >actual &&
461         test_cmp expect actual
462 '
463
464 test_expect_success TIME_IS_64BIT 'set up repository with far-far-future (2^36 + 1) commit' '
465         rm -f .git/index &&
466         echo content >file &&
467         git add file &&
468         GIT_TEST_COMMIT_GRAPH=0 GIT_COMMITTER_DATE="@68719476737 +0000" \
469                 git commit -m "tempori parendum"
470 '
471
472 test_expect_success TIME_IS_64BIT 'generate tar with far-far-future mtime' '
473         git archive HEAD >future.tar
474 '
475
476 test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '
477         echo 4147 >expect &&
478         tar_info future.tar | cut -d" " -f2 >actual &&
479         test_cmp expect actual
480 '
481
482 test_done