diff --git a/support/download/helpers b/support/download/helpers new file mode 100755 index 0000000000..0e0432c884 --- /dev/null +++ b/support/download/helpers @@ -0,0 +1,70 @@ +# 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 : +# - 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 + + 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}/#" \ + --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