#!/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