Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
StevenBlack
GitHub Repository: StevenBlack/hosts
Path: blob/master/stats.sh
1564 views
1
#!/usr/bin/env bash
2
3
# shellcheck enable=require-variable-braces
4
5
set -euo pipefail
6
7
# Ensure required tools are installed
8
for tool in git jq; do
9
if ! command -v "${tool}" > /dev/null 2>&1; then
10
echo "Error: ${tool} not found in PATH" >&2
11
exit 1
12
fi
13
done
14
15
# Clear output file
16
: > stats.out
17
18
# Collect "tag:readmeData.json date" pairs for all tags
19
mapfile -t taglist < <(
20
git for-each-ref --sort=creatordate \
21
--format='%(refname:short) %(creatordate:short)' refs/tags |
22
awk '{print $1 ":readmeData.json " $2}'
23
)
24
25
# Feed all object names into one cat-file process
26
exec 3< <(printf '%s\n' "${taglist[@]}" | cut -d' ' -f1 | git cat-file --batch)
27
28
for line in "${taglist[@]}"; do
29
# Extract the date field by removing everything up to the first space
30
date=${line#* }
31
32
# Read one header line from fd 3
33
if ! read -r -a header_fields <&3; then
34
break
35
fi
36
37
# Skip if header is incomplete
38
if ((${#header_fields[@]} < 3)); then
39
continue
40
fi
41
42
size=${header_fields[2]}
43
44
# Validate that size is numeric
45
if [[ ! "${size}" =~ ^[0-9]+$ ]]; then
46
continue
47
fi
48
49
# Read exactly ${size} bytes of blob content
50
IFS= read -r -N "${size}" blob <&3
51
52
# Consume the newline that follows the blob
53
read -r _ <&3 || true
54
55
# Stream parse JSON only if blob is non-empty
56
if [[ -z "${blob}" ]]; then
57
continue
58
fi
59
60
# Stream parse JSON with jq in "raw input" mode to avoid subshell overhead
61
jq -nr --arg date "${date}" --argjson blob "${blob}" '
62
$blob.base.entries // empty
63
| if type=="array" then
64
.[] | "\($date),\(.)"
65
else
66
"\($date),\(.)"
67
end
68
' >> stats.out 2> /dev/null || true
69
done
70
71