| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- #!/usr/bin/env bash
- set -Eeuo pipefail
- shopt -s dotglob
- # make sure we can GTFO
- trap 'echo >&2 Ctrl+C captured, exiting; exit 1' SIGINT
- # if bashbrew is missing, bail early with a sane error
- bashbrew --version > /dev/null
- 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%'
- uninterestingTarballContent=(
- # "config_diff_2017_01_07.log"
- 'var/log/YaST2/'
- # "ks-script-mqmz_080.log"
- # "ks-script-ycfq606i.log"
- 'var/log/anaconda/'
- # "2016-12-20/"
- 'var/lib/yum/history/'
- 'var/lib/dnf/history/'
- # "a/f8c032d2be757e1a70f00336b55c434219fee230-acl-2.2.51-12.el7-x86_64/var_uuid"
- 'var/lib/yum/yumdb/'
- 'var/lib/dnf/yumdb/'
- # "b42ff584.0"
- 'etc/pki/tls/rootcerts/'
- # "09/401f736622f2c9258d14388ebd47900bbab126"
- 'usr/lib/.build-id/'
- )
- # prints "$2$1$3$1...$N"
- join() {
- local sep="$1"; shift
- local out; printf -v out "${sep//%/%%}%s" "$@"
- echo "${out#$sep}"
- }
- uninterestingTarballGrep="^([.]?/)?($(join '|' "${uninterestingTarballContent[@]}"))"
- if [ "$#" -eq 0 ]; then
- usage >&2
- exit 1
- fi
- pull="$1" # PR number
- shift
- diffDir="$(readlink -f "$BASH_SOURCE")"
- diffDir="$(dirname "$diffDir")"
- tempDir="$(mktemp -d)"
- trap "rm -rf '$tempDir'" EXIT
- cd "$tempDir"
- git clone --quiet \
- https://github.com/docker-library/official-images.git \
- oi
- if [ "$pull" != '0' ]; then
- git -C oi fetch --quiet \
- origin "pull/$pull/merge":refs/heads/pull
- else
- git -C oi fetch --quiet --update-shallow \
- "$diffDir" HEAD:refs/heads/pull
- fi
- if [ "$#" -eq 0 ]; then
- images="$(git -C oi/library diff --no-renames --name-only HEAD...pull -- .)"
- [ -n "$images" ] || exit 0
- images="$(xargs -n1 basename <<<"$images")"
- set -- $images
- fi
- export BASHBREW_CACHE="${BASHBREW_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/bashbrew}"
- export BASHBREW_LIBRARY="$PWD/oi/library"
- : "${BASHBREW_ARCH:=amd64}" # TODO something smarter with arches
- export BASHBREW_ARCH
- # TODO something less hacky than "git archive" hackery, like a "bashbrew archive" or "bashbrew context" or something
- template='
- tempDir="$(mktemp -d)"
- {{- "\n" -}}
- {{- range $.Entries -}}
- {{- $arch := .HasArchitecture arch | ternary arch (.Architectures | first) -}}
- {{- $froms := $.ArchDockerFroms $arch . -}}
- {{- $outDir := join "_" $.RepoName (.Tags | last) -}}
- git -C "$BASHBREW_CACHE/git" archive --format=tar
- {{- " " -}}
- {{- "--prefix=" -}}
- {{- $outDir -}}
- {{- "/" -}}
- {{- " " -}}
- {{- .ArchGitCommit $arch -}}
- {{- ":" -}}
- {{- $dir := .ArchDirectory $arch -}}
- {{- (eq $dir ".") | ternary "" $dir -}}
- {{- "\n" -}}
- mkdir -p "$tempDir/{{- $outDir -}}" && echo "{{- .ArchFile $arch -}}" > "$tempDir/{{- $outDir -}}/.bashbrew-dockerfile-name"
- {{- "\n" -}}
- {{- end -}}
- tar -cC "$tempDir" . && rm -rf "$tempDir"
- '
- copy-tar() {
- local src="$1"; shift
- local dst="$1"; shift
- if [ -n "$allFiles" ]; then
- mkdir -p "$dst"
- cp -al "$src"/*/ "$dst/"
- return
- fi
- local d dockerfiles=()
- for d in "$src"/*/.bashbrew-dockerfile-name; do
- [ -f "$d" ] || continue
- local bf; bf="$(< "$d")"
- local dDir; dDir="$(dirname "$d")"
- dockerfiles+=( "$dDir/$bf" )
- if [ "$bf" = 'Dockerfile' ]; then
- # if "Dockerfile.builder" exists, let's check that too (busybox, hello-world)
- if [ -f "$dDir/$bf.builder" ]; then
- dockerfiles+=( "$dDir/$bf.builder" )
- fi
- fi
- rm "$d" # remove the ".bashbrew-dockerfile-name" file we created
- done
- for d in "${dockerfiles[@]}"; do
- local dDir; dDir="$(dirname "$d")"
- local dDirName; dDirName="$(basename "$dDir")"
- # TODO choke on "syntax" parser directive
- # TODO handle "escape" parser directive reasonably
- local flatDockerfile; flatDockerfile="$(
- gawk '
- BEGIN { line = "" }
- /^[[:space:]]*#/ {
- gsub(/^[[:space:]]+/, "")
- print
- next
- }
- {
- if (match($0, /^(.*)(\\[[:space:]]*)$/, m)) {
- line = line m[1]
- next
- }
- print line $0
- line = ""
- }
- ' "$d"
- )"
- local IFS=$'\n'
- local copyAddContext; copyAddContext="$(awk '
- toupper($1) == "COPY" || toupper($1) == "ADD" {
- for (i = 2; i < NF; i++) {
- if ($i ~ /^--from=/) {
- next
- }
- if ($i !~ /^--chown=/) {
- print $i
- }
- }
- }
- ' <<<"$flatDockerfile")"
- local dBase; dBase="$(basename "$d")"
- local files=(
- "$dBase"
- $copyAddContext
- # some extra files which are likely interesting if they exist, but no big loss if they do not
- ' .dockerignore' # will be used automatically by "docker build"
- ' *.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"
- local f origF failureMatters
- for origF in "${files[@]}"; do
- f="${origF# }" # trim off leading space (indicates we don't care about failure)
- [ "$f" = "$origF" ] && failureMatters=1 || failureMatters=
- local globbed
- # "find: warning: -path ./xxx/ will not match anything because it ends with /."
- local findGlobbedPath="${f%/}"
- findGlobbedPath="${findGlobbedPath#./}"
- local globbedStr; globbedStr="$(cd "$dDir" && find -path "./$findGlobbedPath")"
- local -a globbed=( $globbedStr )
- if [ "${#globbed[@]}" -eq 0 ]; then
- globbed=( "$f" )
- fi
- local g
- for g in "${globbed[@]}"; do
- local srcG="$dDir/$g" dstG="$dst/$dDirName/$g"
- if [ -z "$failureMatters" ] && [ ! -e "$srcG" ]; then
- continue
- fi
- local gDir; gDir="$(dirname "$dstG")"
- mkdir -p "$gDir"
- cp -alT "$srcG" "$dstG"
- if [ -n "$listTarballContents" ]; then
- case "$g" in
- *.tar.* | *.tgz)
- if [ -s "$dstG" ]; then
- tar -tf "$dstG" \
- | grep -vE "$uninterestingTarballGrep" \
- | sed -e 's!^[.]/!!' \
- -r \
- -e 's!([/.-]|^)((lib)?(c?python|py)-?)[0-9]+([.][0-9]+)?([/.-]|$)!\1\2XXX\6!g' \
- | sort \
- > "$dstG 'tar -t'"
- fi
- ;;
- esac
- fi
- done
- done
- done
- }
- # a "bashbrew cat" template that gives us the last / "least specific" tags for the arguments
- # (in other words, this is "bashbrew list --uniq" but last instead of first)
- templateLastTags='
- {{- range .TagEntries -}}
- {{- $.RepoName -}}
- {{- ":" -}}
- {{- .Tags | last -}}
- {{- "\n" -}}
- {{- end -}}
- '
- _metadata-files() {
- bashbrew list "$@" 2>>temp/_bashbrew.err | sort -uV > temp/_bashbrew-list || :
- "$diffDir/_bashbrew-cat-sorted.sh" "$@" 2>>temp/_bashbrew.err > temp/_bashbrew-cat || :
- bashbrew list --uniq "$@" \
- | sort -V \
- | xargs -r bashbrew list --uniq --build-order 2>>temp/_bashbrew.err \
- | xargs -r bashbrew cat --format "$templateLastTags" 2>>temp/_bashbrew.err \
- > temp/_bashbrew-list-build-order || :
- script="$(bashbrew cat --format "$template" "$@")"
- mkdir tar
- ( eval "$script" | tar -xiC tar )
- copy-tar tar temp
- rm -rf tar
- }
- mkdir temp
- git -C temp init --quiet
- git -C temp config user.name 'Bogus'
- git -C temp config user.email 'bogus@bogus'
- # handle "new-image" PRs gracefully
- for img; do touch "$BASHBREW_LIBRARY/$img"; [ -s "$BASHBREW_LIBRARY/$img" ] || echo 'Maintainers: New Image! :D (@docker-library-bot)' > "$BASHBREW_LIBRARY/$img"; done
- _metadata-files "$@"
- git -C temp add . || :
- git -C temp commit --quiet --allow-empty -m 'initial' || :
- git -C oi clean --quiet --force
- git -C oi checkout --quiet pull
- # handle "deleted-image" PRs gracefully :(
- for img; do touch "$BASHBREW_LIBRARY/$img"; [ -s "$BASHBREW_LIBRARY/$img" ] || echo 'Maintainers: Deleted Image D: (@docker-library-bot)' > "$BASHBREW_LIBRARY/$img"; done
- git -C temp rm --quiet -rf . || :
- _metadata-files "$@"
- git -C temp add .
- git -C temp diff \
- --find-copies-harder \
- --find-copies="$findCopies" \
- --find-renames="$findCopies" \
- --ignore-blank-lines \
- --ignore-space-at-eol \
- --ignore-space-change \
- --irreversible-delete \
- --minimal \
- --staged
|