| # 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 |