12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- # Generate a reproducible archive from the content of a directory
- #
- # $1 : input directory
- # $2 : leading component in archive
- # $3 : ISO8601 date: YYYY-MM-DDThh:mm:ssZZ
- # $4 : output file
- # $5... : globs of filenames to exclude from the archive, suitable for
- # find's -path option, and relative to the input directory $1
- #
- # Notes :
- # - the timestamp is internally rounded to the highest entire second
- # less than or equal to the timestamp (i.e. any sub-second fractional
- # part is ignored)
- # - must not be called with CWD as, or below, the input directory
- # - some temporary files are created in CWD, and removed at the end
- #
- # Example:
- # $ find /path/to/temp/dir
- # /path/to/temp/dir/
- # /path/to/temp/dir/some-file
- # /path/to/temp/dir/some-dir/
- # /path/to/temp/dir/some-dir/some-other-file
- #
- # $ mk_tar_gz /path/to/some/dir \
- # foo_bar-1.2.3 \
- # 1970-01-01T00:00:00Z \
- # /path/to/foo.tar.gz \
- # '.git/*' '.svn/*'
- #
- # $ tar tzf /path/to/foo.tar.gz
- # foo_bar-1.2.3/some-file
- # foo_bar-1.2.3/some-dir/some-other-file
- #
- mk_tar_gz() {
- local in_dir="${1}"
- local base_dir="${2}"
- local date="${3}"
- local out="${4}"
- shift 4
- local glob tmp pax_options
- local -a find_opts
- for glob; do
- find_opts+=( -or -path "./${glob#./}" )
- done
- # Drop sub-second precision to play nice with GNU tar's valid_timespec check
- date="$(date -d "${date}" -u +%Y-%m-%dT%H:%M:%S+00:00)"
- pax_options="delete=atime,delete=ctime,delete=mtime"
- pax_options+=",exthdr.name=%d/PaxHeaders/%f,exthdr.mtime={${date}}"
- tmp="$(mktemp --tmpdir="$(pwd)")"
- pushd "${in_dir}" >/dev/null
- # Establish list
- find . -not -type d -and -not \( -false "${find_opts[@]}" \) >"${tmp}.list"
- # Sort list for reproducibility
- LC_ALL=C sort <"${tmp}.list" >"${tmp}.sorted"
- # Create POSIX tarballs, since that's the format the most reproducible
- tar cf - --transform="s#^\./#${base_dir}/#S" \
- --numeric-owner --owner=0 --group=0 --mtime="${date}" \
- --format=posix --pax-option="${pax_options}" \
- -T "${tmp}.sorted" >"${tmp}.tar"
- # Compress the archive
- gzip -6 -n <"${tmp}.tar" >"${out}"
- rm -f "${tmp}"{.list,.sorted,.tar}
- popd >/dev/null
- }
- # Keep this line and the following as last lines in this file.
- # vim: ft=bash
|