aboutsummaryrefslogtreecommitdiff
path: root/utils/outdated.sh
blob: fd8efa27a69b90c5e3c38bbbf00a38317ea68f16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/bin/sh
#
# Scan repos/ for outdated packages using repology.org's latest-version badge.
# Run from the project root.
#
# Usage:
#   ./utils/outdated.sh                 scan all repos
#   ./utils/outdated.sh core extra       scan only specified repos
#   ./utils/outdated.sh llvm libressl    check only specified packages
#   ./utils/outdated.sh -j               output as JSON
#   ./utils/outdated.sh -q               quiet: only print outdated, skip "checking" lines

repos_dir="$(dirname "$0")/../repos"

json_output=false
quiet=false
selected_repos=
selected_pkgs=

known_repos="core extra community wip"

for arg; do
	case "$arg" in
		-j) json_output=true;;
		-q) quiet=true;;
		*)
			case " $known_repos " in
				*" $arg "*) selected_repos="$selected_repos $arg";;
				*) selected_pkgs="$selected_pkgs $arg";;
			esac
			;;
	esac
done

if [ -z "$selected_repos" ]; then
	selected_repos=$known_repos
fi

fetch_version() {
	curl -sS -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" \
		"https://repology.org/badge/latest-versions/${1}.svg" \
		| sed 's/, /,/g' \
		| tr ' ' '\n' \
		| grep -Eo 'central">.*<' \
		| sed 's/<.*//;s/.*>//' \
		| tr ',' '\n' \
		| tail -n1
}

# collect package list into a temp file so the while loop runs in the main shell
tmpfile=$(mktemp -t outdated.XXXXXX)
trap 'rm -f "$tmpfile"' EXIT

for repo in $selected_repos; do
	[ -d "$repos_dir/$repo" ] || continue
	for abuild in "$repos_dir/$repo"/*/abuild; do
		[ -f "$abuild" ] || continue
		dir="${abuild%/abuild}"
		pkgname="${dir##*/}"

		# filter by package name if specific packages were requested
		if [ -n "$selected_pkgs" ]; then
			match=false
			for p in $selected_pkgs; do
				[ "$pkgname" = "$p" ] && match=true && break
			done
			$match || continue
		fi

		printf '%s\t%s\t%s\n' "$repo" "$pkgname" "$dir"
	done
done | sort -t'	' -k2 > "$tmpfile"

total=0
outdated=0
errors=0

if $json_output; then
	printf '{\n  "outdated": ['
	first=true
fi

while IFS='	' read -r repo pkgname dir; do
	curver=$(grep "^version=" "$dir/abuild" | awk -F= '{print $2}')
	[ -n "$curver" ] || continue

	# build repology lookup name from the directory name
	repology_name="$pkgname"
	case "$pkgname" in
		python-*) repology_name="python:${pkgname#python-}";;
		perl-*)   repology_name="perl:${pkgname#perl-}";;
	esac

	# per-package repology name override
	if [ -s "$dir/outdated" ]; then
		display_name=$(head -n1 "$dir/outdated")
		repology_name="$display_name"
	else
		display_name="$pkgname"
	fi

	if ! $quiet; then
		printf '  checking %s/%s ...\r' "$repo" "$display_name" >&2
	fi

	newver=$(fetch_version "$repology_name" 2>/dev/null || true)

	if [ -z "$newver" ] || [ "$newver" = "-" ]; then
		if $json_output; then
			$first || printf ','
			printf '\n    {"repo":"%s","name":"%s","current":"%s","status":"error"}' \
				"$repo" "$display_name" "$curver"
			first=false
		else
			printf '%-12s %-32s %-12s %s\n' "[$repo]" "$display_name" "$curver" "(repology lookup failed)" >&2
		fi
		errors=$((errors + 1))
	elif [ "$curver" != "$newver" ]; then
		if $json_output; then
			$first || printf ','
			printf '\n    {"repo":"%s","name":"%s","current":"%s","latest":"%s"}' \
				"$repo" "$display_name" "$curver" "$newver"
			first=false
		else
			printf '%-12s %-32s %-12s -> %s\n' "[$repo]" "$display_name" "$curver" "$newver"
		fi
		outdated=$((outdated + 1))
	fi
	total=$((total + 1))
done < "$tmpfile"

if $json_output; then
	printf '\n  ]'
	if [ "$errors" -gt 0 ] || [ "$outdated" -gt 0 ]; then
		printf ',\n  "errors": %d,\n  "outdated_count": %d' "$errors" "$outdated"
	else
		printf ',\n  "errors": 0,\n  "outdated_count": 0'
	fi
	printf ',\n  "total": %d\n}\n' "$total"
else
	printf '  \033[0K' >&2
	printf 'Done. %d packages checked, ' "$total" >&2
	if [ "$outdated" -eq 0 ] && [ "$errors" -eq 0 ]; then
		printf 'all up to date.\n' >&2
	else
		printf '%d outdated, %d lookup errors.\n' "$outdated" "$errors" >&2
	fi
fi