Skip to content

Commit 1ce0777

Browse files
committed
Merge pull request #335 from infosiftr/generate-tag-details
Add new "generate-tag-details" helper that creates detailed files with tag data
2 parents 5b364e2 + c2ae7fe commit 1ce0777

File tree

3 files changed

+190
-1
lines changed

3 files changed

+190
-1
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/bin/bash
2+
set -eo pipefail
3+
4+
repo="$1"
5+
if [ -z "$repo" ]; then
6+
echo >&2 "usage: $0 repo"
7+
echo >&2 " ie: $0 hylang"
8+
exit 1
9+
fi
10+
11+
lines="$(curl -fsSL 'https://raw.githubusercontent.com/docker-library/official-images/master/library/'"$repo" | grep -vE '^$|^#')"
12+
if [ -z "$lines" ]; then
13+
echo >&2 "Failed to read manifest file for $repo"
14+
exit 1
15+
fi
16+
17+
IFS=$'\n'
18+
tags=( $(echo "$lines" | awk -F ': +' '{ print $1 }') )
19+
unset IFS
20+
21+
tokenUrl="$(curl -sSLD- "https://registry-1.docker.io/v2/library/$repo/tags/list" -o /dev/null | tr -d '\r' | awk -F ': +' 'tolower($1) == "www-authenticate" && gsub(/^Bearer\s+realm="/, "", $2) { sub(/",/, "?", $2); gsub(/"/, "", $2); gsub(/,/, "\\&", $2); print $2 }')"
22+
token="$(curl -fsSL "$tokenUrl" | tr -d '\r' | sed -r 's/^[{]|[}]$//g' | awk -v RS=',' -F '"' '$2 == "token" { print $4 }')"
23+
authHeader="Authorization: Bearer $token"
24+
25+
get_digest() {
26+
local tag="$1"
27+
curl -sSLD- "https://registry-1.docker.io/v2/library/$repo/manifests/$tag" --header "$authHeader" -o /dev/null | tr -d '\r' | awk -F ': +' 'tolower($1) == "docker-content-digest" { print $2 }'
28+
}
29+
30+
get_manifest() {
31+
local tag="$1"
32+
curl -sSL "https://registry-1.docker.io/v2/library/$repo/manifests/$tag" --header "$authHeader" | tr -d '\r'
33+
}
34+
35+
get_blob_headers() {
36+
local blob="$1"
37+
curl -sSL "https://registry-1.docker.io/v2/library/$repo/blobs/$blob" --header "$authHeader" --head | tr -d '\r'
38+
}
39+
40+
json_get_data() {
41+
local json="$1"; shift
42+
local data="$1"; shift
43+
local strip="$1"; shift || strip='^"|"$'
44+
echo "$json" | awk -F '\t' '$1 ~ /^'"$data"'$/ { gsub(/'"$strip"'/, "", $2); print $2 }'
45+
}
46+
47+
humanSizeUnits=( B KB MB GB TB )
48+
humanSizeScale=1
49+
human_size() {
50+
local bytes="$1"
51+
local unit=0
52+
local unitBytes="$1"
53+
while unitBytes="$(echo "scale=0; $bytes / (1000 ^ $unit)" | bc -l)" && [ "$unitBytes" -gt 1000 ]; do
54+
if [ ! "${humanSizeUnits[$(( unit + 1 ))]}" ]; then
55+
break
56+
fi
57+
unit="$(( unit + 1 ))"
58+
done
59+
echo "$(echo "scale=$humanSizeScale; $bytes / (1000 ^ $unit)" | bc -l) ${humanSizeUnits[$unit]}"
60+
}
61+
62+
size() {
63+
text="$(human_size "$1")"
64+
if [[ "$text" != *' B' ]]; then
65+
text+=" ($1 bytes)"
66+
fi
67+
echo "$text"
68+
}
69+
70+
pdate() {
71+
TZ=America/Los_Angeles date --date="$1" --rfc-2822
72+
}
73+
74+
jsonSh="$(curl -fsSL 'https://raw.githubusercontent.com/dominictarr/JSON.sh/ed3f9dd285ebd4183934adb54ea5a2fda6b25a98/JSON.sh')"
75+
76+
echo "# Tags of \`$repo\`"
77+
78+
# add a simple ToC
79+
echo
80+
for tag in "${tags[@]}"; do
81+
# GitHub heading anchors are strange
82+
href="${repo}:${tag}"
83+
href="${href//./}"
84+
href="${href//:/}"
85+
href="${href,,}"
86+
echo "- [\`$repo:$tag\`](#${href})"
87+
done
88+
89+
declare -A layerData=()
90+
91+
for tag in "${tags[@]}"; do
92+
echo
93+
echo "## \`$repo:$tag\`"
94+
digest="$(get_digest "$tag")"
95+
if [ "$digest" ]; then
96+
echo
97+
echo '```console'
98+
echo "$ docker pull $repo@$digest"
99+
echo '```'
100+
fi
101+
manifest="$(get_manifest "$tag")"
102+
if [ "$manifest" ]; then
103+
parsedManifest="$(echo "$manifest" | bash <(echo "$jsonSh") -l)"
104+
eval "declare -A layerBlobs=( $(echo "$parsedManifest" | awk -F '\t' 'gsub(/^\["fsLayers",/, "", $1) && gsub(/,"blobSum"\]$/, "", $1) { print "[" $1 "]=" $2 }') )"
105+
eval "declare -A layerV1s=( $(echo "$parsedManifest" | awk -F '\t' 'gsub(/^\["history",/, "", $1) && gsub(/,"v1Compatibility"\]$/, "", $1) { print "[" $1 "]=" $2 }') )"
106+
declare -A parentChild=()
107+
declare -A totals=(
108+
[Size]=0
109+
[content-length]=0
110+
)
111+
for i in "${!layerV1s[@]}"; do
112+
layerV1="${layerV1s[$i]%'\n'}" # lol \n
113+
parsedLayerV1="$(echo "$layerV1" | bash <(echo "$jsonSh"))"
114+
layerId="$(json_get_data "$parsedLayerV1" '\["id"\]')"
115+
if [ -z "${layerData[$layerId]}" ]; then
116+
layerData["$layerId"]=1
117+
for field in created parent docker_version Size; do
118+
layerData["${layerId}_${field}"]="$(json_get_data "$parsedLayerV1" '\["'"$field"'"\]')"
119+
done
120+
layerData["${layerId}_container_cmd"]="$(json_get_data "$parsedLayerV1" '\["container_config","Cmd"\]' '')"
121+
layerData["${layerId}_blob"]="${layerBlobs[$i]}"
122+
blobHeaders="$(get_blob_headers "${layerData["${layerId}_blob"]}")"
123+
for header in content-length last-modified; do
124+
layerData["${layerId}_${header}"]="$(echo "$blobHeaders" | awk -F ': +' 'tolower($1) == "'"$header"'" { print $2 }')"
125+
done
126+
fi
127+
parentChild["${layerData[${layerId}_parent]:-none}"]="$layerId"
128+
for field in Size content-length; do
129+
totals["$field"]="$(echo "${totals[$field]} + ${layerData[${layerId}_${field}]}" | bc)"
130+
done
131+
done
132+
echo
133+
echo "- Total Virtual Size: $(size "${totals[Size]}")"
134+
echo "- Total v2 Content-Length: $(size "${totals[content-length]}"); compressed"
135+
if [ "${#parentChild[@]}" -gt 0 ]; then
136+
echo
137+
echo "### Layers (${#parentChild[@]})"
138+
cur="${parentChild[none]}"
139+
while [ "$cur" ]; do
140+
echo
141+
echo "#### \`$cur\`"
142+
cmd="${layerData[${cur}_container_cmd]}"
143+
if [ "$cmd" ]; then
144+
cmd="${cmd//'\u0026'/'&'}"
145+
cmd="${cmd//'\u003c'/'<'}"
146+
cmd="${cmd//'\u003e'/'>'}"
147+
echo
148+
echo '```json'
149+
echo "$cmd"
150+
echo '```'
151+
fi
152+
echo
153+
echo "- Created: $(pdate "${layerData[${cur}_created]}")"
154+
if [ "${layerData[${cur}_parent]}" ]; then
155+
echo "- Parent Layer: \`${layerData[${cur}_parent]}\`"
156+
fi
157+
echo "- Docker Version: ${layerData[${cur}_docker_version]}"
158+
echo "- Virtual Size: $(size "${layerData[${cur}_Size]}")"
159+
echo "- v2 Blob: \`${layerData[${cur}_blob]}\`"
160+
echo "- v2 Content-Length: $(size "${layerData[${cur}_content-length]}"); compressed"
161+
echo "- v2 Last-Modified: $(pdate "${layerData[${cur}_last-modified]}")"
162+
cur="${parentChild[$cur]}"
163+
done
164+
fi
165+
fi
166+
done

