1 #!/usr/bin/perl -w
2
3 our $version = "1.0.5";
4
5 ########################################################################
6 #
7 # portspage
8 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 # This is a script for generating CRUX port listings.
10 # Distributed under the terms of the GPL license.
11 # Report bugs and suggestions to jmcquah at disroot dot org.
12 #
13 # Changelog:
14 # 1.0.5
15 # - Added a table row containing the signify public key
16 # 1.0.4
17 # - Added --date-from-pkgfile (patch from Mikhail Kolesnik)
18 # 1.0.3
19 # - Fixed a problem with tabs in Pkgfile
20 # 1.0.2
21 # - Might as well make it XHTML 1.1
22 # 1.0.1
23 # - Output is now valid XHTML 1.0 Strict
24 #
25 ########################################################################
26
27 use strict;
28 use Cwd qw(cwd getcwd);
29
30 our %options =
31 (
32 title => "CRUX ports",
33 timestamp_accuracy => 1,
34 date_from_file => 0,
35 );
36
37 sub print_usage
38 {
39 print <<EOT;
40 Usage: portspage [OPTION]... [DIRECTORY]
41
42 --title=TITLE set the page title
43 --header=FILE name of file to insert before port listing
44 --footer=FILE name of file to insert after port listing
45 --timestamp-accuracy=LEVEL 0 = no timestamp, 1 = date only, 2 = date and time
46 default is 1
47 --date-from-file take date from newest file instead of directory
48 --date-from-pkgfile take date from Pkgfile instead of directory
49 --version output version information and exit
50
51 Report bugs to <jukka\@karsikkopuu.net>.
52 EOT
53 }
54
55 sub parse_args
56 {
57 foreach my $arg (@ARGV)
58 {
59 if ($arg =~ /^--header=(.*)$/)
60 {
61 $options{header} = $1;
62 }
63 elsif ($arg =~ /^--footer=(.*)$/)
64 {
65 $options{footer} = $1;
66 }
67 elsif ($arg =~ /^--title=(.*)$/)
68 {
69 $options{title} = $1;
70 }
71 elsif ($arg =~ /^--timestamp-accuracy=(0|1|2)$/)
72 {
73 $options{timestamp_accuracy} = $1;
74 }
75 elsif ($arg =~ /^--date-from-file$/)
76 {
77 $options{date_from_file} = 1;
78 }
79 elsif ($arg =~ /^--date-from-pkgfile$/)
80 {
81 $options{date_from_pkgfile} = 1;
82 }
83 elsif ($arg =~ /^--version$/)
84 {
85 print "$version\n";
86 exit 0;
87 }
88 elsif ($arg =~ /^--help$/)
89 {
90 print_usage();
91 exit 0;
92 }
93 else
94 {
95 $options{directory} = $arg;
96 }
97 }
98 }
99
100 sub recurse_tree
101 {
102 my $path = shift;
103 my @list;
104
105 while ($path =~ s/\/\//\//g) {}
106 $path =~ s/\/$//;
107
108 opendir(DIR, $path) or return;
109 ENTRY:
110 foreach my $entry(sort(readdir(DIR)))
111 {
112 next ENTRY if $entry eq ".";
113 next ENTRY if $entry eq "..";
114 push (@list, "$path/$entry") if -f "$path/$entry";
115 push (@list, recurse_tree("$path/$entry")) if -d "$path/$entry";
116 }
117
118 return @list;
119 }
120
121 sub parse_pkgfile
122 {
123 my %parsed;
124 my $pkgfile = shift;
125
126 if (open (FILE, $pkgfile))
127 {
128 while (<FILE>)
129 {
130 if ($_ =~ /^#\s*(.*?):\s*(.*)$/)
131 {
132 my $key = $1;
133 my $value = $2;
134 $value =~ s/</</g;
135 $value =~ s/>/>/g;
136 $value =~ s/&/&/g;
137 $parsed{$key} = $value;
138 }
139 elsif ($_ =~ /^version=(.*)$/)
140 {
141 $parsed{version} = $1;
142 }
143 elsif ($_ =~ /^release=(.*)$/)
144 {
145 $parsed{release} = $1;
146 }
147 }
148 close (FILE);
149 }
150
151 return { %parsed };
152 }
153
154 sub main
155 {
156 my %db;
157
158 parse_args();
159
160 if (!$options{directory})
161 {
162 print_usage();
163 return 0;
164 }
165
166 foreach my $file (recurse_tree($options{directory}))
167 {
168 if ($file =~ q:.*/(.*)/Pkgfile$:)
169 {
170 $db{$1} = parse_pkgfile("$file");
171 }
172 }
173
174 print <<EOH;
175 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
176 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
177
178 <html xmlns="http://www.w3.org/1999/xhtml">
179 <head>
180 EOH
181
182 print " <title>$options{title}</title>\n";
183
184 print <<EOH;
185 <style type="text/css">
186 body
187 {
188 font-family: Verdana, sans-serif;
189 font-size: 85%;
190 padding: 2em;
191 }
192 a
193 {
194 color: black;
195 }
196 table
197 {
198 border: solid #CAD4E9 1px;
199 font-size: 85%;
200 }
201 td
202 {
203 padding: 6px;
204 }
205 tr.header
206 {
207 background-color: #CAD4E9;
208 }
209 tr.odd
210 {
211 background-color: #ECF0F7;
212 }
213 tr.even
214 {
215 background-color: #F7F9FC;
216 }
217 </style>
218 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
219 </head>
220 <body>
221 EOH
222
223 print " <h2>$options{title}</h2>\n";
224
225 if ($options{header})
226 {
227 open(FILE, $options{header}) or die "Couldn't open header file";
228 while (<FILE>)
229 {
230 print " " . $_;
231 }
232 close(FILE);
233 }
234
235
236
237
238 print " <table width=\"100%\" cellspacing=\"0\">\n";
239 my $CWD = getcwd;
240 my @repopath = split /\//, $CWD;
241 my $repo = $repopath[$#repopath];
242 my $pubkey = "/etc/ports/".$repo.".pub";
243 if (-e $pubkey) {
244 open(KH, $pubkey) or die "Couldn't read from public key!";
245 while (my $line = <KH>) {
246 chomp $line;
247 if ($line =~ "untrusted comment") {
248 }
249 else {
250 print " <tr class=\"header\"><td colspan=\"4\">\n";
251 print " <strong>Signify public key:</strong> $line\n";
252 print " </td></tr>\n";
253 }
254 }
255 close(KH);
256 }
257 print " <tr class=\"header\"><td><b>Port</b></td><td><b>Version</b></td><td><b>Description</b></td>";
258 if ($options{timestamp_accuracy} > 0)
259 {
260 print "<td><b>Last modified</b></td>";
261 }
262 print "</tr>\n";
263 our $odd = "odd";
264 my $count = 0;
265 foreach my $port (sort keys %db)
266 {
267 $count++;
268 print " <tr class=\"$odd\"><td>";
269 $db{$port}{URL} ? print "<a href=\"$db{$port}{URL}\">$port</a>" : print "$port";
270 print "</td><td><a href=\"$options{directory}/$port/\">$db{$port}{version}-$db{$port}{release}</a></td><td>";
271 print $db{$port}{Description} if $db{$port}{Description};
272 print "</td>";
273
274 if ($options{timestamp_accuracy} > 0)
275 {
276 my $date;
277
278 if ($options{date_from_file})
279 {
280 my @files = recurse_tree("$options{directory}/$port");
281 my @dates;
282 foreach my $file (@files)
283 {
284 push (@dates, (stat($file))[9]);
285 }
286 @dates = sort @dates;
287 $date = $dates[$#dates];
288
289 }
290 elsif ($options{date_from_pkgfile})
291 {
292 $date = (stat("$options{directory}/$port/Pkgfile"))[9];
293 }
294 else
295 {
296 $date = (stat("$options{directory}/$port"))[9];
297 }
298
299 print "<td>" . isotime($date, $options{timestamp_accuracy}) . "</td>";
300 }
301
302 print "</tr>\n";
303
304 if ($odd eq "odd") { $odd = "even"; }
305 else { $odd = "odd"; }
306 }
307 print " </table>\n";
308 print " <p><b>$count ports</b></p>\n";
309
310 if ($options{footer})
311 {
312 open(FILE, $options{footer}) or die "Couldn't open footer file";
313 while (<FILE>)
314 {
315 print " " . $_;
316 }
317 close(FILE);
318 }
319
320 print " <p><i>Generated by portspage $version on " . isotime() . ".</i></p>\n";
321
322 print <<EOH;
323 </body>
324 </html>
325 EOH
326
327 return 0;
328 }
329
330 sub isotime
331 {
332 my $time = (shift or time);
333 my $accuracy = (shift or 2);
334 my @t = gmtime ($time);
335 my $year = $t[5] + 1900;
336 my $month = sprintf("%02d", $t[4] + 1);
337 my $day = sprintf("%02d", $t[3]);
338
339 if ($accuracy == 1)
340 {
341 return "$year-$month-$day";
342 }
343
344 return "$year-$month-$day " . sprintf("%02d:%02d:%02d UTC", $t[2], $t[1], $t[0]);
345 }
346
347 exit(main());
348
349 # End of file
|