2021-04-29 01:49:41 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
2021-04-26 16:50:36 +00:00
|
|
|
set -e
|
|
|
|
|
|
|
|
verbose=1
|
|
|
|
image="$1"
|
|
|
|
export searchpath="$2"
|
|
|
|
export tarfile="$(mktemp)-$image.tar"
|
|
|
|
|
2021-04-29 01:49:41 +00:00
|
|
|
# check to see if image exists locally
|
|
|
|
if ! docker image inspect "$image" > /dev/null ; then
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2021-04-26 16:50:36 +00:00
|
|
|
# Save image tar to temp file
|
|
|
|
[ $verbose ] && >&2 echo "Exporting image '$image' to temp file '$tarfile'..."
|
|
|
|
docker image save "$image" -o "$tarfile"
|
|
|
|
|
|
|
|
# Set up cleanup to not leave image behind
|
|
|
|
function onexit() {
|
|
|
|
[ $verbose ] && >&2 echo "Cleaning up exported image '$tarfile'"
|
|
|
|
rm "$tarfile"
|
|
|
|
}
|
|
|
|
trap onexit EXIT
|
|
|
|
|
|
|
|
# Extract manifest and config file contents
|
|
|
|
[ $verbose ] && >&2 echo "Collecting metadata from image..."
|
|
|
|
manifest=$(tar -xf "$tarfile" -x manifest.json -O | jq)
|
|
|
|
config_file=$(echo "$manifest" | jq -r '.[0].Config')
|
|
|
|
config=$(tar -f "$tarfile" -x "$config_file" -O | jq)
|
|
|
|
|
|
|
|
# Combine manifest.json and config json to build a map from tar layer directory to layer id sha
|
|
|
|
export idmap=$(echo "$manifest" "$config" | jq -sr '[ [ .[0][0].Layers, .[1].rootfs.diff_ids ] | transpose[] | { (.[0]): .[1] } ] | reduce .[] as $x ({}; . * $x)')
|
|
|
|
|
|
|
|
# Search each layer for a file matching $searchpath
|
|
|
|
# TODO also search for related whiteout files that start with `.wh.`
|
|
|
|
[ $verbose ] && >&2 echo "Searching layers for '$searchpath'..."
|
|
|
|
found=$(echo "$manifest" | jq '.[0].Layers[]' | xargs -I {} sh -c 'digest=$(echo "$idmap" | jq -r ".[\"{}\"]"); tar -f "$tarfile" -x {} -O | tar -t | sed s_^_/_ | grep -wx "$searchpath" | xargs -I [] echo "[]=$digest"')
|
|
|
|
|
2021-04-29 01:49:41 +00:00
|
|
|
foundcount=$(echo "$found" | grep -c . || true)
|
|
|
|
|
2021-04-26 16:50:36 +00:00
|
|
|
# If more than one is found, then bail
|
2021-04-29 01:49:41 +00:00
|
|
|
if [ $foundcount -gt 1 ]; then
|
|
|
|
>&2 echo "File was changed in multiple layers, aborting. Found files and layer ids:"
|
2021-04-26 16:50:36 +00:00
|
|
|
>&2 echo "$found"
|
|
|
|
exit 2
|
2021-04-29 01:49:41 +00:00
|
|
|
elif [ $foundcount -eq 0 ]; then
|
|
|
|
>&2 echo "No files found matching '$searchpath'"
|
|
|
|
exit 3
|
2021-04-26 16:50:36 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
labels=$(echo "$found" | sed 's_^.*$_--label "\0"_' | paste -d' ')
|
|
|
|
|
2021-04-29 01:49:41 +00:00
|
|
|
# Add a layer to the existing image to add the labels and tag the new image with the same image name
|
|
|
|
[ $verbose ] && >&2 echo "Rebuilding image and adding labels: $labels"
|
|
|
|
echo "FROM $image" | eval docker build $labels -t "$image" - &> /dev/null
|
2021-04-26 16:50:36 +00:00
|
|
|
|
2021-04-29 01:49:41 +00:00
|
|
|
echo "Rebuilt image '$image' with the following added labels:"
|
|
|
|
docker image inspect "$image" | jq '.[0].Config.Labels'
|
|
|
|
echo "Run 'docker push $image' to push it to docker hub"
|
2021-04-26 16:50:36 +00:00
|
|
|
|
|
|
|
exit
|
|
|
|
|