xref: /OK3568_Linux_fs/buildroot/support/download/helpers (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1# Generate a reproducible archive from the content of a directory
2#
3# $1    : input directory
4# $2    : leading component in archive
5# $3    : ISO8601 date: YYYY-MM-DDThh:mm:ssZZ
6# $4    : output file
7# $5... : globs of filenames to exclude from the archive, suitable for
8#         find's -path option, and relative to the input directory $1
9#
10# Notes :
11#   - the timestamp is internally rounded to the highest entire second
12#     less than or equal to the timestamp (i.e. any sub-second fractional
13#     part is ignored)
14#   - must not be called with CWD as, or below, the input directory
15#   - some temporary files are created in CWD, and removed at the end
16#
17# Example:
18#   $ find /path/to/temp/dir
19#   /path/to/temp/dir/
20#   /path/to/temp/dir/some-file
21#   /path/to/temp/dir/some-dir/
22#   /path/to/temp/dir/some-dir/some-other-file
23#
24#   $ mk_tar_gz /path/to/some/dir \
25#               foo_bar-1.2.3 \
26#               1970-01-01T00:00:00Z \
27#               /path/to/foo.tar.gz \
28#               '.git/*' '.svn/*'
29#
30#   $ tar tzf /path/to/foo.tar.gz
31#   foo_bar-1.2.3/some-file
32#   foo_bar-1.2.3/some-dir/some-other-file
33#
34mk_tar_gz() {
35    local in_dir="${1}"
36    local base_dir="${2}"
37    local date="${3}"
38    local out="${4}"
39    shift 4
40    local glob tmp pax_options
41    local -a find_opts
42
43    for glob; do
44        find_opts+=( -or -path "./${glob#./}" )
45    done
46
47    # Drop sub-second precision to play nice with GNU tar's valid_timespec check
48    date="$(date -d "${date}" -u +%Y-%m-%dT%H:%M:%S+00:00)"
49
50    pax_options="delete=atime,delete=ctime,delete=mtime"
51    pax_options+=",exthdr.name=%d/PaxHeaders/%f,exthdr.mtime={${date}}"
52
53    tmp="$(mktemp --tmpdir="$(pwd)")"
54    pushd "${in_dir}" >/dev/null
55
56    # Establish list
57    find . -not -type d -and -not \( -false "${find_opts[@]}" \) >"${tmp}.list"
58    # Sort list for reproducibility
59    LC_ALL=C sort <"${tmp}.list" >"${tmp}.sorted"
60
61    # Create POSIX tarballs, since that's the format the most reproducible
62    tar cf - --transform="s#^\./#${base_dir}/#S" \
63             --numeric-owner --owner=0 --group=0 --mtime="${date}" \
64             --format=posix --pax-option="${pax_options}" \
65             -T "${tmp}.sorted" >"${tmp}.tar"
66
67    # Compress the archive
68    gzip -6 -n <"${tmp}.tar" >"${out}"
69
70    rm -f "${tmp}"{.list,.sorted,.tar}
71
72    popd >/dev/null
73}
74
75# Keep this line and the following as last lines in this file.
76# vim: ft=bash
77