-
-
Save damphat/6214499 to your computer and use it in GitHub Desktop.
#! /bin/bash | |
# Description: show dependency tree | |
# Author: damphat | |
if [ $# != 1 ]; then | |
echo 'Usage: apt-rdepends-tree <package>' | |
echo 'Required packages: apt-rdepends' | |
exit 1 | |
fi | |
# tree template | |
T1=" ├─" | |
T2=" │ ├─" | |
T3=" │ └─" | |
# tree template for last node | |
T4=" └─" | |
T5=" ├─" | |
T6=" └─" | |
# mark '1' for parent node, '2' for child node | |
TEXT="$(apt-rdepends $1 | sed -e 's/^/1 /' -e 's/.*: /2 /'; echo '-')" | |
TOTAL=$(echo "$TEXT" | grep '^1' | wc -l) # total parent | |
COUNT=0 | |
echo "$TEXT" | while read line; do | |
tmp=$last | |
[ "${line:0:1}" != "${last:0:1}" ] && tmp=$(echo $last | sed -e 's/^2/3/') | |
[ "${tmp:0:1}" == "1" ] && ((COUNT++)) | |
if [ "$TOTAL" != "$COUNT" ]; then | |
echo $tmp | sed -e "s/^1/$T1/" -e "s/^2/$T2/" -e "s/^3/$T3/" | |
else | |
echo $tmp | sed -e "s/^1/$T4/" -e "s/^2/$T5/" -e "s/^3/$T6/" | |
fi | |
last=$line | |
done |
If I understand well, actually we only get the tree up to depth 2. It would be cool to get it up to any arbitrary depth.
If I understand well, actually we only get the tree up to depth 2. It would be cool to get it up to any arbitrary depth.
That limitation stems from apt-rdepends
output format, as unfortunately it does not nest packages but rather shows each dependency as a top-level package. Fixing this would be non-trivial for such a simple (but amazing) bash script
What an amazing script!
Inspired by this I've created apt-tree, featuring:
- Arbitrary depth, as suggested by @completementgaga , taking care to handle circular dependencies (yes, they exist! See
libc6
) - Suppress duplicate sub-trees, as suggested by @dmak . Packages already printed are marked with
*
- Pass through options to
apt-rdepends
, to allow-r|--reverse
as requested by @willemw12 (among many other possibilities) - Full command-line argument parsing, including
--help
A small example:
$ apt-tree p7zip-full
Reading package lists... Done
Building dependency tree
Reading state information... Done
p7zip-full
├─ libc6
│ ╰─ libgcc1
│ ├─ gcc-8-base
│ ╰─ libc6*
├─ libgcc1*
├─ libstdc++6
│ ├─ gcc-8-base*
│ ├─ libc6*
│ ╰─ libgcc1*
╰─ p7zip
├─ libc6*
├─ libgcc1*
╰─ libstdc++6*
@MestreLion
Hi, Very nice script, thank you. The only missed things we strongly need are:
- Include build-depends for packages, not only Depends
- Mark somehow those packages which are not available (using apt-cache maybe). For example, if "gcc-8-base" is missed in the local apt repository, then show this something like gcc-8-base (-), those which exist, mark as (+)
- Print this graph as a plain-text to be able to iterator over it and build each package from the list
Will try to implement this by myself. May be you consider implementing this :)
MestreLion Hi, Very nice script, thank you. The only missed things we strongly need are:
Thanks @hiddenman , glad you liked!
Currently I'm unable to dive into this, but I can share a few thoughts about each, it may help:
- Include build-depends for packages, not only Depends
Is there a such an option in apt-rdepends
? If so, this is possible.
Also, I believe it should either print the build-depends OR the Depends (controllable by a new --build-depends
flag), as there are very few (if any) use-cases for a combined list including both. And whoever needs both can always run it twice, with and without the flag.
- Mark somehow those packages which are not available (using apt-cache maybe). For example, if "gcc-8-base" is missed in the local apt repository, then show this something like gcc-8-base (-), those which exist, mark as (+)
This might be feasible, possibly best done in parse_deps()
. I suggest the mark be (!)
for not available, and no mark if available.
- Print this graph as a plain-text to be able to iterator over it and build each package from the list
A new --plain
flag can easily do that, perhaps using tr -d
to remove the UTF (and whitespace?) characters. Indentation can be replaced with TABs, or completely stripped if --no-indent
, which would imply --plain
.
Will try to implement this by myself. May be you consider implementing this :)
I will. And if you do, it would be amazing if you could open a PR in my repo!!!
(you can also open a new issue there so we can best discuss the above points instead of polluting the this gist)
Inspired by this I've created apt-tree
Inspired by this, I've created apt-tree.sh — not an improvement or rework of apt-tree
, but a completely different script written from scratch, which operates on genuine apt-cache
directly and doesn't require third-party tools like apt-rdepends
.
It features:
- multiple packages support, both from command line and from a file;
- arbitrary tree depth (automatically stopped when a dependency loop is detected);
- forward and reverse dependencies;
- missing packages are marked as such;
- an option to suppress printing sub-trees already printed before;
- an option to print a flattened list of all recursive dependencies — as an alternative to hierarchical trees;
- an option to show the number of direct dependencies of each package;
- custom tree decoration — prefix, repeating indentation and suffix (plain tabs by default, prefix also applies to list items);
- adjustable verbosity and progress status — from single-line breadcrumbs up to complete
apt-cache
commands; - saving output to file will not be cluttered by verbose messages.
It also provides built-in help page and extensive documentation with examples.
$ apt-tree.sh -nR udev non-existing-package
non-existing-package (missing!)
udev (4)
chkconfig (1)
insserv (0)
glib (4)
elfutils (4)
bzip2 (0)
flex (0)
xz (0)
zlib (0)
lcc-libs (0)
libffi (0)
zlib (0)
libffi (0)
usbutils (3)
libusb (2)
glibc (0)
udev (loop!)
libusb-compat (1)
libusb (repeating)
zlib (0)
Comments and suggestions are welcome.
Very nice @blanktonio !!! I've starred you repo, nice to see a solution that does not depend on third-party. Don't forget to include a license so people can use the tool and contribute to it. It can be either a license file, a small header in code (see mine for an example), or at least a paragraph in README. I personally always use a copyleft license (GPLv3), but any FOSS license will do. Thanks and congrats!
Would be nice to have an option to suppress (filter out) dependencies which are already listed above, e.g.
turns into: