Skip to content

Instantly share code, notes, and snippets.

@augustohp
Last active September 2, 2023 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save augustohp/97916c2a103a0827bfc2430142a4608d to your computer and use it in GitHub Desktop.
Save augustohp/97916c2a103a0827bfc2430142a4608d to your computer and use it in GitHub Desktop.
Lists tags for a Docker image
#!/usr/bin/env sh
#
# Helps listing remote tags for a given repository, going through all available
# pages using Docker Hub API.
#
# TODO Support official images
# TODO Output formating (date, humanize image size)
# TODO Allow different columns to be specified as output
# TODO Support other registries (with the same API, just different host)
#
# shellcheck disable=SC3043
APP_NAME=$(basename "$0")
APP_VERSION="1.1.0"
APP_AUTHOR="augusto.hp+oss@gmail.com"
APP_DEPENDENCIES="curl jq grep sed"
set -e # Stop on failure
OPTION_PAGE=""
OPTION_PAGE_LIMIT=""
OPTION_TAG_PATTERN=""
assert_env()
{
for dep in $APP_DEPENDENCIES
do
if [ -n "$(command -v "$dep")" ]
then
continue
fi
echo "Error: Missing '$dep'" >&2
exit 2
done
}
# -----------------------------------------------------------------------------
# Helpers
join_3_consecutive_lines()
{
sed 'N;N;s/\n/|/g'
}
remove_double_quotes()
{
sed 's/"//g'
}
# -----------------------------------------------------------------------------
# Context
# Usage: count_tags <repository>
count_tags()
{
local repository="$1"
curl -s "https://hub.docker.com/v2/repositories/${repository}/tags?page_size=${page_size}&page=${page}" \
| jq '.count'
}
# Usage: list_tags_single_page <repository> <page>
list_tags_single_page()
{
local repository="$1"
local page="$2"
curl -s "https://hub.docker.com/v2/repositories/${repository}/tags?page_size=${page_size}&page=${page}" \
| jq -c '.results | .[] | .name,.last_updated,.full_size' \
| join_3_consecutive_lines \
| remove_double_quotes
}
# Usage: list_tags_all_pages <repository> [page_limit]
list_tags_all_pages ()
{
local repository="$1"
local page_limit="${2:-}"
local page_size=100
local total_tags=1
local pages=1
local page=1
total_tags="$(count_tags "$1")"
pages=$((total_tags/page_size))
if [ "$pages" -gt "$page_limit" ]
then
pages=$page_limit
fi
while [ "$page" -le "$pages" ]
do
list_tags_single_page "$repository" "$page"
page=$((page+1))
done
}
# -----------------------------------------------------------------------------
# Program
# Usage: display_help
display_help()
{
cat <<-EOT
Usage: $APP_NAME [options] <image name>
$APP_NAME --help
$APP_NAME --page 2 --tag-pattern "^2023" jupyter/scipy-notebook
Displays tags for a Docker Image in a remote Docker Repository. Output is
formatted in a table for ease reading and manipulating on CLI.
Options:
-h, --help Prints this message.
-v, --version Prints version.
-x, --debug Displays debug (-x) information.
-p, --page <number> Single page to fetch from remote repository.
-l, --pages <limit> How many pages to fetch from remote repository.
Defaults to all of them.
-t, --tag-pattern <regex> Pattern passed to "grep" to filter lines.
Bugs and/or suggestions to $APP_AUTHOR.
EOT
}
# Usage: main "$@"
main()
{
local repository=""
while :; do
case "${1:-}" in
# Parsing options ---------------
-h|--help)
display_help
exit 0
;;
-v|--version)
echo "$APP_VERSION"
exit 0
;;
-x|--debug)
set -x
;;
-p|--page)
OPTION_PAGE="$2"
shift
;;
-l|--pages|--page-limit)
OPTION_PAGE_LIMIT="$2"
shift
;;
-t|--tag-pattern)
OPTION_TAG_PATTERN="$2"
shift
;;
# Treating mistakes -------------
-?*)
echo "Error: Unknown '$1' option." >&2
exit 3
;;
*)
# Stops parsing options
break
;;
esac
shift
done
repository="$1"
if [ -n "$OPTION_PAGE" ]
then
list_tags_single_page "$repository"
exit 0
fi
list_tags_all_pages "$repository" "$OPTION_PAGE_LIMIT" \
| grep "${OPTION_TAG_PATTERN}" \
| column --table --separator "|" --table-columns "Tag Name,Last Updated,Size"
return 0
}
assert_env
main "$@"
# vim: set ft=sh ts=4 sw=4 tw=0 noet:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment