#!/usr/bin/env bash # Reading the optional-application catalog. # # Sourced by both front doors -- the interview's checklist during ./install, and # `panama apps` afterwards -- so the two can never disagree about what exists. # One catalog, parsed once, here. # # The format is one file per category under setup/packages/extras/, and a line # is one of: # # gimp a dnf package # flatpak:org.gimp.GIMP a Flathub id # flatpak:com.slack.Slack | Slack either, with a name for the menu # flatpak:com.obsproject.Studio.Plugin.SceneSwitcher # # An indented line belongs to the entry above it and is installed with it, which # is how OBS carries its sixteen plugin extensions as a single thing to tick # rather than seventeen. Comments and blank lines are ignored. # # Without an explicit name, the menu derives one from the last dotted component # of a Flathub id, or uses the package name as it stands. # Every category name, one per line. catalog_categories() { local dir="$1" file for file in "$dir"/*; do [[ -f "$file" ]] && basename "$file" done } # The selectable entries in one category, as `targetlabel`. Indented # continuation lines are folded into the entry above and never listed. catalog_entries() { local file="$1" line target label while IFS= read -r line; do line="${line%%#*}" [[ "$line" =~ ^[[:space:]]*$ ]] && continue [[ "$line" =~ ^[[:space:]] ]] && continue if [[ "$line" == *"|"* ]]; then target="${line%%|*}" label="${line#*|}" else target="$line" label="" fi target="${target#"${target%%[![:space:]]*}"}"; target="${target%"${target##*[![:space:]]}"}" label="${label#"${label%%[![:space:]]*}"}"; label="${label%"${label##*[![:space:]]}"}" if [[ -z "$label" ]]; then label="${target#flatpak:}" [[ "$target" == flatpak:* ]] && label="${label##*.}" fi printf '%s\t%s\n' "$target" "$label" done <"$file" } # Every install target for one entry: the entry itself, then the indented lines # beneath it. Called with the category file and the entry's target. catalog_targets() { local file="$1" want="$2" line target seen=0 while IFS= read -r line; do line="${line%%#*}" [[ "$line" =~ ^[[:space:]]*$ ]] && continue if [[ "$line" =~ ^[[:space:]] ]]; then (( seen == 1 )) || continue line="${line#"${line%%[![:space:]]*}"}" printf '%s\n' "${line%%|*}" | sed 's/[[:space:]]*$//' continue fi target="${line%%|*}" target="${target#"${target%%[![:space:]]*}"}"; target="${target%"${target##*[![:space:]]}"}" if [[ "$target" == "$want" ]]; then seen=1 printf '%s\n' "$target" elif (( seen == 1 )); then break fi done <"$file" } # Every install target in a whole category, in file order. catalog_all_targets() { local file="$1" line while IFS= read -r line; do line="${line%%#*}" [[ "$line" =~ ^[[:space:]]*$ ]] && continue line="${line#"${line%%[![:space:]]*}"}" line="${line%%|*}" printf '%s\n' "${line%"${line##*[![:space:]]}"}" done <"$file" } # Is this target already on the machine? Used to mark the menu, never to skip # silently -- a re-run that reinstalls what is present is harmless, but a menu # that hides it is confusing. catalog_installed() { local target="$1" if [[ "$target" == flatpak:* ]]; then flatpak info "${target#flatpak:}" >/dev/null 2>&1 else rpm -q "$target" >/dev/null 2>&1 fi }