#!/bin/bash set -eo pipefail shopt -s dotglob # make sure we can GTFO trap 'echo >&2 Ctrl+C captured, exiting; exit 1' SIGINT usage() { cat <<-EOUSAGE usage: $0 [PR number] [repo[:tag]] ie: $0 1024 $0 9001 debian php django EOUSAGE } # TODO flags parsing allFiles= listTarballContents=1 findCopies='20%' if [ "$#" -eq 0 ]; then usage >&2 exit 1 fi pull="$1" # PR number shift #dir="$(dirname "$(readlink -f "$BASH_SOURCE")")" tempDir="$(mktemp -d)" trap "rm -rf '$tempDir'" EXIT cd "$tempDir" git clone --quiet --depth 1 \ https://github.com/docker-library/official-images.git \ oi git -C oi fetch --quiet --depth 1 \ origin "pull/$pull/merge":pull images=( "$@" ) if [ "${#images[@]}" -eq 0 ]; then images=( $(git -C oi/library diff --name-only master...pull -- . | xargs -n1 basename) ) fi export BASHBREW_CACHE="${BASHBREW_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/bashbrew}" export BASHBREW_LIBRARY="$PWD/oi/library" # TODO something less hacky than "git archive" hackery, like a "bashbrew archive" or "bashbrew context" or something template=' {{- range $.Entries -}} {{- $from := $.DockerFrom . -}} git -C "$BASHBREW_CACHE/git" archive --format=tar {{- " " -}} {{- "--prefix=" -}} {{- $.RepoName -}} _ {{- .Tags | last -}} {{- "/" -}} {{- " " -}} {{- .GitCommit -}} {{- ":" -}} {{- (eq .Directory ".") | ternary "" .Directory -}} {{- "\n" -}} {{- end -}} ' copy-tar() { local src="$1"; shift local dst="$1"; shift if [ "$allFiles" ]; then mkdir -p "$dst" cp -al "$src"/*/ "$dst/" return fi # "Dockerfile*" at the end here ensures we capture "Dockerfile.builder" style repos in a useful way too (busybox, hello-world) for d in "$src"/*/Dockerfile*; do dDir="$(dirname "$d")" dDirName="$(basename "$dDir")" IFS=$'\n' files=( "$(basename "$d")" $(awk ' toupper($1) == "COPY" || toupper($1) == "ADD" { for (i = 2; i < NF; i++) { print $i } } ' "$d") # some extra files which are likely interesting if they exist, but no big loss if they do not ' *.manifest' # debian/ubuntu "package versions" list ' *.ks' # fedora "kickstart" (rootfs build script) ' build*.txt' # ubuntu "build-info.txt", debian "build-command.txt" # usefulness yet to be proven: #' *.log' #' {MD5,SHA1,SHA256}SUMS' #' *.{md5,sha1,sha256}' # (the space prefix is removed below and is used to ignore non-matching globs so that bad "Dockerfile" entries appropriately lead to failure) ) unset IFS mkdir -p "$dst/$dDirName" for origF in "${files[@]}"; do f="${origF# }" # trim off leading space (indicates we don't care about failure) [ "$f" = "$origF" ] && failureMatters=1 || failureMatters= globbed=( $(cd "$dDir" && eval "echo $f") ) for g in "${globbed[@]}"; do if [ -z "$failureMatters" ] && [ ! -e "$dDir/$g" ]; then continue fi mkdir -p "$(dirname "$dst/$dDirName/$g")" cp -alT "$dDir/$g" "$dst/$dDirName/$g" if [ "$listTarballContents" ]; then case "$g" in *.tar.*|*.tgz) tar -tf "$dst/$dDirName/$g" | sort > "$dst/$dDirName/$g 'tar -t'" ;; esac fi done done done } mkdir temp git -C temp init --quiet for image in "${images[@]}"; do if script="$(bashbrew cat -f "$template" "$image")"; then mkdir tar ( eval "$script" | tar -xiC tar ) copy-tar tar temp rm -rf tar fi done git -C temp add . || : git -C temp commit --quiet --allow-empty -m 'initial' || : git -C oi checkout --quiet pull git -C temp rm --quiet -rf . || : script="$(bashbrew cat -f "$template" "${images[@]}")" mkdir tar ( eval "$script" | tar -xiC tar ) copy-tar tar temp rm -rf tar git -C temp add . git -C temp diff --minimal --find-copies="$findCopies" --find-copies-harder --irreversible-delete --staged