Introduce -D, --database
[pacman-ng.git] / contrib / pactree
blob73bece3a5124c4553936b6e994a15fcc3f6c577b
1 #!/bin/bash
2 # pactree : a simple dependency tree viewer
4 # Copyright (C) 2008 Carlo "carlocci" Bersani <carlocci@gmail.com>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # Original http://carlocci.ngi.it/arch/pactree
20 # Credit to scj for the graphviz idea
22 # set the colors
23 branch1_color="\033[0;33m" #Brown
24 branch2_color="\033[0;37m" #Gray
25 leaf_color="\033[1;32m" #Light green
26 leaf2_color="\033[0;32m" #Green
28 # set the separators
29 separator=" "
30 branch_tip1="|--"
31 branch_tip2="+--"
32 provides="provides "
34 # set the graphviz options
35 # http://www.graphviz.org/doc/info/output.html for available output formats
36 # http://www.graphviz.org/doc/info/colors.html for available colors
37 gformat="png" #output format
38 start_color="red" #START color
39 nodes_color="green" #color of the nodes
40 arrow1_color="chocolate4" #color of the normal arrow
41 arrow2_color="grey" #color of the "provided by" headless arrow
43 readonly prog_name="pactree"
44 readonly prog_ver="0.3"
46 _usage(){
47 echo "This program generates the dependency tree of an installed package"
48 echo "Usage: $prog_name [OPTIONS] <installed packages>"
49 echo
50 echo " OPTIONS:"
51 echo " -c, --color Enable color output"
52 echo " -d, --depth INT Limit the shown dependencies depth"
53 echo " -g, --graph Use graphviz to make an image of the tree"
54 echo " -l, --linear Enable linear output"
55 echo " -r, --reversed Show reversed dependancies"
56 echo " -s, --silent Shh, let me hear those errors!"
57 echo " -u, --unique Print the dependency list with no duplicates"
58 echo
59 echo " -h, --help Print this help message"
60 echo " -v, --version Print the program name and version"
61 echo
62 echo "Example: $prog_name -c -d2 readline"
65 _version(){
66 echo "$prog_name version $prog_ver"
67 echo "Copyright (C) 2008 Carlo \"carlocci\" Bersani <carlocci@gmail.com>"
69 # end of the friendliness
72 # grab a field from the database: $1=path/to/file, $2=field to grab
73 _grabfield(){
74 for line in $(cat "$1" 2>/dev/null ); do
75 if [ -z "$line" ]; then
76 continue;
77 fi;
78 if [[ "$line" =~ %[A-Z]*% ]]; then
79 current="$line"
80 continue;
81 fi;
82 if [ "$current" = "$2" ]; then
83 echo "$line"
84 fi;
85 done
89 # find a dep in the db: $1=dep, $2=field, $3=dbfile, ret=file list
90 _finddep(){
91 for line in $(awk 'BEGIN{RS=""}
93 if ($1=="'"$2"'"){
94 for (i=2 ; i<=NF ; ++i){
95 if ($i ~ /^'"$1"'([<>=]+.*|)$/ ){
96 print FILENAME}
99 }' $(find $pac_db -name $3)); do
100 echo "${line%/*}"
101 done
105 # Recursive function: does all of the work, pays all of the taxes #
106 _tree(){
107 pkg_name="$1"
108 pkg_dirs="$(echo $pac_db/$pkg_name-[0-9]*)"
110 # Is $pkg_name real or provided?
111 [ ! -d "$pkg_dirs" ] && pkg_dirs="$(_finddep $pkg_name %PROVIDES% depends)"
113 for pkg_dir in $pkg_dirs ; do
114 spaces="$2"
115 unset provided
116 branch_tip="$branch_tip1"
117 branch_color="$branch1_color"
118 pkg_name="$(_grabfield "$pkg_dir/desc" %NAME%)"
119 if [ ! "$pkg_name" = "$1" ]; then
120 provided="$leaf2_color $provides$leaf_color$1"
121 branch_tip="$branch_tip2"
122 branch_color="$branch2_color"
123 if [ $graphviz -eq 1 ] && [[ ! "${dep_list[@]}" =~ _$1_ ]] && [ $spaces -ne $((max_depth+1)) ]; then
124 echo "\"$1\" -> \"$pkg_name\" [arrowhead=none, color=$arrow2_color];"
125 dep_list=( "${dep_list[@]}" "_$1_" )
126 _tree "$pkg_name" $((spaces+1))
127 continue
131 # Generate the spacer
132 spacer=""
133 for each in $(seq 1 $spaces); do
134 spacer="$spacer$separator"
135 done
136 spacer="$spacer$branch_tip"
138 [ $silent -ne 1 ] && echo -e "$branch_color$spacer$leaf_color$pkg_name$provided"
140 [ ! -d "$pkg_dir" ] && echo "No $pkg_name in the database (inconsistent database?)" >&2
142 if [[ ! " ${dep_list[@]} " =~ " $pkg_name " ]] && [ $spaces -ne $max_depth ]; then
143 dep_list=( "${dep_list[@]}" "$pkg_name" )
144 if [ $reversed_dep -eq 0 ]; then
145 deps_pkg="$(_grabfield "$pkg_dir/depends" %DEPENDS%)"
146 else
147 reqs_pkg_dir="$(_finddep "$pkg_name" %DEPENDS% depends)"
148 unset deps_pkg
149 for req_pkg_dir in $reqs_pkg_dir; do
150 deps_pkg=$(echo "$deps_pkg" "$(_grabfield "$req_pkg_dir/desc" %NAME%)")
151 done
153 for dep_pkg in $deps_pkg; do
154 spaces=$2 #Bash scoping ;_;
155 if [ $graphviz -eq 1 ]; then
156 echo "\"$1\" -> \"${dep_pkg%%[<>=]*}\" [color=$arrow1_color];"
158 _tree "${dep_pkg%%[<>=]*}" $((spaces+1))
159 done
161 done
165 # Main program: gets all of the money, pays none of the taxes
167 # Command line parameters parser
168 if [ $# -eq 0 ]; then
169 _usage
170 exit 1
173 options=( "$@" )
174 len_options=${#options[@]}
175 for (( n=0 ; n < $len_options ; n++ )); do
176 if [ "${options[$n]}" = "--" ]; then
177 unset options[$n]
178 break
180 if [ "${options[$n]}" = "-h" -o "${options[$n]}" = "--help" ]; then
181 _usage
182 exit 0
185 if [ "${options[$n]}" = "-v" -o "${options[$n]}" = "--version" ]; then
186 _version
187 exit 0
190 if [ "${options[$n]}" = "-l" -o "${options[$n]}" = "--linear" ]; then
191 unset options[$n]
192 linear=1
193 continue
196 if [ "${options[$n]}" = "-s" -o "${options[$n]}" = "--silent" ]; then
197 unset options[$n]
198 silent=1
199 continue
202 if [ "${options[$n]}" = "-u" -o "${options[$n]}" = "--unique" ]; then
203 unset options[$n]
204 silent=1
205 nodup=1
206 continue
209 if [ "${options[$n]}" = "-g" -o "${options[$n]}" = "--graph" ]; then
210 unset options[$n]
211 graphviz=1
212 continue
215 if [ "${options[$n]}" = "-c" -o "${options[$n]}" = "--color" ]; then
216 unset options[$n]
217 colored=1
218 continue
221 if [ "${options[$n]}" = "-r" -o "${options[$n]}" = "--reversed" ]; then
222 unset options[$n]
223 reversed_dep=1
224 continue
227 if [[ "${options[$n]}" =~ -d[[:digit:]]+ || "${options[$n]}" == "--depth" ]]; then
228 if [[ "${options[$n]#-d}" =~ [[:digit:]]+ ]]; then
229 max_depth="${options[$n]#-d}"
230 elif [[ ${options[$((n+1))]} =~ [[:digit:]]+ ]]; then
231 max_depth="${options[$((n+1))]}"
232 unset options[$((n+1))]
233 ((++n))
235 unset options[$n]
236 continue
238 done
239 # End of the dumb command line parser
241 # Env
242 colored=${colored:-0}
243 max_depth=${max_depth:--10}
244 linear=${linear:-0}
245 silent=${silent:-0}
246 nodup=${nodup:-0}
247 graphviz=${graphviz:-0}
248 reversed_dep=${reversed_dep:-0}
250 if [ $colored -ne 1 ]; then
251 unset branch1_color
252 unset leaf_color
253 unset leaf2_color
254 unset branch2_color
257 if [ $linear -eq 1 ]; then
258 unset separator
259 unset branch_tip1
260 unset branch_tip2
261 unset provides
264 if [ $graphviz -eq 1 ]; then
265 silent=1
266 nodup=0
267 if [ ! -f /usr/bin/dot ]; then
268 echo "ERROR: package graphviz is not installed"
269 echo " Run pacman -S graphviz to install it"
270 exit 1
274 if [ ! -r /etc/pacman.conf ]; then
275 echo "ERROR: unable to read /etc/pacman.conf"
276 exit 1
277 else
278 eval $(awk '/DBPath/ {print $1$2$3}' /etc/pacman.conf)
281 pac_db="${DBPath:-/var/lib/pacman}/local"
283 if [ ! -d "$pac_db" ] ; then
284 echo "ERROR: pacman database directory ${pac_db} not found"
285 exit 1
287 # Env End
290 # Program starts
291 _main(){
292 for pkg_name in ${options[@]} ; do
293 [ $graphviz -eq 1 ] && echo -e "\"START\" -> \"$pkg_name\" ;"
294 _tree "$pkg_name" 0
295 if [ $nodup -eq 1 ]; then
296 for pkg_tree in ${dep_list[@]} ; do
297 echo "$pkg_tree"
298 done
300 done
301 if [ $silent -eq 0 ]; then
302 echo -ne '\033[0m' # return colors to normal?
303 echo -ne '\033[?25h' #return cursor to normal?
308 if [ $graphviz -eq 1 ]; then
309 root_pkgs="${options[@]}"
310 # Uncomment for the "generated by pactree" node in graphviz
311 #advert="xyz [height=0.07, fontsize=8.0, label=\"GENERATED WITH PACTREE\",shape=box,color="black",style=filled,fontcolor="white"];\n"
312 if [ $reversed_dep -eq 0 ]; then
313 file_extension="deps.$gformat"
314 else
315 file_extension="reqs.$gformat"
317 echo -e "digraph G { START [color=$start_color, style=filled];\n node [style=filled, color=$nodes_color];\n$(_main)\n$advert}" | dot -T$gformat -o "${root_pkgs// /_}.$file_extension"
318 else _main
321 # vim: set ts=2 sw=2 noet: