Mon Mar 3 05:06:43 2014 UTC ()
Fixes perl interpreter path for the case using builtin perl.


(obache)
diff -r1.34 -r1.35 pkgsrc/pkgtools/pkgdepgraph/Makefile
diff -r1.11 -r1.12 pkgsrc/pkgtools/pkgdepgraph/files/pkgdepgraph.pl

cvs diff -r1.34 -r1.35 pkgsrc/pkgtools/pkgdepgraph/Makefile (switch to unified diff)

--- pkgsrc/pkgtools/pkgdepgraph/Makefile 2014/03/03 05:03:49 1.34
+++ pkgsrc/pkgtools/pkgdepgraph/Makefile 2014/03/03 05:06:43 1.35
@@ -1,68 +1,69 @@ @@ -1,68 +1,69 @@
1# $NetBSD: Makefile,v 1.34 2014/03/03 05:03:49 obache Exp $ 1# $NetBSD: Makefile,v 1.35 2014/03/03 05:06:43 obache Exp $
2# 2#
3 3
4PKGNAME= pkgdepgraph-2.8 4PKGNAME= pkgdepgraph-2.8
5PKGREVISION= 2 5PKGREVISION= 2
6CATEGORIES= pkgtools devel 6CATEGORIES= pkgtools devel
7 7
8MAINTAINER= pkgsrc-users@NetBSD.org 8MAINTAINER= pkgsrc-users@NetBSD.org
9HOMEPAGE= ftp://ftp.NetBSD.org/pub/NetBSD/packages/pkgsrc/doc/pkgsrc.html 9HOMEPAGE= ftp://ftp.NetBSD.org/pub/NetBSD/packages/pkgsrc/doc/pkgsrc.html
10COMMENT= Visual representation of installed NetBSD packages 10COMMENT= Visual representation of installed NetBSD packages
11 11
12# removed so that pkgdepgraph can be used on "client" machines -- @@@ 12# removed so that pkgdepgraph can be used on "client" machines -- @@@
13# DEPENDS+= graphviz-[0-9]*:../../graphics/graphviz 13# DEPENDS+= graphviz-[0-9]*:../../graphics/graphviz
14 14
15WRKSRC= ${WRKDIR} 15WRKSRC= ${WRKDIR}
16USE_TOOLS+= perl:run 16USE_TOOLS+= perl:run
17 17
18NO_CONFIGURE= yes 18NO_CONFIGURE= yes
19 19
20DISTVER= ${PKGVERSION_NOREV} 20DISTVER= ${PKGVERSION_NOREV}
21 21
22.include "../../mk/bsd.prefs.mk" 22.include "../../mk/bsd.prefs.mk"
23 23
24.if ${OPSYS} == "SunOS" || ${OPSYS} == "AIX" 24.if ${OPSYS} == "SunOS" || ${OPSYS} == "AIX"
25USE_TOOLS+= nroff 25USE_TOOLS+= nroff
26.endif 26.endif
27 27
28INSTALLATION_DIRS= bin ${PKGMANDIR}/cat1 ${PKGMANDIR}/man1 28INSTALLATION_DIRS= bin ${PKGMANDIR}/cat1 ${PKGMANDIR}/man1
29 29
30do-extract: 30do-extract:
31 ${CP} ${FILESDIR}/pkgdepgraph.pl ${WRKSRC}/pkgdepgraph.pl 31 ${CP} ${FILESDIR}/pkgdepgraph.pl ${WRKSRC}/pkgdepgraph.pl
32 ${CP} ${FILESDIR}/pkgdepgraph.1 ${WRKSRC}/pkgdepgraph.1.in 32 ${CP} ${FILESDIR}/pkgdepgraph.1 ${WRKSRC}/pkgdepgraph.1.in
33 ${CP} ${FILESDIR}/pkgdepgraph.0 ${WRKSRC}/pkgdepgraph.0.in 33 ${CP} ${FILESDIR}/pkgdepgraph.0 ${WRKSRC}/pkgdepgraph.0.in
34 34
35do-build: 35do-build:
36.for file in pkgdepgraph 36.for file in pkgdepgraph
37 ${SED} -e 's|@PREFIX@|${PREFIX}|g' \ 37 ${SED} -e 's|@PREFIX@|${PREFIX}|g' \
38 -e 's|@PKG_DBDIR@|${PKG_DBDIR}|g' \ 38 -e 's|@PKG_DBDIR@|${PKG_DBDIR}|g' \
39 -e 's|@PKGSRCDIR@|${PKGSRCDIR}|g' \ 39 -e 's|@PKGSRCDIR@|${PKGSRCDIR}|g' \
40 -e 's|@DISTVER@|${DISTVER}|g' \ 40 -e 's|@DISTVER@|${DISTVER}|g' \
 41 -e 's|@PERL5@|${PERL5}|g' \
41 < ${WRKSRC}/${file}.pl \ 42 < ${WRKSRC}/${file}.pl \
42 > ${WRKSRC}/${file} 43 > ${WRKSRC}/${file}
43.endfor 44.endfor
44.for file in pkgdepgraph.1 pkgdepgraph.0 45.for file in pkgdepgraph.1 pkgdepgraph.0
45 ${SED} -e 's|@PKG_DBDIR@|${PKG_DBDIR}|g' \ 46 ${SED} -e 's|@PKG_DBDIR@|${PKG_DBDIR}|g' \
46 -e 's|@PKGSRCDIR@|${PKGSRCDIR}|g' \ 47 -e 's|@PKGSRCDIR@|${PKGSRCDIR}|g' \
47 < ${WRKSRC}/${file}.in \ 48 < ${WRKSRC}/${file}.in \
48 > ${WRKSRC}/${file} 49 > ${WRKSRC}/${file}
49.endfor 50.endfor
50.if ${OPSYS} == "SunOS" || ${OPSYS} == "AIX" 51.if ${OPSYS} == "SunOS" || ${OPSYS} == "AIX"
51 # the pre-generated man-pages are 'mandoc'; these OS need 'man' 52 # the pre-generated man-pages are 'mandoc'; these OS need 'man'
52 nroff -man ${WRKSRC}/pkgdepgraph.1 > ${WRKSRC}/pkgdepgraph.0 53 nroff -man ${WRKSRC}/pkgdepgraph.1 > ${WRKSRC}/pkgdepgraph.0
53.endif 54.endif
54 55
55do-install: 56do-install:
56 ${INSTALL_SCRIPT} ${WRKSRC}/pkgdepgraph ${DESTDIR}${PREFIX}/bin/pkgdepgraph 57 ${INSTALL_SCRIPT} ${WRKSRC}/pkgdepgraph ${DESTDIR}${PREFIX}/bin/pkgdepgraph
57.if !empty(MANINSTALL:Mcatinstall) 58.if !empty(MANINSTALL:Mcatinstall)
58. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss]) 59. if defined(CATMAN_SECTION_SUFFIX) && !empty(CATMAN_SECTION_SUFFIX:M[Yy][Ee][Ss])
59 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkgdepgraph.1 60 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1/pkgdepgraph.1
60. else 61. else
61 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1 62 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.0 ${DESTDIR}${PREFIX}/${PKGMANDIR}/cat1
62. endif 63. endif
63.endif 64.endif
64.if !empty(MANINSTALL:Mmaninstall) 65.if !empty(MANINSTALL:Mmaninstall)
65 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1 66 ${INSTALL_MAN} ${WRKSRC}/pkgdepgraph.1 ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1
66.endif 67.endif
67 68
68.include "../../mk/bsd.pkg.mk" 69.include "../../mk/bsd.pkg.mk"

