-
-
Save lgs/f8aec2223a93bc929139 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
## Updates an existing image with given script coming from stdin. | |
## | |
exname=$(basename $0) | |
usage="$exname DOCKER_IMAGE | |
Update image with stdin instruction. | |
" | |
if [ -z "$1" ]; then | |
echo "Error: you should specify a parent image as first argument." >&2 | |
echo "usage: $usage" | |
exit 1 | |
fi | |
image="$1" | |
shift | |
DOCKER_VERSION=$(docker -v | sed -r 's/^[^0-9.]+([0-9.]+).*$/\1/g') | |
is_cached_code_same() { | |
local cmd | |
cmd="$@" | |
code="$(cat -)" | |
[ "$1" == "-c" ] || return 1 | |
[ "$2" == "$code" ] || return 1 | |
if echo "$code" | egrep "#\s*docker:\s*ALWAYS\s*" >/dev/null 2>&1; then | |
return 1 | |
fi | |
return 0 | |
} | |
DOCKER_INSPECT_CACHE_FORMAT='{{.Id}}{{"\x00"}} | |
{{.Parent}}{{"\x00"}} | |
{{if .Config}}{{range $p := .Config.Cmd}}{{$p}}{{"\x00"}} | |
{{end}}{{end}}{{"\x00"}}' | |
DOCKER_INSPECT_CACHE_FORMAT="$(echo "$DOCKER_INSPECT_CACHE_FORMAT" | tr -d "\n")" | |
export DOCKER_INSPECT_CACHE_FORMAT | |
## | |
# check_cache PARENT_IMAGE | |
# | |
# Checks if no already stored image has PARENT_IMAGE as parent and | |
# same code. If it founds such an image, it'll output its id in stdout | |
# and return 0 errlvl. Otherwise it'll return 1 errlvl. | |
check_cache() { | |
local image | |
image="$1" | |
shift | |
code="$(cat -)" | |
image_id=$(get_image_id "$image") | |
while read-0 id parent; do | |
cmd=() | |
while true; do | |
read-0 elt | |
if [ "$elt" ]; then | |
cmd=("${cmd[@]}" "$elt") | |
else | |
break | |
fi | |
done | |
if [ "$parent" != "$image_id" ]; then | |
continue | |
fi | |
if echo "$code" | is_cached_code_same "${cmd[@]}"; then | |
## not used "$id" as there is a spurious \n that is inserted by --format | |
echo $id | |
return 0 | |
fi | |
done < <(docker inspect --format "$DOCKER_INSPECT_CACHE_FORMAT" $(docker images -qa)) | |
return 1 | |
} | |
docker_update() { | |
local image | |
image="$1" | |
shift | |
code=$(cat -) | |
## Saving CMD and ENTRYPOINT | |
save_cmd=$(docker inspect --format='{{json .Config.Cmd}}' "$image") | |
save_entrypoint=$(docker inspect --format='{{json .Config.Entrypoint}}' "$image") | |
## Checking cache in case already built. | |
if cached=$(echo "$code" | check_cache "$image"); then | |
echo "cached" | |
docker tag "$cached" "$image" | |
else | |
## Running code in container | |
container_id=$(docker run -d \ | |
--entrypoint /bin/bash \ | |
"$@" "$image" -c \ | |
"$code" | |
) | |
if [ "$(docker wait "$container_id")" != "0" ]; then | |
echo "Update of image "$image" failed ! (container: $container_id)" | |
echo "=== code:" | |
echo "$code" | |
echo "=== logs:" | |
docker logs "$container_id" | |
exit 1 | |
fi | |
docker commit --author "$exname" --message "$exname" \ | |
"$container_id" "$image" >/dev/null && | |
docker rm $container_id >/dev/null | |
echo "updated" | |
fi | |
## Final commit to restore CMD and ENTRYPOINT | |
docker build -t "$image" - <<EOF >/dev/null 2>&1 | |
FROM $image | |
CMD $save_cmd | |
ENTRYPOINT $save_entrypoint | |
EOF | |
} | |
read-0() { | |
while [ "$1" ]; do | |
IFS=$'\0' read -r -d '' "$1" || return 1 | |
shift | |
done | |
} | |
get_image_id() { | |
docker inspect --format '{{.Id}}' "$1" | |
} | |
docker_update "$image" "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment