Recursive dependencies, recursive uninstall, variants
Shreevatsa R
shreevatsa.public at gmail.com
Fri Apr 25 10:59:12 PDT 2008
Hi MacPorts developers,
I was planning to write some non-trivial code before posting to this
list, but I thought I would first check if I was doing anything
stupid.
I found that the "port deps" command only lists the explicit
dependencies of a port, and not everything that the port actually
depends on ("recursive dependencies"). This meant that often
installing something trivial looking would start pulling in something
enormous that I didn't want to install, and I would have to kill it,
or wait hours. Contrast this to something like Debian's apt (used by
Fink too), which when you try to install something, gives a message
like:
# apt-get install nautilus
Reading Package Lists... Done
Building Dependency Tree... Done
The following extra packages will be installed:
bonobo libmedusa0 libnautilus0
The following NEW packages will be installed:
bonobo libmedusa0 libnautilus0 nautilus
0 packages upgraded, 4 newly installed, 0 to remove and 1 not upgraded.
Need to get 8329kB of archives. After unpacking 17.2MB will be used.
Do you want to continue? [Y/n]
So deciding that at least knowing all dependencies of a port
beforehand would help, I tried writing a command for recursive
dependencies. The proc action_deps does a lot of stuff, and it's not
easy getting just the list of dependencies with no extra output, so I
wrote my own "bare" proc that does the actual dependencies, etc., and
rdeps that recursively calls it:
proc add_to_set {set_var item} {
upvar $set_var var
if {[lsearch -exact $var $item] == -1} { lappend var $item }
}
proc actdeps {portname depstype} {
array unset portinfo
array set portinfo [lindex [mportsearch $portname no exact] 1]
#set deps [map {x {lindex [split $x :] end}} $portinfo($depstype)]
set deps []
if {[info exists portinfo($depstype)]} {
foreach i $portinfo($depstype) {
lappend deps [lindex [split $i :] end]
}
}
return $deps
}
proc rdeps {portname {depth 0}} {
global shownports
if [info exists shownports] { } else { set shownports [] }
add_to_set shownports $portname
set depstypes {depends_build depends_lib depends_run}
set depstypes_descr {"build" "library" "runtime"}
foreach depstype $depstypes depsdecr $depstypes_descr {
foreach port [actdeps $portname $depstype] {
if {[lsearch $shownports $port] == -1} {
puts "[string repeat \t $depth]$port"
rdeps $port [expr {$depth + 1}]
}
}
}
}
proc action_rdeps {action portlist opts} {
foreachport $portlist {
rdeps $portname
}
}
And "rdeps action_rdeps" in action_array. Yeah, it uses a global
variable to avoid printing the same ports again, but it works:
~$ port rdeps subversion
expat
neon
gettext
libiconv
gperf
ncurses
ncursesw
openssl
zlib
apr
apr-util
db44
sqlite3
gawk
gmake
readline
This is not great code, but it does what I want. (It is also the only
Tcl I have ever written, so please tell me what I'm doing stupidly.)
I was planning to do the same for variants (because I install
something and later discover I should have installed one of its
dependencies with a different variant), and for uninstall (because it
is a real pain to uninstall ports).
More specifically, I was planning to
(1) make a general (simple) function for getting a specific port's
"tree of dependencies" (and/or tree of dependents) and then something
to act on it. Uninstall would then be trivial.
(2) Also, putting something to return the list of dependencies of a
port in the MacPorts API itself.
(3) Also, looking at action_deps, it seems to share a lot in common
with other functions (searching for ports, etc.), so that part can be
cleaned up...
Comments?
-Shreevatsa
More information about the macports-dev
mailing list