From owner-freebsd-ports@FreeBSD.ORG Sat Dec 6 22:24:50 2003 Return-Path: Delivered-To: freebsd-ports@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 7099916A4CE for ; Sat, 6 Dec 2003 22:24:50 -0800 (PST) Received: from albatross.mail.pas.earthlink.net (albatross.mail.pas.earthlink.net [207.217.120.120]) by mx1.FreeBSD.org (Postfix) with ESMTP id CC7D143F93 for ; Sat, 6 Dec 2003 22:24:48 -0800 (PST) (envelope-from chris@behanna.org) Received: from user183.net446.oh.sprint-hsd.net ([65.40.131.183] helo=192.168.1.2) by albatross.mail.pas.earthlink.net with esmtp (Exim 3.33 #1) id 1ASsLY-0004Cw-00 for ports@freebsd.org; Sat, 06 Dec 2003 22:24:48 -0800 From: Chris BeHanna Organization: Western Pennsylvania Pizza Disposal Unit To: ports@freebsd.org Date: Sun, 7 Dec 2003 01:24:46 -0500 User-Agent: KMail/1.5.4 References: <20031206181534.GE31053@genius.tao.org.uk> In-Reply-To: <20031206181534.GE31053@genius.tao.org.uk> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_ues0/89L6eFAYWp" Message-Id: <200312070124.46973.chris@behanna.org> Subject: Re: Managing ports and their dependencies. X-BeenThere: freebsd-ports@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: chris@behanna.org List-Id: Porting software to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Dec 2003 06:24:50 -0000 --Boundary-00=_ues0/89L6eFAYWp Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Saturday 06 December 2003 13:15, Josef Karthauser wrote: > I've got loads and loads of ports installed on my box, most of which I > probably don't use, but I've no idea which ones these are. Things like > kde install lots of dependancies, and so I've no idea just by looking at > the installed port names which ones I need and which ones I don't need. > > It should be possible to display ports and their dependancies as a > connected graph, and then the ports that appear on the leaves of the > tree would be the ones that I can consider removing. > > Does anyone have any code for doing something like this? I thought > I'd ask before I started knocking it up myself. I started out trying to do this with p5-GraphViz, but the result was an unreadable mess. I'll attach what I have, which I intended to submit as a port someday, but it's not ready for that just now. -- Chris BeHanna Software Engineer (Remove "bogus" before responding.) chris@bogus.behanna.org Turning coffee into software since 1990. --Boundary-00=_ues0/89L6eFAYWp Content-Type: text/plain; charset="iso-8859-1"; name="portgraph" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="portgraph" #!/usr/bin/perl # # $RCSfile: portgraph,v $ # # Copyright 2002 Christopher G. BeHanna, all rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY CHRISTOPHER G. BEHANNA ("THE AUTHOR") "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE THE AUTHOR BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # $Author: behanna $ # $Date: 2003/03/09 07:31:59 $ # $Revision: 1.1 $ # $Source: /raid5/chris_cvs/personal/utils/portgraph/portgraph,v $ # # Analyze FreeBSD installed ports dependencies. # use POSIX; use GraphViz; use strict; my $usage = "portsgraph [-g] [dbdir]\n" . "\t-g Generate image of dependency graph, named portdeps.png\n"; my $graphics = "false"; my $pngfile = "portdeps.png"; if (scalar(@ARGV) < 1 or $ARGV[0] =~ "/\-help/") { die "$usage\n"; } if ($ARGV[0] eq "-g") { $graphics = "true"; shift; } # # Yes, we grovel through all the +REQUIRES files. It would be faster to take # advantage of portupgrade's pkgdb, but portupgrade doesn't have a "show me only # the immediate dependencies rather than all the recursive dependencies" mode. # my $dbdir = $ARGV[0] || "/var/db/pkg"; my %node = ( 'name' => undef, 'deps' => undef, 'parents' => undef, 'seen' => undef ); my $blanks = " "; my %depshash = (); my $dbdirp = POSIX::opendir($dbdir) or die "Couldn't open $dbdir: $!\n"; my @portslist = POSIX::readdir($dbdirp); POSIX::closedir($dbdirp); my $line = ""; my $port = ""; for my $i (@portslist) { $port = $i; $port =~ s/\-[0-9].*$//; my $reqfile = "$dbdir/$i/+REQUIRED_BY"; if ( -e "$reqfile" ) { open(REQFILE, $reqfile) or die "Couldn't open $reqfile: $!\n"; while ($line = ) { chomp($line); $line =~ s/\-[0-9].*$//; push(@{$depshash{$line}}, $port); } close( REQFILE ); } } # # Now we have a hash of arrays. Each key is a port, and each value is a # list of that port's dependencies. # if (1 eq 0) { for my $i (keys %depshash) { print "$i depends upon:\n"; for my $j (@{$depshash{$i}}) { print "\t$j\n"; } } } # # If we're generating a PNG file, build it and get out. # if ($graphics eq "true") { my $graph = GraphViz->new('nooverlap' => 1, 'directed' => 1, 'concentrate' => 1); for my $i (keys %depshash) { $graph->add_node($i); } for my $i (keys %depshash) { for my $j (@{$depshash{$i}}) { $graph->add_edge($i => $j, 'color' => 'black', 'dir' => 'forward', 'arrowhead' => 'normal'); } } open(PNGFILE, ">$pngfile") or die "$pngfile: $!\n"; binmode(\*PNGFILE); $graph->as_png(\*PNGFILE); close( PNGFILE ); exit 0; } # # Build a dependency tree. Start by making a node for each project. # my %deptree = (); for my $i (keys %depshash) { %{$deptree{$i}} = %node; $deptree{$i}{'name'} = $i; } # # Now, for each dependency listed in the original hash of arrays, insert the # reference to that dependency's node in the port's dependency list. # for my $i (keys %deptree) { for my $j (@{$depshash{$i}}) { if (not defined $deptree{$i}{'deps'}) { $deptree{$i}{'deps'} = {}; } $deptree{$i}{'deps'}->{$j} = $deptree{$j}; if (not defined $deptree{$j}{'parents'}) { $deptree{$j}{'parents'} = {}; } $deptree{$j}{'parents'}->{$i} = $deptree{$i}; } } # # Identify the root(s). These are nodes that have no parents. # my @roots = (); for my $i (keys %deptree) { if (not defined $deptree{$i}{'parents'}) { push(@roots, ($deptree{$i})); } } # # Print the tree. # my $indent = 0; if ($graphics eq "false") { for my $i (@roots) { printdeps($i); } } ##### # # sub printdeps # # Param: reference to a node. # ##### sub printdeps { my $root = shift; $indent+=2; # if (defined $root->{'seen'}) { # print substr($blanks, 0, $indent) . # "Cycle detected for node $root->{'name'}!\n"; # $indent--; # return; # } print substr($blanks, 0, $indent) . "$root->{'name'}\n"; $root->{'seen'} = "true"; for my $i (keys %{$root->{'deps'}}) { printdeps($root->{'deps'}->{$i}); } $indent-=2; } --Boundary-00=_ues0/89L6eFAYWp--