cvs diff -r1.11 -r1.12 pkgsrc/pkgtools/pkgdepgraph/files/pkgdepgraph.pl (switch to unified diff)

--- pkgsrc/pkgtools/pkgdepgraph/files/pkgdepgraph.pl 2005/06/26 17:34:19 1.11
+++ pkgsrc/pkgtools/pkgdepgraph/files/pkgdepgraph.pl 2014/03/03 05:06:43 1.12
@@ -1,737 +1,737 @@ @@ -1,737 +1,737 @@
1#!@PREFIX@/bin/perl 1#!@PERL5@
2 2
3# Copyright (c) 2002, 2003, 2004 by Andrew Brown <atatat@netbsd.org> 3# Copyright (c) 2002, 2003, 2004 by Andrew Brown <atatat@netbsd.org>
4# Absolutely no warranty. 4# Absolutely no warranty.
5 5
6# $NetBSD: pkgdepgraph.pl,v 1.11 2005/06/26 17:34:19 atatat Exp $ 6# $NetBSD: pkgdepgraph.pl,v 1.12 2014/03/03 05:06:43 obache Exp $
7# pkgdepgraph: @DISTVER@ 7# pkgdepgraph: @DISTVER@
8 8
9use strict; 9use strict;
10# no strict 'refs'; 10# no strict 'refs';
11 11
12use Getopt::Long; 12use Getopt::Long;
13Getopt::Long::Configure("bundling"); 13Getopt::Long::Configure("bundling");
14my(@opts, %opt); 14my(@opts, %opt);
15my($iam, $version, $usecolor, $group, $locations, $order, $versions); 15my($iam, $version, $usecolor, $group, $locations, $order, $versions);
16my($limit, $delete, $rebuild, $force, @outofdate, @update, $clean); 16my($limit, $delete, $rebuild, $force, @outofdate, @update, $clean);
17my($pkg_dbdir, $pkgsrcdir, $packages, $pkgadd, $fetch, $make); 17my($pkg_dbdir, $pkgsrcdir, $packages, $pkgadd, $fetch, $make);
18my($all, $target, $exists, $reverse, $simple, @subgraph, @impact, %impactof); 18my($all, $target, $exists, $reverse, $simple, @subgraph, @impact, %impactof);
19 19
20$version = '@DISTVER@'; 20$version = '@DISTVER@';
21($iam = $0) =~ s:.*/::; 21($iam = $0) =~ s:.*/::;
22@opts = ('A', 'a+', 'C', 'c', 'D', 'd=s', 'e', 'F', 'f', 'g', 'i=s', 22@opts = ('A', 'a+', 'C', 'c', 'D', 'd=s', 'e', 'F', 'f', 'g', 'i=s',
23 'K=s', 'L', 'l', 'M=s', 'm=s', 'O=s', 'o', 'P=s', 'R', 'r', 23 'K=s', 'L', 'l', 'M=s', 'm=s', 'O=s', 'o', 'P=s', 'R', 'r',
24 'S=s', 's', 't=s', 'U=s', 'v'); 24 'S=s', 's', 't=s', 'U=s', 'v');
25 25
26%opt = ( 26%opt = (
27 'A' => \$pkgadd, 27 'A' => \$pkgadd,
28 'a' => \$all, 28 'a' => \$all,
29 # 'C' => implies "realclean", handled later 29 # 'C' => implies "realclean", handled later
30 # 'c' => implies "clean", handled later 30 # 'c' => implies "clean", handled later
31 'D' => \$delete, 31 'D' => \$delete,
32 'd' => \$pkg_dbdir, 32 'd' => \$pkg_dbdir,
33 'e' => \$exists, 33 'e' => \$exists,
34 'F' => \$fetch, 34 'F' => \$fetch,
35 'f' => \$force, 35 'f' => \$force,
36 'g' => \$group, 36 'g' => \$group,
37 'i' => \@impact, 37 'i' => \@impact,
38 'K' => \$packages, 38 'K' => \$packages,
39 'L' => \$limit, 39 'L' => \$limit,
40 'l' => \$locations, 40 'l' => \$locations,
41 'M' => \$make, 41 'M' => \$make,
42 'm' => \$target, 42 'm' => \$target,
43 'O' => \@outofdate, 43 'O' => \@outofdate,
44 'o' => \$order, 44 'o' => \$order,
45 'P' => \$pkgsrcdir, 45 'P' => \$pkgsrcdir,
46 'R' => \$rebuild, 46 'R' => \$rebuild,
47 'r' => \$reverse, 47 'r' => \$reverse,
48 'S' => \@subgraph, 48 'S' => \@subgraph,
49 's' => \$simple, 49 's' => \$simple,
50 # 't' => goes to rebuild, handled later 50 # 't' => goes to rebuild, handled later
51 'U' => \@update, 51 'U' => \@update,
52 'v' => \$versions, 52 'v' => \$versions,
53 ); 53 );
54die("usage: $iam [-AaCcDeFfgLloRrsv] [-d pkg_dbdir] [-i impact]\n", 54die("usage: $iam [-AaCcDeFfgLloRrsv] [-d pkg_dbdir] [-i impact]\n",
55 " " x (length($iam) + 8), 55 " " x (length($iam) + 8),
56 "[-K packages] [-M make] [-m target] [-O package]\n", 56 "[-K packages] [-M make] [-m target] [-O package]\n",
57 " " x (length($iam) + 8), 57 " " x (length($iam) + 8),
58 "[-P pkgsrcdir] [-S package] [-t target] [-U package]\n", 58 "[-P pkgsrcdir] [-S package] [-t target] [-U package]\n",
59 " " x (length($iam) + 8), 59 " " x (length($iam) + 8),
60 "[data ...]\n") 60 "[data ...]\n")
61 if (!GetOptions(\%opt, @opts)); 61 if (!GetOptions(\%opt, @opts));
62 62
63die("$iam: -D, -F, -m, and -R are mutually exclusive -- please pick one\n") 63die("$iam: -D, -F, -m, and -R are mutually exclusive -- please pick one\n")
64 if (($delete != 0) +  64 if (($delete != 0) +
65 ($fetch != 0) + 65 ($fetch != 0) +
66 ($target ne "") + 66 ($target ne "") +
67 ($rebuild ne "") > 1); 67 ($rebuild ne "") > 1);
68 68
69$pkg_dbdir ||= $ENV{'PKG_DBDIR'} || "@PKG_DBDIR@"; 69$pkg_dbdir ||= $ENV{'PKG_DBDIR'} || "@PKG_DBDIR@";
70$pkgsrcdir ||= $ENV{'PKGSRCDIR'} || "@PKGSRCDIR@"; 70$pkgsrcdir ||= $ENV{'PKGSRCDIR'} || "@PKGSRCDIR@";
71$packages = $ENV{'PKG_PATH'} if (!$packages); 71$packages = $ENV{'PKG_PATH'} if (!$packages);
72$packages = $ENV{'PACKAGES'} . "/All" if (!$packages && $ENV{'PACKAGES'}); 72$packages = $ENV{'PACKAGES'} . "/All" if (!$packages && $ENV{'PACKAGES'});
73$packages = $pkgsrcdir . "/packages/All" if (!$packages); 73$packages = $pkgsrcdir . "/packages/All" if (!$packages);
74$rebuild &&= $opt{t} || "install"; 74$rebuild &&= $opt{t} || "install";
75$clean = "clean" if ($opt{c}); 75$clean = "clean" if ($opt{c});
76$clean = "CLEANDEPENDS=YES clean" if ($opt{C}); 76$clean = "CLEANDEPENDS=YES clean" if ($opt{C});
77$make ||= $ENV{'MAKE'} || "make"; 77$make ||= $ENV{'MAKE'} || "make";
78 78
79my(@pkgs, $pkg, $req, %req, %dep, @reqs, @rreqs); 79my(@pkgs, $pkg, $req, %req, %dep, @reqs, @rreqs);
80my(%clusters, $cluster); 80my(%clusters, $cluster);
81my(%where, $pkgcnt, $num, %num, @num, %ord, $suffix); 81my(%where, $pkgcnt, $num, %num, @num, %ord, $suffix);
82my(%color, $color, %vuln); 82my(%color, $color, %vuln);
83my(%need, %forced, $label); 83my(%need, %forced, $label);
84my($recolor, @graph); 84my($recolor, @graph);
85my(%vpkgs); 85my(%vpkgs);
86 86
87# @pkgs - list of all installed pkgs 87# @pkgs - list of all installed pkgs
88# %req - pkg to ref to hash of pkgs that it requires 88# %req - pkg to ref to hash of pkgs that it requires
89# %dep - pkg to ref to hash of pkgs that depend on it 89# %dep - pkg to ref to hash of pkgs that depend on it
90# %clusters - pkg prefix to number of pkgs that share the prefix 90# %clusters - pkg prefix to number of pkgs that share the prefix
91# %where - pkg to location in source tree 91# %where - pkg to location in source tree
92# %num/@num - pkg to group number/group number array ref 92# %num/@num - pkg to group number/group number array ref
93# %ord - pkg to its height in the tree 93# %ord - pkg to its height in the tree
94# %color - pkg to pkg color (green, yellow, red, etc) 94# %color - pkg to pkg color (green, yellow, red, etc)
95# %vuln - pkg to vulnerabilities recorded against it 95# %vuln - pkg to vulnerabilities recorded against it
96# %need - pkg to version required (pkg is out of date)  96# %need - pkg to version required (pkg is out of date)
97# %forced - pkg marked as "forced" to be out of date 97# %forced - pkg marked as "forced" to be out of date
98# %vpkgs - pkg is viewable (part of selected subgraph) 98# %vpkgs - pkg is viewable (part of selected subgraph)
99 99
100## 100##
101## load out-of-date or security problem list (if given), or a graph to 101## load out-of-date or security problem list (if given), or a graph to
102## recolor 102## recolor
103## 103##
104$recolor = 0; 104$recolor = 0;
105if (@ARGV || ! -t) { 105if (@ARGV || ! -t) {
106 $usecolor = 1; 106 $usecolor = 1;
107 while (<>) { 107 while (<>) {
108 if (/^digraph/) { 108 if (/^digraph/) {
109 $recolor = 1; 109 $recolor = 1;
110 @graph = ($_); 110 @graph = ($_);
111 } 111 }
112 elsif ($recolor > 0) { 112 elsif ($recolor > 0) {
113 push(@graph, $_); 113 push(@graph, $_);
114 $recolor++ if (/^subgraph/); 114 $recolor++ if (/^subgraph/);
115 $recolor-- if (/^\}/); 115 $recolor-- if (/^\}/);
116 $recolor -= ($recolor == 0); 116 $recolor -= ($recolor == 0);
117 } 117 }
118 elsif (m:^([^/\s]+)\t([^/\s]+/[^/\s]+)\t(\d+[^/\s]*)$:) { 118 elsif (m:^([^/\s]+)\t([^/\s]+/[^/\s]+)\t(\d+[^/\s]*)$:) {
119 $where{"$1-$3"} = $2; 119 $where{"$1-$3"} = $2;
120 } 120 }
121 elsif (/^Version mismatch: '(\S+)' (\S+) vs (\S+)/) { 121 elsif (/^Version mismatch: '(\S+)' (\S+) vs (\S+)/) {
122 $color{"$1-$2"} = "red"; 122 $color{"$1-$2"} = "red";
123 $need{"$1-$2"} = "$1-$3"; 123 $need{"$1-$2"} = "$1-$3";
124 } 124 }
125 elsif (/^Unknown package: '(\S+)' version (\S+)/) { 125 elsif (/^Unknown package: '(\S+)' version (\S+)/) {
126 $color{"$1-$2"} = "purple"; 126 $color{"$1-$2"} = "purple";
127 } 127 }
128 elsif (/Package (\S+) has a (\S+) vulnerability/) { 128 elsif (/Package (\S+) has a (\S+) vulnerability/) {
129 $vuln{$1} = $2; 129 $vuln{$1} = $2;
130 $color{$1} = "red"; 130 $color{$1} = "red";
131 } 131 }
132 } 132 }
133} 133}
134 134
135## 135##
136## load pkg list 136## load pkg list
137## 137##
138opendir(P, $pkg_dbdir) || die("opendir"); 138opendir(P, $pkg_dbdir) || die("opendir");
139@pkgs = grep(/-/ && -d "$pkg_dbdir/$_" && -f "$pkg_dbdir/$_/+BUILD_INFO", 139@pkgs = grep(/-/ && -d "$pkg_dbdir/$_" && -f "$pkg_dbdir/$_/+BUILD_INFO",
140 readdir(P)); 140 readdir(P));
141closedir(P); 141closedir(P);
142$pkgcnt = @pkgs; 142$pkgcnt = @pkgs;
143 143
144## 144##
145## where are they needed 145## where are they needed
146## 146##
147foreach $pkg (@pkgs) { 147foreach $pkg (@pkgs) {
148 $where{$pkg} ||= $pkg; 148 $where{$pkg} ||= $pkg;
149 open(R, "<$pkg_dbdir/$pkg/+BUILD_INFO") || 149 open(R, "<$pkg_dbdir/$pkg/+BUILD_INFO") ||
150 die("$pkg: +BUILD_INFO: $!\n"); 150 die("$pkg: +BUILD_INFO: $!\n");
151 while (<R>) { 151 while (<R>) {
152 if (/^PKGPATH\s*=\s*(\S+)/) { 152 if (/^PKGPATH\s*=\s*(\S+)/) {
153 $where{$pkg} = $1 if ($where{$pkg} eq $pkg); 153 $where{$pkg} = $1 if ($where{$pkg} eq $pkg);
154 last; 154 last;
155 } 155 }
156 } 156 }
157 close(R); 157 close(R);
158 next if (!open(R, "<$pkg_dbdir/$pkg/+REQUIRED_BY")); 158 next if (!open(R, "<$pkg_dbdir/$pkg/+REQUIRED_BY"));
159 while ($req = <R>) { 159 while ($req = <R>) {
160 chomp($req); 160 chomp($req);
161 $req{$req}->{$pkg} = 1; 161 $req{$req}->{$pkg} = 1;
162 $dep{$pkg}->{$req} = 1; 162 $dep{$pkg}->{$req} = 1;
163 } 163 }
164 close(R); 164 close(R);
165} 165}
166 166
167## 167##
168## reset %where based on "better" information, if we have it 168## reset %where based on "better" information, if we have it
169## 169##
170foreach $pkg (@pkgs) { 170foreach $pkg (@pkgs) {
171 if ($need{$pkg} && $where{$need{$pkg}}) { 171 if ($need{$pkg} && $where{$need{$pkg}}) {
172 $where{$pkg} = $where{$need{$pkg}}; 172 $where{$pkg} = $where{$need{$pkg}};
173 } 173 }
174} 174}
175 175
176## 176##
177## if we're recoloring an existing graph, recolor it now and finish 177## if we're recoloring an existing graph, recolor it now and finish
178## 178##
179if ($recolor) { 179if ($recolor) {
180 my(%over, %nver, @label, $ocolor); 180 my(%over, %nver, @label, $ocolor);
181 map({ /(.*)-(.*)/ && ($nver{$1} = $2) } @pkgs); 181 map({ /(.*)-(.*)/ && ($nver{$1} = $2) } @pkgs);
182 182
183 foreach (@graph) { 183 foreach (@graph) {
184 # we don't recolor edges 184 # we don't recolor edges
185 ($pkg) = (/\"([^\"]+)\"/); 185 ($pkg) = (/\"([^\"]+)\"/);
186 $pkg =~ s/(.*)-(.*)/$1/; 186 $pkg =~ s/(.*)-(.*)/$1/;
187 $over{$pkg} = $2; 187 $over{$pkg} = $2;
188 188
189 if (/, EDGE$/) { 189 if (/, EDGE$/) {
190 if (defined($nver{$pkg})) { 190 if (defined($nver{$pkg})) {
191 s/color=\"[^\"]+\"/color=\"green\"/; 191 s/color=\"[^\"]+\"/color=\"green\"/;
192 } 192 }
193 else { 193 else {
194 s/color=\"[^\"]+\"/color=\"black\"/; 194 s/color=\"[^\"]+\"/color=\"black\"/;
195 } 195 }
196 } 196 }
197 197
198 elsif (/label=/) { 198 elsif (/label=/) {
199 s/color=\"([^\"]+)\"/color="NEWCOLOR"/; 199 s/color=\"([^\"]+)\"/color="NEWCOLOR"/;
200 $ocolor = $1; 200 $ocolor = $1;
201 s/label=\"([^\"]+)\"/label="NEWLABEL"/; 201 s/label=\"([^\"]+)\"/label="NEWLABEL"/;
202 $label = $1; 202 $label = $1;
203 if ($nver{$pkg}) { 203 if ($nver{$pkg}) {
204 if ($nver{$pkg} ne $over{$pkg} || $ocolor ne "red") { 204 if ($nver{$pkg} ne $over{$pkg} || $ocolor ne "red") {
205 s/NEWCOLOR/green/; 205 s/NEWCOLOR/green/;
206 } 206 }
207 else { 207 else {
208 s/NEWCOLOR/$ocolor/; 208 s/NEWCOLOR/$ocolor/;
209 } 209 }
210 210
211 @label = split(/\\n/, $label); 211 @label = split(/\\n/, $label);
212 $label = ""; 212 $label = "";
213 213
214 # "where" tag 214 # "where" tag
215 if ($label[0] =~ m:/:) { 215 if ($label[0] =~ m:/:) {
216 $label .= "\\n" . shift(@label); 216 $label .= "\\n" . shift(@label);
217 } 217 }
218 218
219 # installed pkg 219 # installed pkg
220 $label[0] =~ s/(.*$pkg)-\S*$/$1-$nver{$pkg}/ if ($nver{$pkg}); 220 $label[0] =~ s/(.*$pkg)-\S*$/$1-$nver{$pkg}/ if ($nver{$pkg});
221 $label .= "\\n" . shift(@label); 221 $label .= "\\n" . shift(@label);
222 222
223 # "needed" pkg 223 # "needed" pkg
224 if ($label[0] =~ /^$pkg-(.*)/) { 224 if ($label[0] =~ /^$pkg-(.*)/) {
225 $label .= "\\n$label[0]" if ($1 ne $nver{$pkg}); 225 $label .= "\\n$label[0]" if ($1 ne $nver{$pkg});
226 shift(@label); 226 shift(@label);
227 } 227 }
228 228
229 # there shouldn't be anything left, but... 229 # there shouldn't be anything left, but...
230 $label .= "\\n" . join("\\n", @label); 230 $label .= "\\n" . join("\\n", @label);
231 231
232 $label =~ s/\\n//; 232 $label =~ s/\\n//;
233 } 233 }
234 else { 234 else {
235 s/NEWCOLOR/black/; 235 s/NEWCOLOR/black/;
236 } 236 }
237 s/NEWLABEL/$label/; 237 s/NEWLABEL/$label/;
238 } 238 }
239 print; 239 print;
240 } 240 }
241 exit(0); 241 exit(0);
242} 242}
243 243
244## 244##
245## eliminate redundancies by deleting edges that are redundant 245## eliminate redundancies by deleting edges that are redundant
246## 246##
247foreach $pkg (@pkgs) { 247foreach $pkg (@pkgs) {
248 @reqs = sort(keys %{$req{$pkg}}); 248 @reqs = sort(keys %{$req{$pkg}});
249 @rreqs = recurse(\%req, @reqs); 249 @rreqs = recurse(\%req, @reqs);
250 map(delete($req{$pkg}->{$_}), @rreqs); 250 map(delete($req{$pkg}->{$_}), @rreqs);
251 251
252 @reqs = sort(keys %{$dep{$pkg}}); 252 @reqs = sort(keys %{$dep{$pkg}});
253 @rreqs = recurse(\%dep, @reqs); 253 @rreqs = recurse(\%dep, @reqs);
254 map(delete($dep{$pkg}->{$_}), @rreqs); 254 map(delete($dep{$pkg}->{$_}), @rreqs);
255} 255}
256 256
257## 257##
258## create a hash of clusters of package prefixes, with counts. later, 258## create a hash of clusters of package prefixes, with counts. later,
259## clusters that have more than one member can be marked as subgraphs. 259## clusters that have more than one member can be marked as subgraphs.
260## 260##
261## the outer map() iterates over each pkg name after all instances of 261## the outer map() iterates over each pkg name after all instances of
262## _ in the pkg name have been changed to - (for the purposes of 262## _ in the pkg name have been changed to - (for the purposes of
263## accurate clustering). the inner map() breaks each pkg name up into 263## accurate clustering). the inner map() breaks each pkg name up into
264## tokens that end in - and loops over the resulting list, appending 264## tokens that end in - and loops over the resulting list, appending
265## each one to $a. for example: 265## each one to $a. for example:
266## 266##
267## pkg: one_two-three-4.56 267## pkg: one_two-three-4.56
268## tokens: one- two- three- 268## tokens: one- two- three-
269## $a: one- one-two- one-two-three- 269## $a: one- one-two- one-two-three-
270## 270##
271map({ $a = ""; 271map({ $a = "";
272 ($b = $_) =~ s/_/-/g; 272 ($b = $_) =~ s/_/-/g;
273 map({ $a .= $_; $clusters{$a}++; } 273 map({ $a .= $_; $clusters{$a}++; }
274 $b =~ /([^-]*-)/g); } 274 $b =~ /([^-]*-)/g); }
275 @pkgs); 275 @pkgs);
276 276
277## 277##
278## impose some sort of order on the pkgs by assigning them numbers 278## impose some sort of order on the pkgs by assigning them numbers
279## that indicate their height in the graph. leaf pkgs will always 279## that indicate their height in the graph. leaf pkgs will always
280## have an order of 1, and each pkg above will be numbered at least 2 280## have an order of 1, and each pkg above will be numbered at least 2
281## (possibly higher, if there exists another longer path to another 281## (possibly higher, if there exists another longer path to another
282## leaf). 282## leaf).
283## 283##
284map(order(1, $_), @pkgs); 284map(order(1, $_), @pkgs);
285 285
286## 286##
287## assign each pkg a group number, and count the number of pkgs in 287## assign each pkg a group number, and count the number of pkgs in
288## that group. the group numbers are arbitrary, and serve only to 288## that group. the group numbers are arbitrary, and serve only to
289## identify pkgs that belong to the same group. 289## identify pkgs that belong to the same group.
290## 290##
291$num = 1; 291$num = 1;
292foreach $pkg (@pkgs) { 292foreach $pkg (@pkgs) {
293 my($pkgnum); 293 my($pkgnum);
294 # my direct requirements 294 # my direct requirements
295 @reqs = sort(keys %{$req{$pkg}}); 295 @reqs = sort(keys %{$req{$pkg}});
296 # all the requirements of my requirements 296 # all the requirements of my requirements
297 @rreqs = recurse(\%req, @reqs); 297 @rreqs = recurse(\%req, @reqs);
298 # the lowest group number from all of those 298 # the lowest group number from all of those
299 $pkgnum = number($pkg, @reqs, @rreqs) || $num; 299 $pkgnum = number($pkg, @reqs, @rreqs) || $num;
300 # stuff all those into the list for that group  300 # stuff all those into the list for that group
301 push(@{$num[$pkgnum]}, $pkg, @reqs, @rreqs); 301 push(@{$num[$pkgnum]}, $pkg, @reqs, @rreqs);
302 # now check for packages coming from other groups 302 # now check for packages coming from other groups
303 foreach $req ($pkg, @reqs, @rreqs) { 303 foreach $req ($pkg, @reqs, @rreqs) {
304 # no group yet, skip on 304 # no group yet, skip on
305 next if (!$num{$req}); 305 next if (!$num{$req});
306 # was $req in a different group 306 # was $req in a different group
307 if ($num{$req} != $pkgnum) { 307 if ($num{$req} != $pkgnum) {
308 # yes, pull that group into the current group  308 # yes, pull that group into the current group
309 push(@{$num[$pkgnum]}, @{$num[$num{$req}]}); 309 push(@{$num[$pkgnum]}, @{$num[$num{$req}]});
310 # empty out the old group 310 # empty out the old group
311 @{$num[$num{$req}]} = (); 311 @{$num[$num{$req}]} = ();
312 } 312 }
313 } 313 }
314 # reduce the group list 314 # reduce the group list
315 @{$num[$pkgnum]} = uniq(sort(@{$num[$pkgnum]})); 315 @{$num[$pkgnum]} = uniq(sort(@{$num[$pkgnum]}));
316 # make sure all packages in this group know  316 # make sure all packages in this group know
317 map($num{$_} = $pkgnum, @{$num[$pkgnum]}); 317 map($num{$_} = $pkgnum, @{$num[$pkgnum]});
318 # skip to next available group number 318 # skip to next available group number
319 $num += ($num == $pkgnum); 319 $num += ($num == $pkgnum);
320} 320}
321 321
322## 322##
323## if we want to check a specific pkg for rebuild impact, mark it as 323## if we want to check a specific pkg for rebuild impact, mark it as
324## "forced" to be out of date, unless it already *is* out of date. 324## "forced" to be out of date, unless it already *is* out of date.
325## 325##
326if (@outofdate) { 326if (@outofdate) {
327 $usecolor = 1; 327 $usecolor = 1;
328 canonicalize(@outofdate); 328 canonicalize(@outofdate);
329 329
330 foreach (@outofdate) { 330 foreach (@outofdate) {
331 if ($color{$_} ne "red") { 331 if ($color{$_} ne "red") {
332 $color{$_} = "red"; 332 $color{$_} = "red";
333 $need{$_} = $_; 333 $need{$_} = $_;
334 $forced{$_} = " (forced)"; 334 $forced{$_} = " (forced)";
335 } 335 }
336 } 336 }
337} 337}
338 338
339## 339##
340## if we want to update a specific package, mark all non-related 340## if we want to update a specific package, mark all non-related
341## packages as "green". this avoids rebuilding unnecessary pkgs that 341## packages as "green". this avoids rebuilding unnecessary pkgs that
342## don't depend on any of the same dependencies as the given pkg. if 342## don't depend on any of the same dependencies as the given pkg. if
343## $force is set, mark *all* dependencies of the given pkg as out of 343## $force is set, mark *all* dependencies of the given pkg as out of
344## date. 344## date.
345## 345##
346if (@update) { 346if (@update) {
347 my(@leftover); 347 my(@leftover);
348 348
349 canonicalize(@update); 349 canonicalize(@update);
350 @update = uniq(sort(@update, recurse(\%req, @update))); 350 @update = uniq(sort(@update, recurse(\%req, @update)));
351 351
352 if ($force) { 352 if ($force) {
353 foreach (@update) { 353 foreach (@update) {
354 if ($color{$_} ne "red") { 354 if ($color{$_} ne "red") {
355 $color{$_} = "red"; 355 $color{$_} = "red";
356 $need{$_} = $_; 356 $need{$_} = $_;
357 $forced{$_} = " (forced)"; 357 $forced{$_} = " (forced)";
358 } 358 }
359 } 359 }
360 } 360 }
361 361
362 foreach (sort(@pkgs)) { 362 foreach (sort(@pkgs)) {
363 if ($_ eq $update[0]) { 363 if ($_ eq $update[0]) {
364 shift(@update); 364 shift(@update);
365 } 365 }
366 else { 366 else {
367 push(@leftover, $_); 367 push(@leftover, $_);
368 } 368 }
369 } 369 }
370 370
371 delete(@color{@leftover}); 371 delete(@color{@leftover});
372 delete(@need{@leftover}); 372 delete(@need{@leftover});
373} 373}
374 374
375## 375##
376## pick packages for a subgraph 376## pick packages for a subgraph
377## 377##
378## + means up from given package, - means down, ++ means all the way 378## + means up from given package, - means down, ++ means all the way
379## up, -- means all the way down, = means all "connected" packages, etc. 379## up, -- means all the way down, = means all "connected" packages, etc.
380## 380##
381if (@subgraph) { 381if (@subgraph) {
382 my ($sub, $up, $down, $eq); 382 my ($sub, $up, $down, $eq);
383 foreach (@subgraph) { 383 foreach (@subgraph) {
384 ($sub) = (/^([-+=]+)/); 384 ($sub) = (/^([-+=]+)/);
385 s/^[-+=]+//; 385 s/^[-+=]+//;
386 $sub = "+-" if ($sub eq ""); 386 $sub = "+-" if ($sub eq "");
387 canonicalize($_); 387 canonicalize($_);
388 $up = join("", ($sub =~ /(\+)/g)); 388 $up = join("", ($sub =~ /(\+)/g));
389 $down = join("", ($sub =~ /(-)/g)); 389 $down = join("", ($sub =~ /(-)/g));
390 $eq = join("", ($sub =~ /(=)/g)); 390 $eq = join("", ($sub =~ /(=)/g));
391 if ($eq) { 391 if ($eq) {
392 map($vpkgs{$_} = 1, @{$num[$num{$_}]}); 392 map($vpkgs{$_} = 1, @{$num[$num{$_}]});
393 } 393 }
394 else { 394 else {
395 if ($up) { 395 if ($up) {
396 @reqs = sort(keys %{$req{$_}}); 396 @reqs = sort(keys %{$req{$_}});
397 @rreqs = (length($up) > 1) ? recurse(\%req, @reqs) : (); 397 @rreqs = (length($up) > 1) ? recurse(\%req, @reqs) : ();
398 map($vpkgs{$_} = 1, ($_, @reqs, @rreqs)); 398 map($vpkgs{$_} = 1, ($_, @reqs, @rreqs));
399 } 399 }
400 if ($down) { 400 if ($down) {
401 @reqs = sort(keys %{$dep{$_}}); 401 @reqs = sort(keys %{$dep{$_}});
402 @rreqs = (length($down) > 1) ? recurse(\%dep, @reqs) : (); 402 @rreqs = (length($down) > 1) ? recurse(\%dep, @reqs) : ();
403 map($vpkgs{$_} = 1, ($_, @reqs, @rreqs)); 403 map($vpkgs{$_} = 1, ($_, @reqs, @rreqs));
404 } 404 }
405 } 405 }
406 } 406 }
407} 407}
408else { 408else {
409 @vpkgs{@pkgs} = (1) x @pkgs; 409 @vpkgs{@pkgs} = (1) x @pkgs;
410} 410}
411 411
412## 412##
413## if checking for rebuild impact, also mark packages that are too 413## if checking for rebuild impact, also mark packages that are too
414## deeply involved as "green" so that they're not candidates for 414## deeply involved as "green" so that they're not candidates for
415## destruction 415## destruction
416## 416##
417if (@impact) { 417if (@impact) {
418 my ($impact); 418 my ($impact);
419 419
420 # step 1: canonicalize anything that's not a number (ie, is the 420 # step 1: canonicalize anything that's not a number (ie, is the
421 # name of a pkg) and eliminate duplicates (we just don't need 'em) 421 # name of a pkg) and eliminate duplicates (we just don't need 'em)
422 foreach (@impact) { 422 foreach (@impact) {
423 next if (/^\d+$/); 423 next if (/^\d+$/);
424 canonicalize($_); 424 canonicalize($_);
425 } 425 }
426 @impact = uniq(sort(@impact)); 426 @impact = uniq(sort(@impact));
427 427
428 # step 2: the "default" impact allows for anything to be rebuilt, 428 # step 2: the "default" impact allows for anything to be rebuilt,
429 # but numeric values in @impact are also allowed, so pick the 429 # but numeric values in @impact are also allowed, so pick the
430 # lowest one (specifying both 1 and 2 really means just 1) 430 # lowest one (specifying both 1 and 2 really means just 1)
431 $impact = $ord{(sort(byord @pkgs))[0]}; 431 $impact = $ord{(sort(byord @pkgs))[0]};
432 while ($impact[0] =~ /^\d+$/) { 432 while ($impact[0] =~ /^\d+$/) {
433 $_ = shift(@impact); 433 $_ = shift(@impact);
434 $impact = $_ if ($_ < $impact); 434 $impact = $_ if ($_ < $impact);
435 } 435 }
436 436
437 # step 3: anything that would have too great an impact on the tree 437 # step 3: anything that would have too great an impact on the tree
438 # gets marked (the impactof() function will check the @impact 438 # gets marked (the impactof() function will check the @impact
439 # array to avoid specific pkgs being rebuild) 439 # array to avoid specific pkgs being rebuild)
440 foreach $pkg (keys %vpkgs) { 440 foreach $pkg (keys %vpkgs) {
441 next if (impactof($impact, $pkg) <= $impact); 441 next if (impactof($impact, $pkg) <= $impact);
442 $vpkgs{$pkg} = 2; 442 $vpkgs{$pkg} = 2;
443 } 443 }
444 444
445 # step 4: anything so marked gets tagged as green. this tagging 445 # step 4: anything so marked gets tagged as green. this tagging
446 # is a separate step so that we can properly judge impact over the 446 # is a separate step so that we can properly judge impact over the
447 # entire tree (marking too early could prematurely split chunks 447 # entire tree (marking too early could prematurely split chunks
448 # that need to be rebuilt) 448 # that need to be rebuilt)
449 foreach $pkg (keys %vpkgs) { 449 foreach $pkg (keys %vpkgs) {
450 $color{$pkg} = "green" if ($vpkgs{$pkg} == 2); 450 $color{$pkg} = "green" if ($vpkgs{$pkg} == 2);
451 } 451 }
452} 452}
453 453
454## 454##
455## translate "older" alternate output modes to the new generic version 455## translate "older" alternate output modes to the new generic version
456## 456##
457if ($fetch) { 457if ($fetch) {
458 $target = "fetch"; 458 $target = "fetch";
459} 459}
460elsif ($rebuild) { 460elsif ($rebuild) {
461 $exists = 1; 461 $exists = 1;
462 $limit = 1; 462 $limit = 1;
463 $target = $rebuild; 463 $target = $rebuild;
464} 464}
465elsif ($delete) { 465elsif ($delete) {
466 $all++; 466 $all++;
467 $simple = 1; 467 $simple = 1;
468} 468}
469 469
470## 470##
471## "target" output mode, ordered by ascendency 471## "target" output mode, ordered by ascendency
472## 472##
473if ($target || $simple) { 473if ($target || $simple) {
474 my(@targets); 474 my(@targets);
475 printf("PKG_PATH=\"$packages\"\nexport PKG_PATH\n") 475 printf("PKG_PATH=\"$packages\"\nexport PKG_PATH\n")
476 if ($pkgadd && $rebuild); 476 if ($pkgadd && $rebuild);
477 @targets = grep((color($_) eq "red" && !$limit) || 477 @targets = grep((color($_) eq "red" && !$limit) ||
478 (color($_) ne "green" && 478 (color($_) ne "green" &&
479 ($all || ($ord{$_} == 1 && $limit))) || 479 ($all || ($ord{$_} == 1 && $limit))) ||
480 ($all > 1), keys %vpkgs); 480 ($all > 1), keys %vpkgs);
481 @targets = sort(byord @targets); 481 @targets = sort(byord @targets);
482 @targets = reverse(@targets) if (!$reverse); 482 @targets = reverse(@targets) if (!$reverse);
483 print_package(@targets); 483 print_package(@targets);
484 print("true\n") if (!$simple); 484 print("true\n") if (!$simple);
485 exit(0); 485 exit(0);
486} 486}
487 487
488## 488##
489## show left overs as a graph 489## show left overs as a graph
490## 490##
491printf("digraph \"%s packages\" {\n", 491printf("digraph \"%s packages\" {\n",
492 $limit ? "out of date" : "installed"); 492 $limit ? "out of date" : "installed");
493printf("label = \"%s packages %s, generated by %s v%s, on %s\";\n", 493printf("label = \"%s packages %s, generated by %s v%s, on %s\";\n",
494 $limit ? "out of date" : "installed", 494 $limit ? "out of date" : "installed",
495 @subgraph ? "subgraph (@subgraph)" : "graph", 495 @subgraph ? "subgraph (@subgraph)" : "graph",
496 $iam, $version, scalar(localtime)); 496 $iam, $version, scalar(localtime));
497foreach $pkg (sort(bynum keys %vpkgs)) { 497foreach $pkg (sort(bynum keys %vpkgs)) {
498 $color = color($pkg); 498 $color = color($pkg);
499 next if ($limit && $color eq "green"); 499 next if ($limit && $color eq "green");
500 $label = $pkg; 500 $label = $pkg;
501 $label =~ s/(.*)-.*/$1/ if (!$versions); 501 $label =~ s/(.*)-.*/$1/ if (!$versions);
502 $label = "($ord{$pkg}) $label" if ($order); 502 $label = "($ord{$pkg}) $label" if ($order);
503 $label = "$where{$pkg}\\n$label" if ($locations); 503 $label = "$where{$pkg}\\n$label" if ($locations);
504 $label .= "\\n$need{$pkg}$forced{$pkg}" if ($need{$pkg}); 504 $label .= "\\n$need{$pkg}$forced{$pkg}" if ($need{$pkg});
505 if ($vuln{$pkg}) { 505 if ($vuln{$pkg}) {
506 $label .= "\\n(no update available)" if (!$need{$pkg}); 506 $label .= "\\n(no update available)" if (!$need{$pkg});
507 $label .= "\\n[$vuln{$pkg}]"; 507 $label .= "\\n[$vuln{$pkg}]";
508 } 508 }
509 $suffix = "\t// \#$ord{$pkg}, group $num{$pkg}, " . 509 $suffix = "\t// \#$ord{$pkg}, group $num{$pkg}, " .
510 (exists($impactof{$pkg}) ? "impact $impactof{$pkg}, " : "") . 510 (exists($impactof{$pkg}) ? "impact $impactof{$pkg}, " : "") .
511 scalar(@{$num[$num{$pkg}]}) . " members, $pkgcnt pkgs"; 511 scalar(@{$num[$num{$pkg}]}) . " members, $pkgcnt pkgs";
512 $suffix .= ", LEAF" if ($ord{$pkg} == 1); 512 $suffix .= ", LEAF" if ($ord{$pkg} == 1);
513 513
514 ## 514 ##
515 ## scan the cluster list, but in the opposite order so in the case 515 ## scan the cluster list, but in the opposite order so in the case
516 ## of pkgs with a common "multi-token" prefix, we only emit the 516 ## of pkgs with a common "multi-token" prefix, we only emit the
517 ## one with the longest name. we have to prepend the names to a 517 ## one with the longest name. we have to prepend the names to a
518 ## buffer so that they end up being printed in the reverse of 518 ## buffer so that they end up being printed in the reverse of
519 ## discovery order, so that we end up with the "least-specific" 519 ## discovery order, so that we end up with the "least-specific"
520 ## subgroup announced first. 520 ## subgroup announced first.
521 ## 521 ##
522 ($a = $pkg) =~ s/_/-/g; 522 ($a = $pkg) =~ s/_/-/g;
523 $b = 1; 523 $b = 1;
524 $cluster = ""; 524 $cluster = "";
525 while ($group && $a =~ s/-[^-]+-?$/-/) { 525 while ($group && $a =~ s/-[^-]+-?$/-/) {
526 next if ($clusters{$a} == $b); 526 next if ($clusters{$a} == $b);
527 $b = $clusters{$a}; 527 $b = $clusters{$a};
528 $cluster = sprintf("subgraph \"cluster_%s\" {\n", substr($a, 0, -1)) . 528 $cluster = sprintf("subgraph \"cluster_%s\" {\n", substr($a, 0, -1)) .
529 sprintf("label = \"%s (%d)\";\n", substr($a, 0, -1), $b) . 529 sprintf("label = \"%s (%d)\";\n", substr($a, 0, -1), $b) .
530 $cluster; 530 $cluster;
531 } 531 }
532 print($cluster); 532 print($cluster);
533 printf("\"%s\" [color=\"%s\",label=\"%s\"];$suffix\n", $pkg, 533 printf("\"%s\" [color=\"%s\",label=\"%s\"];$suffix\n", $pkg,
534 $usecolor ? $color : "black", $label); 534 $usecolor ? $color : "black", $label);
535 $cluster =~ s/label = .*\n//g; 535 $cluster =~ s/label = .*\n//g;
536 $cluster =~ s/.+\{/\}/g; 536 $cluster =~ s/.+\{/\}/g;
537 print($cluster); 537 print($cluster);
538 @reqs = sort(keys %{$req{$pkg}}); 538 @reqs = sort(keys %{$req{$pkg}});
539 $suffix =~ s/, LEAF$//; 539 $suffix =~ s/, LEAF$//;
540 $suffix .= ", EDGE"; 540 $suffix .= ", EDGE";
541 foreach $req (@reqs) { 541 foreach $req (@reqs) {
542 $color = color($req); 542 $color = color($req);
543 next if ($limit && $color eq "green"); 543 next if ($limit && $color eq "green");
544 printf("\"%s\" -> \"%s\" [color=\"%s\"];$suffix\n", $req, $pkg, 544 printf("\"%s\" -> \"%s\" [color=\"%s\"];$suffix\n", $req, $pkg,
545 $usecolor ? $color : "black"); 545 $usecolor ? $color : "black");
546 } 546 }
547} 547}
548print("}\n"); 548print("}\n");
549 549
550## 550##
551## print sh(1) style commands to handle work on a given package, or 551## print sh(1) style commands to handle work on a given package, or
552## just the package name if $simple is set 552## just the package name if $simple is set
553## 553##
554sub print_package { 554sub print_package {
555 foreach (@_) { 555 foreach (@_) {
556 printf("( pkg_info -qe %s || ", /(.*)-.*/) if ($exists && !$simple); 556 printf("( pkg_info -qe %s || ", /(.*)-.*/) if ($exists && !$simple);
557 if ($simple) { 557 if ($simple) {
558 print($_); 558 print($_);
559 } 559 }
560 elsif ($pkgadd) { 560 elsif ($pkgadd) {
561 printf("( pkg_add %s.tgz", ($need{$_} || $_)); 561 printf("( pkg_add %s.tgz", ($need{$_} || $_));
562 } 562 }
563 else { 563 else {
564 print("( cd $pkgsrcdir/$where{$_} && $make $target"); 564 print("( cd $pkgsrcdir/$where{$_} && $make $target");
565 print(" && $make $clean") if ($clean); 565 print(" && $make $clean") if ($clean);
566 } 566 }
567 if (!$simple) { 567 if (!$simple) {
568 print(" )") if ($exists); 568 print(" )") if ($exists);
569 print(" ) &&"); 569 print(" ) &&");
570 } 570 }
571 print("\n"); 571 print("\n");
572 } 572 }
573} 573}
574 574
575## 575##
576## find all dependencies above or below a given node 576## find all dependencies above or below a given node
577## 577##
578sub recurse { 578sub recurse {
579 my(@list, @new, $map); 579 my(@list, @new, $map);
580 @list = (); 580 @list = ();
581 $map = shift; 581 $map = shift;
582 foreach (@_) { 582 foreach (@_) {
583 @new = keys %{$map->{$_}}; 583 @new = keys %{$map->{$_}};
584 push(@list, @new, recurse($map, @new)); 584 push(@list, @new, recurse($map, @new));
585 } 585 }
586 uniq(sort(@list)); 586 uniq(sort(@list));
587} 587}
588 588
589## 589##
590## canonicalize a pkg name based on what we have installed 590## canonicalize a pkg name based on what we have installed
591## 591##
592sub canonicalize { 592sub canonicalize {
593 my($canon, $pkg); 593 my($canon, $pkg);
594 594
595 foreach $pkg (@_) { 595 foreach $pkg (@_) {
596 # attempt to find actual pkg, first by argument given... 596 # attempt to find actual pkg, first by argument given...
597 ($canon) = grep($pkg eq $_, @pkgs); 597 ($canon) = grep($pkg eq $_, @pkgs);
598 598
599 # ...then by comparing against the internal list sans version numbers 599 # ...then by comparing against the internal list sans version numbers
600 ($canon) = grep(($a = $_) =~ s/(.*)-.*/$1/ && $pkg eq $a, @pkgs) 600 ($canon) = grep(($a = $_) =~ s/(.*)-.*/$1/ && $pkg eq $a, @pkgs)
601 if (!defined($canon)); 601 if (!defined($canon));
602 602
603 die("package '$pkg' not found\n") 603 die("package '$pkg' not found\n")
604 if (!defined($canon)); 604 if (!defined($canon));
605 605
606 $pkg = $canon; 606 $pkg = $canon;
607 } 607 }
608 608
609 @_; 609 @_;
610} 610}
611 611
612## 612##
613## lowest group number of a set of packages 613## lowest group number of a set of packages
614## 614##
615sub number { 615sub number {
616 my($n, $pkg); 616 my($n, $pkg);
617 $n = 0; 617 $n = 0;
618 foreach $pkg (@_) { 618 foreach $pkg (@_) {
619 $n = $num{$pkg} if ($n == 0 || $num{$pkg} < $n); 619 $n = $num{$pkg} if ($n == 0 || $num{$pkg} < $n);
620 } 620 }
621 $n + 0; 621 $n + 0;
622} 622}
623 623
624## 624##
625## pick a color based on the color of the dependencies 625## pick a color based on the color of the dependencies
626## 626##
627sub color { 627sub color {
628 my($pkg) = @_; 628 my($pkg) = @_;
629 if ($color{$pkg}) { 629 if ($color{$pkg}) {
630 $color{$pkg}; 630 $color{$pkg};
631 } 631 }
632 else { 632 else {
633 my($req, @reqs, $color); 633 my($req, @reqs, $color);
634 @reqs = sort(keys %{$req{$pkg}}); 634 @reqs = sort(keys %{$req{$pkg}});
635 @reqs = (@reqs, recurse(\%req, @reqs)); 635 @reqs = (@reqs, recurse(\%req, @reqs));
636 $color = "green"; 636 $color = "green";
637 foreach $req (@reqs) { 637 foreach $req (@reqs) {
638 if ($color{$req} eq "red") { 638 if ($color{$req} eq "red") {
639 return "orange";  639 return "orange";
640 } 640 }
641 elsif ($color{$req} eq "purple") { 641 elsif ($color{$req} eq "purple") {
642 $color = "blue"; 642 $color = "blue";
643 } 643 }
644 } 644 }
645 $color; 645 $color;
646 } 646 }
647} 647}
648 648
649## 649##
650## bynum - higher numbers come last 650## bynum - higher numbers come last
651## 651##
652sub bynum { 652sub bynum {
653 return $num{$a} <=> $num{$b} || 653 return $num{$a} <=> $num{$b} ||
654 $a cmp $b; 654 $a cmp $b;
655} 655}
656 656
657## 657##
658## byord - higher orders come first 658## byord - higher orders come first
659## 659##
660sub byord { 660sub byord {
661 return $ord{$b} <=> $ord{$a} || 661 return $ord{$b} <=> $ord{$a} ||
662 $b cmp $a; 662 $b cmp $a;
663} 663}
664 664
665## 665##
666## order - the order of a pkg is one higher than anything below it  666## order - the order of a pkg is one higher than anything below it
667## 667##
668sub order { 668sub order {
669 my($n, @pkgs) = @_; 669 my($n, @pkgs) = @_;
670 my($pkg); 670 my($pkg);
671 foreach $pkg (@pkgs) { 671 foreach $pkg (@pkgs) {
672 $ord{$pkg} = $n if ($ord{$pkg} <= $n); 672 $ord{$pkg} = $n if ($ord{$pkg} <= $n);
673 order($n + 1, sort(keys %{$req{$pkg}})); 673 order($n + 1, sort(keys %{$req{$pkg}}));
674 } 674 }
675} 675}
676 676
677## 677##
678## uniq - eliminate adjacent duplicate entries in an array 678## uniq - eliminate adjacent duplicate entries in an array
679## 679##
680sub uniq { 680sub uniq {
681 my($i); 681 my($i);
682 for ($i = 0; $i < $#_; ) { 682 for ($i = 0; $i < $#_; ) {
683 if ($_[$i] eq $_[$i + 1]) { 683 if ($_[$i] eq $_[$i + 1]) {
684 splice(@_, $i, 1); 684 splice(@_, $i, 1);
685 } 685 }
686 else { 686 else {
687 $i++; 687 $i++;
688 } 688 }
689 } 689 }
690 @_; 690 @_;
691} 691}
692 692
693## 693##
694## impactof - impact of pkg delete/rebuild is the longest path (either 694## impactof - impact of pkg delete/rebuild is the longest path (either
695## up or down the tree) that encompasses all things that need 695## up or down the tree) that encompasses all things that need
696## rebuilding 696## rebuilding
697## 697##
698sub impactof { 698sub impactof {
699 my ($impact, $pkg) = @_; 699 my ($impact, $pkg) = @_;
700 my (@in, @out); 700 my (@in, @out);
701 701
702 # if we already know or it's dead-simple, get out early 702 # if we already know or it's dead-simple, get out early
703 return $impactof{$pkg} if (exists($impactof{$pkg})); 703 return $impactof{$pkg} if (exists($impactof{$pkg}));
704 return $impactof{$pkg} = 0 if (color($pkg) eq "green"); 704 return $impactof{$pkg} = 0 if (color($pkg) eq "green");
705 705
706 # starting with the given pkg, repeatedly look up and down the 706 # starting with the given pkg, repeatedly look up and down the
707 # tree for connected pkgs that also require a rebuild 707 # tree for connected pkgs that also require a rebuild
708 @out = ($pkg); 708 @out = ($pkg);
709 do { 709 do {
710 @in = @out; 710 @in = @out;
711 @out = ($pkg); 711 @out = ($pkg);
712 push(@out, grep(color($_) ne "green", recurse(\%dep, @in))); 712 push(@out, grep(color($_) ne "green", recurse(\%dep, @in)));
713 push(@out, grep(color($_) ne "green", recurse(\%req, @out))); 713 push(@out, grep(color($_) ne "green", recurse(\%req, @out)));
714 @out = uniq(sort(byord @out)); 714 @out = uniq(sort(byord @out));
715 } while (@in != @out); 715 } while (@in != @out);
716 716
717 # check to see if the set of related pkgs intersects with the set 717 # check to see if the set of related pkgs intersects with the set
718 # we want to avoid and if so, mark this set as "too expensive" 718 # we want to avoid and if so, mark this set as "too expensive"
719 $a = ""; 719 $a = "";
720 if (@impact) { 720 if (@impact) {
721 foreach $b (@impact) { 721 foreach $b (@impact) {
722 if (grep($_ eq $b, @out)) { 722 if (grep($_ eq $b, @out)) {
723 $a = $b; 723 $a = $b;
724 $impact++; 724 $impact++;
725 last; 725 last;
726 } 726 }
727 } 727 }
728 } 728 }
729 729
730 # if we didn't hit anything, the impact is the one less than the 730 # if we didn't hit anything, the impact is the one less than the
731 # highest ordered remotely connected pkg we found (the longest 731 # highest ordered remotely connected pkg we found (the longest
732 # path from the top to the bottom of the set to be rebuilt) 732 # path from the top to the bottom of the set to be rebuilt)
733 $impact = $ord{$out[0]} - 1 if ($a eq ""); 733 $impact = $ord{$out[0]} - 1 if ($a eq "");
734 @impactof{@in} = ($impact) x @in; 734 @impactof{@in} = ($impact) x @in;
735 735
736 $impactof{$pkg}; 736 $impactof{$pkg};
737} 737}