diff --git a/schema.sql b/sql/schema.sql similarity index 80% rename from schema.sql rename to sql/schema.sql index f198da6..f597797 100644 --- a/schema.sql +++ b/sql/schema.sql @@ -1,9 +1,3 @@ - --- TODO: "system" -> "repository"? --- TODO: index of (reverse) man page references? --- TODO: Use some consistent naming of tables and columns - - CREATE TABLE systems ( id integer PRIMARY KEY, -- hardcoded ID. name varchar NOT NULL, @@ -12,52 +6,49 @@ CREATE TABLE systems ( short varchar NOT NULL ); - CREATE TABLE contents ( hash bytea PRIMARY KEY, content varchar NOT NULL ); - --- Note: If there are multiple arches available for the same package, then --- generally only a single one is chosen (not stored here which one). --- Also, a package may be listed here even if it has no man pages indexed, in --- order for the fetcher to determine whether it has already processed the --- package or not. This doesn't mean all packages of a repository are listed --- here. For example, the Arch fetcher checks the file list of a package before --- considering to handle it. -CREATE TABLE package ( +CREATE TABLE packages ( id SERIAL PRIMARY KEY, system integer NOT NULL REFERENCES systems(id), - category varchar, -- depends on system (e.g. "community" on Arch, "x11" on Debian) + category varchar, name varchar NOT NULL, - version varchar NOT NULL, - released date NOT NULL, - UNIQUE(system, name, version) + UNIQUE(system, name, category) -- Note the order, lookups on (system,name) are common ); +CREATE TABLE package_versions ( + id SERIAL PRIMARY KEY, + package integer NOT NULL REFERENCES packages(id), + version varchar NOT NULL, + released date NOT NULL, + UNIQUE(package, version) +); CREATE TABLE man ( - package integer NOT NULL REFERENCES package(id), - name varchar NOT NULL, -- 'fopen', 'du', etc (TODO: An index on name_from_filename(filename) may also work) - section varchar NOT NULL, -- extracted from filename (TODO: Is this column really necessary?) - filename varchar NOT NULL, -- full path + file name - locale varchar, -- parsed from the file name, NULL for the "main" man page (in the C or en_US locale) + package integer NOT NULL REFERENCES package_versions(id), + name varchar NOT NULL, + section varchar NOT NULL, + filename varchar NOT NULL, + locale varchar, hash bytea NOT NULL REFERENCES contents(hash), UNIQUE(package, filename) ); - -CREATE INDEX ON man USING hash (hash); +CREATE INDEX ON man (hash); CREATE INDEX ON man (name); + CREATE TABLE man_index AS SELECT DISTINCT name, section FROM man; CREATE INDEX ON man_index USING btree(lower(name) text_pattern_ops); CREATE TABLE stats_cache AS SELECT count(distinct hash) AS hashes, count(distinct name) AS mans, count(*) AS files, count(distinct package) AS packages FROM man; + INSERT INTO systems (id, name, release, short, relorder) VALUES (1, 'Arch Linux', NULL, 'arch', 0), (2, 'Ubuntu', '4.10', 'ubuntu-warty', 0), @@ -153,6 +144,7 @@ INSERT INTO systems (id, name, release, short, relorder) VALUES (92, 'Ubuntu', '15.10', 'ubuntu-wily', 22), (93, 'Ubuntu', '16.04', 'ubuntu-xenial', 23); + -- Removes any path components and compression extensions from the filename. CREATE OR REPLACE FUNCTION basename_from_filename(fn text) RETURNS text AS $$ DECLARE @@ -178,16 +170,3 @@ $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION name_from_filename(text) RETURNS text AS $$ SELECT regexp_replace(basename_from_filename($1), E'^(.+)\\.[^.]+$', E'\\1'); $$ LANGUAGE SQL; - - - - --- Some handy admin queries - ---BEGIN; ---DELETE FROM man WHERE package IN(SELECT id FROM package WHERE name = ''); ---DELETE FROM package WHERE name = ''; ---DELETE FROM contents c WHERE NOT EXISTS(SELECT 1 FROM man m WHERE m.hash = c.hash); ---COMMIT; - ---DELETE FROM package WHERE system = 18 AND NOT EXISTS(SELECT 1 FROM man WHERE id = package); diff --git a/sql/update-2016-10-02.sql b/sql/update-2016-10-02.sql new file mode 100644 index 0000000..a669314 --- /dev/null +++ b/sql/update-2016-10-02.sql @@ -0,0 +1,30 @@ +CREATE TABLE packages ( + id SERIAL PRIMARY KEY, + system integer NOT NULL REFERENCES systems(id), + category varchar, + name varchar NOT NULL, + UNIQUE(system, name, category) -- Note the order, lookups on (system,name) are common +); + +CREATE TABLE package_versions ( + id SERIAL PRIMARY KEY, + package integer NOT NULL REFERENCES packages(id), + version varchar NOT NULL, + released date NOT NULL, + UNIQUE(package, version) +); + +INSERT INTO packages (system, category, name) SELECT system, category, name FROM package GROUP BY system, category, name; +INSERT INTO package_versions (id, package, version, released) + SELECT p.id, pn.id, p.version, p.released FROM package p JOIN packages pn ON pn.system = p.system AND pn.category = p.category AND pn.name = p.name; + +SELECT setval('package_versions_id_seq', nextval('package_id_seq')); + +ALTER TABLE man DROP CONSTRAINT man_package_fkey; +ALTER TABLE man ADD FOREIGN KEY (package) REFERENCES package_versions(id); + +-- Use a proper b-tree index +DROP INDEX man_hash_idx; +CREATE INDEX ON man (hash); + +-- DROP TABLE package; diff --git a/util/common.sh b/util/common.sh index f30ee18..668bad4 100644 --- a/util/common.sh +++ b/util/common.sh @@ -11,13 +11,18 @@ trap "rm -rf $TMP" EXIT # Usage: add_pkginfo sysid category name version date # Returns 0 if the package is already in the database or if an error occured. -# Otherwise adds the package, sets PKGID to the new ID, and returns 1. +# Otherwise adds the package, sets PKGID to the new package_versions.id, and returns 1. PKGID= add_pkginfo() { - RES=`echo "SELECT id FROM package WHERE system = :'sysid' AND name = :'name' AND version = :'ver'"\ - | $PSQL -v "sysid=$1" -v "name=$3" -v "ver=$4"` + RES=`echo "SELECT pv.id FROM packages p JOIN package_versions pv ON pv.package = p.id + WHERE p.system = :'sysid' AND p.category = :'cat' AND p.name = :'name' AND pv.version = :'ver'"\ + | $PSQL -v "sysid=$1" -v "cat=$2" -v "name=$3" -v "ver=$4"` [ "$?" -ne 0 -o -n "$RES" ] && return 0 - RES=`echo "INSERT INTO package (system, category, name, version, released) VALUES(:'sysid',:'cat',:'name',:'ver',:'rel') RETURNING id"\ + RES=`echo " + INSERT INTO packages (system, category, name) VALUES(:'sysid', :'cat', :'name') ON CONFLICT DO NOTHING; + INSERT INTO package_versions (version, released, package) VALUES(:'ver', :'rel', + (SELECT packages.id FROM packages WHERE system = :'sysid' AND category = :'cat' AND name = :'name')) + RETURNING id"\ | $PSQL -v "sysid=$1" -v "cat=$2" -v "name=$3" -v "ver=$4" -v "rel=$5"` [ "$?" -ne 0 ] && return 0 PKGID=$RES diff --git a/util/deb.sh b/util/deb.sh index 6d918fa..6ed77ab 100755 --- a/util/deb.sh +++ b/util/deb.sh @@ -31,11 +31,10 @@ checkpkg() { DATE=`date -d "$DATE" +%F` # Insert package in the database - PKGID=`echo "INSERT INTO package (system, category, name, version, released) VALUES(:'sysid',:'cat',:'name',:'ver',:'rel') RETURNING id"\ - | $PSQL -v "sysid=$SYSID" -v "cat=$SECTION" -v "name=$NAME" -v "ver=$VERSION" -v "rel=$DATE"` + add_pkginfo $SYSID $SECTION $NAME $VERSION $DATE # Extract and handle the man pages - if [ "$?" -eq 0 -a -n "$PKGID" ]; then + if [ "$?" -eq 1 -a -n "$PKGID" ]; then # Old format if [ "`head -c8 \"$FN\"`" = "0.939000" ]; then tail -n+3 "$FN" | tail -c+"`head -n2 \"$FN\" | tail -n1`" | tail -c+2 | add_tar - $PKGID -z @@ -116,11 +115,13 @@ syncrepo() { if($p && $v && $s && $f) { $f =~ s{^(Debian-1.[12])/}{dists/$1/main/}; print "$p $v $s $f" if $pkg{$p} && $pkg{$p} == 1 - && !$db->selectrow_arrayref(q{SELECT 1 FROM package WHERE system = ? AND name = ? AND version = ?}, {}, $sysid, $p, $v); + && !$db->selectrow_arrayref(q{ + SELECT 1 FROM packages p JOIN package_versions pv ON pv.package = p.id + WHERE p.system = ? AND p.category = ? AND p.name = ? AND pv.version = ?}, {}, $sysid, $s, $p, $v); #warn "Duplicate package? $p\n" if $pkg{$p} && $pkg{$p} == 2; $pkg{$p} = 2; } - $p=$v=$f=undef + $p=$v=$f=$s=undef } } close F; diff --git a/util/freebsd.sh b/util/freebsd.sh index e4427a9..4ff7014 100755 --- a/util/freebsd.sh +++ b/util/freebsd.sh @@ -52,8 +52,7 @@ check_pkg() { # return fi - PKGID=`echo "INSERT INTO package (system, category, name, version, released) VALUES(:'sysid',:'cat',:'name',:'ver',:'rel') RETURNING id"\ - | $PSQL -v "sysid=$SYSID" -v "cat=$CAT" -v "name=$NAME" -v "ver=$VER" -v "rel=$DATE"` + add_pkginfo $SYSID $CAT $NAME $VER $DATE add_tar "$TMP/$FN" $PKGID rm -f "$TMP/$FN" } @@ -84,8 +83,8 @@ check_pkgdir() { # echo "== Error fetching package index for /$CAT/" continue fi - perl -l - "$TMP/pkgnames" "$TMP/pkglist" $SYSID <<'EOP' >"$TMP/newpkgs" - ($names, $list, $sysid) = @ARGV; + perl -l - "$TMP/pkgnames" "$TMP/pkglist" $SYSID $CAT <<'EOP' >"$TMP/newpkgs" + ($names, $list, $sysid, $cat) = @ARGV; use DBI; $db = DBI->connect('dbi:Pg:dbname=manned', 'manned', '', {RaiseError => 1}); @@ -103,7 +102,9 @@ check_pkgdir() { # if(!$n || !$names{$n} || !$v) { warn "== Unknown package: $c\n"; } else { - print "$c $n $v" if !$db->selectrow_arrayref(q{SELECT 1 FROM package WHERE system = ? AND name = ? AND version = ?}, {}, $sysid, $n, $v); + print "$c $n $v" if !$db->selectrow_arrayref(q{ + SELECT 1 FROM packages p JOIN package_versions pv ON pv.package = p.id + WHERE p.system = ? AND p.category = ? AND p.name = ? AND pv.version = ?}, {}, $sysid, $cat, $n, $v); } } close F; @@ -720,15 +721,7 @@ f9_1() { } f9_2() { - MIR="http://ftp.dk.freebsd.org/pub/FreeBSD/releases/i386/9.2-RELEASE/" - echo "============ $MIR" - check_dist 86 "$MIR/base.txz" "core-base" "2013-09-27" - check_dist 86 "$MIR/games.txz" "core-games" "2013-09-27" - check_pkgdir 86 "$MIR/packages" -} - -f9_3() { - MIR="http://ftp.dk.freebsd.org/pub/FreeBSD/releases/i386/9.2-RELEASE/" + MIR="http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/9.2-RELEASE/" echo "============ $MIR" check_dist 86 "$MIR/base.txz" "core-base" "2013-09-27" check_dist 86 "$MIR/games.txz" "core-games" "2013-09-27" diff --git a/www/index.pl b/www/index.pl index aea587f..523a6f7 100755 --- a/www/index.pl +++ b/www/index.pl @@ -46,8 +46,23 @@ TUWF::register( qr// => \&home, qr{info/about} => \&about, qr{browse/search} => \&browsesearch, - qr{browse/([^/]+)} => \&browsesys, - qr{browse/([^/]+)/([^/]+)(?:/([^/]+))?} => \&browsepkg, + + qr{pkg/([^/]+)} => \&pkg_list, + # pkg/$system/$category/$name (/$version); $category may contain a slash, too. + qr{pkg/([^/]+)/(.+)?} => \&pkg_info, + + # Redirects for old URLs. + # /browse/ has been moved to /pkg/ with the package category added to the path + qr{browse/([^/]+)} => sub { $_[0]->resRedirect("/pkg/$_[1]", 'perm'); }, + qr{browse/([^/]+)/([^/]+)(?:/([^/]+))?} => sub { + my($self, $sys, $name, $ver) = @_; + $sys = $self->{sysbyshort}{$sys}; + return $self->resNotFound if !$sys; + my $pkgs = $self->dbPackageGet(sysid => $sys->{id}, name => $name, results => 1); + return $self->resNotFound if !@$pkgs; + $self->resRedirect("/pkg/$sys->{short}/$pkgs->[0]{category}/$name".($ver ? "/$ver" :''), 'perm'); + }, + qr{xml/search\.xml} => \&xmlsearch, qr{([^/]+)/([0-9a-f]{8})} => \&man, qr{([^/]+)/([0-9a-f]{8})/src} => \&src, @@ -82,13 +97,13 @@ sub home { $sys = $sys{$sys}; (my $img = $sys->[0]{short}) =~ s/^(.+)-.+$/$1/; li; - a href => "/browse/$sys->[0]{short}" if @$sys == 1; + a href => "/pkg/$sys->[0]{short}" if @$sys == 1; span style => "background-image: url('images/$img.png')", ''; b $sys->[0]{name}; if(@$sys > 1) { my $i = 0; for(reverse @$sys) { - a href => "/browse/$_->{short}", ++$i > 3 ? (class => 'hidden') : (), $_->{release}; + a href => "/pkg/$_->{short}", ++$i > 3 ? (class => 'hidden') : (), $_->{release}; lit ' '; } a href => "#", class => 'more', 'more...' if $i > 3; @@ -272,7 +287,7 @@ sub browsesearch { } -sub browsesys { +sub pkg_list { my($self, $short) = @_; my $sys = $self->{sysbyshort}{$short}; @@ -284,7 +299,7 @@ sub browsesys { ); return $self->resNotFound if $f->{_err}; - my $pkg = $self->dbPackageList( + my $pkg = $self->dbPackageGet( hasman => 1, sysid => $sys->{id}, char => $f->{c} eq 'all' ? undef : $f->{c}, @@ -299,7 +314,7 @@ sub browsesys { use utf8; if($more) { p class => 'pagination'; - a href => "/browse/$short?c=$f->{c};s=$pkg->[199]{name}", 'next »'; + a href => "/pkg/$short?c=$f->{c};s=$pkg->[199]{name}", 'next »'; end; } }; @@ -310,7 +325,7 @@ sub browsesys { p id => 'charselect'; for('all', 0, 'a'..'z') { - a href => "/browse/$short?c=$_", $_?uc$_:'#' if $_ ne $f->{c}; + a href => "/pkg/$short?c=$_", $_?uc$_:'#' if $_ ne $f->{c}; b $_?uc$_:'#' if $_ eq $f->{c}; } end; @@ -320,7 +335,7 @@ sub browsesys { ul id => 'packages'; for(@$pkg) { li; - a href => "/browse/$short/$_->{name}", $_->{name}; + a href => "/pkg/$short/$_->{category}/$_->{name}", $_->{name}; i ' '.$_->{category}; end; } @@ -330,14 +345,44 @@ sub browsesys { } -sub browsepkg { - my($self, $short, $name, $ver) = @_; +sub pkg_frompath { + my($self, $sys, $path) = @_; + + # $path should be "$category/$name" or "$category/$name/$version", since + # $category may contain a slash, let's try both options. + + # $category/$name + # e.g. contrib/games/alien + if($path =~ m{^(.+)/([^/]+)$}) { + my($category, $name) = ($1, $2); + my $pkg = $self->dbPackageGet(sysid => $sys, category => $category, name => $name, hasman => 1)->[0]; + return ($pkg, '') if $pkg; + } + + # $category/$name/$version + # e.g. contrib/games/alien/10.2 + if($path =~ m{^(.+)/([^/]+)/([^/]+)$}) { + my($category, $name, $version) = ($1, $2, $3); + my $pkg = $self->dbPackageGet(sysid => $sys, category => $category, name => $name, hasman => 1)->[0]; + return ($pkg, $version) if $pkg; + } + + (undef, ''); +} + + +sub pkg_info { + my($self, $short, $path) = @_; my $sys = $self->{sysbyshort}{$short}; return $self->resNotFound if !$sys; - my $pkgs = $self->dbPackageGet($sys->{id}, $name); - my $sel = $ver ? (grep $_->{version} eq $ver, @$pkgs)[0] : $pkgs->[0]; + my($pkg, $ver) = pkg_frompath($self, $sys->{id}, $path); + return $self->resNotFound if !$pkg; + + my $vers = $self->dbPackageVersions($pkg->{id}); + + my $sel = $ver ? (grep $_->{version} eq $ver, @$vers)[0] : $vers->[0]; return $self->resNotFound if !$sel; my $f = $self->formValidate({ get => 's', required => 0}); @@ -346,33 +391,30 @@ sub browsepkg { my $mans = $self->dbManInfo(package => $sel->{id}, results => 201, start => $f->{s}, sort => 'name'); my $more = @$mans > 200 && pop @$mans; + # Latest version of this package determines last modification date of the page. + $self->setLastMod($vers->[0]{released}); + # TODO: A "previous" link would be nice... my $next = sub { use utf8; if($more) { p class => 'pagination'; - a href => "/browse/$sys->{short}/$name/$sel->{version}?s=$mans->[199]{name}", 'next »'; + a href => "/pkg/$sys->{short}/$pkg->{category}/$pkg->{name}/$sel->{version}?s=$mans->[199]{name}", 'next »'; end; } }; - # Latest version of this package determines last modification date of the page. - $self->setLastMod($pkgs->[0]{released}); - - my $title = "$sys->{name}".($sys->{release}?" $sys->{release}":"")." / $name $sel->{version}"; + my $title = "$sys->{name}".($sys->{release}?" $sys->{release}":"")." / $pkg->{category} / $pkg->{name} $sel->{version}"; $self->htmlHeader(title => $title); h1 $title; - # TODO: Link back to the system browsing page - h2 'Versions'; ul id => 'packages'; - for(@$pkgs) { + for(@$vers) { li; txt "$_->{released} "; - a href => "/browse/$sys->{short}/$name/$_->{version}", $_->{version} if $_ != $sel; + a href => "/pkg/$sys->{short}/$pkg->{category}/$pkg->{name}/$_->{version}", $_->{version} if $_ != $sel; b " $_->{version}" if $_ == $sel; - i " $_->{category}"; end; } end; @@ -405,13 +447,13 @@ sub manjslist { do { my %pkgs; for(@{$sys{$_}}) { - my $pn = "$_->{package}-$_->{version}"; - $pkgs{$pn} = [ $_->{package}, $_->{version}, [], $_->{released} ] if !$pkgs{$pn}; - push @{$pkgs{$pn}[2]}, [ $_->{section}, $_->{locale}, substr $_->{hash}, 0, 8 ]; + my $pn = "$_->{category}-$_->{package}-$_->{version}"; + $pkgs{$pn} = [ $_->{category}, $_->{package}, $_->{version}, [], $_->{released} ] if !$pkgs{$pn}; + push @{$pkgs{$pn}[3]}, [ $_->{section}, $_->{locale}, substr $_->{hash}, 0, 8 ]; } [ grep - delete($_->[3]) && ($_->[2] = [sort { $a->[0] cmp $b->[0] || ($a->[1]||'') cmp ($b->[1]||'') } @{$_->[2]}]), - sort { $a->[0] cmp $b->[0] || $b->[3] cmp $a->[3] } values %pkgs ]; + delete($_->[4]) && ($_->[3] = [sort { $a->[0] cmp $b->[0] || ($a->[1]||'') cmp ($b->[1]||'') } @{$_->[3]}]), + sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] || $b->[4] cmp $a->[4] } values %pkgs ]; } ], sort { my $x=$self->{sysbyid}{$a}; my $y=$self->{sysbyid}{$b}; $x->{name} cmp $y->{name} or $y->{relorder} <=> $x->{relorder} } keys %sys @@ -650,7 +692,7 @@ sub dbManContent { } -# Options: name, section, shorthash, locale, package, start, results, sort +# Options: name, section, shorthash, package, start, results, sort sub dbManInfo { my $s = shift; my %o = @_; @@ -662,21 +704,21 @@ sub dbManInfo { $o{section} ? ('m.section = ?' => $o{section}) : (), $o{shorthash} ? (q{substring(m.hash from 1 for 4) = decode(?, 'hex')} => $o{shorthash}) : (), $o{hash} ? (q{m.hash = decode(?, 'hex')} => $o{hash}) : (), - $o{locale} ? ('m.locale = ?', $o{locale}) : exists $o{locale} ? ('m.locale IS NULL' => 1) : (), $o{start} ? ('m.name > ?' => $o{start}) : (), ); # TODO: Flags to indicate what to information to fetch return $s->dbAll(q{ - SELECT p.system, p.category, p.name AS package, p.version, p.released, m.name, m.section, m.filename, m.locale, encode(m.hash, 'hex') AS hash - FROM package p - JOIN man m ON m.package = p.id + SELECT p.system, p.category, p.name AS package, pv.version, pv.released, m.name, m.section, m.filename, m.locale, encode(m.hash, 'hex') AS hash + FROM packages p + JOIN package_versions pv ON p.id = pv.package + JOIN man m ON m.package = pv.id !W !s LIMIT ? }, \%where, - $o{sort} ? 'ORDER BY name, locale NULLS FIRST' : '', + $o{sort} ? 'ORDER BY name' : '', $o{results}||10000 ); } @@ -705,29 +747,25 @@ sub dbSystemGet { } -# TODO: Optimize # Options: sysid char hasman start results -sub dbPackageList { +sub dbPackageGet { my $s = shift; my %o = (results => 10, @_); my @where = ( $o{sysid} ? ('system = ?' => $o{sysid}) : (), + $o{category} ? ('category = ?' => $o{category}) : (), + $o{name} ? ('name = ?' => $o{name}) : (), $o{start} ? ('name > ?' => $o{start}) : (), - defined($o{hasman}) ? ('!s EXISTS(SELECT 1 FROM man m WHERE m.package = p.id)' => $o{hasman}?'':'NOT') : (), + # This seems slow, perhaps cache? + defined($o{hasman}) ? ('!s EXISTS(SELECT 1 FROM package_versions pv WHERE pv.package = p.id AND EXISTS(SELECT 1 FROM man m WHERE m.package = pv.id))' => $o{hasman}?'':'NOT') : (), $o{char} ? ( 'LOWER(SUBSTR(name, 1, 1)) = ?' => $o{char} ) : (), defined($o{char}) && !$o{char} ? ( '(ASCII(name) < 97 OR ASCII(name) > 122) AND (ASCII(name) < 65 OR ASCII(name) > 90)' => 1 ) : (), - # Only get the latest version - # TODO: This is more efficient than using, e.g. SELECT DISTINCT to achieve - # the same effect. The downside of this solution is that packages of which - # the latest release does not include man pages are not listed, even if an - # earlier version does have mans. - 'NOT EXISTS(SELECT 1 FROM package p2 WHERE p2.system = p.system AND p2.name = p.name AND p2.released > p.released)' ); return $s->dbAll(q{ - SELECT name, category - FROM package p + SELECT id, system, name, category + FROM packages p !W ORDER BY name LIMIT ?}, @@ -735,18 +773,16 @@ sub dbPackageList { } -# TODO: Optimize? -sub dbPackageGet { - my($s, $sysid, $name) = @_; +sub dbPackageVersions { + my($s, $id) = @_; return $s->dbAll(q{ - SELECT id, category, name, version, released - FROM package p - WHERE system = ? - AND name = ? - AND EXISTS(SELECT 1 FROM man m WHERE m.package = p.id) + SELECT id, version, released + FROM package_versions v + WHERE package = ? + AND EXISTS(SELECT 1 FROM man m WHERE m.package = v.id) ORDER BY released DESC}, - $sysid, $name) + $id) } diff --git a/www/man.js b/www/man.js index cea5e72..ad1ff68 100644 --- a/www/man.js +++ b/www/man.js @@ -346,7 +346,7 @@ function bsDecode(s) { /* Structure of VARS.mans: [ ["System", "Full name", "short", [ - [ "package", "version", [ + [ "category", "package", "version", [ [ "section", "locale"||null ], ... ], @@ -358,6 +358,8 @@ function bsDecode(s) { ], ... ] + + The godawful navigation code desperately needs a rewrite. */ navShowLocales = false; @@ -410,14 +412,14 @@ function navCreate(nav) { function navCreatePkg(nav, view, dd, sys, n) { var pkg = sys[3][n]; - var isold = n > 0 && sys[3][n-1][0] == pkg[0]; - if(isold && !pkg[3]) + var isold = n > 0 && sys[3][n-1][0] == pkg[0] && sys[3][n-1][1] == pkg[1];; + if(isold && !pkg[4]) return false; var mannum = 0; var pdd = tag('dd', null); - for(var i=0; i 0) { - dd.appendChild(tag('dt', tag('a', {href:'/browse/'+sys[2]+'/'+pkg[0]+'/'+pkg[1]}, pkg[0]), - isold || !sys[3][n+1] || sys[3][n+1][0] != pkg[0] ? null : tag('a', - {href:'#', _pkgn: pkg[0], _pkgi:n, 'class':'expand', + dd.appendChild(tag('dt', tag('a', {href:'/pkg/'+sys[2]+'/'+pkg[0]+'/'+pkg[1]+'/'+pkg[2]}, pkg[1]), + isold || !sys[3][n+1] || sys[3][n+1][0] != pkg[0] || sys[3][n+1][1] != pkg[1] ? null : tag('a', + {href:'#', _pkgn: pkg[0]+'-'+pkg[1], _pkgi:n, 'class':'expand', title: 'Show/hide historical versions of this package', onclick: function() { - for(var j=this._pkgi+1; j 1 && VARS.mans[i-2][0] == VARS.mans[i-1][0] ? VARS.mans[i-1][4] : !!a.shift(); for(var i=0; i 0 && VARS.mans[i][3][j-1][0] == VARS.mans[i][3][j][0]) - VARS.mans[i][3][j][3] = j > 1 && VARS.mans[i][3][j-2][0] == VARS.mans[i][3][j-1][0] ? VARS.mans[i][3][j-1][3] : !!a.shift(); + if(j > 0 && VARS.mans[i][3][j-1][0] == VARS.mans[i][3][j][0] && VARS.mans[i][3][j-1][1] == VARS.mans[i][3][j][1]) + VARS.mans[i][3][j][4] = j > 1 && VARS.mans[i][3][j-2][0] == VARS.mans[i][3][j-1][0] && VARS.mans[i][3][j-2][1] == VARS.mans[i][3][j-1][1] ? VARS.mans[i][3][j-1][4] : !!a.shift(); }