#!/bin/bash # # Purpose : Show which version of CoreDesktop this machine is running # # CoreDesktop is a rolling release, so its version is the date of the commit # the local checkout is on, plus the short hash to tell same-day commits apart, # e.g. 2026.10.22 (c5f0651). The kernel and video driver are shown separately # because they come from Arch, not CoreDesktop, along with any newer release of # either that update would install. # # Sibling projects (see sibling) are listed with their versions too. If any has # a newer version, version asks, for each one, whether to update it now. # # version --check prints the newer version and exits 0 if one is available, # exits 1 if this machine is up to date, or 2 if it couldn't check. COREDESKTOP="$HOME/.local/share/coredesktop" source "$COREDESKTOP/utils.sh" if ! git -C "$COREDESKTOP" rev-parse --git-dir &> /dev/null; then echo "CoreDesktop isn't installed in $COREDESKTOP." exit 2 fi # Version string for a commit, e.g. 2026.10.22 (c5f0651) describe() { git -C "$COREDESKTOP" log -1 --format='%cd (%h)' --date=format:%Y.%m.%d "$1" } # Print the newer version if the remote has commits this checkout doesn't. # Returns 1 if up to date, 2 if the remote couldn't be reached. newer_version() { GIT_TERMINAL_PROMPT=0 timeout 30 git -C "$COREDESKTOP" fetch --quiet &> /dev/null || return 2 local behind behind="$(git -C "$COREDESKTOP" rev-list --count 'HEAD..@{upstream}' 2> /dev/null)" || return 2 (( behind > 0 )) || return 1 describe '@{upstream}' } if [ "$1" = "--check" ]; then newer_version exit fi version="$(describe HEAD)" # Local edits to the checkout mean this isn't exactly the version above if [ -n "$(git -C "$COREDESKTOP" status --porcelain --untracked-files=no)" ]; then version="$version, modified" fi if latest="$(newer_version)"; then version="$version, $latest is available (run update)" fi # A version without its epoch and pkgrel, e.g. 1:26.2.6-1 is 26.2.6. Arch's # kernel puts its suffix in the version too (7.2.14.arch1), so drop that. upstream() { local v="${1#*:}" v="${v%-*}" echo "${v%.arch*}" } # Packages with a newer version in the repos, as "name old -> new" lines. # checkupdates syncs a copy of the package database, so it needs no root and # doesn't leave a partial upgrade behind. Empty if it couldn't check. pending="" if command -v checkupdates &> /dev/null; then pending="$(timeout 30 checkupdates 2> /dev/null)" fi # Print the newer upstream version of package $1 if the repos have one. A # rebuild of the same version (only the pkgrel changed) doesn't count. newer_package() { local name old _ new while read -r name old _ new; do [ "$name" = "$1" ] || continue [ "$(upstream "$old")" != "$(upstream "$new")" ] && upstream "$new" return done <<< "$pending" return 1 } kernel="$(uname -r)" # The package the running kernel came from (linux, linux-lts, ...) kernel_pkg="$(cat "/usr/lib/modules/$kernel/pkgbase" 2> /dev/null)" case "$kernel" in *-lts) kernel_pkg="${kernel_pkg:-linux-lts}" ;; *-zen) kernel_pkg="${kernel_pkg:-linux-zen}" ;; *-hardened) kernel_pkg="${kernel_pkg:-linux-hardened}" ;; *) kernel_pkg="${kernel_pkg:-linux}" ;; esac # If the running kernel's modules are gone, a newer kernel was installed if [ ! -d "/usr/lib/modules/$kernel" ]; then kernel="$kernel (newer kernel installed, reboot to use it)" fi if latest="$(newer_package "$kernel_pkg")"; then kernel="$kernel, $latest is available (run update)" fi # NVIDIA's driver if nvidia.sh installed it, otherwise Mesa, which drives # Intel and AMD graphics (vulkan-intel and vulkan-radeon are built with it) driver="" for pkg in nvidia-utils nvidia-580xx-utils mesa; do if installed="$(pacman -Q "$pkg" 2> /dev/null)"; then case "$pkg" in nvidia*) driver="NVIDIA $(upstream "${installed#* }")" ;; *) driver="Mesa $(upstream "${installed#* }")" ;; esac if latest="$(newer_package "$pkg")"; then driver="$driver, $latest is available (run update)" fi break fi done # 10-pacman.sh rewrites this log on every update if [ -f "$PACMAN_UPDATE_LOG" ]; then last_update="$(date -r "$PACMAN_UPDATE_LOG" '+%Y-%m-%d %H:%M')" else last_update="never" fi echo "CoreDesktop $version" echo "Kernel $kernel" [ -n "$driver" ] && echo "Video driver $driver" echo "Last update $last_update" # Sibling projects, as "nameinstalledavailable" lines (see sibling) siblings="$(bash "$COREDESKTOP/sibling" check --porcelain 2> /dev/null)" newer_siblings=() if [ -n "$siblings" ]; then echo echo "Sibling projects" width=0 while IFS=$'\t' read -r name _; do (( ${#name} > width )) && width=${#name} done <<< "$siblings" while IFS=$'\t' read -r name installed available; do case "$available" in "") ;; "?") installed="$installed, couldn't check for a newer version" ;; *) installed="$installed, $available is available" newer_siblings+=("$name"$'\t'"$available") ;; esac printf ' %-*s %s\n' "$width" "$name" "$installed" done <<< "$siblings" fi # Packages newer than the mirror's last sync aren't shown above, or installed if age="$(mirror_age_hours)" && (( age >= MIRROR_STALE_HOURS )); then if (( age >= 48 )); then ago="$(( age / 24 )) days"; else ago="$age hours"; fi echo echo -e "\e[33mYour package mirror ($(first_mirror)) last synced with Arch $ago ago, so" echo -e "newer packages may be missing. Run update to switch to up-to-date mirrors.\e[0m" fi # Offer each newer sibling, but only to someone at the terminal to answer if (( ${#newer_siblings[@]} > 0 )) && [ -t 0 ] && [ -t 1 ]; then echo chosen=() for sibling in "${newer_siblings[@]}"; do IFS=$'\t' read -r name available <<< "$sibling" read -rp "Update $name to $available? [y/N] " response [[ "$response" =~ ^[yY]([eE][sS])?$ ]] && chosen+=("$name") done if (( ${#chosen[@]} > 0 )); then echo bash "$COREDESKTOP/sibling" update "${chosen[@]}" exit fi fi