pkg-get/scripts/pkg-repgen.pl

346 lines
10 KiB
Perl
Executable File

#!/usr/bin/env perl
#
# pkg-repgen: generates a binary repository for pkg-get
#
# requires prt-get
#
# html index generation code adapted from Jukka Heino's portspage
#
# usage: pkg-repgen [<pkgname1>..<pkgnameN>]
#
use warnings;
use strict;
use Getopt::Long;
use Digest::file qw(digest_file_hex);
our $prtget = "/usr/bin/prt-get"; our $prtdir;
our $title = "CRUX Packages"; our $header; our $footer;
GetOptions("prtdir=s"=>\$prtdir, "title=s"=>\$title, "header=s"=>\$header, "footer=s"=>\$footer);
# Use compression-mode defined in pkgmk-conf
our $compress = "gz";
open CONFIG, "/etc/pkgmk.conf" or die "Could not open /etc/pkgmk.conf";
while (<CONFIG>) {
$compress = $1 if m/^PKGMK_COMPRESSION_MODE=(.*)(\#|$)/;
}
close CONFIG;
$compress =~ s/["' ]//g;
$prtget .= " --no-std-config --config-set=\"prtdir $prtdir\"" if ($prtdir);
my @dirlist = glob("*#*.pkg.tar.$compress"); my @packages;
if ($#ARGV >= 0) { # single packages
foreach my $pkgname (@ARGV) {
my @hits = sort grep { /^$pkgname\#/ } @dirlist;
push(@packages,$hits[-1]) if (@hits);
}
} else {
@packages = @dirlist;
}
# Populate hashes using a single run of prt-get
our %path; our %depends; our %descrip; our %flags;
my @validkeys = @dirlist;
map { s/\#.*// } @validkeys;
my %printme = map { $_ => 1 } @validkeys;
open (my $ppf, "$prtget printf '%n^%p^%e^%d^%E:%O:%R\n' |");
while (<$ppf>) {
chomp;
my ($name,$repo,$deps,$desc,$prepostread) = split /\^/;
next if (! $printme{$name});
$path{$name} = $repo . "/" . $name;
$depends{$name} = $deps;
$desc =~ s/\:/ /g;
$descrip{$name} = $desc;
$flags{$name} = $prepostread;
}
close ($ppf);
# Needed for alternating colors in the html index
my %parity = ( 0 => "even", 1 => "odd" );
# Generate the metadata files
($#ARGV >= 0) ? pkg_single() : pkg_dir();
# Generate README and PKGINST
pkgreadscripts();
######################## individual packages ########################
sub pkg_single {
my ($pname, $dbO, $oname, $pdeps, $desc, $du, $md5, $ppr);
my $count = 0; my ($pver, $url, $date); # needed for the html index
foreach my $db ("PKGREPO", "PKGDEPS", "index.html") {
my $firstrun = 0; my $dbNew;
my $status = "+ Generating ";
if ($db eq "PKGREPO") {
$status .= "repository\n";
} elsif ($db eq "PKGDEPS") {
$status .= "dependencies\n";
} else {
$status .= "html index\n";
}
print $status;
open (my $dbOld, "$db") or $firstrun=1;
if ( ($firstrun == 1) and ($db eq "index.html") ) {
printheader();
rename($db, "$db.new");
open ($dbNew, ">>$db.new");
} else {
open ($dbNew, ">$db.new");
}
PACKAGE: foreach my $p (sort @packages) {
$count++ if ($db eq "index.html");
$pname = $p; $pver = $p;
$pname =~ s/#.*//; $pver =~ s/.*#(.*)\.pkg\.tar\.*/$1/;
if ($db eq "PKGREPO") {
$du = (-s $p);
$md5 = digest_file_hex($p,"MD5");
$desc = (! $descrip{$pname}) ? "N.A." : $descrip{$pname};
$ppr = (! $flags{$pname}) ? "no:no:no" : $flags{$pname};
printf $dbNew "%-s:%-s:%-s:%-s:%-s\n",
$p, $du, $md5, $desc, $ppr if ($firstrun == 1);
} elsif ($db eq "PKGDEPS") {
$pdeps = (! $depends{$pname}) ? "" : $depends{$pname};
printf $dbNew "%-30s:%s\n", $pname, $pdeps if ($firstrun == 1);
} else {
$date = isotime( (stat($p))[9], 1);
$url = $p;
$url =~ s/\#/\%23/;
htmlrow($dbNew,$parity{($count % 2)},$pname,$url,$pver,
$descrip{$pname},$date) if ($firstrun == 1);
}
next PACKAGE if ($firstrun == 1);
while ($dbO = <$dbOld>) {
chomp($dbO);
if (($db eq "index.html") and ($dbO !~ m/^<tr class/)) {
# Try to ensure that header lines are copied verbatim,
# by exploiting the alphabetical sorting below.
# Not guaranteed to work with every locale!
$oname = " 0";
} else {
# should be able to extract the old pkg name from this line
$oname = $dbO;
$oname =~ s/\s*\:.*// if ($db eq "PKGDEPS");
$oname =~ s/(.*)\#.*pkg\.tar.*/$1/ if ($db eq "PKGREPO");
$oname =~ s/.*a href="(.*)\%23.*/$1/ if ($db eq "index.html");
$count++ if ($db eq "index.html");
}
if ($oname lt $pname) {
print $dbNew "$dbO\n";
} elsif (($oname ge $pname) and ($db eq "PKGREPO")) {
printf $dbNew "%-s:%-s:%-s:%-s:%-s\n", $p, $du, $md5, $desc, $ppr;
} elsif (($oname ge $pname) and ($db eq "PKGDEPS")) {
printf $dbNew "%-30s:%s\n", $pname, $pdeps
} else {
# either overwrite the old entry in the html index,
# or insert this entry before the first line that
# would come after $p when sorted alphabetically.
htmlrow($dbNew,$parity{($count % 2)},$pname,$url,$pver,
$descrip{$pname},$date);
}
print $dbNew "$dbO\n" if ($oname gt $pname);
last if ($oname ge $pname);
}
}
while ( ($firstrun != 1) and ($dbO = <$dbOld>) ) {
if ($db eq "index.html") {
$count++;
$dbO =~ s/class="(even|odd)"/class="$parity{($count % 2)}"/;
}
print $dbNew $dbO;
}
close($dbNew);
($firstrun == 1) or close($dbOld);
rename("$db.new", "$db");
printfooter($count) if (($firstrun == 1) and ($db eq "index.html"));
}
}
######################## full repository ########################
sub pkg_dir {
print "+ Generating dependencies\n";
open (my $iD, ">PKGDEPS");
print "+ Generating repository\n";
open (my $iR, ">PKGREPO");
printheader();
my $count = 0;
open (my $ih, '>>index.html');
foreach my $p (@packages) {
chomp($p);
my $date = isotime( (stat($p))[9], 1);
$count++;
my ($name, $version, $url) = ($p, $p, $p);
$name =~ s/\#.*//;
$version =~ s/^.*\#//;
$version =~ s/\.pkg\.tar\.[gbx]z*//;
$url =~ s/\#/\%23/;
if (($depends{$name}) and ($depends{$name} ne "")) {
printf $iD "%-30s : %-s\n", $name, $depends{$name};
}
my $du = (-s $p);
my $md5 = digest_file_hex($p,"MD5");
if (! $descrip{$name}) {$descrip{$name} = "N.A.";}
if (! $flags{$name}) { $flags{$name} = "no:no:no"; }
printf $iR "%-s:%-s:%-s:%-s:%-s\n", $p,$du,$md5,$descrip{$name},$flags{$name};
htmlrow($ih,$parity{($count % 2)},$name,$url, $version,$descrip{$name},$date);
}
close($ih);
printfooter($count);
close($iR);
close($iD);
}
# consolidate all the README and install scripts for the available packages
sub pkgreadscripts {
print "+ Generating README\n";
open (my $fR, '>PKGREAD');
print $fR "# README files for repository. Do NOT remove this line.\n";
print "+ Generating scripts\n";
open (my $fS, '>PKGINST');
print $fS '#!/usr/bin/env bash
#
# PKGINST: pre- and post-install scripts for CRUX packages
#
run_script() {
case "$1" in
';
foreach my $name (sort @dirlist) {
$name =~ s/\#.*//;
if (-f "$path{$name}/README"){
print $fR "##### PKGREADME: $name\n";
open(my $readme, "$path{$name}/README");
while (<$readme>){ print $fR $_; }
close($readme);
}
foreach my $when ("pre", "post") {
if (-f "$path{$name}/${when}-install"){
print $fS " $name.$when)\n";
open(my $rs, "$path{$name}/${when}-install");
while (<$rs>){
chomp;
print $fS " $_\n"
unless (m/^\#(!.*sh|\s*EOF|\s*End)/);
}
close($rs);
print $fS " ;;\n";
}
}
}
print $fS " esac\n}\n\n";
print $fS '[ "$1" ] && [[ "$2" == @(pre|post) ]] && run_script "$1.$2"';
print $fS "\n";
close $fS;
close $fR;
}
######################## html index subs ########################
sub printheader {
open (my $ih, '>index.html');
print $ih <<EOH;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
EOH
print $ih " <title>$title</title>\n";
print $ih <<EOH;
<style type="text/css">
body
{
font-family: Verdana, sans-serif;
font-size: 85%;
padding: 2em;
}
a
{
color: #67550d;
}
table
{
border: solid #e5dccf 1px;
font-size: 85%;
}
td
{
padding: 6px;
}
tr.header
{
background-color: #e5dccf;
}
tr.odd
{
background-color: #f7f3ed;
}
tr.even
{
background-color: #fcf9f8;
}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
</head>
<body>
EOH
print $ih " <h2>$title</h2>\n";
if ($header) {
open(FILE, $header) or die "Couldn't open header file";
while (<FILE>) { print $ih " " . $_; }
close(FILE);
}
print $ih " <table width=\"100%\" cellspacing=\"0\">\n";
print $ih " <tr class=\"header\"><td><b>Port</b></td><td><b>Version</b></td><td><b>Description</b></td>";
print $ih "<td><b>Last modified</b></td>";
print $ih "</tr>\n";
close($ih);
}
sub htmlrow {
my ($ih, $odd, $name, $url, $version, $desc, $date) = @_;
print $ih "<tr class=\"$odd\"><td>$name</td>";
print $ih "<td><a href=\"$url\">$version</a></td>";
print $ih "<td>$desc</td><td>$date</td></tr>\n";
}
sub printfooter {
my $count = $_[0];
open (my $ih, '>>index.html');
print $ih " </table>\n";
print $ih " <p><b>$count packages</b></p>\n";
if ($footer) {
open(FILE, $footer) or die "Couldn't open footer file";
while (<FILE>) { print $ih " " . $_; }
close(FILE);
}
print $ih " <p><i>Generated by <a href=\"http://www.varlock.com\">pkg-repgen</a> on " . isotime() . ".</i></p>\n";
print $ih <<EOH;
</body>
</html>
EOH
close($ih);
}
sub isotime {
my $time = (shift or time);
my $accuracy = (shift or 2);
my @t = gmtime ($time);
my $year = $t[5] + 1900;
my $month = sprintf("%02d", $t[4] + 1);
my $day = sprintf("%02d", $t[3]);
return "$year-$month-$day" if ($accuracy == 1);
return "$year-$month-$day " . sprintf("%02d:%02d:%02d UTC", $t[2], $t[1], $t[0]);
}