.template-helpers/template.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
%%TAGS%%
44

5-
For more information about this image and its history, please see the [relevant manifest file (`library/%%REPO%%`)](https://github.com/docker-library/official-images/blob/master/library/%%REPO%%). This image is updated via pull requests to [the `docker-library/official-images` GitHub repo](https://github.com/docker-library/official-images).
5+
For more information about this image and its history, please see [the relevant manifest file (`library/%%REPO%%`)](https://github.com/docker-library/official-images/blob/master/library/%%REPO%%). This image is updated via pull requests to [the `docker-library/official-images` GitHub repo](https://github.com/docker-library/official-images).
6+
7+
For detailed information about the virtual/transfer sizes and individual layers of each of the above supported tags, please see [the `%%REPO%%/tag-details.md` file](https://github.com/docker-library/docs/blob/master/%%REPO%%/tag-details.md) in [the `docker-library/docs` GitHub repo](https://github.com/docker-library/docs).
68

79
%%CONTENT%%%%VARIANT%%%%LICENSE%%
810

update-tag-details.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
set -eo pipefail
3+
4+
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
5+
helperDir='.template-helpers'
6+
7+
repos=( "$@" )
8+
if [ ${#repos[@]} -eq 0 ]; then
9+
repos=( */ )
10+
fi
11+
repos=( "${repos[@]%/}" )
12+
13+
for repo in "${repos[@]}"; do
14+
echo -n "$repo ... "
15+
{
16+
echo "<!-- THIS FILE IS GENERATED BY '$helperDir/generate-tag-details.sh' -->"
17+
echo
18+
"$helperDir/generate-tag-details.sh" "$repo"
19+
} > "$repo/tag-details.md"
20+
echo 'done'
21+
done

0 commit comments

Comments
 (0)