Merge pull request #1033 from AladW/view-prefix
[aurutils.git] / lib / aur-depends
blobd1f4cb17cf6a99a0cb69db159ec9c51463a38ec9
1 #!/bin/bash
2 # aur-depends - retrieve package dependencies using AurJson
3 [[ -v AUR_DEBUG ]] && set -o xtrace
4 argv0=depends
5 PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
7 # default options
8 max_request=30 mode=pkgname
10 # default options (dependency types)
11 resolve_depends=1 resolve_makedepends=1 resolve_checkdepends=1 resolve_optdepends=0
13 # $1 pkgname $2 pkgbase $3 pkgver [$4 deps] [$5 mdeps] [$6 cdeps] [$7 odeps]
14 pivot_table() {
15 awk -F'\t' 'BEGIN {
16 format = "%s\t%s\t%s\t%s\t%s\n"
17 } {
18 # Print header (package without dependencies)
19 printf(format, $1, $1, $2, $3, "Self")
21 # Print one line for each dependency
22 split($4, depends, ",")
23 split($5, makedepends, ",")
24 split($6, checkdepends, ",")
25 split($7, optdepends, ",")
27 for (idx in depends)
28 printf(format, $1, depends[idx], $2, $3, "Depends")
29 for (idx in makedepends)
30 printf(format, $1, makedepends[idx], $2, $3, "MakeDepends")
31 for (idx in checkdepends)
32 printf(format, $1, checkdepends[idx], $2, $3, "CheckDepends")
33 for (idx in optdepends)
34 printf(format, $1, optdepends[idx], $2, $3, "OptDepends")
35 }' "$@"
38 # $1 pkgname $2 depends $3 pkgbase
39 pkgbase_graph() {
40 awk '{
41 pkgbase[$1] = $3
42 depends[$2] = 1
44 END {
45 for (pkg in depends) {
46 if (pkg in pkgbase) {
47 printf("%s\t%s\n", pkg, pkgbase[pkg])
50 }' "$@"
53 tr_ver() {
54 sed -r 's/[<>=].*$//g'
57 # shellcheck disable=SC2086
58 chain() {
59 local a sub fmt=$1
60 shift 1
62 # Top-level AUR request
63 aur query -t info "$@" >json/0 || exit
65 # Top-level dependencies
66 aur format -f "$fmt" --delim=, json/0 | pivot_table - >tsv/0
67 (( PIPESTATUS[0] )) && exit 2 # format error
69 if [[ ! -s tsv/0 ]]; then
70 return 0 # no packages found
73 # In the below, all intermediary results are stored (originally done to
74 # simplify debugging). Strictly speaking, only the current and previous
75 # step are required. With a limited amount of requests (e.g. ~7 total
76 # for large meta-packages such as ros-indigo-desktop and ~250 AUR
77 # dependencies) the difference is unlikely to be noticeable.
78 for (( a = 1; a <= max_request; ++a )); do
79 sub=$(( a - 1 ))
81 # Avoid querying duplicates (#4)
82 cut -f1 tsv/$sub >> seen # mark pkgname as seen
83 # Note: `grep` exits with status 1 if no matches are found
84 cut -f2 tsv/$sub | tr_ver | grep -Fxvf seen | \
85 aur query -t info - > json/$a || exit # rpc error
87 if [[ ! -s json/$a ]]; then
88 return $a # no unique results (seen \ tsv == [empty])
90 aur format -f "$fmt" --delim=, json/$a | pivot_table - >tsv/$a
91 (( PIPESTATUS[0] )) && exit 2
93 if [[ ! -s tsv/$a ]]; then
94 return $a # no results, recursion complete
96 cut -f2 tsv/$sub >> seen # mark depends as seen
97 done
99 # recursion limit exceeded
100 return $max_request
103 trap_exit() {
104 if [[ ! -v AUR_DEBUG ]]; then
105 rm -rf -- "$tmp"
106 else
107 printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$tmp"
111 usage() {
112 printf >&2 'usage: %s [-abGnt]\n' "$argv0"
113 exit 1
116 source /usr/share/makepkg/util/parseopts.sh
118 opt_short='abJGnt'
119 opt_long=('table' 'pkgbase' 'pkgname' 'pkgname-all' 'graph' 'optdepends'
120 'no-depends' 'no-makedepends' 'no-checkdepends' 'json' 'raw')
121 opt_hidden=('dump-options')
123 if ! parseopts "$opt_short" "${opt_long[@]}" "${opt_hidden[@]}" -- "$@"; then
124 usage
126 set -- "${OPTRET[@]}"
128 while true; do
129 case "$1" in
130 -b|--pkgbase)
131 mode=pkgbase ;;
132 -n|--pkgname)
133 mode=pkgname ;;
134 -a|--pkgname-all)
135 mode=pkgname_all ;;
136 -G|--graph)
137 mode=pkgbase_graph ;;
138 -t|--table)
139 mode=table ;;
140 -J|--json)
141 mode=json ;;
142 --raw)
143 mode=json_raw ;;
144 --no-depends)
145 resolve_depends=0 ;;
146 --no-makedepends)
147 resolve_makedepends=0 ;;
148 --no-checkdepends)
149 resolve_checkdepends=0 ;;
150 --optdepends)
151 resolve_optdepends=1 ;;
152 --dump-options)
153 printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
154 printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
155 exit ;;
156 --) shift; break ;;
157 esac
158 shift
159 done
161 # shellcheck disable=SC2174
162 mkdir -pm 0700 "${TMPDIR:-/tmp}/aurutils-$UID"
163 tmp=$(mktemp -d --tmpdir "aurutils-$UID/$argv0.XXXXXXXX") || exit
164 trap 'trap_exit' EXIT
166 # select dependency types
167 fmt="%n\t%b\t%v\t"
168 (( resolve_depends )) && fmt+="%D"
169 fmt+="\t"
170 (( resolve_makedepends )) && fmt+="%M"
171 fmt+="\t"
172 (( resolve_checkdepends )) && fmt+="%c"
173 fmt+="\t"
174 (( resolve_optdepends )) && fmt+="%O"
175 fmt+="\n"
177 # resolve dependency tree
178 rings=0
179 if cd "$tmp" && mkdir json tsv; then
180 # tsv/*: pkgname\tdepends\tpkgbase\pkgver
181 chain "$fmt" "$@"; rings=$?
182 depends=(tsv/*) json=(json/*)
184 # check iteration number
185 case $rings in
186 0) printf >&2 '%s: no packages found\n' "$argv0"
187 exit 1 ;;
188 1) true # no dependencies
190 "$max_request")
191 printf >&2 '%s: total requests: %d (out of range)\n' "$argv0" $(( max_request + 1 ))
192 exit 34 ;;
193 esac
195 # preserve tsort exit status
196 set -o pipefail
198 case $mode in
199 # pkgname (AUR, total order)
200 pkgname)
201 grep -Fxf <(cut -f1 "${depends[@]}") <(cut -f1,2 "${depends[@]}" | tsort | tac)
202 wait "$!" ;; # status of last process substitution
203 # pkgname (all, total order)
204 pkgname_all)
205 cut -f1,2 "${depends[@]}" | tsort | tac
207 # pkgbase (AUR, total order)
208 pkgbase)
209 pkgbase_graph "${depends[@]}" | tsort | tac
211 # pkgbase (AUR, graph)
212 pkgbase_graph)
213 pkgbase_graph "${depends[@]}" | sort -k1b,1 -k1 -u
215 # all information
216 json)
217 aur format "${json[@]}" --union 'Name' --json
219 json_raw)
220 cat "${json[@]}"
222 table)
223 cat "${depends[@]}"
226 printf >&2 '%s: invalid argument' "$argv0"
227 exit 22 ;;
228 esac
229 else
230 exit
233 # vim: set et sw=4 sts=4 ft=sh: