aboutsummaryrefslogtreecommitdiffstats
path: root/is_required
blob: f64c95f781e68256d552fd0fc978dc28eebb4b16 (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
#!/bin/bash
# Show which SBo packages require a given package, marking installed ones.

SBO_REPO="${SBO_REPO:-/var/lib/sbopkg/SBo-git}"
PKG_LOG="${PKG_LOG:-/var/log/packages}"

# Colors (disabled when stdout is not a terminal)
if [[ -t 1 ]]; then
    C_RESET='\033[0m'
    C_INSTALLED='\033[1;32m'    # bold green  — installed
    C_MISSING='\033[0;33m'      # yellow      — not installed
    C_TARGET='\033[1;36m'       # bold cyan   — the queried package
    C_CATEGORY='\033[2;37m'     # dim white   — category label
    C_HEADER='\033[1;37m'       # bold white  — section headers
    C_ERROR='\033[1;31m'        # bold red    — errors
    C_SEP='\033[0;90m'          # dark grey   — separators
else
    C_RESET='' C_INSTALLED='' C_MISSING=''
    C_TARGET='' C_CATEGORY='' C_HEADER='' C_ERROR='' C_SEP=''
fi

usage() {
    cat <<EOF
Usage: $(basename "$0") [OPTIONS] <package>

Show SBo packages that list <package> in their REQUIRES field.

Options:
  -i   show only installed dependents
  -u   show only uninstalled dependents
  -r   recursive: also find what requires those packages (one level)
  -h   this help

Symbols:
  [I]  installed on this system
  [ ]  not installed
EOF
    exit 0
}

die() { printf "${C_ERROR}error:${C_RESET} %s\n" "$*" >&2; exit 1; }

OPT_INSTALLED=0
OPT_UNINSTALLED=0
OPT_RECURSIVE=0

while getopts "iurh" opt; do
    case "$opt" in
        i) OPT_INSTALLED=1 ;;
        u) OPT_UNINSTALLED=1 ;;
        r) OPT_RECURSIVE=1 ;;
        h) usage ;;
        *) usage ;;
    esac
done
shift $((OPTIND - 1))

[[ $# -lt 1 ]] && usage
TARGET="$1"

[[ -d "$SBO_REPO" ]] || die "SBo repo not found at $SBO_REPO (set \$SBO_REPO)"
[[ -d "$PKG_LOG"  ]] || die "package log not found at $PKG_LOG (set \$PKG_LOG)"

# Build installed-package name set (strip version-arch-build suffix)
declare -A INSTALLED
while IFS= read -r entry; do
    name="${entry##*/}"              # basename
    name="${name%-*-*-*}"            # strip last three dash-fields
    INSTALLED["$name"]=1
done < <(find "$PKG_LOG" -maxdepth 1 -follow -type f)

is_installed() { [[ -n "${INSTALLED[$1]+set}" ]]; }

# Search .info files for packages that require TARGET (whole-word match)
find_dependents() {
    local pkg="$1"
    grep -rl "REQUIRES=.*\b${pkg}\b" "$SBO_REPO" --include="*.info" 2>/dev/null
}

print_result() {
    local info_file="$1"
    local prgnam
    prgnam=$(grep -m1 '^PRGNAM=' "$info_file" | cut -d'"' -f2)
    local category
    category=$(awk -F'/' '{print $(NF-2)}' <<< "$info_file")

    if is_installed "$prgnam"; then
        [[ $OPT_UNINSTALLED -eq 1 ]] && return
        printf "${C_INSTALLED}[I] %-40s${C_RESET}  ${C_CATEGORY}(%s)${C_RESET}\n" \
            "$prgnam" "$category"
    else
        [[ $OPT_INSTALLED -eq 1 ]] && return
        printf "${C_MISSING}[ ] %-40s${C_RESET}  ${C_CATEGORY}(%s)${C_RESET}\n" \
            "$prgnam" "$category"
    fi
}

printf "${C_HEADER}Packages requiring ${C_TARGET}'%s'${C_RESET}${C_HEADER}:${C_RESET}\n" "$TARGET"
printf "${C_SEP}%s${C_RESET}\n" "────────────────────────────────────────────────────"

mapfile -t DIRECT < <(find_dependents "$TARGET")

if [[ ${#DIRECT[@]} -eq 0 ]]; then
    printf "${C_SEP}(none found)${C_RESET}\n"
    exit 0
fi

for f in "${DIRECT[@]}"; do
    print_result "$f"
done | sort

if [[ $OPT_RECURSIVE -eq 1 ]]; then
    declare -A SEEN
    for f in "${DIRECT[@]}"; do
        prgnam=$(grep -m1 '^PRGNAM=' "$f" | cut -d'"' -f2)
        SEEN["$prgnam"]=1
    done

    printf "\n${C_HEADER}Packages requiring those (one level up):${C_RESET}\n"
    printf "${C_SEP}%s${C_RESET}\n" "────────────────────────────────────────────────────"

    declare -A SECOND_LEVEL
    for f in "${DIRECT[@]}"; do
        prgnam=$(grep -m1 '^PRGNAM=' "$f" | cut -d'"' -f2)
        while IFS= read -r f2; do
            p2=$(grep -m1 '^PRGNAM=' "$f2" | cut -d'"' -f2)
            [[ -z "${SEEN[$p2]+set}" && -z "${SECOND_LEVEL[$p2]+set}" ]] || continue
            SECOND_LEVEL["$p2"]="$f2"
        done < <(find_dependents "$prgnam")
    done

    if [[ ${#SECOND_LEVEL[@]} -eq 0 ]]; then
        printf "${C_SEP}(none found)${C_RESET}\n"
    else
        for p2 in "${!SECOND_LEVEL[@]}"; do
            print_result "${SECOND_LEVEL[$p2]}"
        done | sort
    fi
fi