| @@ -1,1954 +1,1957 @@ | | | @@ -1,1954 +1,1957 @@ |
1 | #!@PERL5@ | | 1 | #!@PERL5@ |
2 | | | 2 | |
3 | # $NetBSD: lintpkgsrc.pl,v 1.19 2020/12/17 16:08:44 rillig Exp $ | | 3 | # $NetBSD: lintpkgsrc.pl,v 1.20 2020/12/17 16:17:45 rillig Exp $ |
4 | | | 4 | |
5 | # Written by David Brownlee <abs@netbsd.org>. | | 5 | # Written by David Brownlee <abs@netbsd.org>. |
6 | # | | 6 | # |
7 | # Caveats: | | 7 | # Caveats: |
8 | # The 'Makefile parsing' algorithm used to obtain package versions and | | 8 | # The 'Makefile parsing' algorithm used to obtain package versions and |
9 | # DEPENDS information is geared towards speed rather than perfection, | | 9 | # DEPENDS information is geared towards speed rather than perfection, |
10 | # though it has gotten somewhat better over time, it only parses the | | 10 | # though it has gotten somewhat better over time, it only parses the |
11 | # simpler Makefile conditionals. | | 11 | # simpler Makefile conditionals. |
12 | # | | 12 | # |
13 | # TODO: Handle fun DEPENDS like avifile-devel with | | 13 | # TODO: Handle fun DEPENDS like avifile-devel with |
14 | # {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} | | 14 | # {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} |
15 | | | 15 | |
16 | $^W = 1; | | 16 | $^W = 1; |
17 | use locale; | | 17 | use locale; |
18 | use strict; | | 18 | use strict; |
19 | use Getopt::Std; | | 19 | use Getopt::Std; |
20 | use File::Find; | | 20 | use File::Find; |
21 | use File::Basename; | | 21 | use File::Basename; |
22 | use IPC::Open3; | | 22 | use IPC::Open3; |
23 | use Cwd 'realpath', 'getcwd'; | | 23 | use Cwd 'realpath', 'getcwd'; |
24 | | | 24 | |
25 | # Buildtime configuration | | 25 | # Buildtime configuration |
26 | my $conf_make = '@MAKE@'; | | 26 | my $conf_make = '@MAKE@'; |
27 | my $conf_pkgsrcdir = '@PKGSRCDIR@'; | | 27 | my $conf_pkgsrcdir = '@PKGSRCDIR@'; |
28 | my $conf_prefix = '@PREFIX@'; | | 28 | my $conf_prefix = '@PREFIX@'; |
29 | my $conf_sysconfdir = '@PKG_SYSCONFDIR@'; | | 29 | my $conf_sysconfdir = '@PKG_SYSCONFDIR@'; |
30 | | | 30 | |
31 | my ( | | 31 | my ( |
32 | $pkglist, # list of Pkg packages | | 32 | $pkglist, # list of Pkg packages |
33 | $pkg_installver, # installed version of pkg_install pseudo-pkg | | 33 | $pkg_installver, # installed version of pkg_install pseudo-pkg |
34 | $default_vars, # Set for Makefiles, inc PACKAGES & PKGSRCDIR | | 34 | $default_vars, # Set for Makefiles, inc PACKAGES & PKGSRCDIR |
35 | %opt, # Command line options | | 35 | %opt, # Command line options |
36 | @matched_prebuiltpackages, # List of obsolete prebuilt package paths | | 36 | @matched_prebuiltpackages, # List of obsolete prebuilt package paths |
37 | @prebuilt_pkgdirs, # Use to follow symlinks in prebuilt pkgdirs | | 37 | @prebuilt_pkgdirs, # Use to follow symlinks in prebuilt pkgdirs |
38 | %prebuilt_pkgdir_cache, # To avoid symlink loops in prebuilt_pkgdirs | | 38 | %prebuilt_pkgdir_cache, # To avoid symlink loops in prebuilt_pkgdirs |
39 | ); | | 39 | ); |
40 | | | 40 | |
41 | $ENV{PATH} .= | | 41 | $ENV{PATH} .= |
42 | ":/bin:/usr/bin:/sbin:/usr/sbin:${conf_prefix}/sbin:${conf_prefix}/bin"; | | 42 | ":/bin:/usr/bin:/sbin:/usr/sbin:${conf_prefix}/sbin:${conf_prefix}/bin"; |
43 | | | 43 | |
44 | if ( | | 44 | if ( |
45 | !getopts( 'BDE:I:K:LM:OP:RSVdg:himopruyz', \%opt ) | | 45 | !getopts( 'BDE:I:K:LM:OP:RSVdg:himopruyz', \%opt ) |
46 | || $opt{h} | | 46 | || $opt{h} |
47 | || !( | | 47 | || !( |
48 | defined $opt{d} | | 48 | defined $opt{d} |
49 | || defined $opt{g} | | 49 | || defined $opt{g} |
50 | || defined $opt{i} | | 50 | || defined $opt{i} |
51 | || defined $opt{m} | | 51 | || defined $opt{m} |
52 | || defined $opt{o} | | 52 | || defined $opt{o} |
53 | || defined $opt{p} | | 53 | || defined $opt{p} |
54 | || defined $opt{r} | | 54 | || defined $opt{r} |
55 | || defined $opt{u} | | 55 | || defined $opt{u} |
56 | || defined $opt{B} | | 56 | || defined $opt{B} |
57 | || defined $opt{D} | | 57 | || defined $opt{D} |
58 | || defined $opt{R} | | 58 | || defined $opt{R} |
59 | || defined $opt{O} | | 59 | || defined $opt{O} |
60 | || defined $opt{S} | | 60 | || defined $opt{S} |
61 | || defined $opt{E} | | 61 | || defined $opt{E} |
62 | || defined $opt{y} | | 62 | || defined $opt{y} |
63 | || defined $opt{z} | | 63 | || defined $opt{z} |
64 | ) | | 64 | ) |
65 | ) | | 65 | ) |
66 | { | | 66 | { |
67 | | | 67 | |
68 | usage_and_exit(); | | 68 | usage_and_exit(); |
69 | } | | 69 | } |
70 | $| = 1; | | 70 | $| = 1; |
71 | | | 71 | |
72 | # Horrible kludge to ensure we have a value for testing in conditionals, but | | 72 | # Horrible kludge to ensure we have a value for testing in conditionals, but |
73 | # gets removed in the final evaluation | | 73 | # gets removed in the final evaluation |
74 | my $magic_undefined = 'M_a_G_i_C_uNdEfInEd'; | | 74 | my $magic_undefined = 'M_a_G_i_C_uNdEfInEd'; |
75 | | | 75 | |
76 | get_default_makefile_vars(); # $default_vars | | 76 | get_default_makefile_vars(); # $default_vars |
77 | | | 77 | |
78 | if ( $opt{D} && @ARGV ) { | | 78 | if ( $opt{D} && @ARGV ) { |
79 | foreach my $file (@ARGV) { | | 79 | foreach my $file (@ARGV) { |
80 | if ( -d $file ) { | | 80 | if ( -d $file ) { |
81 | $file .= "/Makefile"; | | 81 | $file .= "/Makefile"; |
82 | } | | 82 | } |
83 | if ( !-f $file ) { | | 83 | if ( !-f $file ) { |
84 | fail("No such file: $file"); | | 84 | fail("No such file: $file"); |
85 | } | | 85 | } |
86 | my ( $pkgname, $vars ) = parse_makefile_pkgsrc($file); | | 86 | my ( $pkgname, $vars ) = parse_makefile_pkgsrc($file); |
87 | $pkgname ||= 'uNDEFINEd'; | | 87 | $pkgname ||= 'uNDEFINEd'; |
88 | print "$file -> $pkgname\n"; | | 88 | print "$file -> $pkgname\n"; |
89 | foreach my $varname ( sort keys %{$vars} ) { | | 89 | foreach my $varname ( sort keys %{$vars} ) { |
90 | print "\t$varname = $vars->{$varname}\n"; | | 90 | print "\t$varname = $vars->{$varname}\n"; |
91 | } | | 91 | } |
92 | | | 92 | |
93 | #if ($opt{d}) { | | 93 | #if ($opt{d}) { |
94 | # pkgsrc_check_depends(); | | 94 | # pkgsrc_check_depends(); |
95 | #} | | 95 | #} |
96 | } | | 96 | } |
97 | exit; | | 97 | exit; |
98 | } | | 98 | } |
99 | | | 99 | |
100 | sub main() { | | 100 | sub main() { |
101 | my ( $pkgsrcdir, $pkgdistdir ); | | 101 | my ( $pkgsrcdir, $pkgdistdir ); |
102 | | | 102 | |
103 | $pkgsrcdir = $default_vars->{PKGSRCDIR}; | | 103 | $pkgsrcdir = $default_vars->{PKGSRCDIR}; |
104 | $pkgdistdir = $default_vars->{DISTDIR}; | | 104 | $pkgdistdir = $default_vars->{DISTDIR}; |
105 | | | 105 | |
106 | if ( $opt{r} && !$opt{o} && !$opt{m} && !$opt{p} ) { | | 106 | if ( $opt{r} && !$opt{o} && !$opt{m} && !$opt{p} ) { |
107 | $opt{o} = $opt{m} = $opt{p} = 1; | | 107 | $opt{o} = $opt{m} = $opt{p} = 1; |
108 | } | | 108 | } |
109 | if ( $opt{o} || $opt{m} ) { | | 109 | if ( $opt{o} || $opt{m} ) { |
110 | my (@baddist); | | 110 | my (@baddist); |
111 | | | 111 | |
112 | @baddist = | | 112 | @baddist = |
113 | scan_pkgsrc_distfiles_vs_distinfo( $pkgsrcdir, $pkgdistdir, $opt{o}, | | 113 | scan_pkgsrc_distfiles_vs_distinfo( $pkgsrcdir, $pkgdistdir, $opt{o}, |
114 | $opt{m} ); | | 114 | $opt{m} ); |
115 | if ( $opt{r} ) { | | 115 | if ( $opt{r} ) { |
116 | verbose("Unlinking 'bad' distfiles\n"); | | 116 | verbose("Unlinking 'bad' distfiles\n"); |
117 | foreach my $distfile (@baddist) { | | 117 | foreach my $distfile (@baddist) { |
118 | unlink("$pkgdistdir/$distfile"); | | 118 | unlink("$pkgdistdir/$distfile"); |
119 | } | | 119 | } |
120 | } | | 120 | } |
121 | } | | 121 | } |
122 | | | 122 | |
123 | # Remove all distfiles that are / are not part of an installed package | | 123 | # Remove all distfiles that are / are not part of an installed package |
124 | if ($opt{y} || $opt{z}) | | 124 | if ($opt{y} || $opt{z}) |
125 | { | | 125 | { |
126 | my(@pkgs, @installed, %distfiles, @pkgdistfiles, @dldistfiles); | | 126 | my(@pkgs, @installed, %distfiles, @pkgdistfiles, @dldistfiles); |
127 | my(@tmpdistfiles, @orphan, $found, @parent); | | 127 | my(@tmpdistfiles, @orphan, $found, @parent); |
128 | | | 128 | |
129 | @pkgs = list_installed_packages(); | | 129 | @pkgs = list_installed_packages(); |
130 | scan_pkgsrc_makefiles($pkgsrcdir); | | 130 | scan_pkgsrc_makefiles($pkgsrcdir); |
131 | | | 131 | |
132 | # list the installed packages and the directory they live in | | 132 | # list the installed packages and the directory they live in |
133 | foreach my $pkgname (sort @pkgs) | | 133 | foreach my $pkgname (sort @pkgs) |
134 | { | | 134 | { |
135 | if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) | | 135 | if ($pkgname =~ /^([^*?[]+)-([\d*?[].*)/) |
136 | { | | 136 | { |
137 | foreach my $pkgver ($pkglist->pkgver($1)) | | 137 | foreach my $pkgver ($pkglist->pkgver($1)) |
138 | { | | 138 | { |
139 | $pkgver->var('dir') =~ /-current/ && next; | | 139 | $pkgver->var('dir') =~ /-current/ && next; |
140 | push(@installed, $pkgver); | | 140 | push(@installed, $pkgver); |
141 | last; | | 141 | last; |
142 | } | | 142 | } |
143 | } | | 143 | } |
144 | } | | 144 | } |
145 | | | 145 | |
146 | # distfiles belonging to the currently installed packages | | 146 | # distfiles belonging to the currently installed packages |
147 | foreach my $pkgver (sort @installed) | | 147 | foreach my $pkgver (sort @installed) |
148 | { | | 148 | { |
149 | if (open(DISTINFO, "$pkgsrcdir/" .$pkgver->var('dir'). "/distinfo")) | | 149 | if (open(DISTINFO, "$pkgsrcdir/" .$pkgver->var('dir'). "/distinfo")) |
150 | { | | 150 | { |
151 | while( <DISTINFO> ) | | 151 | while( <DISTINFO> ) |
152 | { | | 152 | { |
153 | if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) | | 153 | if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) |
154 | { | | 154 | { |
155 | my($dn); | | 155 | my($dn); |
156 | if ($2 =~ /^patch-[\w.+\-]+$/) | | 156 | if ($2 =~ /^patch-[\w.+\-]+$/) |
157 | { next; } | | 157 | { next; } |
158 | $dn = $2; | | 158 | $dn = $2; |
159 | # Strip leading ./ which sometimes gets added | | 159 | # Strip leading ./ which sometimes gets added |
160 | # because of DISTSUBDIR=. | | 160 | # because of DISTSUBDIR=. |
161 | $dn =~ s/^(\.\/)*//; | | 161 | $dn =~ s/^(\.\/)*//; |
162 | if (!defined $distfiles{$dn}) | | 162 | if (!defined $distfiles{$dn}) |
163 | { | | 163 | { |
164 | $distfiles{$dn}{name} = $dn; | | 164 | $distfiles{$dn}{name} = $dn; |
165 | push (@pkgdistfiles, $dn); | | 165 | push (@pkgdistfiles, $dn); |
166 | } | | 166 | } |
167 | } | | 167 | } |
168 | } | | 168 | } |
169 | close(DISTINFO); | | 169 | close(DISTINFO); |
170 | } | | 170 | } |
171 | } | | 171 | } |
172 | | | 172 | |
173 | # distfiles downloaded on the current system | | 173 | # distfiles downloaded on the current system |
174 | @tmpdistfiles = listdir("$pkgdistdir"); | | 174 | @tmpdistfiles = listdir("$pkgdistdir"); |
175 | foreach my $tmppkg (@tmpdistfiles) | | 175 | foreach my $tmppkg (@tmpdistfiles) |
176 | { | | 176 | { |
177 | if ($tmppkg ne "pkg-vulnerabilities") | | 177 | if ($tmppkg ne "pkg-vulnerabilities") |
178 | { push (@dldistfiles, $tmppkg); } | | 178 | { push (@dldistfiles, $tmppkg); } |
179 | } | | 179 | } |
180 | | | 180 | |
181 | # sort the two arrays to make searching a bit faster | | 181 | # sort the two arrays to make searching a bit faster |
182 | @dldistfiles = sort { $a cmp $b } @dldistfiles; | | 182 | @dldistfiles = sort { $a cmp $b } @dldistfiles; |
183 | @pkgdistfiles = sort { $a cmp $b } @pkgdistfiles; | | 183 | @pkgdistfiles = sort { $a cmp $b } @pkgdistfiles; |
184 | | | 184 | |
185 | if ($opt{y}) | | 185 | if ($opt{y}) |
186 | { | | 186 | { |
187 | # looking for files that are downloaded on the current system | | 187 | # looking for files that are downloaded on the current system |
188 | # but do not belong to any currently installed package i.e. orphaned | | 188 | # but do not belong to any currently installed package i.e. orphaned |
189 | $found = 0; | | 189 | $found = 0; |
190 | foreach my $dldf (@dldistfiles) | | 190 | foreach my $dldf (@dldistfiles) |
191 | { | | 191 | { |
192 | foreach my $pkgdf (@pkgdistfiles) | | 192 | foreach my $pkgdf (@pkgdistfiles) |
193 | { | | 193 | { |
194 | if ($dldf eq $pkgdf) | | 194 | if ($dldf eq $pkgdf) |
195 | { $found = 1; } | | 195 | { $found = 1; } |
196 | } | | 196 | } |
197 | if ($found != 1) | | 197 | if ($found != 1) |
198 | { | | 198 | { |
199 | push (@orphan, $dldf); | | 199 | push (@orphan, $dldf); |
200 | print "Orphaned file: $dldf\n"; | | 200 | print "Orphaned file: $dldf\n"; |
201 | } | | 201 | } |
202 | $found = 0; | | 202 | $found = 0; |
203 | } | | 203 | } |
204 | | | 204 | |
205 | if ($opt{r}) | | 205 | if ($opt{r}) |
206 | { | | 206 | { |
207 | safe_chdir("$pkgdistdir"); | | 207 | safe_chdir("$pkgdistdir"); |
208 | verbose("Unlinking 'orphaned' distfiles\n"); | | 208 | verbose("Unlinking 'orphaned' distfiles\n"); |
209 | foreach my $distfile (@orphan) | | 209 | foreach my $distfile (@orphan) |
210 | { unlink($distfile) } | | 210 | { unlink($distfile) } |
211 | } | | 211 | } |
212 | } | | 212 | } |
213 | | | 213 | |
214 | if ($opt{z}) | | 214 | if ($opt{z}) |
215 | { | | 215 | { |
216 | # looking for files that are downloaded on the current system | | 216 | # looking for files that are downloaded on the current system |
217 | # but belong to a currently installed package i.e. parented | | 217 | # but belong to a currently installed package i.e. parented |
218 | $found = 0; | | 218 | $found = 0; |
219 | foreach my $pkgdf (@pkgdistfiles) | | 219 | foreach my $pkgdf (@pkgdistfiles) |
220 | { | | 220 | { |
221 | foreach my $dldf (@dldistfiles) | | 221 | foreach my $dldf (@dldistfiles) |
222 | { | | 222 | { |
223 | if ($pkgdf eq $dldf) | | 223 | if ($pkgdf eq $dldf) |
224 | { $found = 1; } | | 224 | { $found = 1; } |
225 | } | | 225 | } |
226 | if ($found == 1) | | 226 | if ($found == 1) |
227 | { | | 227 | { |
228 | push (@parent, $pkgdf); | | 228 | push (@parent, $pkgdf); |
229 | print "Parented file: $pkgdf\n"; | | 229 | print "Parented file: $pkgdf\n"; |
230 | } | | 230 | } |
231 | $found = 0; | | 231 | $found = 0; |
232 | } | | 232 | } |
233 | } | | 233 | } |
234 | | | 234 | |
235 | if ($opt{r}) | | 235 | if ($opt{r}) |
236 | { | | 236 | { |
237 | safe_chdir("$pkgdistdir"); | | 237 | safe_chdir("$pkgdistdir"); |
238 | verbose("Unlinking 'parented' distfiles\n"); | | 238 | verbose("Unlinking 'parented' distfiles\n"); |
239 | foreach my $distfile (@parent) | | 239 | foreach my $distfile (@parent) |
240 | { unlink($distfile) } | | 240 | { unlink($distfile) } |
241 | } | | 241 | } |
242 | } | | 242 | } |
243 | | | 243 | |
244 | # List BROKEN packages | | 244 | # List BROKEN packages |
245 | if ( $opt{B} ) { | | 245 | if ( $opt{B} ) { |
246 | scan_pkgsrc_makefiles($pkgsrcdir); | | 246 | scan_pkgsrc_makefiles($pkgsrcdir); |
247 | foreach my $pkgver ( $pkglist->pkgver ) { | | 247 | foreach my $pkgver ( $pkglist->pkgver ) { |
248 | $pkgver->var('BROKEN') || next; | | 248 | $pkgver->var('BROKEN') || next; |
249 | print $pkgver->pkgname . ': ' . $pkgver->var('BROKEN') . "\n"; | | 249 | print $pkgver->pkgname . ': ' . $pkgver->var('BROKEN') . "\n"; |
250 | } | | 250 | } |
251 | } | | 251 | } |
252 | | | 252 | |
253 | # List obsolete or NO_BIN_ON_FTP/RESTRICTED prebuilt packages | | 253 | # List obsolete or NO_BIN_ON_FTP/RESTRICTED prebuilt packages |
254 | # | | 254 | # |
255 | if ( $opt{p} || $opt{O} || $opt{R} ) { | | 255 | if ( $opt{p} || $opt{O} || $opt{R} ) { |
256 | scan_pkgsrc_makefiles($pkgsrcdir); | | 256 | scan_pkgsrc_makefiles($pkgsrcdir); |
257 | | | 257 | |
258 | @prebuilt_pkgdirs = ( $default_vars->{PACKAGES} ); | | 258 | @prebuilt_pkgdirs = ( $default_vars->{PACKAGES} ); |
259 | %prebuilt_pkgdir_cache = (); | | 259 | %prebuilt_pkgdir_cache = (); |
260 | | | 260 | |
261 | while (@prebuilt_pkgdirs) { | | 261 | while (@prebuilt_pkgdirs) { |
262 | find( \&check_prebuilt_packages, shift @prebuilt_pkgdirs ); | | 262 | find( \&check_prebuilt_packages, shift @prebuilt_pkgdirs ); |
263 | } | | 263 | } |
264 | | | 264 | |
265 | if ( $opt{r} ) { | | 265 | if ( $opt{r} ) { |
266 | verbose("Unlinking listed prebuilt packages\n"); | | 266 | verbose("Unlinking listed prebuilt packages\n"); |
267 | foreach my $pkgfile (@matched_prebuiltpackages) { | | 267 | foreach my $pkgfile (@matched_prebuiltpackages) { |
268 | unlink($pkgfile); | | 268 | unlink($pkgfile); |
269 | } | | 269 | } |
270 | } | | 270 | } |
271 | } | | 271 | } |
272 | | | 272 | |
273 | if ( $opt{S} ) { | | 273 | if ( $opt{S} ) { |
274 | my (%in_subdir); | | 274 | my (%in_subdir); |
275 | | | 275 | |
276 | foreach my $cat ( list_pkgsrc_categories($pkgsrcdir) ) { | | 276 | foreach my $cat ( list_pkgsrc_categories($pkgsrcdir) ) { |
277 | my $vars = parse_makefile_vars("$pkgsrcdir/$cat/Makefile"); | | 277 | my $vars = parse_makefile_vars("$pkgsrcdir/$cat/Makefile"); |
278 | | | 278 | |
279 | if ( !$vars->{SUBDIR} ) { | | 279 | if ( !$vars->{SUBDIR} ) { |
280 | print "Warning - no SUBDIR for $cat\n"; | | 280 | print "Warning - no SUBDIR for $cat\n"; |
281 | next; | | 281 | next; |
282 | } | | 282 | } |
283 | foreach my $pkgdir ( split( /\s+/, $vars->{SUBDIR} ) ) { | | 283 | foreach my $pkgdir ( split( /\s+/, $vars->{SUBDIR} ) ) { |
284 | $in_subdir{"$cat/$pkgdir"} = 1; | | 284 | $in_subdir{"$cat/$pkgdir"} = 1; |
285 | } | | 285 | } |
286 | } | | 286 | } |
287 | | | 287 | |
288 | scan_pkgsrc_makefiles($pkgsrcdir); | | 288 | scan_pkgsrc_makefiles($pkgsrcdir); |
289 | foreach my $pkgver ( $pkglist->pkgver ) { | | 289 | foreach my $pkgver ( $pkglist->pkgver ) { |
290 | if ( !defined $in_subdir{ $pkgver->var('dir') } ) { | | 290 | if ( !defined $in_subdir{ $pkgver->var('dir') } ) { |
291 | print $pkgver->var('dir') . ": Not in SUBDIR\n"; | | 291 | print $pkgver->var('dir') . ": Not in SUBDIR\n"; |
292 | } | | 292 | } |
293 | } | | 293 | } |
294 | } | | 294 | } |
295 | | | 295 | |
296 | if ( $opt{g} ) { | | 296 | if ( $opt{g} ) { |
297 | my $tmpfile = "$opt{g}.tmp.$$"; | | 297 | my $tmpfile = "$opt{g}.tmp.$$"; |
298 | | | 298 | |
299 | scan_pkgsrc_makefiles($pkgsrcdir); | | 299 | scan_pkgsrc_makefiles($pkgsrcdir); |
300 | if ( !open( TABLE, ">$tmpfile" ) ) { | | 300 | if ( !open( TABLE, ">$tmpfile" ) ) { |
301 | fail("Unable to write '$tmpfile': $!"); | | 301 | fail("Unable to write '$tmpfile': $!"); |
302 | } | | 302 | } |
303 | foreach my $pkgver ( $pkglist->pkgver ) { | | 303 | foreach my $pkgver ( $pkglist->pkgver ) { |
304 | print TABLE $pkgver->pkg . "\t" | | 304 | print TABLE $pkgver->pkg . "\t" |
305 | . $pkgver->var('dir') . "\t" | | 305 | . $pkgver->var('dir') . "\t" |
306 | . $pkgver->ver . "\n"; | | 306 | . $pkgver->ver . "\n"; |
307 | } | | 307 | } |
308 | if ( !close(TABLE) ) { | | 308 | if ( !close(TABLE) ) { |
309 | fail("Error while writing '$tmpfile': $!"); | | 309 | fail("Error while writing '$tmpfile': $!"); |
310 | } | | 310 | } |
311 | if ( !rename( $tmpfile, $opt{g} ) ) { | | 311 | if ( !rename( $tmpfile, $opt{g} ) ) { |
312 | fail("Error in rename('$tmpfile','$opt{g}'): $!"); | | 312 | fail("Error in rename('$tmpfile','$opt{g}'): $!"); |
313 | } | | 313 | } |
314 | } | | 314 | } |
315 | | | 315 | |
316 | if ( $opt{d} ) { | | 316 | if ( $opt{d} ) { |
317 | scan_pkgsrc_makefiles($pkgsrcdir); | | 317 | scan_pkgsrc_makefiles($pkgsrcdir); |
318 | pkgsrc_check_depends(); | | 318 | pkgsrc_check_depends(); |
319 | } | | 319 | } |
320 | | | 320 | |
321 | if ( $opt{i} || $opt{u} ) { | | 321 | if ( $opt{i} || $opt{u} ) { |
322 | my ( @pkgs, @update ); | | 322 | my ( @pkgs, @update ); |
323 | | | 323 | |
324 | @pkgs = list_installed_packages(); | | 324 | @pkgs = list_installed_packages(); |
325 | scan_pkgsrc_makefiles($pkgsrcdir); | | 325 | scan_pkgsrc_makefiles($pkgsrcdir); |
326 | | | 326 | |
327 | foreach my $pkgname ( sort @pkgs ) { | | 327 | foreach my $pkgname ( sort @pkgs ) { |
328 | if ( $_ = invalid_version($pkgname) ) { | | 328 | if ( $_ = invalid_version($pkgname) ) { |
329 | print $_; | | 329 | print $_; |
330 | | | 330 | |
331 | if ( $pkgname =~ /^([^*?[]+)-([\d*?[].*)/ ) { | | 331 | if ( $pkgname =~ /^([^*?[]+)-([\d*?[].*)/ ) { |
332 | foreach my $pkgver ( $pkglist->pkgver($1) ) { | | 332 | foreach my $pkgver ( $pkglist->pkgver($1) ) { |
333 | $pkgver->var('dir') =~ /-current/ && next; | | 333 | $pkgver->var('dir') =~ /-current/ && next; |
334 | push( @update, $pkgver ); | | 334 | push( @update, $pkgver ); |
335 | last; | | 335 | last; |
336 | } | | 336 | } |
337 | } | | 337 | } |
338 | } | | 338 | } |
339 | } | | 339 | } |
340 | | | 340 | |
341 | if ( $opt{u} ) { | | 341 | if ( $opt{u} ) { |
342 | print "\nREQUIRED details for packages that could be updated:\n"; | | 342 | print "\nREQUIRED details for packages that could be updated:\n"; |
343 | | | 343 | |
344 | foreach my $pkgver (@update) { | | 344 | foreach my $pkgver (@update) { |
345 | print $pkgver->pkg . ':'; | | 345 | print $pkgver->pkg . ':'; |
346 | if ( open( PKGINFO, 'pkg_info -R ' . $pkgver->pkg . '|' ) ) { | | 346 | if ( open( PKGINFO, 'pkg_info -R ' . $pkgver->pkg . '|' ) ) { |
347 | my ($list); | | 347 | my ($list); |
348 | | | 348 | |
349 | while (<PKGINFO>) { | | 349 | while (<PKGINFO>) { |
350 | if (/Required by:/) { | | 350 | if (/Required by:/) { |
351 | $list = 1; | | 351 | $list = 1; |
352 | } | | 352 | } |
353 | elsif ($list) { | | 353 | elsif ($list) { |
354 | chomp; | | 354 | chomp; |
355 | s/-\d.*//; | | 355 | s/-\d.*//; |
356 | print " $_"; | | 356 | print " $_"; |
357 | } | | 357 | } |
358 | } | | 358 | } |
359 | close(PKGINFO); | | 359 | close(PKGINFO); |
360 | } | | 360 | } |
361 | print "\n"; | | 361 | print "\n"; |
362 | } | | 362 | } |
363 | | | 363 | |
364 | print | | 364 | print |
365 | "\nRunning '${conf_make} fetch-list | sh' for each package:\n"; | | 365 | "\nRunning '${conf_make} fetch-list | sh' for each package:\n"; |
366 | foreach my $pkgver (@update) { | | 366 | foreach my $pkgver (@update) { |
367 | my ($pkgdir); | | 367 | my ($pkgdir); |
368 | | | 368 | |
369 | $pkgdir = $pkgver->var('dir'); | | 369 | $pkgdir = $pkgver->var('dir'); |
370 | if ( !defined($pkgdir) ) { | | 370 | if ( !defined($pkgdir) ) { |
371 | fail( | | 371 | fail( |
372 | 'Unable to determine ' . $pkgver->pkg . ' directory' ); | | 372 | 'Unable to determine ' . $pkgver->pkg . ' directory' ); |
373 | } | | 373 | } |
374 | | | 374 | |
375 | print "$pkgsrcdir/$pkgdir\n"; | | 375 | print "$pkgsrcdir/$pkgdir\n"; |
376 | safe_chdir("$pkgsrcdir/$pkgdir"); | | 376 | safe_chdir("$pkgsrcdir/$pkgdir"); |
377 | system("${conf_make} fetch-list | sh"); | | 377 | system("${conf_make} fetch-list | sh"); |
378 | } | | 378 | } |
379 | } | | 379 | } |
380 | } | | 380 | } |
381 | | | 381 | |
382 | if ( $opt{E} ) { | | 382 | if ( $opt{E} ) { |
383 | scan_pkgsrc_makefiles($pkgsrcdir); | | 383 | scan_pkgsrc_makefiles($pkgsrcdir); |
384 | store_pkgsrc_makefiles( $opt{E} ); | | 384 | store_pkgsrc_makefiles( $opt{E} ); |
385 | } | | 385 | } |
386 | } | | 386 | } |
387 | | | 387 | |
388 | sub canonicalize_pkgname($) { | | 388 | sub canonicalize_pkgname($) { |
389 | my ($pkgname) = @_; | | 389 | my ($pkgname) = @_; |
390 | | | 390 | |
391 | $pkgname =~ s,^py\d+(?:pth|)-,py-,; | | 391 | $pkgname =~ s,^py\d+(?:pth|)-,py-,; |
392 | $pkgname =~ s,^ruby\d+-,ruby-,; | | 392 | $pkgname =~ s,^ruby\d+-,ruby-,; |
393 | $pkgname =~ s,^php\d+-,php-,; | | 393 | $pkgname =~ s,^php\d+-,php-,; |
394 | return $pkgname; | | 394 | return $pkgname; |
395 | } | | 395 | } |
396 | | | 396 | |
397 | # Could speed up by building a cache of package names to paths, then processing | | 397 | # Could speed up by building a cache of package names to paths, then processing |
398 | # each package name once against the tests. | | 398 | # each package name once against the tests. |
399 | sub check_prebuilt_packages() { | | 399 | sub check_prebuilt_packages() { |
400 | | | 400 | |
401 | if ( $_ eq 'distfiles' || $_ eq 'pkgsrc' ) { | | 401 | if ( $_ eq 'distfiles' || $_ eq 'pkgsrc' ) { |
402 | | | 402 | |
403 | # Skip these subdirs if present | | 403 | # Skip these subdirs if present |
404 | $File::Find::prune = 1; | | 404 | $File::Find::prune = 1; |
405 | | | 405 | |
406 | } | | 406 | } |
407 | elsif (/(.+)-(\d.*)\.t[bg]z$/) { | | 407 | elsif (/(.+)-(\d.*)\.t[bg]z$/) { |
408 | my ( $pkg, $ver ) = ( $1, $2 ); | | 408 | my ( $pkg, $ver ) = ( $1, $2 ); |
409 | | | 409 | |
410 | $pkg = canonicalize_pkgname($pkg); | | 410 | $pkg = canonicalize_pkgname($pkg); |
411 | | | 411 | |
412 | my ($pkgs); | | 412 | my ($pkgs); |
413 | if ( $pkgs = $pkglist->pkgs($pkg) ) { | | 413 | if ( $pkgs = $pkglist->pkgs($pkg) ) { |
414 | my ($pkgver) = $pkgs->pkgver($ver); | | 414 | my ($pkgver) = $pkgs->pkgver($ver); |
415 | | | 415 | |
416 | if ( !defined $pkgver ) { | | 416 | if ( !defined $pkgver ) { |
417 | if ( $opt{p} ) { | | 417 | if ( $opt{p} ) { |
418 | print "$File::Find::dir/$_\n"; | | 418 | print "$File::Find::dir/$_\n"; |
419 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); | | 419 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); |
420 | } | | 420 | } |
421 | | | 421 | |
422 | # Pick probably the last version | | 422 | # Pick probably the last version |
423 | $pkgver = $pkgs->latestver; | | 423 | $pkgver = $pkgs->latestver; |
424 | } | | 424 | } |
425 | | | 425 | |
426 | if ( $opt{R} && $pkgver->var('RESTRICTED') ) { | | 426 | if ( $opt{R} && $pkgver->var('RESTRICTED') ) { |
427 | print "$File::Find::dir/$_\n"; | | 427 | print "$File::Find::dir/$_\n"; |
428 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); | | 428 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); |
429 | } | | 429 | } |
430 | | | 430 | |
431 | if ( $opt{O} && $pkgver->var('OSVERSION_SPECIFIC') ) { | | 431 | if ( $opt{O} && $pkgver->var('OSVERSION_SPECIFIC') ) { |
432 | print "$File::Find::dir/$_\n"; | | 432 | print "$File::Find::dir/$_\n"; |
433 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); | | 433 | push( @matched_prebuiltpackages, "$File::Find::dir/$_" ); |
434 | } | | 434 | } |
435 | } | | 435 | } |
436 | | | 436 | |
437 | } | | 437 | } |
438 | elsif ( -d $_ ) { | | 438 | elsif ( -d $_ ) { |
439 | if ( $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} ) { | | 439 | if ( $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} ) { |
440 | $File::Find::prune = 1; | | 440 | $File::Find::prune = 1; |
441 | return; | | 441 | return; |
442 | } | | 442 | } |
443 | | | 443 | |
444 | $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} = 1; | | 444 | $prebuilt_pkgdir_cache{"$File::Find::dir/$_"} = 1; |
445 | if ( -l $_ ) { | | 445 | if ( -l $_ ) { |
446 | my ($dest) = readlink($_); | | 446 | my ($dest) = readlink($_); |
447 | | | 447 | |
448 | if ( substr( $dest, 0, 1 ) ne '/' ) { | | 448 | if ( substr( $dest, 0, 1 ) ne '/' ) { |
449 | $dest = "$File::Find::dir/$dest"; | | 449 | $dest = "$File::Find::dir/$dest"; |
450 | } | | 450 | } |
451 | if ( !$prebuilt_pkgdir_cache{$dest} ) { | | 451 | if ( !$prebuilt_pkgdir_cache{$dest} ) { |
452 | push( @prebuilt_pkgdirs, $dest ); | | 452 | push( @prebuilt_pkgdirs, $dest ); |
453 | } | | 453 | } |
454 | } | | 454 | } |
455 | } | | 455 | } |
456 | } | | 456 | } |
457 | | | 457 | |
458 | # Dewey decimal verson number matching - or thereabouts | | 458 | # Dewey decimal verson number matching - or thereabouts |
459 | # Also handles 'nb<N>' suffix (checked iff values otherwise identical) | | 459 | # Also handles 'nb<N>' suffix (checked iff values otherwise identical) |
460 | # | | 460 | # |
461 | sub deweycmp($$$) { | | 461 | sub deweycmp($$$) { |
462 | my ( $match, $test, $val ) = @_; | | 462 | my ( $match, $test, $val ) = @_; |
463 | my ( $cmp, $match_nb, $val_nb ); | | 463 | my ( $cmp, $match_nb, $val_nb ); |
464 | | | 464 | |
465 | $match_nb = $val_nb = 0; | | 465 | $match_nb = $val_nb = 0; |
466 | if ( $match =~ /(.*)nb(.*)/ ) { | | 466 | if ( $match =~ /(.*)nb(.*)/ ) { |
467 | | | 467 | |
468 | # Handle nb<N> suffix | | 468 | # Handle nb<N> suffix |
469 | $match = $1; | | 469 | $match = $1; |
470 | $match_nb = $2; | | 470 | $match_nb = $2; |
471 | } | | 471 | } |
472 | | | 472 | |
473 | if ( $val =~ /(.*)nb(.*)/ ) { | | 473 | if ( $val =~ /(.*)nb(.*)/ ) { |
474 | | | 474 | |
475 | # Handle nb<N> suffix | | 475 | # Handle nb<N> suffix |
476 | $val = $1; | | 476 | $val = $1; |
477 | $val_nb = $2; | | 477 | $val_nb = $2; |
478 | } | | 478 | } |
479 | | | 479 | |
480 | $cmp = deweycmp_extract( $match, $val ); | | 480 | $cmp = deweycmp_extract( $match, $val ); |
481 | | | 481 | |
482 | if ( !$cmp ) { | | 482 | if ( !$cmp ) { |
483 | | | 483 | |
484 | # Iff otherwise identical, check nb suffix | | 484 | # Iff otherwise identical, check nb suffix |
485 | $cmp = deweycmp_extract( $match_nb, $val_nb ); | | 485 | $cmp = deweycmp_extract( $match_nb, $val_nb ); |
486 | } | | 486 | } |
487 | | | 487 | |
488 | eval "$cmp $test 0"; | | 488 | eval "$cmp $test 0"; |
489 | } | | 489 | } |
490 | | | 490 | |
491 | sub convert_to_standard_dewey(@) { | | 491 | sub convert_to_standard_dewey(@) { |
492 | my ( $elem, $underscore, @temp ); | | 492 | my ( $elem, $underscore, @temp ); |
493 | | | 493 | |
494 | # According to the current implementation in pkg_install/lib/str.c | | 494 | # According to the current implementation in pkg_install/lib/str.c |
495 | # as of 2002/06/02, '_' before a number, '.', and 'pl' get treated as 0, | | 495 | # as of 2002/06/02, '_' before a number, '.', and 'pl' get treated as 0, |
496 | # while 'rc' and 'pre' get treated as -1; beta as '-2', alpha as '-3'. | | 496 | # while 'rc' and 'pre' get treated as -1; beta as '-2', alpha as '-3'. |
497 | # Other characters are converted to lower | | 497 | # Other characters are converted to lower |
498 | # case and then to a number: a->1, b->2, c->3, etc. Numbers stay the same. | | 498 | # case and then to a number: a->1, b->2, c->3, etc. Numbers stay the same. |
499 | # 'nb' is a special case that's already been handled when we are here. | | 499 | # 'nb' is a special case that's already been handled when we are here. |
500 | foreach $elem (@_) { | | 500 | foreach $elem (@_) { |
501 | if ( $elem =~ /\d+/ ) { | | 501 | if ( $elem =~ /\d+/ ) { |
502 | push( @temp, $elem ); | | 502 | push( @temp, $elem ); |
503 | | | 503 | |
504 | } | | 504 | } |
505 | elsif ( $elem =~ /^pl$/ or $elem =~ /^\.$/ ) { | | 505 | elsif ( $elem =~ /^pl$/ or $elem =~ /^\.$/ ) { |
506 | push( @temp, 0 ); | | 506 | push( @temp, 0 ); |
507 | | | 507 | |
508 | } | | 508 | } |
509 | elsif ( $elem =~ /^_$/ ) { | | 509 | elsif ( $elem =~ /^_$/ ) { |
510 | push( @temp, 0 ); | | 510 | push( @temp, 0 ); |
511 | | | 511 | |
512 | } | | 512 | } |
513 | elsif ( $elem =~ /^pre$/ ) { | | 513 | elsif ( $elem =~ /^pre$/ ) { |
514 | push( @temp, -1 ); | | 514 | push( @temp, -1 ); |
515 | | | 515 | |
516 | } | | 516 | } |
517 | elsif ( $elem =~ /^rc$/ ) { | | 517 | elsif ( $elem =~ /^rc$/ ) { |
518 | push( @temp, -1 ); | | 518 | push( @temp, -1 ); |
519 | | | 519 | |
520 | } | | 520 | } |
521 | elsif ( $elem =~ /^beta$/ ) { | | 521 | elsif ( $elem =~ /^beta$/ ) { |
522 | push( @temp, -2 ); | | 522 | push( @temp, -2 ); |
523 | | | 523 | |
524 | } | | 524 | } |
525 | elsif ( $elem =~ /^alpha$/ ) { | | 525 | elsif ( $elem =~ /^alpha$/ ) { |
526 | push( @temp, -3 ); | | 526 | push( @temp, -3 ); |
527 | | | 527 | |
528 | } | | 528 | } |
529 | else { | | 529 | else { |
530 | push( @temp, 0 ); | | 530 | push( @temp, 0 ); |
531 | push( @temp, ord($elem) - ord("a") + 1 ); | | 531 | push( @temp, ord($elem) - ord("a") + 1 ); |
532 | } | | 532 | } |
533 | } | | 533 | } |
534 | @temp; | | 534 | @temp; |
535 | } | | 535 | } |
536 | | | 536 | |
537 | sub deweycmp_extract($$) { | | 537 | sub deweycmp_extract($$) { |
538 | my ( $match, $val ) = @_; | | 538 | my ( $match, $val ) = @_; |
539 | my ( $cmp, @matchlist, @vallist, $i, $len ); | | 539 | my ( $cmp, @matchlist, @vallist, $i, $len ); |
540 | | | 540 | |
541 | @matchlist = convert_to_standard_dewey( split( /(\D+)/, lc($match) ) ); | | 541 | @matchlist = convert_to_standard_dewey( split( /(\D+)/, lc($match) ) ); |
542 | @vallist = convert_to_standard_dewey( split( /(\D+)/, lc($val) ) ); | | 542 | @vallist = convert_to_standard_dewey( split( /(\D+)/, lc($val) ) ); |
543 | $cmp = 0; | | 543 | $cmp = 0; |
544 | $i = 0; | | 544 | $i = 0; |
545 | if ( $#matchlist > $#vallist ) { | | 545 | if ( $#matchlist > $#vallist ) { |
546 | $len = $#matchlist; | | 546 | $len = $#matchlist; |
547 | } | | 547 | } |
548 | else { | | 548 | else { |
549 | $len = $#vallist; | | 549 | $len = $#vallist; |
550 | } | | 550 | } |
551 | while ( !$cmp && ( $i++ <= $len ) ) { | | 551 | while ( !$cmp && ( $i++ <= $len ) ) { |
552 | if ( !@matchlist ) { | | 552 | if ( !@matchlist ) { |
553 | push( @matchlist, 0 ); | | 553 | push( @matchlist, 0 ); |
554 | } | | 554 | } |
555 | if ( !@vallist ) { | | 555 | if ( !@vallist ) { |
556 | push( @vallist, 0 ); | | 556 | push( @vallist, 0 ); |
557 | } | | 557 | } |
558 | $cmp = ( shift @matchlist <=> shift @vallist ); | | 558 | $cmp = ( shift @matchlist <=> shift @vallist ); |
559 | } | | 559 | } |
560 | $cmp; | | 560 | $cmp; |
561 | } | | 561 | } |
562 | | | 562 | |
563 | sub fail(@) { | | 563 | sub fail(@) { |
564 | | | 564 | |
565 | print STDERR @_, "\n"; | | 565 | print STDERR @_, "\n"; |
566 | exit(3); | | 566 | exit(3); |
567 | } | | 567 | } |
568 | | | 568 | |
569 | sub get_default_makefile_vars() { | | 569 | sub get_default_makefile_vars() { |
570 | | | 570 | |
571 | chomp( $pkg_installver = `pkg_info -V 2>/dev/null || echo 20010302` ); | | 571 | chomp( $pkg_installver = `pkg_info -V 2>/dev/null || echo 20010302` ); |
572 | | | 572 | |
573 | chomp( $_ = `uname -srm` ); | | 573 | chomp( $_ = `uname -srm` ); |
574 | ( | | 574 | ( |
575 | $default_vars->{OPSYS}, | | 575 | $default_vars->{OPSYS}, |
576 | $default_vars->{OS_VERSION}, | | 576 | $default_vars->{OS_VERSION}, |
577 | $default_vars->{MACHINE} | | 577 | $default_vars->{MACHINE} |
578 | ) = (split); | | 578 | ) = (split); |
579 | if ( !$default_vars->{MACHINE} ) { | | 579 | if ( !$default_vars->{MACHINE} ) { |
580 | die('Unable to extract machine from uname'); | | 580 | die('Unable to extract machine from uname'); |
581 | } | | 581 | } |
582 | | | 582 | |
583 | # Handle systems without uname -p (NetBSD pre 1.4) | | 583 | # Handle systems without uname -p (NetBSD pre 1.4) |
584 | chomp( $default_vars->{MACHINE_ARCH} = `uname -p 2>/dev/null` ); | | 584 | chomp( $default_vars->{MACHINE_ARCH} = `uname -p 2>/dev/null` ); |
585 | | | 585 | |
586 | if ( !$default_vars->{MACHINE_ARCH} | | 586 | if ( !$default_vars->{MACHINE_ARCH} |
587 | && $default_vars->{OS_VERSION} eq 'NetBSD' ) | | 587 | && $default_vars->{OS_VERSION} eq 'NetBSD' ) |
588 | { | | 588 | { |
589 | chomp( $default_vars->{MACHINE_ARCH} = `sysctl -n hw.machine_arch` ); | | 589 | chomp( $default_vars->{MACHINE_ARCH} = `sysctl -n hw.machine_arch` ); |
590 | } | | 590 | } |
591 | | | 591 | |
592 | if ( !$default_vars->{MACHINE_ARCH} ) { | | 592 | if ( !$default_vars->{MACHINE_ARCH} ) { |
593 | $default_vars->{MACHINE_ARCH} = $default_vars->{MACHINE}; | | 593 | $default_vars->{MACHINE_ARCH} = $default_vars->{MACHINE}; |
594 | } | | 594 | } |
595 | | | 595 | |
596 | $default_vars->{OBJECT_FMT} = 'x'; | | 596 | $default_vars->{OBJECT_FMT} = 'x'; |
597 | $default_vars->{LOWER_OPSYS} = lc( $default_vars->{OPSYS} ); | | 597 | $default_vars->{LOWER_OPSYS} = lc( $default_vars->{OPSYS} ); |
598 | | | 598 | |
599 | if ( $opt{P} ) { | | 599 | if ( $opt{P} ) { |
600 | $default_vars->{PKGSRCDIR} = realpath($opt{P}); | | 600 | $default_vars->{PKGSRCDIR} = realpath($opt{P}); |
601 | } | | 601 | } |
602 | else { | | 602 | else { |
603 | $default_vars->{PKGSRCDIR} = $conf_pkgsrcdir; | | 603 | $default_vars->{PKGSRCDIR} = $conf_pkgsrcdir; |
604 | } | | 604 | } |
605 | | | 605 | |
606 | $default_vars->{DESTDIR} = ''; | | 606 | $default_vars->{DESTDIR} = ''; |
607 | $default_vars->{LOCALBASE} = '/usr/pkg'; | | 607 | $default_vars->{LOCALBASE} = '/usr/pkg'; |
608 | $default_vars->{X11BASE} = '/usr/X11R6'; | | 608 | $default_vars->{X11BASE} = '/usr/X11R6'; |
609 | | | 609 | |
610 | my ($vars); | | 610 | my ($vars); |
611 | if ( -f '/etc/mk.conf' && ( $vars = parse_makefile_vars('/etc/mk.conf') ) ) | | 611 | if ( -f '/etc/mk.conf' && ( $vars = parse_makefile_vars('/etc/mk.conf') ) ) |
612 | { | | 612 | { |
613 | foreach my $var ( keys %{$vars} ) { | | 613 | foreach my $var ( keys %{$vars} ) { |
614 | $default_vars->{$var} = $vars->{$var}; | | 614 | $default_vars->{$var} = $vars->{$var}; |
615 | } | | 615 | } |
616 | } | | 616 | } |
617 | elsif ( -f ${conf_sysconfdir} . '/mk.conf' && ( $vars = parse_makefile_vars(${conf_sysconfdir} . '/mk.conf') ) ) | | 617 | elsif ( -f ${conf_sysconfdir} . '/mk.conf' && ( $vars = parse_makefile_vars(${conf_sysconfdir} . '/mk.conf') ) ) |
618 | { | | 618 | { |
619 | foreach my $var ( keys %{$vars} ) { | | 619 | foreach my $var ( keys %{$vars} ) { |
620 | $default_vars->{$var} = $vars->{$var}; | | 620 | $default_vars->{$var} = $vars->{$var}; |
621 | } | | 621 | } |
622 | } | | 622 | } |
623 | | | 623 | |
624 | if ( $opt{P} ) { | | 624 | if ( $opt{P} ) { |
625 | $default_vars->{PKGSRCDIR} = realpath($opt{P}); | | 625 | $default_vars->{PKGSRCDIR} = realpath($opt{P}); |
626 | } | | 626 | } |
627 | | | 627 | |
628 | if ( $opt{M} ) { | | 628 | if ( $opt{M} ) { |
629 | $default_vars->{DISTDIR} = realpath($opt{M}); | | 629 | $default_vars->{DISTDIR} = realpath($opt{M}); |
630 | } | | 630 | } |
631 | else { | | 631 | else { |
632 | $default_vars->{DISTDIR} ||= $default_vars->{PKGSRCDIR} . '/distfiles'; | | 632 | $default_vars->{DISTDIR} ||= $default_vars->{PKGSRCDIR} . '/distfiles'; |
633 | } | | 633 | } |
634 | | | 634 | |
635 | if ( $opt{K} ) { | | 635 | if ( $opt{K} ) { |
636 | $default_vars->{PACKAGES} = realpath($opt{K}); | | 636 | $default_vars->{PACKAGES} = realpath($opt{K}); |
637 | } | | 637 | } |
638 | | | 638 | |
639 | # Extract some variables from bsd.pkg.mk | | 639 | # Extract some variables from bsd.pkg.mk |
640 | my ($mkvars); | | 640 | my ($mkvars); |
641 | $mkvars = parse_makefile_vars( | | 641 | $mkvars = parse_makefile_vars( |
642 | "$default_vars->{PKGSRCDIR}/mk/bsd.pkg.mk", | | 642 | "$default_vars->{PKGSRCDIR}/mk/bsd.pkg.mk", |
643 | "$default_vars->{PKGSRCDIR}/mk/scripts" | | 643 | "$default_vars->{PKGSRCDIR}/mk/scripts" |
644 | ); | | 644 | ); |
645 | foreach my $varname ( keys %{$mkvars} ) { | | 645 | foreach my $varname ( keys %{$mkvars} ) { |
646 | if ( $varname =~ /_REQD$/ || $varname eq 'EXTRACT_SUFX' ) { | | 646 | if ( $varname =~ /_REQD$/ || $varname eq 'EXTRACT_SUFX' ) { |
647 | $default_vars->{$varname} = $mkvars->{$varname}; | | 647 | $default_vars->{$varname} = $mkvars->{$varname}; |
648 | } | | 648 | } |
649 | } | | 649 | } |
650 | | | 650 | |
651 | $default_vars->{PACKAGES} ||= $default_vars->{PKGSRCDIR} . '/packages'; | | 651 | $default_vars->{PACKAGES} ||= $default_vars->{PKGSRCDIR} . '/packages'; |
652 | } | | 652 | } |
653 | | | 653 | |
654 | # Determine if a package version is current. If not, report correct version | | 654 | # Determine if a package version is current. If not, report correct version |
655 | # if found | | 655 | # if found |
656 | # | | 656 | # |
657 | sub invalid_version($) { | | 657 | sub invalid_version($) { |
658 | my ($pkgmatch) = @_; | | 658 | my ($pkgmatch) = @_; |
659 | my ( $fail, $ok ); | | 659 | my ( $fail, $ok ); |
660 | my ( @pkgmatches, @todo ); | | 660 | my ( @pkgmatches, @todo ); |
661 | | | 661 | |
662 | @todo = ($pkgmatch); | | 662 | @todo = ($pkgmatch); |
663 | | | 663 | |
664 | # We handle {} here, everything else in package_globmatch | | 664 | # We handle {} here, everything else in package_globmatch |
665 | while ( $pkgmatch = shift @todo ) { | | 665 | while ( $pkgmatch = shift @todo ) { |
666 | if ( $pkgmatch =~ /(.*)\{([^{}]+)}(.*)/ ) { | | 666 | if ( $pkgmatch =~ /(.*)\{([^{}]+)}(.*)/ ) { |
667 | foreach ( split( ',', $2 ) ) { | | 667 | foreach ( split( ',', $2 ) ) { |
668 | push( @todo, "$1$_$3" ); | | 668 | push( @todo, "$1$_$3" ); |
669 | } | | 669 | } |
670 | } | | 670 | } |
671 | else { | | 671 | else { |
672 | push( @pkgmatches, $pkgmatch ); | | 672 | push( @pkgmatches, $pkgmatch ); |
673 | } | | 673 | } |
674 | } | | 674 | } |
675 | | | 675 | |
676 | foreach $pkgmatch (@pkgmatches) { | | 676 | foreach $pkgmatch (@pkgmatches) { |
677 | my ( $pkg, $badver ) = package_globmatch($pkgmatch); | | 677 | my ( $pkg, $badver ) = package_globmatch($pkgmatch); |
678 | | | 678 | |
679 | if ( defined($badver) ) { | | 679 | if ( defined($badver) ) { |
680 | my ($pkgs); | | 680 | my ($pkgs); |
681 | | | 681 | |
682 | if ( $pkgs = $pkglist->pkgs($pkg) ) { | | 682 | if ( $pkgs = $pkglist->pkgs($pkg) ) { |
683 | $fail .= | | 683 | $fail .= |
684 | "Version mismatch: '$pkg' $badver vs " | | 684 | "Version mismatch: '$pkg' $badver vs " |
685 | . join( ',', $pkgs->versions ) . "\n"; | | 685 | . join( ',', $pkgs->versions ) . "\n"; |
686 | } | | 686 | } |
687 | else { | | 687 | else { |
688 | $fail .= "Unknown package: '$pkg' version $badver\n"; | | 688 | $fail .= "Unknown package: '$pkg' version $badver\n"; |
689 | } | | 689 | } |
690 | } | | 690 | } |
691 | else { | | 691 | else { |
692 | | | 692 | |
693 | # If we find one match, don't bitch about others | | 693 | # If we find one match, don't bitch about others |
694 | $ok = 1; | | 694 | $ok = 1; |
695 | } | | 695 | } |
696 | } | | 696 | } |
697 | $ok && ( $fail = undef ); | | 697 | $ok && ( $fail = undef ); |
698 | $fail; | | 698 | $fail; |
699 | } | | 699 | } |
700 | | | 700 | |
701 | # List (recursive) non directory contents of specified directory | | 701 | # List (recursive) non directory contents of specified directory |
702 | # | | 702 | # |
703 | #TODO this entire sub should be replaced with direct calls to | | 703 | #TODO this entire sub should be replaced with direct calls to |
704 | # File::Find | | 704 | # File::Find |
705 | sub listdir($$) { | | 705 | sub listdir($$) { |
706 | my ( $base, $dir ) = @_; | | 706 | my ( $base, $dir ) = @_; |
707 | my ($thisdir); | | 707 | my ($thisdir); |
708 | my ( @list, @thislist ); | | 708 | my ( @list, @thislist ); |
709 | | | 709 | |
710 | $thisdir = $base; | | 710 | $thisdir = $base; |
711 | if ( defined($dir) ) { | | 711 | if ( defined($dir) ) { |
712 | $thisdir .= "/$dir"; | | 712 | $thisdir .= "/$dir"; |
713 | $dir .= '/'; | | 713 | $dir .= '/'; |
714 | } | | 714 | } |
715 | else { | | 715 | else { |
716 | $dir = ''; | | 716 | $dir = ''; |
717 | } | | 717 | } |
718 | | | 718 | |
719 | opendir( DIR, $thisdir ) || fail("Unable to opendir($thisdir): $!"); | | 719 | opendir( DIR, $thisdir ) || fail("Unable to opendir($thisdir): $!"); |
720 | @thislist = grep( substr( $_, 0, 1 ) ne '.' && $_ ne 'CVS', readdir(DIR) ); | | 720 | @thislist = grep( substr( $_, 0, 1 ) ne '.' && $_ ne 'CVS', readdir(DIR) ); |
721 | closedir(DIR); | | 721 | closedir(DIR); |
722 | foreach my $entry (@thislist) { | | 722 | foreach my $entry (@thislist) { |
723 | if ( -d "$thisdir/$entry" ) { | | 723 | if ( -d "$thisdir/$entry" ) { |
724 | push( @list, listdir( $base, "$dir$entry" ) ); | | 724 | push( @list, listdir( $base, "$dir$entry" ) ); |
725 | } | | 725 | } |
726 | else { | | 726 | else { |
727 | push( @list, "$dir$entry" ); | | 727 | push( @list, "$dir$entry" ); |
728 | } | | 728 | } |
729 | } | | 729 | } |
730 | @list; | | 730 | @list; |
731 | } | | 731 | } |
732 | | | 732 | |
733 | # Use pkg_info to list installed packages | | 733 | # Use pkg_info to list installed packages |
734 | # | | 734 | # |
735 | sub list_installed_packages() { | | 735 | sub list_installed_packages() { |
736 | my (@pkgs); | | 736 | my (@pkgs); |
737 | | | 737 | |
738 | open( PKG_INFO, 'pkg_info -e "*" |' ) || fail("Unable to run pkg_info: $!"); | | 738 | open( PKG_INFO, 'pkg_info -e "*" |' ) || fail("Unable to run pkg_info: $!"); |
739 | while ( defined( my $pkg = <PKG_INFO> ) ) { | | 739 | while ( defined( my $pkg = <PKG_INFO> ) ) { |
740 | chomp($pkg); | | 740 | chomp($pkg); |
741 | push( @pkgs, canonicalize_pkgname($pkg) ); | | 741 | push( @pkgs, canonicalize_pkgname($pkg) ); |
742 | } | | 742 | } |
743 | close(PKG_INFO); | | 743 | close(PKG_INFO); |
744 | | | 744 | |
745 | @pkgs; | | 745 | @pkgs; |
746 | } | | 746 | } |
747 | | | 747 | |
748 | # List top level pkgsrc categories | | 748 | # List top level pkgsrc categories |
749 | # | | 749 | # |
750 | sub list_pkgsrc_categories($) { | | 750 | sub list_pkgsrc_categories($) { |
751 | my ($pkgsrcdir) = @_; | | 751 | my ($pkgsrcdir) = @_; |
752 | my (@categories); | | 752 | my (@categories); |
753 | | | 753 | |
754 | opendir( BASE, $pkgsrcdir ) || die("Unable to opendir($pkgsrcdir): $!"); | | 754 | opendir( BASE, $pkgsrcdir ) || die("Unable to opendir($pkgsrcdir): $!"); |
755 | @categories = | | 755 | @categories = |
756 | grep( substr( $_, 0, 1 ) ne '.' | | 756 | grep( substr( $_, 0, 1 ) ne '.' |
757 | && $_ ne 'CVS' | | 757 | && $_ ne 'CVS' |
758 | && -f "$pkgsrcdir/$_/Makefile", | | 758 | && -f "$pkgsrcdir/$_/Makefile", |
759 | readdir(BASE) ); | | 759 | readdir(BASE) ); |
760 | closedir(BASE); | | 760 | closedir(BASE); |
761 | @categories; | | 761 | @categories; |
762 | } | | 762 | } |
763 | | | 763 | |
764 | # For a given category, list potentially valid pkgdirs | | 764 | # For a given category, list potentially valid pkgdirs |
765 | # | | 765 | # |
766 | sub list_pkgsrc_pkgdirs($$) { | | 766 | sub list_pkgsrc_pkgdirs($$) { |
767 | my ( $pkgsrcdir, $cat ) = @_; | | 767 | my ( $pkgsrcdir, $cat ) = @_; |
768 | my (@pkgdirs); | | 768 | my (@pkgdirs); |
769 | | | 769 | |
770 | if ( !opendir( CAT, "$pkgsrcdir/$cat" ) ) { | | 770 | if ( !opendir( CAT, "$pkgsrcdir/$cat" ) ) { |
771 | die("Unable to opendir($pkgsrcdir/cat): $!"); | | 771 | die("Unable to opendir($pkgsrcdir/cat): $!"); |
772 | } | | 772 | } |
773 | @pkgdirs = | | 773 | @pkgdirs = |
774 | sort grep( $_ ne 'Makefile' | | 774 | sort grep( $_ ne 'Makefile' |
775 | && $_ ne 'pkg' | | 775 | && $_ ne 'pkg' |
776 | && $_ ne 'CVS' | | 776 | && $_ ne 'CVS' |
777 | && substr( $_, 0, 1 ) ne '.', | | 777 | && substr( $_, 0, 1 ) ne '.', |
778 | readdir(CAT) ); | | 778 | readdir(CAT) ); |
779 | closedir(CAT); | | 779 | closedir(CAT); |
780 | @pkgdirs; | | 780 | @pkgdirs; |
781 | } | | 781 | } |
782 | | | 782 | |
783 | sub glob2regex($) { | | 783 | sub glob2regex($) { |
784 | my ($glob) = @_; | | 784 | my ($glob) = @_; |
785 | my ( @chars, $in_alt ); | | 785 | my ( @chars, $in_alt ); |
786 | my ($regex); | | 786 | my ($regex); |
787 | | | 787 | |
788 | @chars = split( //, $glob ); | | 788 | @chars = split( //, $glob ); |
789 | while ( defined( $_ = shift @chars ) ) { | | 789 | while ( defined( $_ = shift @chars ) ) { |
790 | if ( $_ eq '*' ) { | | 790 | if ( $_ eq '*' ) { |
791 | $regex .= '.*'; | | 791 | $regex .= '.*'; |
792 | } | | 792 | } |
793 | elsif ( $_ eq '?' ) { | | 793 | elsif ( $_ eq '?' ) { |
794 | $regex .= '.'; | | 794 | $regex .= '.'; |
795 | } | | 795 | } |
796 | elsif ( $_ eq '+' ) { | | 796 | elsif ( $_ eq '+' ) { |
797 | $regex .= '.'; | | 797 | $regex .= '.'; |
798 | } | | 798 | } |
799 | elsif ( $_ eq '\\+' ) { | | 799 | elsif ( $_ eq '\\+' ) { |
800 | $regex .= $_ . shift @chars; | | 800 | $regex .= $_ . shift @chars; |
801 | } | | 801 | } |
802 | elsif ( $_ eq '.' || $_ eq '|' ) { | | 802 | elsif ( $_ eq '.' || $_ eq '|' ) { |
803 | $regex .= quotemeta; | | 803 | $regex .= quotemeta; |
804 | } | | 804 | } |
805 | elsif ( $_ eq '{' ) { | | 805 | elsif ( $_ eq '{' ) { |
806 | $regex .= '('; | | 806 | $regex .= '('; |
807 | ++$in_alt; | | 807 | ++$in_alt; |
808 | } | | 808 | } |
809 | elsif ( $_ eq '}' ) { | | 809 | elsif ( $_ eq '}' ) { |
810 | if ( !$in_alt ) { | | 810 | if ( !$in_alt ) { |
811 | | | 811 | |
812 | # Error | | 812 | # Error |
813 | return undef; | | 813 | return undef; |
814 | } | | 814 | } |
815 | $regex .= ')'; | | 815 | $regex .= ')'; |
816 | --$in_alt; | | 816 | --$in_alt; |
817 | } | | 817 | } |
818 | elsif ( $_ eq ',' && $in_alt ) { | | 818 | elsif ( $_ eq ',' && $in_alt ) { |
819 | $regex .= '|'; | | 819 | $regex .= '|'; |
820 | } | | 820 | } |
821 | else { | | 821 | else { |
822 | $regex .= $_; | | 822 | $regex .= $_; |
823 | } | | 823 | } |
824 | } | | 824 | } |
825 | | | 825 | |
826 | if ($in_alt) { | | 826 | if ($in_alt) { |
827 | | | 827 | |
828 | # Error | | 828 | # Error |
829 | return undef; | | 829 | return undef; |
830 | } | | 830 | } |
831 | if ( $regex eq $glob ) { | | 831 | if ( $regex eq $glob ) { |
832 | return (''); | | 832 | return (''); |
833 | } | | 833 | } |
834 | if ( $opt{D} ) { | | 834 | if ( $opt{D} ) { |
835 | print "glob2regex: $glob -> $regex\n"; | | 835 | print "glob2regex: $glob -> $regex\n"; |
836 | } | | 836 | } |
837 | '^' . $regex . '$'; | | 837 | '^' . $regex . '$'; |
838 | } | | 838 | } |
839 | | | 839 | |
840 | # Perform some (reasonable) subset of 'pkg_info -e' / glob(3) | | 840 | # Perform some (reasonable) subset of 'pkg_info -e' / glob(3) |
841 | # Returns (sometimes best guess at) package name, | | 841 | # Returns (sometimes best guess at) package name, |
842 | # and either 'problem version' or undef if all OK | | 842 | # and either 'problem version' or undef if all OK |
843 | # | | 843 | # |
844 | sub package_globmatch($) { | | 844 | sub package_globmatch($) { |
845 | my ($pkgmatch) = @_; | | 845 | my ($pkgmatch) = @_; |
846 | my ( $matchpkgname, $matchver, $regex ); | | 846 | my ( $matchpkgname, $matchver, $regex ); |
847 | | | 847 | |
848 | if ( $pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/ ) { | | 848 | if ( $pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/ ) { |
849 | | | 849 | |
850 | # (package)(cmp)(dewey) | | 850 | # (package)(cmp)(dewey) |
851 | my ( $test, @pkgvers ); | | 851 | my ( $test, @pkgvers ); |
852 | | | 852 | |
853 | ( $matchpkgname, $test, $matchver ) = ( $1, $2, $3 ); | | 853 | ( $matchpkgname, $test, $matchver ) = ( $1, $2, $3 ); |
854 | if ( @pkgvers = $pkglist->pkgver($matchpkgname) ) { | | 854 | if ( @pkgvers = $pkglist->pkgver($matchpkgname) ) { |
855 | foreach my $pkgver (@pkgvers) { | | 855 | foreach my $pkgver (@pkgvers) { |
856 | if ( $test eq '-' ) { | | 856 | if ( $test eq '-' ) { |
857 | if ( $pkgver->ver eq $matchver ) { | | 857 | if ( $pkgver->ver eq $matchver ) { |
858 | $matchver = undef; | | 858 | $matchver = undef; |
859 | last; | | 859 | last; |
860 | } | | 860 | } |
861 | } | | 861 | } |
862 | else { | | 862 | else { |
863 | if ( deweycmp( $pkgver->ver, $test, $matchver ) ) { | | 863 | if ( deweycmp( $pkgver->ver, $test, $matchver ) ) { |
864 | $matchver = undef; | | 864 | $matchver = undef; |
865 | last; | | 865 | last; |
866 | } | | 866 | } |
867 | } | | 867 | } |
868 | } | | 868 | } |
869 | | | 869 | |
870 | if ( $matchver && $test ne '-' ) { | | 870 | if ( $matchver && $test ne '-' ) { |
871 | $matchver = "$test$matchver"; | | 871 | $matchver = "$test$matchver"; |
872 | } | | 872 | } |
873 | } | | 873 | } |
874 | | | 874 | |
875 | } | | 875 | } |
876 | elsif ( $pkgmatch =~ /^([^[]+)-([\d*?{[].*)$/ ) { | | 876 | elsif ( $pkgmatch =~ /^([^[]+)-([\d*?{[].*)$/ ) { |
877 | | | 877 | |
878 | # (package)-(globver) | | 878 | # (package)-(globver) |
879 | my (@pkgnames); | | 879 | my (@pkgnames); |
880 | | | 880 | |
881 | ( $matchpkgname, $matchver ) = ( $1, $2 ); | | 881 | ( $matchpkgname, $matchver ) = ( $1, $2 ); |
882 | | | 882 | |
883 | if ( defined $pkglist->pkgs($matchpkgname) ) { | | 883 | if ( defined $pkglist->pkgs($matchpkgname) ) { |
884 | push( @pkgnames, $matchpkgname ); | | 884 | push( @pkgnames, $matchpkgname ); |
885 | | | 885 | |
886 | } | | 886 | } |
887 | elsif ( $regex = glob2regex($matchpkgname) ) { | | 887 | elsif ( $regex = glob2regex($matchpkgname) ) { |
888 | foreach my $pkg ( $pkglist->pkgs ) { | | 888 | foreach my $pkg ( $pkglist->pkgs ) { |
889 | ( $pkg->pkg() =~ /$regex/ ) && push( @pkgnames, $pkg->pkg() ); | | 889 | ( $pkg->pkg() =~ /$regex/ ) && push( @pkgnames, $pkg->pkg() ); |
890 | } | | 890 | } |
891 | } | | 891 | } |
892 | | | 892 | |
893 | # Try to convert $matchver into regex version | | 893 | # Try to convert $matchver into regex version |
894 | # | | 894 | # |
895 | $regex = glob2regex($matchver); | | 895 | $regex = glob2regex($matchver); |
896 | | | 896 | |
897 | foreach my $pkg (@pkgnames) { | | 897 | foreach my $pkg (@pkgnames) { |
898 | if ( defined $pkglist->pkgver( $pkg, $matchver ) ) { | | 898 | if ( defined $pkglist->pkgver( $pkg, $matchver ) ) { |
899 | return ($matchver); | | 899 | return ($matchver); |
900 | } | | 900 | } |
901 | | | 901 | |
902 | if ($regex) { | | 902 | if ($regex) { |
903 | foreach my $ver ( $pkglist->pkgs($pkg)->versions ) { | | 903 | foreach my $ver ( $pkglist->pkgs($pkg)->versions ) { |
904 | if ( $ver =~ /$regex/ ) { | | 904 | if ( $ver =~ /$regex/ ) { |
905 | $matchver = undef; | | 905 | $matchver = undef; |
906 | last; | | 906 | last; |
907 | } | | 907 | } |
908 | } | | 908 | } |
909 | } | | 909 | } |
910 | | | 910 | |
911 | $matchver || last; | | 911 | $matchver || last; |
912 | } | | 912 | } |
913 | | | 913 | |
914 | # last ditch attempt to handle the whole DEPENDS as a glob | | 914 | # last ditch attempt to handle the whole DEPENDS as a glob |
915 | # | | 915 | # |
916 | if ( $matchver && ( $regex = glob2regex($pkgmatch) ) ) { | | 916 | if ( $matchver && ( $regex = glob2regex($pkgmatch) ) ) { |
917 | | | 917 | |
918 | # (large-glob) | | 918 | # (large-glob) |
919 | foreach my $pkgver ( $pkglist->pkgver ) { | | 919 | foreach my $pkgver ( $pkglist->pkgver ) { |
920 | if ( $pkgver->pkgname =~ /$regex/ ) { | | 920 | if ( $pkgver->pkgname =~ /$regex/ ) { |
921 | $matchver = undef; | | 921 | $matchver = undef; |
922 | last; | | 922 | last; |
923 | } | | 923 | } |
924 | } | | 924 | } |
925 | } | | 925 | } |
926 | | | 926 | |
927 | } | | 927 | } |
928 | else { | | 928 | else { |
929 | ( $matchpkgname, $matchver ) = ( $pkgmatch, 'missing' ); | | 929 | ( $matchpkgname, $matchver ) = ( $pkgmatch, 'missing' ); |
930 | } | | 930 | } |
931 | | | 931 | |
932 | ( $matchpkgname, $matchver ); | | 932 | ( $matchpkgname, $matchver ); |
933 | } | | 933 | } |
934 | | | 934 | |
935 | # Parse a pkgsrc package makefile and return the pkgname and set variables | | 935 | # Parse a pkgsrc package makefile and return the pkgname and set variables |
936 | # | | 936 | # |
937 | sub parse_makefile_pkgsrc($) { | | 937 | sub parse_makefile_pkgsrc($) { |
938 | my ($file) = @_; | | 938 | my ($file) = @_; |
939 | my ( $pkgname, $vars ); | | 939 | my ( $pkgname, $vars ); |
940 | | | 940 | |
941 | $vars = parse_makefile_vars($file); | | 941 | $vars = parse_makefile_vars($file); |
942 | | | 942 | |
943 | if ( !$vars ) { | | 943 | if ( !$vars ) { |
944 | | | 944 | |
945 | # Missing Makefile | | 945 | # Missing Makefile |
946 | return undef; | | 946 | return undef; |
947 | } | | 947 | } |
948 | | | 948 | |
949 | if ( defined $vars->{PKGNAME} ) { | | 949 | if ( defined $vars->{PKGNAME} ) { |
950 | $pkgname = $vars->{PKGNAME}; | | 950 | $pkgname = $vars->{PKGNAME}; |
951 | | | 951 | |
952 | } | | 952 | } |
953 | elsif ( defined $vars->{DISTNAME} ) { | | 953 | elsif ( defined $vars->{DISTNAME} ) { |
954 | $pkgname = $vars->{DISTNAME}; | | 954 | $pkgname = $vars->{DISTNAME}; |
955 | } | | 955 | } |
956 | | | 956 | |
957 | if ( defined $vars->{PKGNAME} ) { | | 957 | if ( defined $vars->{PKGNAME} ) { |
958 | debug("$file: PKGNAME=$vars->{PKGNAME}\n"); | | 958 | debug("$file: PKGNAME=$vars->{PKGNAME}\n"); |
959 | } | | 959 | } |
960 | if ( defined $vars->{DISTNAME} ) { | | 960 | if ( defined $vars->{DISTNAME} ) { |
961 | debug("$file: DISTNAME=$vars->{DISTNAME}\n"); | | 961 | debug("$file: DISTNAME=$vars->{DISTNAME}\n"); |
962 | } | | 962 | } |
963 | | | 963 | |
964 | if ( !defined $pkgname || $pkgname !~ /(.*)-(\d.*)/ ) { | | 964 | if ( !defined $pkgname || $pkgname !~ /(.*)-(\d.*)/ ) { |
965 | | | 965 | |
966 | # invoke make here as a last resort | | 966 | # invoke make here as a last resort |
967 | my ($pkgsrcdir) = ( $file =~ m:(/.*)/: ); | | 967 | my ($pkgsrcdir) = ( $file =~ m:(/.*)/: ); |
968 | my $pid = open3( \*WTR, \*RDR, \*ERR, | | 968 | my $pid = open3( \*WTR, \*RDR, \*ERR, |
969 | "cd $pkgsrcdir ; ${conf_make} show-vars VARNAMES=PKGNAME" ); | | 969 | "cd $pkgsrcdir ; ${conf_make} show-vars VARNAMES=PKGNAME" ); |
970 | if ( !$pid ) { | | 970 | if ( !$pid ) { |
971 | warn "$file: Unable to run make: $!"; | | 971 | warn "$file: Unable to run make: $!"; |
972 | } | | 972 | } |
973 | else { | | 973 | else { |
974 | close(WTR); | | 974 | close(WTR); |
975 | my @errors = <ERR>; | | 975 | my @errors = <ERR>; |
976 | close(ERR); | | 976 | close(ERR); |
977 | my ($makepkgname) = <RDR>; | | 977 | my ($makepkgname) = <RDR>; |
978 | close(RDR); | | 978 | close(RDR); |
979 | wait; | | 979 | wait; |
980 | chomp @errors; | | 980 | chomp @errors; |
981 | if (@errors) { warn "\n$file: @errors\n"; } | | 981 | if (@errors) { warn "\n$file: @errors\n"; } |
982 | | | 982 | |
983 | if ( $makepkgname =~ /(.*)-(\d.*)/ ) { | | 983 | if ( $makepkgname =~ /(.*)-(\d.*)/ ) { |
984 | $pkgname = $makepkgname; | | 984 | $pkgname = $makepkgname; |
985 | } | | 985 | } |
986 | } | | 986 | } |
987 | } | | 987 | } |
988 | | | 988 | |
989 | if ( defined $pkgname ) { | | 989 | if ( defined $pkgname ) { |
990 | if ( $pkgname =~ /^pkg_install-(\d+)$/ && $1 < $pkg_installver ) { | | 990 | if ( $pkgname =~ /^pkg_install-(\d+)$/ && $1 < $pkg_installver ) { |
991 | $pkgname = "pkg_install-$pkg_installver"; | | 991 | $pkgname = "pkg_install-$pkg_installver"; |
992 | } | | 992 | } |
993 | | | 993 | |
994 | $pkgname = canonicalize_pkgname($pkgname); | | 994 | $pkgname = canonicalize_pkgname($pkgname); |
995 | | | 995 | |
996 | if ( defined $vars->{PKGREVISION} | | 996 | if ( defined $vars->{PKGREVISION} |
997 | and not $vars->{PKGREVISION} =~ /^\s*$/ ) | | 997 | and not $vars->{PKGREVISION} =~ /^\s*$/ ) |
998 | { | | 998 | { |
999 | if ( $vars->{PKGREVISION} =~ /\D/ ) { | | 999 | if ( $vars->{PKGREVISION} =~ /^\$\{(_(CVS|GIT|HG|SVN)_PKGVERSION):.*\}$/ ) { |
| | | 1000 | # See wip/mk/*-package.mk. |
| | | 1001 | } |
| | | 1002 | elsif ( $vars->{PKGREVISION} =~ /\D/ ) { |
1000 | print | | 1003 | print |
1001 | "\nBogus: PKGREVISION $vars->{PKGREVISION} (from $file)\n"; | | 1004 | "\nBogus: PKGREVISION $vars->{PKGREVISION} (from $file)\n"; |
1002 | | | 1005 | |
1003 | } | | 1006 | } |
1004 | elsif ( $vars->{PKGREVISION} ) { | | 1007 | elsif ( $vars->{PKGREVISION} ) { |
1005 | $pkgname .= "nb"; | | 1008 | $pkgname .= "nb"; |
1006 | $pkgname .= $vars->{PKGREVISION}; | | 1009 | $pkgname .= $vars->{PKGREVISION}; |
1007 | } | | 1010 | } |
1008 | } | | 1011 | } |
1009 | | | 1012 | |
1010 | if ( $pkgname =~ /\$/ ) { | | 1013 | if ( $pkgname =~ /\$/ ) { |
1011 | print "\nBogus: $pkgname (from $file)\n"; | | 1014 | print "\nBogus: $pkgname (from $file)\n"; |
1012 | | | 1015 | |
1013 | } | | 1016 | } |
1014 | elsif ( $pkgname =~ /(.*)-(\d.*)/ ) { | | 1017 | elsif ( $pkgname =~ /(.*)-(\d.*)/ ) { |
1015 | if ($pkglist) { | | 1018 | if ($pkglist) { |
1016 | my ($pkgver) = $pkglist->add( $1, $2 ); | | 1019 | my ($pkgver) = $pkglist->add( $1, $2 ); |
1017 | | | 1020 | |
1018 | debug("add $1 $2\n"); | | 1021 | debug("add $1 $2\n"); |
1019 | | | 1022 | |
1020 | foreach | | 1023 | foreach |
1021 | my $var (qw(DEPENDS RESTRICTED OSVERSION_SPECIFIC BROKEN)) | | 1024 | my $var (qw(DEPENDS RESTRICTED OSVERSION_SPECIFIC BROKEN)) |
1022 | { | | 1025 | { |
1023 | $pkgver->var( $var, $vars->{$var} ); | | 1026 | $pkgver->var( $var, $vars->{$var} ); |
1024 | } | | 1027 | } |
1025 | | | 1028 | |
1026 | if ( defined $vars->{NO_BIN_ON_FTP} ) { | | 1029 | if ( defined $vars->{NO_BIN_ON_FTP} ) { |
1027 | $pkgver->var( 'RESTRICTED', 'NO_BIN_ON_FTP' ); | | 1030 | $pkgver->var( 'RESTRICTED', 'NO_BIN_ON_FTP' ); |
1028 | } | | 1031 | } |
1029 | | | 1032 | |
1030 | if ( $file =~ m:([^/]+/[^/]+)/Makefile$: ) { | | 1033 | if ( $file =~ m:([^/]+/[^/]+)/Makefile$: ) { |
1031 | $pkgver->var( 'dir', $1 ); | | 1034 | $pkgver->var( 'dir', $1 ); |
1032 | } | | 1035 | } |
1033 | else { | | 1036 | else { |
1034 | $pkgver->var( 'dir', 'unknown' ); | | 1037 | $pkgver->var( 'dir', 'unknown' ); |
1035 | } | | 1038 | } |
1036 | } | | 1039 | } |
1037 | } | | 1040 | } |
1038 | else { | | 1041 | else { |
1039 | print "Cannot extract $pkgname version ($file)\n"; | | 1042 | print "Cannot extract $pkgname version ($file)\n"; |
1040 | } | | 1043 | } |
1041 | | | 1044 | |
1042 | return ( $pkgname, $vars ); | | 1045 | return ( $pkgname, $vars ); |
1043 | | | 1046 | |
1044 | } | | 1047 | } |
1045 | else { | | 1048 | else { |
1046 | return (undef); | | 1049 | return (undef); |
1047 | } | | 1050 | } |
1048 | } | | 1051 | } |
1049 | | | 1052 | |
1050 | # Extract variable assignments from Makefile | | 1053 | # Extract variable assignments from Makefile |
1051 | # Much unpalatable magic to avoid having to use make (all for speed) | | 1054 | # Much unpalatable magic to avoid having to use make (all for speed) |
1052 | # | | 1055 | # |
1053 | sub parse_makefile_vars($$) { | | 1056 | sub parse_makefile_vars($$) { |
1054 | my ( $file, $cwd ) = @_; | | 1057 | my ( $file, $cwd ) = @_; |
1055 | my ( | | 1058 | my ( |
1056 | $pkgname, %vars, $plus, $value, @data, | | 1059 | $pkgname, %vars, $plus, $value, @data, |
1057 | %incfiles, # Cache of previously included fils | | 1060 | %incfiles, # Cache of previously included fils |
1058 | %incdirs, # Directories in which to check for includes | | 1061 | %incdirs, # Directories in which to check for includes |
1059 | @if_false | | 1062 | @if_false |
1060 | ); # 0:true 1:false 2:nested-false&nomore-elsif | | 1063 | ); # 0:true 1:false 2:nested-false&nomore-elsif |
1061 | | | 1064 | |
1062 | if ( !open( FILE, $file ) ) { | | 1065 | if ( !open( FILE, $file ) ) { |
1063 | return (undef); | | 1066 | return (undef); |
1064 | } | | 1067 | } |
1065 | @data = map { chomp; $_ } <FILE>; | | 1068 | @data = map { chomp; $_ } <FILE>; |
1066 | close(FILE); | | 1069 | close(FILE); |
1067 | | | 1070 | |
1068 | $incdirs{"."} = 1; | | 1071 | $incdirs{"."} = 1; |
1069 | $incdirs{ dirname($file) } = 1; | | 1072 | $incdirs{ dirname($file) } = 1; |
1070 | | | 1073 | |
1071 | # Some Makefiles depend on these being set | | 1074 | # Some Makefiles depend on these being set |
1072 | if ( $file eq '/etc/mk.conf' ) { | | 1075 | if ( $file eq '/etc/mk.conf' ) { |
1073 | $vars{LINTPKGSRC} = 'YES'; | | 1076 | $vars{LINTPKGSRC} = 'YES'; |
1074 | } | | 1077 | } |
1075 | else { | | 1078 | else { |
1076 | %vars = %{$default_vars}; | | 1079 | %vars = %{$default_vars}; |
1077 | } | | 1080 | } |
1078 | $vars{BSD_PKG_MK} = 'YES'; | | 1081 | $vars{BSD_PKG_MK} = 'YES'; |
1079 | | | 1082 | |
1080 | if ($cwd) { | | 1083 | if ($cwd) { |
1081 | $vars{'.CURDIR'} = $cwd; | | 1084 | $vars{'.CURDIR'} = $cwd; |
1082 | | | 1085 | |
1083 | } | | 1086 | } |
1084 | elsif ( $file =~ m#(.*)/# ) { | | 1087 | elsif ( $file =~ m#(.*)/# ) { |
1085 | $vars{'.CURDIR'} = $1; | | 1088 | $vars{'.CURDIR'} = $1; |
1086 | | | 1089 | |
1087 | } | | 1090 | } |
1088 | else { | | 1091 | else { |
1089 | $vars{'.CURDIR'} = getcwd; | | 1092 | $vars{'.CURDIR'} = getcwd; |
1090 | } | | 1093 | } |
1091 | | | 1094 | |
1092 | $incdirs{ $vars{'.CURDIR'} } = 1; | | 1095 | $incdirs{ $vars{'.CURDIR'} } = 1; |
1093 | if ( $opt{L} ) { | | 1096 | if ( $opt{L} ) { |
1094 | print "$file\n"; | | 1097 | print "$file\n"; |
1095 | } | | 1098 | } |
1096 | | | 1099 | |
1097 | while ( defined( $_ = shift(@data) ) ) { | | 1100 | while ( defined( $_ = shift(@data) ) ) { |
1098 | s/\s*[^\\]#.*//; | | 1101 | s/\s*[^\\]#.*//; |
1099 | | | 1102 | |
1100 | # Continuation lines | | 1103 | # Continuation lines |
1101 | # | | 1104 | # |
1102 | while ( substr( $_, -1 ) eq "\\" ) { | | 1105 | while ( substr( $_, -1 ) eq "\\" ) { |
1103 | substr( $_, -2 ) = shift @data; | | 1106 | substr( $_, -2 ) = shift @data; |
1104 | } | | 1107 | } |
1105 | | | 1108 | |
1106 | # Conditionals | | 1109 | # Conditionals |
1107 | # | | 1110 | # |
1108 | if (m#^\.\s*if(|def|ndef)\s+(.*)#) { | | 1111 | if (m#^\.\s*if(|def|ndef)\s+(.*)#) { |
1109 | my ( $type, $false ); | | 1112 | my ( $type, $false ); |
1110 | | | 1113 | |
1111 | $type = $1; | | 1114 | $type = $1; |
1112 | if ( $if_false[$#if_false] ) { | | 1115 | if ( $if_false[$#if_false] ) { |
1113 | push( @if_false, 2 ); | | 1116 | push( @if_false, 2 ); |
1114 | | | 1117 | |
1115 | } | | 1118 | } |
1116 | elsif ( $type eq '' ) { | | 1119 | elsif ( $type eq '' ) { |
1117 | | | 1120 | |
1118 | # Straight if | | 1121 | # Straight if |
1119 | push( @if_false, parse_eval_make_false( $2, \%vars ) ); | | 1122 | push( @if_false, parse_eval_make_false( $2, \%vars ) ); |
1120 | | | 1123 | |
1121 | } | | 1124 | } |
1122 | else { | | 1125 | else { |
1123 | $false = !defined( $vars{ parse_expand_vars( $2, \%vars ) } ); | | 1126 | $false = !defined( $vars{ parse_expand_vars( $2, \%vars ) } ); |
1124 | if ( $type eq 'ndef' ) { | | 1127 | if ( $type eq 'ndef' ) { |
1125 | $false = !$false; | | 1128 | $false = !$false; |
1126 | } | | 1129 | } |
1127 | push( @if_false, $false ? 1 : 0 ); | | 1130 | push( @if_false, $false ? 1 : 0 ); |
1128 | } | | 1131 | } |
1129 | debug("$file: .if$type (! @if_false)\n"); | | 1132 | debug("$file: .if$type (! @if_false)\n"); |
1130 | next; | | 1133 | next; |
1131 | } | | 1134 | } |
1132 | | | 1135 | |
1133 | if ( m#^\.\s*elif\s+(.*)# && @if_false ) { | | 1136 | if ( m#^\.\s*elif\s+(.*)# && @if_false ) { |
1134 | if ( $if_false[$#if_false] == 0 ) { | | 1137 | if ( $if_false[$#if_false] == 0 ) { |
1135 | $if_false[$#if_false] = 2; | | 1138 | $if_false[$#if_false] = 2; |
1136 | } | | 1139 | } |
1137 | elsif ( $if_false[$#if_false] == 1 | | 1140 | elsif ( $if_false[$#if_false] == 1 |
1138 | && !parse_eval_make_false( $1, \%vars ) ) | | 1141 | && !parse_eval_make_false( $1, \%vars ) ) |
1139 | { | | 1142 | { |
1140 | $if_false[$#if_false] = 0; | | 1143 | $if_false[$#if_false] = 0; |
1141 | } | | 1144 | } |
1142 | debug("$file: .elif (! @if_false)\n"); | | 1145 | debug("$file: .elif (! @if_false)\n"); |
1143 | next; | | 1146 | next; |
1144 | } | | 1147 | } |
1145 | | | 1148 | |
1146 | if ( m#^\.\s*else\b# && @if_false ) { | | 1149 | if ( m#^\.\s*else\b# && @if_false ) { |
1147 | $if_false[$#if_false] = $if_false[$#if_false] == 1 ? 0 : 1; | | 1150 | $if_false[$#if_false] = $if_false[$#if_false] == 1 ? 0 : 1; |
1148 | debug("$file: .else (! @if_false)\n"); | | 1151 | debug("$file: .else (! @if_false)\n"); |
1149 | next; | | 1152 | next; |
1150 | } | | 1153 | } |
1151 | | | 1154 | |
1152 | if (m#^\.\s*endif\b#) { | | 1155 | if (m#^\.\s*endif\b#) { |
1153 | pop(@if_false); | | 1156 | pop(@if_false); |
1154 | debug("$file: .endif (! @if_false)\n"); | | 1157 | debug("$file: .endif (! @if_false)\n"); |
1155 | next; | | 1158 | next; |
1156 | } | | 1159 | } |
1157 | | | 1160 | |
1158 | $if_false[$#if_false] && next; | | 1161 | $if_false[$#if_false] && next; |
1159 | | | 1162 | |
1160 | # Included files (just unshift onto @data) | | 1163 | # Included files (just unshift onto @data) |
1161 | # | | 1164 | # |
1162 | if (m#^\.\s*include\s+"([^"]+)"#) { | | 1165 | if (m#^\.\s*include\s+"([^"]+)"#) { |
1163 | my ($incfile) = parse_expand_vars( $1, \%vars ); | | 1166 | my ($incfile) = parse_expand_vars( $1, \%vars ); |
1164 | | | 1167 | |
1165 | # At this point just skip any includes which we were not able to | | 1168 | # At this point just skip any includes which we were not able to |
1166 | # fully expand | | 1169 | # fully expand |
1167 | if ( $incfile =~ m#/mk/bsd# | | 1170 | if ( $incfile =~ m#/mk/bsd# |
1168 | || $incfile =~ /$magic_undefined/ | | 1171 | || $incfile =~ /$magic_undefined/ |
1169 | || $incfile =~ /\$\{/ | | 1172 | || $incfile =~ /\$\{/ |
1170 | || ( !$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)# ) ) | | 1173 | || ( !$opt{d} && $incfile =~ m#/(buildlink[^/]*\.mk)# ) ) |
1171 | { | | 1174 | { |
1172 | debug("$file: .include \"$incfile\" skipped\n"); | | 1175 | debug("$file: .include \"$incfile\" skipped\n"); |
1173 | } | | 1176 | } |
1174 | else { | | 1177 | else { |
1175 | debug("$file: .include \"$incfile\"\n"); | | 1178 | debug("$file: .include \"$incfile\"\n"); |
1176 | | | 1179 | |
1177 | # Expand any simple vars in $incfile | | 1180 | # Expand any simple vars in $incfile |
1178 | # | | 1181 | # |
1179 | | | 1182 | |
1180 | if ( substr( $incfile, 0, 1 ) ne '/' ) { | | 1183 | if ( substr( $incfile, 0, 1 ) ne '/' ) { |
1181 | foreach my $dir ( keys %incdirs ) { | | 1184 | foreach my $dir ( keys %incdirs ) { |
1182 | if ( -f "$dir/$incfile" ) { | | 1185 | if ( -f "$dir/$incfile" ) { |
1183 | $incfile = "$dir/$incfile"; | | 1186 | $incfile = "$dir/$incfile"; |
1184 | last; | | 1187 | last; |
1185 | } | | 1188 | } |
1186 | } | | 1189 | } |
1187 | } | | 1190 | } |
1188 | | | 1191 | |
1189 | # perl 5.6.1 realpath() cannot handle files, only directories | | 1192 | # perl 5.6.1 realpath() cannot handle files, only directories |
1190 | # If the last component is a symlink this will give a false | | 1193 | # If the last component is a symlink this will give a false |
1191 | # negative, but that is not a problem as the duplicate check | | 1194 | # negative, but that is not a problem as the duplicate check |
1192 | # is for performance | | 1195 | # is for performance |
1193 | $incfile =~ m#^(.+)(/[^/]+)$#; | | 1196 | $incfile =~ m#^(.+)(/[^/]+)$#; |
1194 | | | 1197 | |
1195 | if ( !-f $incfile ) { | | 1198 | if ( !-f $incfile ) { |
1196 | if ( !$opt{L} ) { | | 1199 | if ( !$opt{L} ) { |
1197 | verbose("\n"); | | 1200 | verbose("\n"); |
1198 | } | | 1201 | } |
1199 | | | 1202 | |
1200 | verbose("$file: Cannot locate $incfile in " | | 1203 | verbose("$file: Cannot locate $incfile in " |
1201 | . join( " ", sort keys %incdirs ) | | 1204 | . join( " ", sort keys %incdirs ) |
1202 | . "\n" ); | | 1205 | . "\n" ); |
1203 | | | 1206 | |
1204 | } | | 1207 | } |
1205 | else { | | 1208 | else { |
1206 | $incfile = realpath($1) . $2; | | 1209 | $incfile = realpath($1) . $2; |
1207 | | | 1210 | |
1208 | if ( !$incfiles{$incfile} ) { | | 1211 | if ( !$incfiles{$incfile} ) { |
1209 | if ( $opt{L} ) { | | 1212 | if ( $opt{L} ) { |
1210 | print "inc $incfile\n"; | | 1213 | print "inc $incfile\n"; |
1211 | } | | 1214 | } |
1212 | $incfiles{$incfile} = 1; | | 1215 | $incfiles{$incfile} = 1; |
1213 | | | 1216 | |
1214 | if ( !open( FILE, $incfile ) ) { | | 1217 | if ( !open( FILE, $incfile ) ) { |
1215 | verbose( | | 1218 | verbose( |
1216 | "Cannot open '$incfile' (from $file): $_ $!\n"); | | 1219 | "Cannot open '$incfile' (from $file): $_ $!\n"); |
1217 | } | | 1220 | } |
1218 | else { | | 1221 | else { |
1219 | my $NEWCURDIR = $incfile; | | 1222 | my $NEWCURDIR = $incfile; |
1220 | $NEWCURDIR =~ s#/[^/]*$##; | | 1223 | $NEWCURDIR =~ s#/[^/]*$##; |
1221 | $incdirs{$NEWCURDIR} = 1; | | 1224 | $incdirs{$NEWCURDIR} = 1; |
1222 | unshift( @data, ".CURDIR=$vars{'.CURDIR'}" ); | | 1225 | unshift( @data, ".CURDIR=$vars{'.CURDIR'}" ); |
1223 | unshift( @data, map { chomp; $_ } <FILE> ); | | 1226 | unshift( @data, map { chomp; $_ } <FILE> ); |
1224 | unshift( @data, ".CURDIR=$NEWCURDIR" ); | | 1227 | unshift( @data, ".CURDIR=$NEWCURDIR" ); |
1225 | close(FILE); | | 1228 | close(FILE); |
1226 | } | | 1229 | } |
1227 | } | | 1230 | } |
1228 | } | | 1231 | } |
1229 | } | | 1232 | } |
1230 | next; | | 1233 | next; |
1231 | } | | 1234 | } |
1232 | | | 1235 | |
1233 | if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) { | | 1236 | if (/^ *([-\w\.]+)\s*([:+?]?)=\s*(.*)/) { |
1234 | my ($key); | | 1237 | my ($key); |
1235 | | | 1238 | |
1236 | $key = $1; | | 1239 | $key = $1; |
1237 | $plus = $2; | | 1240 | $plus = $2; |
1238 | $value = $3; | | 1241 | $value = $3; |
1239 | | | 1242 | |
1240 | if ( $plus eq ':' ) { | | 1243 | if ( $plus eq ':' ) { |
1241 | $vars{$key} = parse_expand_vars( $value, \%vars ); | | 1244 | $vars{$key} = parse_expand_vars( $value, \%vars ); |
1242 | } | | 1245 | } |
1243 | elsif ( $plus eq '+' && defined $vars{$key} ) { | | 1246 | elsif ( $plus eq '+' && defined $vars{$key} ) { |
1244 | $vars{$key} .= " $value"; | | 1247 | $vars{$key} .= " $value"; |
1245 | } | | 1248 | } |
1246 | elsif ( $plus ne '?' || !defined $vars{$key} ) { | | 1249 | elsif ( $plus ne '?' || !defined $vars{$key} ) { |
1247 | $vars{$key} = $value; | | 1250 | $vars{$key} = $value; |
1248 | } | | 1251 | } |
1249 | debug("assignment: $key$plus=[$value] ($vars{$key})\n"); | | 1252 | debug("assignment: $key$plus=[$value] ($vars{$key})\n"); |
1250 | | | 1253 | |
1251 | # Give python a little hand (XXX - do we wanna consider actually | | 1254 | # Give python a little hand (XXX - do we wanna consider actually |
1252 | # implementing make .for loops, etc? | | 1255 | # implementing make .for loops, etc? |
1253 | # | | 1256 | # |
1254 | if ( $key eq "PYTHON_VERSIONS_ACCEPTED" ) { | | 1257 | if ( $key eq "PYTHON_VERSIONS_ACCEPTED" ) { |
1255 | my ($pv); | | 1258 | my ($pv); |
1256 | | | 1259 | |
1257 | foreach $pv ( split( /\s+/, $vars{PYTHON_VERSIONS_ACCEPTED} ) ) | | 1260 | foreach $pv ( split( /\s+/, $vars{PYTHON_VERSIONS_ACCEPTED} ) ) |
1258 | { | | 1261 | { |
1259 | $vars{"_PYTHON_VERSION_FIRSTACCEPTED"} ||= $pv; | | 1262 | $vars{"_PYTHON_VERSION_FIRSTACCEPTED"} ||= $pv; |
1260 | $vars{"_PYTHON_VERSION_${pv}_OK"} = "yes"; | | 1263 | $vars{"_PYTHON_VERSION_${pv}_OK"} = "yes"; |
1261 | } | | 1264 | } |
1262 | } | | 1265 | } |
1263 | } | | 1266 | } |
1264 | } | | 1267 | } |
1265 | | | 1268 | |
1266 | debug("$file: expand\n"); | | 1269 | debug("$file: expand\n"); |
1267 | | | 1270 | |
1268 | # Handle variable substitutions FRED = a-${JIM:S/-/-b-/} | | 1271 | # Handle variable substitutions FRED = a-${JIM:S/-/-b-/} |
1269 | # | | 1272 | # |
1270 | my ($loop); | | 1273 | my ($loop); |
1271 | | | 1274 | |
1272 | for ( $loop = 1 ; $loop ; ) { | | 1275 | for ( $loop = 1 ; $loop ; ) { |
1273 | $loop = 0; | | 1276 | $loop = 0; |
1274 | foreach my $key ( keys %vars ) { | | 1277 | foreach my $key ( keys %vars ) { |
1275 | if ( index( $vars{$key}, '$' ) == -1 ) { | | 1278 | if ( index( $vars{$key}, '$' ) == -1 ) { |
1276 | next; | | 1279 | next; |
1277 | } | | 1280 | } |
1278 | | | 1281 | |
1279 | $_ = parse_expand_vars( $vars{$key}, \%vars ); | | 1282 | $_ = parse_expand_vars( $vars{$key}, \%vars ); |
1280 | if ( $_ ne $vars{$key} ) { | | 1283 | if ( $_ ne $vars{$key} ) { |
1281 | $vars{$key} = $_; | | 1284 | $vars{$key} = $_; |
1282 | $loop = 1; | | 1285 | $loop = 1; |
1283 | | | 1286 | |
1284 | } | | 1287 | } |
1285 | elsif ( $vars{$key} =~ | | 1288 | elsif ( $vars{$key} =~ |
1286 | m#\$\{([\w.]+):([CS]([^{}])[^{}\3]+\3[^{}\3]*\3[g1]*(|:[^{}]+)|U[^{}]+)\}# ) | | 1289 | m#\$\{([\w.]+):([CS]([^{}])[^{}\3]+\3[^{}\3]*\3[g1]*(|:[^{}]+)|U[^{}]+)\}# ) |
1287 | { | | 1290 | { |
1288 | my ( $left, $subvar, $right ) = ( $`, $1, $' ); | | 1291 | my ( $left, $subvar, $right ) = ( $`, $1, $' ); |
1289 | my (@patterns) = split( ':', $2 ); | | 1292 | my (@patterns) = split( ':', $2 ); |
1290 | my ($result); | | 1293 | my ($result); |
1291 | | | 1294 | |
1292 | $result = $vars{$subvar}; | | 1295 | $result = $vars{$subvar}; |
1293 | $result ||= ''; | | 1296 | $result ||= ''; |
1294 | | | 1297 | |
1295 | # If $vars{$subvar} contains a $ skip it on this pass. | | 1298 | # If $vars{$subvar} contains a $ skip it on this pass. |
1296 | # Hopefully it will get substituted and we can catch it | | 1299 | # Hopefully it will get substituted and we can catch it |
1297 | # next time around. | | 1300 | # next time around. |
1298 | if ( index( $result, '${' ) != -1 ) { | | 1301 | if ( index( $result, '${' ) != -1 ) { |
1299 | next; | | 1302 | next; |
1300 | } | | 1303 | } |
1301 | | | 1304 | |
1302 | debug( | | 1305 | debug( |
1303 | "$file: substitutelist $key ($result) $subvar (@patterns)\n" | | 1306 | "$file: substitutelist $key ($result) $subvar (@patterns)\n" |
1304 | ); | | 1307 | ); |
1305 | foreach (@patterns) { | | 1308 | foreach (@patterns) { |
1306 | if (m#(U)(.*)#) { | | 1309 | if (m#(U)(.*)#) { |
1307 | $result ||= $2; | | 1310 | $result ||= $2; |
1308 | } elsif (m#([CS])(.)([^/]+)\2([^/]*)\2([1g]*)#) { | | 1311 | } elsif (m#([CS])(.)([^/]+)\2([^/]*)\2([1g]*)#) { |
1309 | | | 1312 | |
1310 | my ( $how, $from, $to, $global ) = ( $1, $3, $4, $5 ); | | 1313 | my ( $how, $from, $to, $global ) = ( $1, $3, $4, $5 ); |
1311 | | | 1314 | |
1312 | debug( | | 1315 | debug( |
1313 | "$file: substituteglob $subvar, $how, $from, $to, $global\n" | | 1316 | "$file: substituteglob $subvar, $how, $from, $to, $global\n" |
1314 | ); | | 1317 | ); |
1315 | if ( $how eq 'S' ) { | | 1318 | if ( $how eq 'S' ) { |
1316 | | | 1319 | |
1317 | # Limited substitution - keep ^ and $ | | 1320 | # Limited substitution - keep ^ and $ |
1318 | $from =~ s/([?.{}\]\[*+])/\\$1/g; | | 1321 | $from =~ s/([?.{}\]\[*+])/\\$1/g; |
1319 | } | | 1322 | } |
1320 | $to =~ s/\\(\d)/\$$1/g; # Change \1 etc to $1 | | 1323 | $to =~ s/\\(\d)/\$$1/g; # Change \1 etc to $1 |
1321 | $to =~ s/\&/\$&/g; # Change & to $1 | | 1324 | $to =~ s/\&/\$&/g; # Change & to $1 |
1322 | | | 1325 | |
1323 | my ($notfirst); | | 1326 | my ($notfirst); |
1324 | if ( $global =~ s/1// ) { | | 1327 | if ( $global =~ s/1// ) { |
1325 | ( $from, $notfirst ) = split( '\s', $from, 2 ); | | 1328 | ( $from, $notfirst ) = split( '\s', $from, 2 ); |
1326 | } | | 1329 | } |
1327 | | | 1330 | |
1328 | debug( | | 1331 | debug( |
1329 | "$file: substituteperl $subvar, $how, $from, $to\n" | | 1332 | "$file: substituteperl $subvar, $how, $from, $to\n" |
1330 | ); | | 1333 | ); |
1331 | eval "\$result =~ s/$from/$to/$global"; | | 1334 | eval "\$result =~ s/$from/$to/$global"; |
1332 | if ( defined $notfirst ) { | | 1335 | if ( defined $notfirst ) { |
1333 | $result .= " $notfirst"; | | 1336 | $result .= " $notfirst"; |
1334 | } | | 1337 | } |
1335 | } | | 1338 | } |
1336 | else { | | 1339 | else { |
1337 | next; | | 1340 | next; |
1338 | } | | 1341 | } |
1339 | } | | 1342 | } |
1340 | | | 1343 | |
1341 | $vars{$key} = $left . $result . $right; | | 1344 | $vars{$key} = $left . $result . $right; |
1342 | $loop = 1; | | 1345 | $loop = 1; |
1343 | } | | 1346 | } |
1344 | } | | 1347 | } |
1345 | } | | 1348 | } |
1346 | | | 1349 | |
1347 | foreach my $key ( keys %vars ) { | | 1350 | foreach my $key ( keys %vars ) { |
1348 | $vars{$key} =~ s/$magic_undefined//; | | 1351 | $vars{$key} =~ s/$magic_undefined//; |
1349 | } | | 1352 | } |
1350 | \%vars; | | 1353 | \%vars; |
1351 | } | | 1354 | } |
1352 | | | 1355 | |
1353 | sub parse_expand_vars($$) { | | 1356 | sub parse_expand_vars($$) { |
1354 | my ( $line, $vars ) = @_; | | 1357 | my ( $line, $vars ) = @_; |
1355 | | | 1358 | |
1356 | while ( $line =~ /\$\{([-\w.]+)\}/ ) { | | 1359 | while ( $line =~ /\$\{([-\w.]+)\}/ ) { |
1357 | if ( defined( ${$vars}{$1} ) ) { | | 1360 | if ( defined( ${$vars}{$1} ) ) { |
1358 | $line = $` . ${$vars}{$1} . $'; | | 1361 | $line = $` . ${$vars}{$1} . $'; |
1359 | } | | 1362 | } |
1360 | else { | | 1363 | else { |
1361 | $line = $` . $magic_undefined . $'; | | 1364 | $line = $` . $magic_undefined . $'; |
1362 | } | | 1365 | } |
1363 | } | | 1366 | } |
1364 | $line; | | 1367 | $line; |
1365 | } | | 1368 | } |
1366 | | | 1369 | |
1367 | sub parse_expand_vars_dumb($$) { | | 1370 | sub parse_expand_vars_dumb($$) { |
1368 | my ( $line, $vars ) = @_; | | 1371 | my ( $line, $vars ) = @_; |
1369 | | | 1372 | |
1370 | while ( $line =~ /\$\{([-\w.]+)\}/ ) { | | 1373 | while ( $line =~ /\$\{([-\w.]+)\}/ ) { |
1371 | if ( defined( ${$vars}{$1} ) ) { | | 1374 | if ( defined( ${$vars}{$1} ) ) { |
1372 | $line = $` . ${$vars}{$1} . $'; | | 1375 | $line = $` . ${$vars}{$1} . $'; |
1373 | } | | 1376 | } |
1374 | else { | | 1377 | else { |
1375 | $line = $` . $magic_undefined . $'; | | 1378 | $line = $` . $magic_undefined . $'; |
1376 | } | | 1379 | } |
1377 | } | | 1380 | } |
1378 | $line; | | 1381 | $line; |
1379 | } | | 1382 | } |
1380 | | | 1383 | |
1381 | sub parse_eval_make_false($$) { | | 1384 | sub parse_eval_make_false($$) { |
1382 | my ( $line, $vars ) = @_; | | 1385 | my ( $line, $vars ) = @_; |
1383 | my ( $false, $test ); | | 1386 | my ( $false, $test ); |
1384 | | | 1387 | |
1385 | $false = 0; | | 1388 | $false = 0; |
1386 | $test = parse_expand_vars_dumb( $line, $vars ); | | 1389 | $test = parse_expand_vars_dumb( $line, $vars ); |
1387 | | | 1390 | |
1388 | # XXX This is _so_ wrong - need to parse this correctly | | 1391 | # XXX This is _so_ wrong - need to parse this correctly |
1389 | $test =~ s/""/\r/g; | | 1392 | $test =~ s/""/\r/g; |
1390 | $test =~ s/"//g; # " | | 1393 | $test =~ s/"//g; # " |
1391 | $test =~ s/\r/""/g; | | 1394 | $test =~ s/\r/""/g; |
1392 | | | 1395 | |
1393 | debug("conditional: $test\n"); | | 1396 | debug("conditional: $test\n"); |
1394 | | | 1397 | |
1395 | # XXX Could do something with target | | 1398 | # XXX Could do something with target |
1396 | while ( $test =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/ ) { | | 1399 | while ( $test =~ /(target|empty|make|defined|exists)\s*\(([^()]+)\)/ ) { |
1397 | my $testname = $1; | | 1400 | my $testname = $1; |
1398 | my $varname = $2; | | 1401 | my $varname = $2; |
1399 | my $var; | | 1402 | my $var; |
1400 | | | 1403 | |
1401 | # Implement (some of) make's :M modifier | | 1404 | # Implement (some of) make's :M modifier |
1402 | if ( $varname =~ /^([^:]+):M(.+)$/ ) { | | 1405 | if ( $varname =~ /^([^:]+):M(.+)$/ ) { |
1403 | $varname = $1; | | 1406 | $varname = $1; |
1404 | my $match = $2; | | 1407 | my $match = $2; |
1405 | | | 1408 | |
1406 | $var = $${vars}{$varname}; | | 1409 | $var = $${vars}{$varname}; |
1407 | $var = parse_expand_vars( $var, $vars ) if defined $var; | | 1410 | $var = parse_expand_vars( $var, $vars ) if defined $var; |
1408 | | | 1411 | |
1409 | $match =~ s/([{.+])/\\$1/g; | | 1412 | $match =~ s/([{.+])/\\$1/g; |
1410 | $match =~ s/\*/.*/g; | | 1413 | $match =~ s/\*/.*/g; |
1411 | $match =~ s/\?/./g; | | 1414 | $match =~ s/\?/./g; |
1412 | $match = '^' . $match . '$'; | | 1415 | $match = '^' . $match . '$'; |
1413 | $var = ( $var =~ /$match/ ) if defined $var; | | 1416 | $var = ( $var =~ /$match/ ) if defined $var; |
1414 | } | | 1417 | } |
1415 | else { | | 1418 | else { |
1416 | $var = $${vars}{$varname}; | | 1419 | $var = $${vars}{$varname}; |
1417 | $var = parse_expand_vars( $var, $vars ) if defined $var; | | 1420 | $var = parse_expand_vars( $var, $vars ) if defined $var; |
1418 | } | | 1421 | } |
1419 | | | 1422 | |
1420 | if ( defined $var && $var eq $magic_undefined ) { | | 1423 | if ( defined $var && $var eq $magic_undefined ) { |
1421 | $var = undef; | | 1424 | $var = undef; |
1422 | } | | 1425 | } |
1423 | | | 1426 | |
1424 | if ( $testname eq 'exists' ) { | | 1427 | if ( $testname eq 'exists' ) { |
1425 | $_ = ( -e $varname ) ? 1 : 0; | | 1428 | $_ = ( -e $varname ) ? 1 : 0; |
1426 | | | 1429 | |
1427 | } | | 1430 | } |
1428 | elsif ( $testname eq 'defined' ) { | | 1431 | elsif ( $testname eq 'defined' ) { |
1429 | $_ = defined($var) ? 1 : 0; | | 1432 | $_ = defined($var) ? 1 : 0; |
1430 | | | 1433 | |
1431 | } | | 1434 | } |
1432 | elsif ( $testname eq 'empty' ) { | | 1435 | elsif ( $testname eq 'empty' ) { |
1433 | $_ = ( ( not defined($var) or ( length($var) == 0 ) ) ? 1 : 0 ); | | 1436 | $_ = ( ( not defined($var) or ( length($var) == 0 ) ) ? 1 : 0 ); |
1434 | | | 1437 | |
1435 | } | | 1438 | } |
1436 | else { | | 1439 | else { |
1437 | $_ = 0; | | 1440 | $_ = 0; |
1438 | } | | 1441 | } |
1439 | | | 1442 | |
1440 | $test =~ s/$testname\s*\([^()]+\)/$_/; | | 1443 | $test =~ s/$testname\s*\([^()]+\)/$_/; |
1441 | debug("conditional: update to $test\n"); | | 1444 | debug("conditional: update to $test\n"); |
1442 | } | | 1445 | } |
1443 | | | 1446 | |
1444 | while ( $test =~ /([^\s()\|\&]+)\s+(!=|==)\s+([^\s()]+)/ ) { | | 1447 | while ( $test =~ /([^\s()\|\&]+)\s+(!=|==)\s+([^\s()]+)/ ) { |
1445 | if ( $2 eq '==' ) { | | 1448 | if ( $2 eq '==' ) { |
1446 | $_ = ( $1 eq $3 ) ? 1 : 0; | | 1449 | $_ = ( $1 eq $3 ) ? 1 : 0; |
1447 | } | | 1450 | } |
1448 | else { | | 1451 | else { |
1449 | $_ = ( $1 ne $3 ) ? 1 : 0; | | 1452 | $_ = ( $1 ne $3 ) ? 1 : 0; |
1450 | } | | 1453 | } |
1451 | $test =~ s/[^\s()\|\&]+\s+(!=|==)\s+[^\s()]+/$_/; | | 1454 | $test =~ s/[^\s()\|\&]+\s+(!=|==)\s+[^\s()]+/$_/; |
1452 | } | | 1455 | } |
1453 | | | 1456 | |
1454 | if ( $test !~ /[^<>\d()\s&|.!]/ ) { | | 1457 | if ( $test !~ /[^<>\d()\s&|.!]/ ) { |
1455 | $false = eval "($test)?0:1"; | | 1458 | $false = eval "($test)?0:1"; |
1456 | if ( !defined $false ) { | | 1459 | if ( !defined $false ) { |
1457 | fail("Eval failed $line - $test"); | | 1460 | fail("Eval failed $line - $test"); |
1458 | } | | 1461 | } |
1459 | debug( "conditional: evaluated to " . ( $false ? 0 : 1 ) . "\n" ); | | 1462 | debug( "conditional: evaluated to " . ( $false ? 0 : 1 ) . "\n" ); |
1460 | | | 1463 | |
1461 | } | | 1464 | } |
1462 | else { | | 1465 | else { |
1463 | $false = 0; | | 1466 | $false = 0; |
1464 | debug("conditional: defaulting to 0\n"); | | 1467 | debug("conditional: defaulting to 0\n"); |
1465 | } | | 1468 | } |
1466 | $false; | | 1469 | $false; |
1467 | } | | 1470 | } |
1468 | | | 1471 | |
1469 | # chdir() || fail() | | 1472 | # chdir() || fail() |
1470 | # | | 1473 | # |
1471 | sub safe_chdir($) { | | 1474 | sub safe_chdir($) { |
1472 | my ($dir) = @_; | | 1475 | my ($dir) = @_; |
1473 | | | 1476 | |
1474 | debug("chdir: $dir"); | | 1477 | debug("chdir: $dir"); |
1475 | if ( !chdir($dir) ) { | | 1478 | if ( !chdir($dir) ) { |
1476 | fail("Unable to chdir($dir): $!"); | | 1479 | fail("Unable to chdir($dir): $!"); |
1477 | } | | 1480 | } |
1478 | } | | 1481 | } |
1479 | | | 1482 | |
1480 | # Generate pkgname->category/pkg mapping, optionally check DEPENDS | | 1483 | # Generate pkgname->category/pkg mapping, optionally check DEPENDS |
1481 | # | | 1484 | # |
1482 | sub scan_pkgsrc_makefiles($$) { | | 1485 | sub scan_pkgsrc_makefiles($$) { |
1483 | my ( $pkgsrcdir, $check_depends ) = @_; | | 1486 | my ( $pkgsrcdir, $check_depends ) = @_; |
1484 | my (@categories); | | 1487 | my (@categories); |
1485 | | | 1488 | |
1486 | if ($pkglist) { | | 1489 | if ($pkglist) { |
1487 | | | 1490 | |
1488 | # Already done | | 1491 | # Already done |
1489 | return; | | 1492 | return; |
1490 | } | | 1493 | } |
1491 | | | 1494 | |
1492 | if ( $opt{I} ) { | | 1495 | if ( $opt{I} ) { |
1493 | load_pkgsrc_makefiles( $opt{I} ); | | 1496 | load_pkgsrc_makefiles( $opt{I} ); |
1494 | return; | | 1497 | return; |
1495 | } | | 1498 | } |
1496 | | | 1499 | |
1497 | $pkglist = new PkgList; | | 1500 | $pkglist = new PkgList; |
1498 | @categories = list_pkgsrc_categories($pkgsrcdir); | | 1501 | @categories = list_pkgsrc_categories($pkgsrcdir); |
1499 | verbose('Scan Makefiles: '); | | 1502 | verbose('Scan Makefiles: '); |
1500 | | | 1503 | |
1501 | if ( !$opt{L} ) { | | 1504 | if ( !$opt{L} ) { |
1502 | verbose( '_' x @categories . "\b" x @categories ); | | 1505 | verbose( '_' x @categories . "\b" x @categories ); |
1503 | } | | 1506 | } |
1504 | else { | | 1507 | else { |
1505 | verbose("\n"); | | 1508 | verbose("\n"); |
1506 | } | | 1509 | } |
1507 | | | 1510 | |
1508 | foreach my $cat ( sort @categories ) { | | 1511 | foreach my $cat ( sort @categories ) { |
1509 | foreach my $pkgdir ( list_pkgsrc_pkgdirs( $pkgsrcdir, $cat ) ) { | | 1512 | foreach my $pkgdir ( list_pkgsrc_pkgdirs( $pkgsrcdir, $cat ) ) { |
1510 | my ( $pkg, $vars ) = | | 1513 | my ( $pkg, $vars ) = |
1511 | parse_makefile_pkgsrc("$pkgsrcdir/$cat/$pkgdir/Makefile"); | | 1514 | parse_makefile_pkgsrc("$pkgsrcdir/$cat/$pkgdir/Makefile"); |
1512 | } | | 1515 | } |
1513 | | | 1516 | |
1514 | if ( !$opt{L} ) { | | 1517 | if ( !$opt{L} ) { |
1515 | verbose('.'); | | 1518 | verbose('.'); |
1516 | } | | 1519 | } |
1517 | } | | 1520 | } |
1518 | | | 1521 | |
1519 | if ( !$opt{L} ) { | | 1522 | if ( !$opt{L} ) { |
1520 | my ($len); | | 1523 | my ($len); |
1521 | | | 1524 | |
1522 | $_ = $pkglist->numpkgver() . ' packages'; | | 1525 | $_ = $pkglist->numpkgver() . ' packages'; |
1523 | $len = @categories - length($_); | | 1526 | $len = @categories - length($_); |
1524 | verbose( "\b" x @categories, $_, ' ' x $len, "\b" x $len, "\n" ); | | 1527 | verbose( "\b" x @categories, $_, ' ' x $len, "\b" x $len, "\n" ); |
1525 | } | | 1528 | } |
1526 | } | | 1529 | } |
1527 | | | 1530 | |
1528 | # Cross reference all depends | | 1531 | # Cross reference all depends |
1529 | # | | 1532 | # |
1530 | sub pkgsrc_check_depends() { | | 1533 | sub pkgsrc_check_depends() { |
1531 | | | 1534 | |
1532 | foreach my $pkgver ( $pkglist->pkgver ) { | | 1535 | foreach my $pkgver ( $pkglist->pkgver ) { |
1533 | my ( $err, $msg ); | | 1536 | my ( $err, $msg ); |
1534 | | | 1537 | |
1535 | defined $pkgver->var('DEPENDS') || next; | | 1538 | defined $pkgver->var('DEPENDS') || next; |
1536 | foreach my $depend ( split( " ", $pkgver->var('DEPENDS') ) ) { | | 1539 | foreach my $depend ( split( " ", $pkgver->var('DEPENDS') ) ) { |
1537 | | | 1540 | |
1538 | $depend =~ s/:.*// || next; | | 1541 | $depend =~ s/:.*// || next; |
1539 | | | 1542 | |
1540 | $depend = canonicalize_pkgname($depend); | | 1543 | $depend = canonicalize_pkgname($depend); |
1541 | if ( ( $msg = invalid_version($depend) ) ) { | | 1544 | if ( ( $msg = invalid_version($depend) ) ) { |
1542 | if ( !defined($err) ) { | | 1545 | if ( !defined($err) ) { |
1543 | print $pkgver->pkgname . " DEPENDS errors:\n"; | | 1546 | print $pkgver->pkgname . " DEPENDS errors:\n"; |
1544 | } | | 1547 | } |
1545 | $err = 1; | | 1548 | $err = 1; |
1546 | $msg =~ s/(\n)(.)/$1\t$2/g; | | 1549 | $msg =~ s/(\n)(.)/$1\t$2/g; |
1547 | print "\t$msg"; | | 1550 | print "\t$msg"; |
1548 | } | | 1551 | } |
1549 | } | | 1552 | } |
1550 | } | | 1553 | } |
1551 | } | | 1554 | } |
1552 | | | 1555 | |
1553 | # Extract all distinfo entries, then verify contents of distfiles | | 1556 | # Extract all distinfo entries, then verify contents of distfiles |
1554 | # | | 1557 | # |
1555 | sub scan_pkgsrc_distfiles_vs_distinfo($$$$) { | | 1558 | sub scan_pkgsrc_distfiles_vs_distinfo($$$$) { |
1556 | my ( $pkgsrcdir, $pkgdistdir, $check_unref, $check_distinfo ) = @_; | | 1559 | my ( $pkgsrcdir, $pkgdistdir, $check_unref, $check_distinfo ) = @_; |
1557 | my (@categories); | | 1560 | my (@categories); |
1558 | my ( %distfiles, %sumfiles, @distwarn, $numpkg ); | | 1561 | my ( %distfiles, %sumfiles, @distwarn, $numpkg ); |
1559 | my (%bad_distfiles); | | 1562 | my (%bad_distfiles); |
1560 | | | 1563 | |
1561 | @categories = list_pkgsrc_categories($pkgsrcdir); | | 1564 | @categories = list_pkgsrc_categories($pkgsrcdir); |
1562 | | | 1565 | |
1563 | verbose( 'Scan distinfo: ' . '_' x @categories . "\b" x @categories ); | | 1566 | verbose( 'Scan distinfo: ' . '_' x @categories . "\b" x @categories ); |
1564 | $numpkg = 0; | | 1567 | $numpkg = 0; |
1565 | foreach my $cat ( sort @categories ) { | | 1568 | foreach my $cat ( sort @categories ) { |
1566 | foreach my $pkgdir ( list_pkgsrc_pkgdirs( $pkgsrcdir, $cat ) ) { | | 1569 | foreach my $pkgdir ( list_pkgsrc_pkgdirs( $pkgsrcdir, $cat ) ) { |
1567 | if ( open( DISTINFO, "$pkgsrcdir/$cat/$pkgdir/distinfo" ) ) { | | 1570 | if ( open( DISTINFO, "$pkgsrcdir/$cat/$pkgdir/distinfo" ) ) { |
1568 | ++$numpkg; | | 1571 | ++$numpkg; |
1569 | while (<DISTINFO>) { | | 1572 | while (<DISTINFO>) { |
1570 | if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) { | | 1573 | if (m/^(\w+) ?\(([^\)]+)\) = (\S+)/) { |
1571 | my ( $dn, $ds, $dt ); | | 1574 | my ( $dn, $ds, $dt ); |
1572 | $dt = $1; | | 1575 | $dt = $1; |
1573 | $dn = $2; | | 1576 | $dn = $2; |
1574 | $ds = $3; | | 1577 | $ds = $3; |
1575 | if ( $dn =~ /^patch-[\w.+\-]+$/ ) { | | 1578 | if ( $dn =~ /^patch-[\w.+\-]+$/ ) { |
1576 | next; | | 1579 | next; |
1577 | } | | 1580 | } |
1578 | | | 1581 | |
1579 | # Strip leading ./ which sometimes gets added | | 1582 | # Strip leading ./ which sometimes gets added |
1580 | # because of DISTSUBDIR=. | | 1583 | # because of DISTSUBDIR=. |
1581 | $dn =~ s/^(\.\/)*//; | | 1584 | $dn =~ s/^(\.\/)*//; |
1582 | if ( !defined $distfiles{$dn} ) { | | 1585 | if ( !defined $distfiles{$dn} ) { |
1583 | $distfiles{$dn}{sumtype} = $dt; | | 1586 | $distfiles{$dn}{sumtype} = $dt; |
1584 | $distfiles{$dn}{sum} = $ds; | | 1587 | $distfiles{$dn}{sum} = $ds; |
1585 | $distfiles{$dn}{path} = "$cat/$pkgdir"; | | 1588 | $distfiles{$dn}{path} = "$cat/$pkgdir"; |
1586 | | | 1589 | |
1587 | } | | 1590 | } |
1588 | elsif ($distfiles{$dn}{sumtype} eq $dt | | 1591 | elsif ($distfiles{$dn}{sumtype} eq $dt |
1589 | && $distfiles{$dn}{sum} ne $ds ) | | 1592 | && $distfiles{$dn}{sum} ne $ds ) |
1590 | { | | 1593 | { |
1591 | push( @distwarn, | | 1594 | push( @distwarn, |
1592 | "checksum mismatch between '$dt' for '$dn' " | | 1595 | "checksum mismatch between '$dt' for '$dn' " |
1593 | . "in $cat/$pkgdir and $distfiles{$dn}{path}\n" | | 1596 | . "in $cat/$pkgdir and $distfiles{$dn}{path}\n" |
1594 | ); | | 1597 | ); |
1595 | } | | 1598 | } |
1596 | } | | 1599 | } |
1597 | } | | 1600 | } |
1598 | close(DISTINFO); | | 1601 | close(DISTINFO); |
1599 | } | | 1602 | } |
1600 | } | | 1603 | } |
1601 | verbose('.'); | | 1604 | verbose('.'); |
1602 | } | | 1605 | } |
1603 | verbose(" ($numpkg packages)\n"); | | 1606 | verbose(" ($numpkg packages)\n"); |
1604 | | | 1607 | |
1605 | # check each file in $pkgdistdir | | 1608 | # check each file in $pkgdistdir |
1606 | find ( { wanted => sub { | | 1609 | find ( { wanted => sub { |
1607 | my ($dist); | | 1610 | my ($dist); |
1608 | if ( -f $File::Find::name ) | | 1611 | if ( -f $File::Find::name ) |
1609 | { | | 1612 | { |
1610 | my $distn = $File::Find::name; | | 1613 | my $distn = $File::Find::name; |
1611 | $distn =~ s/$pkgdistdir\/?//g; | | 1614 | $distn =~ s/$pkgdistdir\/?//g; |
1612 | #pkg/47516 ignore cvs dirs | | 1615 | #pkg/47516 ignore cvs dirs |
1613 | return if $distn =~ m/^\.cvsignore/; | | 1616 | return if $distn =~ m/^\.cvsignore/; |
1614 | return if $distn =~ m/^CVS\//; | | 1617 | return if $distn =~ m/^CVS\//; |
1615 | if ( !defined ($dist = $distfiles{$distn} ) ) { | | 1618 | if ( !defined ($dist = $distfiles{$distn} ) ) { |
1616 | $bad_distfiles{$distn} = 1; | | 1619 | $bad_distfiles{$distn} = 1; |
1617 | } | | 1620 | } |
1618 | else { | | 1621 | else { |
1619 | if ( $dist->{sum} ne 'IGNORE' ) { | | 1622 | if ( $dist->{sum} ne 'IGNORE' ) { |
1620 | push( @{ $sumfiles{ $dist->{sumtype} } }, $distn ); | | 1623 | push( @{ $sumfiles{ $dist->{sumtype} } }, $distn ); |
1621 | } | | 1624 | } |
1622 | } | | 1625 | } |
1623 | } | | 1626 | } |
1624 | } }, | | 1627 | } }, |
1625 | ($pkgdistdir) ); | | 1628 | ($pkgdistdir) ); |
1626 | | | 1629 | |
1627 | if ( $check_unref && %bad_distfiles ) { | | 1630 | if ( $check_unref && %bad_distfiles ) { |
1628 | verbose( scalar( keys %bad_distfiles ), | | 1631 | verbose( scalar( keys %bad_distfiles ), |
1629 | " unreferenced file(s) in '$pkgdistdir':\n" ); | | 1632 | " unreferenced file(s) in '$pkgdistdir':\n" ); |
1630 | print join( "\n", sort keys %bad_distfiles ), "\n"; | | 1633 | print join( "\n", sort keys %bad_distfiles ), "\n"; |
1631 | } | | 1634 | } |
1632 | | | 1635 | |
1633 | if ($check_distinfo) { | | 1636 | if ($check_distinfo) { |
1634 | if (@distwarn) { | | 1637 | if (@distwarn) { |
1635 | verbose(@distwarn); | | 1638 | verbose(@distwarn); |
1636 | } | | 1639 | } |
1637 | | | 1640 | |
1638 | verbose("checksum mismatches\n"); | | 1641 | verbose("checksum mismatches\n"); |
1639 | safe_chdir($pkgdistdir); | | 1642 | safe_chdir($pkgdistdir); |
1640 | foreach my $sum ( keys %sumfiles ) { | | 1643 | foreach my $sum ( keys %sumfiles ) { |
1641 | if ( $sum eq 'Size' ) { | | 1644 | if ( $sum eq 'Size' ) { |
1642 | foreach my $file ( @{ $sumfiles{$sum} } ) { | | 1645 | foreach my $file ( @{ $sumfiles{$sum} } ) { |
1643 | if ( !-f $file || -S $file != $distfiles{$file}{sum} ) { | | 1646 | if ( !-f $file || -S $file != $distfiles{$file}{sum} ) { |
1644 | print $file, " (Size)\n"; | | 1647 | print $file, " (Size)\n"; |
1645 | $bad_distfiles{$file} = 1; | | 1648 | $bad_distfiles{$file} = 1; |
1646 | } | | 1649 | } |
1647 | } | | 1650 | } |
1648 | next; | | 1651 | next; |
1649 | } | | 1652 | } |
1650 | | | 1653 | |
1651 | my $pid = open3(my $in, my $out, undef, "xargs", "digest", $sum); | | 1654 | my $pid = open3(my $in, my $out, undef, "xargs", "digest", $sum); |
1652 | defined($pid) || fail "fork"; | | 1655 | defined($pid) || fail "fork"; |
1653 | my $pid2 = fork(); | | 1656 | my $pid2 = fork(); |
1654 | defined($pid2) || fail "fork"; | | 1657 | defined($pid2) || fail "fork"; |
1655 | if ($pid2) { | | 1658 | if ($pid2) { |
1656 | close($in); | | 1659 | close($in); |
1657 | } else { | | 1660 | } else { |
1658 | print $in "@{$sumfiles{$sum}}"; | | 1661 | print $in "@{$sumfiles{$sum}}"; |
1659 | exit 0; | | 1662 | exit 0; |
1660 | } | | 1663 | } |
1661 | while (<$out>) { | | 1664 | while (<$out>) { |
1662 | if (m/^$sum ?\(([^\)]+)\) = (\S+)/) { | | 1665 | if (m/^$sum ?\(([^\)]+)\) = (\S+)/) { |
1663 | if ( $distfiles{$1}{sum} ne $2 ) { | | 1666 | if ( $distfiles{$1}{sum} ne $2 ) { |
1664 | print $1, " ($sum)\n"; | | 1667 | print $1, " ($sum)\n"; |
1665 | $bad_distfiles{$1} = 1; | | 1668 | $bad_distfiles{$1} = 1; |
1666 | } | | 1669 | } |
1667 | } | | 1670 | } |
1668 | } | | 1671 | } |
1669 | close($out); | | 1672 | close($out); |
1670 | waitpid( $pid, 0 ) || fail "xargs digest $sum"; | | 1673 | waitpid( $pid, 0 ) || fail "xargs digest $sum"; |
1671 | waitpid( $pid2, 0 ) || fail "pipe write to xargs"; | | 1674 | waitpid( $pid2, 0 ) || fail "pipe write to xargs"; |
1672 | } | | 1675 | } |
1673 | safe_chdir('/'); # Do not want to stay in $pkgdistdir | | 1676 | safe_chdir('/'); # Do not want to stay in $pkgdistdir |
1674 | } | | 1677 | } |
1675 | ( sort keys %bad_distfiles ); | | 1678 | ( sort keys %bad_distfiles ); |
1676 | } | | 1679 | } |
1677 | | | 1680 | |
1678 | sub load_pkgsrc_makefiles() { | | 1681 | sub load_pkgsrc_makefiles() { |
1679 | | | 1682 | |
1680 | open( STORE, "<$_[0]" ) || die("Cannot read pkgsrc store from $_[0]: $!\n"); | | 1683 | open( STORE, "<$_[0]" ) || die("Cannot read pkgsrc store from $_[0]: $!\n"); |
1681 | my ($pkgver); | | 1684 | my ($pkgver); |
1682 | our ( $pkgcnt, $pkgnum, $subpkgcnt, $subpkgnum ); | | 1685 | our ( $pkgcnt, $pkgnum, $subpkgcnt, $subpkgnum ); |
1683 | $pkglist = new PkgList; | | 1686 | $pkglist = new PkgList; |
1684 | while (<STORE>) { | | 1687 | while (<STORE>) { |
1685 | eval $_; | | 1688 | eval $_; |
1686 | } | | 1689 | } |
1687 | close(STORE); | | 1690 | close(STORE); |
1688 | } | | 1691 | } |
1689 | | | 1692 | |
1690 | sub store_pkgsrc_makefiles() { | | 1693 | sub store_pkgsrc_makefiles() { |
1691 | open( STORE, ">$_[0]" ) || die("Cannot save pkgsrc store to $_[0]: $!\n"); | | 1694 | open( STORE, ">$_[0]" ) || die("Cannot save pkgsrc store to $_[0]: $!\n"); |
1692 | my $was = select(STORE); | | 1695 | my $was = select(STORE); |
1693 | print( | | 1696 | print( |
1694 | 'sub __pkgcount { $subpkgnum += $_[0]; ', | | 1697 | 'sub __pkgcount { $subpkgnum += $_[0]; ', |
1695 | 'verbose("\rReading pkgsrc database: ', | | 1698 | 'verbose("\rReading pkgsrc database: ', |
1696 | '$pkgnum / $pkgcnt ($subpkgnum / $subpkgcnt) pkgs"); }', | | 1699 | '$pkgnum / $pkgcnt ($subpkgnum / $subpkgcnt) pkgs"); }', |
1697 | "\n" | | 1700 | "\n" |
1698 | ); | | 1701 | ); |
1699 | $pkglist->store; | | 1702 | $pkglist->store; |
1700 | print("verbose(\"...done\\n\");\n"); | | 1703 | print("verbose(\"...done\\n\");\n"); |
1701 | select($was); | | 1704 | select($was); |
1702 | close(STORE); | | 1705 | close(STORE); |
1703 | } | | 1706 | } |
1704 | | | 1707 | |
1705 | # Remember to update manual page when modifying option list | | 1708 | # Remember to update manual page when modifying option list |
1706 | # | | 1709 | # |
1707 | sub usage_and_exit() { | | 1710 | sub usage_and_exit() { |
1708 | print "Usage: lintpkgsrc [opts] [makefiles] | | 1711 | print "Usage: lintpkgsrc [opts] [makefiles] |
1709 | opts: | | 1712 | opts: |
1710 | -h : This help. [see lintpkgsrc(1) for more information] | | 1713 | -h : This help. [see lintpkgsrc(1) for more information] |
1711 | | | 1714 | |
1712 | Installed package options: Distfile options: | | 1715 | Installed package options: Distfile options: |
1713 | -i : Check version against pkgsrc -m : List distinfo mismatches | | 1716 | -i : Check version against pkgsrc -m : List distinfo mismatches |
1714 | -u : As -i + fetch dist (may change) -o : List obsolete (no distinfo) | | 1717 | -u : As -i + fetch dist (may change) -o : List obsolete (no distinfo) |
1715 | -y : Remove orphan distfiles | | 1718 | -y : Remove orphan distfiles |
1716 | -z : Remove installed distfiles | | 1719 | -z : Remove installed distfiles |
1717 | | | 1720 | |
1718 | Prebuilt package options: Makefile options: | | 1721 | Prebuilt package options: Makefile options: |
1719 | -p : List old/obsolete -B : List packages marked as 'BROKEN' | | 1722 | -p : List old/obsolete -B : List packages marked as 'BROKEN' |
1720 | -O : List OSVERSION_SPECIFIC -d : Check 'DEPENDS' up to date | | 1723 | -O : List OSVERSION_SPECIFIC -d : Check 'DEPENDS' up to date |
1721 | -R : List NO_BIN_ON_FTP/RESTRICTED -S : List packages not in 'SUBDIRS' | | 1724 | -R : List NO_BIN_ON_FTP/RESTRICTED -S : List packages not in 'SUBDIRS' |
1722 | | | 1725 | |
1723 | Misc: | | 1726 | Misc: |
1724 | -E file : Export the internal pkgsrc database to file | | 1727 | -E file : Export the internal pkgsrc database to file |
1725 | -I file : Import the internal pkgsrc database to file (for use with -i) | | 1728 | -I file : Import the internal pkgsrc database to file (for use with -i) |
1726 | -g file : Generate 'pkgname pkgdir pkgver' map in file | | 1729 | -g file : Generate 'pkgname pkgdir pkgver' map in file |
1727 | -r : Remove bad files (Without -m -o -p or -V implies all, can use -R) | | 1730 | -r : Remove bad files (Without -m -o -p or -V implies all, can use -R) |
1728 | | | 1731 | |
1729 | Modifiers: | | 1732 | Modifiers: |
1730 | -K path : Set PACKAGES basedir (default PKGSRCDIR/packages) | | 1733 | -K path : Set PACKAGES basedir (default PKGSRCDIR/packages) |
1731 | -M path : Set DISTDIR (default PKGSRCDIR/distfiles) | | 1734 | -M path : Set DISTDIR (default PKGSRCDIR/distfiles) |
1732 | -P path : Set PKGSRCDIR (default $conf_pkgsrcdir) | | 1735 | -P path : Set PKGSRCDIR (default $conf_pkgsrcdir) |
1733 | -D : Debug makefile and glob parsing | | 1736 | -D : Debug makefile and glob parsing |
1734 | -L : List each Makefile when scanned | | 1737 | -L : List each Makefile when scanned |
1735 | "; | | 1738 | "; |
1736 | exit; | | 1739 | exit; |
1737 | } | | 1740 | } |
1738 | | | 1741 | |
1739 | sub verbose(@) { | | 1742 | sub verbose(@) { |
1740 | | | 1743 | |
1741 | if ( -t STDERR ) { | | 1744 | if ( -t STDERR ) { |
1742 | print STDERR @_; | | 1745 | print STDERR @_; |
1743 | } | | 1746 | } |
1744 | } | | 1747 | } |
1745 | | | 1748 | |
1746 | sub debug(@) { | | 1749 | sub debug(@) { |
1747 | | | 1750 | |
1748 | ( $opt{D} ) && print STDERR 'DEBUG: ', @_; | | 1751 | ( $opt{D} ) && print STDERR 'DEBUG: ', @_; |
1749 | } | | 1752 | } |
1750 | | | 1753 | |
1751 | # PkgList is the master list of all packages in pkgsrc. | | 1754 | # PkgList is the master list of all packages in pkgsrc. |
1752 | # | | 1755 | # |
1753 | package PkgList; | | 1756 | package PkgList; |
1754 | | | 1757 | |
1755 | sub add($@) { | | 1758 | sub add($@) { |
1756 | my $self = shift; | | 1759 | my $self = shift; |
1757 | | | 1760 | |
1758 | if ( !$self->pkgs( $_[0] ) ) { | | 1761 | if ( !$self->pkgs( $_[0] ) ) { |
1759 | $self->{_pkgs}{ $_[0] } = new Pkgs $_[0]; | | 1762 | $self->{_pkgs}{ $_[0] } = new Pkgs $_[0]; |
1760 | } | | 1763 | } |
1761 | $self->pkgs( $_[0] )->add(@_); | | 1764 | $self->pkgs( $_[0] )->add(@_); |
1762 | } | | 1765 | } |
1763 | | | 1766 | |
1764 | sub new($) { | | 1767 | sub new($) { |
1765 | my $class = shift; | | 1768 | my $class = shift; |
1766 | my $self = {}; | | 1769 | my $self = {}; |
1767 | bless $self, $class; | | 1770 | bless $self, $class; |
1768 | return $self; | | 1771 | return $self; |
1769 | } | | 1772 | } |
1770 | | | 1773 | |
1771 | sub numpkgver($) { | | 1774 | sub numpkgver($) { |
1772 | my $self = shift; | | 1775 | my $self = shift; |
1773 | scalar( $self->pkgver ); | | 1776 | scalar( $self->pkgver ); |
1774 | } | | 1777 | } |
1775 | | | 1778 | |
1776 | sub pkgver($@) { | | 1779 | sub pkgver($@) { |
1777 | my $self = shift; | | 1780 | my $self = shift; |
1778 | | | 1781 | |
1779 | if ( @_ == 0 ) { | | 1782 | if ( @_ == 0 ) { |
1780 | my (@list); | | 1783 | my (@list); |
1781 | foreach my $pkg ( $self->pkgs ) { | | 1784 | foreach my $pkg ( $self->pkgs ) { |
1782 | push( @list, $pkg->pkgver ); | | 1785 | push( @list, $pkg->pkgver ); |
1783 | } | | 1786 | } |
1784 | return (@list); | | 1787 | return (@list); |
1785 | } | | 1788 | } |
1786 | | | 1789 | |
1787 | if ( defined $self->{_pkgs}{ $_[0] } ) { | | 1790 | if ( defined $self->{_pkgs}{ $_[0] } ) { |
1788 | return ( @_ > 1 ) | | 1791 | return ( @_ > 1 ) |
1789 | ? $self->{_pkgs}{ $_[0] }->pkgver( $_[1] ) | | 1792 | ? $self->{_pkgs}{ $_[0] }->pkgver( $_[1] ) |
1790 | : $self->{_pkgs}{ $_[0] }->pkgver(); | | 1793 | : $self->{_pkgs}{ $_[0] }->pkgver(); |
1791 | } | | 1794 | } |
1792 | return; | | 1795 | return; |
1793 | } | | 1796 | } |
1794 | | | 1797 | |
1795 | sub pkgs($@) { | | 1798 | sub pkgs($@) { |
1796 | my $self = shift; | | 1799 | my $self = shift; |
1797 | | | 1800 | |
1798 | if (@_) { | | 1801 | if (@_) { |
1799 | return $self->{_pkgs}{ $_[0] }; | | 1802 | return $self->{_pkgs}{ $_[0] }; |
1800 | } | | 1803 | } |
1801 | else { | | 1804 | else { |
1802 | return ( sort { $a->pkg cmp $b->pkg } values %{ $self->{_pkgs} } ); | | 1805 | return ( sort { $a->pkg cmp $b->pkg } values %{ $self->{_pkgs} } ); |
1803 | } | | 1806 | } |
1804 | return; | | 1807 | return; |
1805 | } | | 1808 | } |
1806 | | | 1809 | |
1807 | sub store($) { | | 1810 | sub store($) { |
1808 | my $self = shift; | | 1811 | my $self = shift; |
1809 | my @pkgs = keys %{ $self->{_pkgs} }; | | 1812 | my @pkgs = keys %{ $self->{_pkgs} }; |
1810 | my ( $cnt, $subcnt ) = $self->count; | | 1813 | my ( $cnt, $subcnt ) = $self->count; |
1811 | | | 1814 | |
1812 | print("\$pkgcnt = $cnt;\n"); | | 1815 | print("\$pkgcnt = $cnt;\n"); |
1813 | print("\$subpkgcnt = $subcnt;\n"); | | 1816 | print("\$subpkgcnt = $subcnt;\n"); |
1814 | map( $self->{_pkgs}{$_}->store, keys %{ $self->{_pkgs} } ); | | 1817 | map( $self->{_pkgs}{$_}->store, keys %{ $self->{_pkgs} } ); |
1815 | } | | 1818 | } |
1816 | | | 1819 | |
1817 | sub count($) { | | 1820 | sub count($) { |
1818 | my $self = shift; | | 1821 | my $self = shift; |
1819 | my ( $pkgcnt, $pkgsubcnt ); | | 1822 | my ( $pkgcnt, $pkgsubcnt ); |
1820 | | | 1823 | |
1821 | map { | | 1824 | map { |
1822 | $pkgcnt++; | | 1825 | $pkgcnt++; |
1823 | $pkgsubcnt += $self->{_pkgs}{$_}->count; | | 1826 | $pkgsubcnt += $self->{_pkgs}{$_}->count; |
1824 | } keys %{ $self->{_pkgs} }; | | 1827 | } keys %{ $self->{_pkgs} }; |
1825 | wantarray ? ( $pkgcnt, $pkgsubcnt ) : $pkgcnt; | | 1828 | wantarray ? ( $pkgcnt, $pkgsubcnt ) : $pkgcnt; |
1826 | } | | 1829 | } |
1827 | | | 1830 | |
1828 | # Pkgs is all versions of a given package (eg: apache-1.x and apache-2.x) | | 1831 | # Pkgs is all versions of a given package (eg: apache-1.x and apache-2.x) |
1829 | # | | 1832 | # |
1830 | package Pkgs; | | 1833 | package Pkgs; |
1831 | | | 1834 | |
1832 | sub add($@) { | | 1835 | sub add($@) { |
1833 | my $self = shift; | | 1836 | my $self = shift; |
1834 | | | 1837 | |
1835 | $self->{_pkgver}{ $_[1] } = new PkgVer @_; | | 1838 | $self->{_pkgver}{ $_[1] } = new PkgVer @_; |
1836 | } | | 1839 | } |
1837 | | | 1840 | |
1838 | sub new($@) { | | 1841 | sub new($@) { |
1839 | my $class = shift; | | 1842 | my $class = shift; |
1840 | my $self = {}; | | 1843 | my $self = {}; |
1841 | | | 1844 | |
1842 | bless $self, $class; | | 1845 | bless $self, $class; |
1843 | $self->{_pkg} = $_[0]; | | 1846 | $self->{_pkg} = $_[0]; |
1844 | return $self; | | 1847 | return $self; |
1845 | } | | 1848 | } |
1846 | | | 1849 | |
1847 | sub versions($) { | | 1850 | sub versions($) { |
1848 | my $self = shift; | | 1851 | my $self = shift; |
1849 | | | 1852 | |
1850 | return sort { $b cmp $a } keys %{ $self->{_pkgver} }; | | 1853 | return sort { $b cmp $a } keys %{ $self->{_pkgver} }; |
1851 | } | | 1854 | } |
1852 | | | 1855 | |
1853 | sub pkg($) { | | 1856 | sub pkg($) { |
1854 | my $self = shift; | | 1857 | my $self = shift; |
1855 | $self->{_pkg}; | | 1858 | $self->{_pkg}; |
1856 | } | | 1859 | } |
1857 | | | 1860 | |
1858 | sub pkgver($@) { | | 1861 | sub pkgver($@) { |
1859 | my $self = shift; | | 1862 | my $self = shift; |
1860 | | | 1863 | |
1861 | if (@_) { | | 1864 | if (@_) { |
1862 | if ( $self->{_pkgver}{ $_[0] } ) { | | 1865 | if ( $self->{_pkgver}{ $_[0] } ) { |
1863 | return ( $self->{_pkgver}{ $_[0] } ); | | 1866 | return ( $self->{_pkgver}{ $_[0] } ); |
1864 | } | | 1867 | } |
1865 | return; | | 1868 | return; |
1866 | } | | 1869 | } |
1867 | return sort { $b->ver() cmp $a->ver() } values %{ $self->{_pkgver} }; | | 1870 | return sort { $b->ver() cmp $a->ver() } values %{ $self->{_pkgver} }; |
1868 | } | | 1871 | } |
1869 | | | 1872 | |
1870 | sub latestver($) { | | 1873 | sub latestver($) { |
1871 | my $self = shift; | | 1874 | my $self = shift; |
1872 | | | 1875 | |
1873 | ( $self->pkgver() )[0]; | | 1876 | ( $self->pkgver() )[0]; |
1874 | } | | 1877 | } |
1875 | | | 1878 | |
1876 | sub store($) { | | 1879 | sub store($) { |
1877 | my $self = shift; | | 1880 | my $self = shift; |
1878 | | | 1881 | |
1879 | print("\$pkgnum++;\n"); | | 1882 | print("\$pkgnum++;\n"); |
1880 | map( $self->{_pkgver}{$_}->store, keys %{ $self->{_pkgver} } ); | | 1883 | map( $self->{_pkgver}{$_}->store, keys %{ $self->{_pkgver} } ); |
1881 | } | | 1884 | } |
1882 | | | 1885 | |
1883 | sub count($) { | | 1886 | sub count($) { |
1884 | my $self = shift; | | 1887 | my $self = shift; |
1885 | | | 1888 | |
1886 | scalar( keys %{ $self->{_pkgver} } ); | | 1889 | scalar( keys %{ $self->{_pkgver} } ); |
1887 | } | | 1890 | } |
1888 | | | 1891 | |
1889 | # PkgVer is a unique package+version | | 1892 | # PkgVer is a unique package+version |
1890 | # | | 1893 | # |
1891 | package PkgVer; | | 1894 | package PkgVer; |
1892 | | | 1895 | |
1893 | sub new($$$) { | | 1896 | sub new($$$) { |
1894 | my $class = shift; | | 1897 | my $class = shift; |
1895 | my $self = {}; | | 1898 | my $self = {}; |
1896 | | | 1899 | |
1897 | bless $self, $class; | | 1900 | bless $self, $class; |
1898 | $self->{_pkg} = $_[0]; | | 1901 | $self->{_pkg} = $_[0]; |
1899 | $self->{_ver} = $_[1]; | | 1902 | $self->{_ver} = $_[1]; |
1900 | return $self; | | 1903 | return $self; |
1901 | } | | 1904 | } |
1902 | | | 1905 | |
1903 | sub pkgname($) { | | 1906 | sub pkgname($) { |
1904 | my $self = shift; | | 1907 | my $self = shift; |
1905 | | | 1908 | |
1906 | $self->pkg . '-' . $self->ver; | | 1909 | $self->pkg . '-' . $self->ver; |
1907 | } | | 1910 | } |
1908 | | | 1911 | |
1909 | sub pkg($) { | | 1912 | sub pkg($) { |
1910 | my $self = shift; | | 1913 | my $self = shift; |
1911 | | | 1914 | |
1912 | $self->{_pkg}; | | 1915 | $self->{_pkg}; |
1913 | } | | 1916 | } |
1914 | | | 1917 | |
1915 | sub var($$$) { | | 1918 | sub var($$$) { |
1916 | my $self = shift; | | 1919 | my $self = shift; |
1917 | my ( $key, $val ) = @_; | | 1920 | my ( $key, $val ) = @_; |
1918 | | | 1921 | |
1919 | ( defined $val ) | | 1922 | ( defined $val ) |
1920 | ? ( $self->{$key} = $val ) | | 1923 | ? ( $self->{$key} = $val ) |
1921 | : $self->{$key}; | | 1924 | : $self->{$key}; |
1922 | } | | 1925 | } |
1923 | | | 1926 | |
1924 | sub ver($) { | | 1927 | sub ver($) { |
1925 | my $self = shift; | | 1928 | my $self = shift; |
1926 | | | 1929 | |
1927 | $self->{_ver}; | | 1930 | $self->{_ver}; |
1928 | } | | 1931 | } |
1929 | | | 1932 | |
1930 | sub vars($) { | | 1933 | sub vars($) { |
1931 | my $self = shift; | | 1934 | my $self = shift; |
1932 | | | 1935 | |
1933 | grep( !/^_(pkg|ver)$/, keys %{$self} ); | | 1936 | grep( !/^_(pkg|ver)$/, keys %{$self} ); |
1934 | } | | 1937 | } |
1935 | | | 1938 | |
1936 | sub store($) { | | 1939 | sub store($) { |
1937 | my $self = shift; | | 1940 | my $self = shift; |
1938 | my $data; | | 1941 | my $data; |
1939 | | | 1942 | |
1940 | ( $data = $self->{_pkg} ) =~ s/([\\\$\@\%\"])/\\$1/g; | | 1943 | ( $data = $self->{_pkg} ) =~ s/([\\\$\@\%\"])/\\$1/g; |
1941 | print("\$pkgver = \$pkglist->add(\"$data\", \""); | | 1944 | print("\$pkgver = \$pkglist->add(\"$data\", \""); |
1942 | | | 1945 | |
1943 | ( $data = $self->{_ver} ) =~ s/([\\\$\@\%\"])/\\$1/g; | | 1946 | ( $data = $self->{_ver} ) =~ s/([\\\$\@\%\"])/\\$1/g; |
1944 | print("$data\"); __pkgcount(1);\n"); | | 1947 | print("$data\"); __pkgcount(1);\n"); |
1945 | | | 1948 | |
1946 | foreach ( $self->vars ) { | | 1949 | foreach ( $self->vars ) { |
1947 | ( $data = $self->{$_} ) =~ s/([\\\$\@\%\"])/\\$1/g; | | 1950 | ( $data = $self->{$_} ) =~ s/([\\\$\@\%\"])/\\$1/g; |
1948 | print("\$pkgver->var(\"$_\", \"$data\");\n"); | | 1951 | print("\$pkgver->var(\"$_\", \"$data\");\n"); |
1949 | } | | 1952 | } |
1950 | } | | 1953 | } |
1951 | | | 1954 | |
1952 | package main; | | 1955 | package main; |
1953 | | | 1956 | |
1954 | main(); | | 1957 | main(); |