www: Add some new flexible URL formats
New canonical permalink format is now: /man.<hash>/<system>/<name>.<section> Including the system name makes for more predictable navigation between man pages of the same system. This new URL format also fixes a problem with not being able to browse from a package's page to the correct page when the package has multiple versions of the same man. This is also yak shaving for some new navigation and formatting features I have planned.
This commit is contained in:
parent
46b4a5f7e0
commit
997dd8728c
1 changed files with 189 additions and 101 deletions
290
www/index.pl
290
www/index.pl
|
|
@ -177,7 +177,7 @@ sub man_pref {
|
||||||
|
|
||||||
|
|
||||||
# Given the name of a man page with optional section, find out the actual name
|
# Given the name of a man page with optional section, find out the actual name
|
||||||
# and section prefix of the man page and the preferred version.
|
# and section suffix of the man page and the preferred version.
|
||||||
sub man_pref_name {
|
sub man_pref_name {
|
||||||
my($name, $where) = @_;
|
my($name, $where) = @_;
|
||||||
|
|
||||||
|
|
@ -378,25 +378,55 @@ TUWF::get '/info/about' => sub {
|
||||||
<h3>Man pages</h3>
|
<h3>Man pages</h3>
|
||||||
<p>The following URLs are available to refer to an individual man page:</p>
|
<p>The following URLs are available to refer to an individual man page:</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>/<name>/<8-hex-digits></code></dt><dd>
|
<dt><code>/<name>[.<section>]</code> or <code>/man/<name>[.<section>]</code></dt><dd>
|
||||||
This is the permalink format for a specific man page (e.g. <a href="/ls/910be0ed">/ls/910be0ed</a>).</dd>
|
|
||||||
<dt><code>/<name>[.<section>]</code></dt><dd>
|
|
||||||
Will try to get the latest and most-close-to-upstream version of a man
|
Will try to get the latest and most-close-to-upstream version of a man
|
||||||
page (e.g. <a href="/socket">/socket</a> or <a
|
page. That this will fetch the man page from any of the available
|
||||||
href="/socket.7">/socket.7</a>). Note that this will fetch the man page
|
systems, so may result in confusing scenarios for system-specific
|
||||||
from any of the available systems, so may result in confusing scenarios
|
documentation. I try to at least keep the selection algorithm stable and
|
||||||
for system-specific documentation. I try to at least keep the selection
|
deterministic, but can't provide any guarantees. Examples:<br>
|
||||||
algorithm stable and deterministic, but can't provide any
|
<a href="/socket">/socket</a><br>
|
||||||
guarantees.</dd>
|
<a href="/socket.7">/socket.7</a><br>
|
||||||
|
<a href="/man/socket.7">/man/socket.7</a></dd>
|
||||||
<dt><code>/man/<system>/<name>[.<section>]</code></dt><dd>
|
<dt><code>/man/<system>/<name>[.<section>]</code></dt><dd>
|
||||||
Will get the latest version of a man page from the given system (e.g. <a
|
Will get the latest version of a man page from the given system, e.g.:<br>
|
||||||
href="/man/ubuntu-xenial/rsync">/man/ubuntu-xenial/rsync</a>)</dd>
|
<a href="/man/ubuntu/rsync">/man/ubuntu/rsync</a><br>
|
||||||
|
<a href="/man/ubuntu-xenial/rsync">/man/ubuntu-xenial/rsync</a></dd>
|
||||||
<dt><code>/man/<system>/<category>/<package>/<name>[.<section>]</code></dt><dd>
|
<dt><code>/man/<system>/<category>/<package>/<name>[.<section>]</code></dt><dd>
|
||||||
Will get the latest version of a man page from the given package (e.g. <a
|
Will get the latest version of a man page from the given package, e.g.:<br>
|
||||||
href="/man/ubuntu-xenial/net/rsync/rsync">/man/ubuntu-xenial/net/rsync/rsync</a>)</dd>
|
<a href="/man/ubuntu-xenial/net/rsync/rsync">/man/ubuntu-xenial/net/rsync/rsync</a></dd>
|
||||||
<dt><code>/man/<system>/<category>/<package>/<version>/<name>[.<section>]</code></dt><dd>
|
<dt><code>/man/<system>/<category>/<package>/<version>/<name>[.<section>]</code></dt><dd>
|
||||||
Will get the man page from a specific package version (e.g. <a
|
Will get the man page from a specific package version, e.g.:<br>
|
||||||
href="/man/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync">/man/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync</a>)</dd>
|
<a href="/man/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync">/man/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync</a></dd>
|
||||||
|
<dt><code>/man.<language>/...</code></dt><dd>
|
||||||
|
Adding a language code to the <code>/man/</code> component will select
|
||||||
|
the man page in the requested language. The man page has to be available
|
||||||
|
in that language, otherwise you will get a 404. Redirects to other
|
||||||
|
languages as fallback may be implemented in the future. English man
|
||||||
|
pages are typically not tagged with a language at all, so explicitely
|
||||||
|
requesting <code>/man.en/...</code> will usually fail. This, too, may be
|
||||||
|
improved in the future. Examples:<br>
|
||||||
|
<a href="/man.de/faked-tcp">/man.de/faked-tcp</a><br>
|
||||||
|
<a href="/man.fr/fedora/rsync.1">/man.de/fedora/rsync.1</a></dd>
|
||||||
|
<dt><code>/man.<8-hex-digits>/...</code></dt><dd>
|
||||||
|
Permalink format. Adding the shorthash of the man page to the
|
||||||
|
<code>/man/</code> component of the above URLs will get that specific
|
||||||
|
man page from the requested system and/or package. The contents of the
|
||||||
|
man page should generally be the same regardless of which system or
|
||||||
|
package is included in the URL, but the UI may provide a different
|
||||||
|
nagivation context. Examples:<br>
|
||||||
|
<a href="/man.910be0ed/ls">/man.910be0ed/ls</a><br>
|
||||||
|
<a href="/man.910be0ed/fedora/ls">/man.910be0ed/fedora/ls</a><br>
|
||||||
|
<a href="/man.910be0ed/arch/ls">/man.910be0ed/arch/ls</a><br>
|
||||||
|
<a href="/man.910be0ed/fedora/everything/coreutils-common/ls">/man.910be0ed/fedora/everything/coreutils-common/ls</a></dd>
|
||||||
|
<dt><code>/raw...</code></dt><dd>
|
||||||
|
In all of the above URL formats, you can change <code>/man</code> with
|
||||||
|
<code>/raw</code> to get the raw UTF-8 encoded man page source, e.g.:<br>
|
||||||
|
<a href="/raw/socket.7">/raw/socket.7</a><br>
|
||||||
|
<a href="/raw/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync">/raw/ubuntu-xenial/net/rsync/3.1.1-3ubuntu1/rsync</a><br>
|
||||||
|
<a href="/raw.de/faked-tcp">/raw.de/faked-tcp</a><br>
|
||||||
|
<a href="/raw.910be0ed/fedora/ls">/raw.910be0ed/fedora/ls</a></dd>
|
||||||
|
<dt><code>/<name>/<8-hex-digits></code></dt><dd>
|
||||||
|
Old permalink format for a specific man page (e.g. <a href="/ls/910be0ed">/ls/910be0ed</a>).</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>In all URLs where an optional <code>.<section></code> can be provided,
|
<p>In all URLs where an optional <code>.<section></code> can be provided,
|
||||||
the search is performed as a prefix match. For example, <a
|
the search is performed as a prefix match. For example, <a
|
||||||
|
|
@ -607,30 +637,48 @@ TUWF::get '/xml/search.xml' => sub {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TUWF::get qr{/([^/]+)/([0-9a-f]{8})/src} => sub {
|
# Object to represent the various URLs to a man page.
|
||||||
my $name = normalize_name tuwf->capture(1);
|
#
|
||||||
my $hash = tuwf->capture(2);
|
# Parameters:
|
||||||
|
# fmt => man|txt|raw
|
||||||
my $nfo = tuwf->dbRowi('
|
# shorthash => 8-char hex
|
||||||
SELECT m.name, m.section, v.released, c.content
|
# lang => language code
|
||||||
FROM files f
|
# system => system shortname
|
||||||
JOIN mans m ON m.id = f.man
|
# category => package category
|
||||||
JOIN package_versions v ON v.id = f.pkgver
|
# package => name of the package
|
||||||
JOIN contents c ON c.id = f.content
|
# version => package version
|
||||||
WHERE m.name =', \$name, 'AND f.shorthash =', \shorthash_to_int($hash), '
|
# man => name of the man page
|
||||||
LIMIT 1'
|
# section => man page section
|
||||||
);
|
#
|
||||||
return tuwf->resNotFound if !$nfo->{name};
|
# URL format:
|
||||||
|
# /$fmt[.$shorthash][.$lang][/$system[/$category/$package[/$version]]]/$man[.$section]
|
||||||
tuwf->resLastMod($nfo->{released});
|
#
|
||||||
tuwf->resHeader('Content-Type', 'text/plain; charset=UTF-8');
|
# Note that the URL format has some ambiguity:
|
||||||
tuwf->resHeader('Content-Disposition', sprintf 'filename="%s.%s"', $nfo->{name}, $nfo->{section});
|
# - $category may contain a slash, so a database lookup is required to
|
||||||
lit $nfo->{content};
|
# disambiguate between URLs with [/$version] and those without.
|
||||||
|
# - $man may contain a dot, so a database lookup is required to disambiguate
|
||||||
|
# between URLs with [.$section] and those without
|
||||||
|
#
|
||||||
|
# $system may also refer to system shortnames without the version suffix (e.g.
|
||||||
|
# 'ubuntu' rather than 'ubuntu-impish'). In that case the man page from the
|
||||||
|
# latest release of that system is chosen.
|
||||||
|
package ManUrl {
|
||||||
|
sub new { my($p,%o)=@_; bless \%o, $p }
|
||||||
|
sub set { my($o,@o)=@_; bless +{%$o,@o}, ref $o }
|
||||||
|
sub mansect { $_[0]{man}.(defined $_[0]{section} ? ".$_[0]{section}" : '') }
|
||||||
|
use overload '""' => sub {
|
||||||
|
my($o)=@_;
|
||||||
|
"/$o->{fmt}".(defined $o->{shorthash} ? ".$o->{shorthash}" : '').(defined $o->{lang} ? ".$o->{lang}" : '')
|
||||||
|
.(defined $o->{system} ? ("/$o->{system}"
|
||||||
|
.(defined $o->{category} ? ("/$o->{category}/$o->{package}"
|
||||||
|
.(defined $o->{version} ? "/$o->{version}" : '')) : '')) : '')
|
||||||
|
.'/'.$o->mansect
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
sub man_nav_ {
|
sub man_nav_ {
|
||||||
my($man, $toc, $htmllang) = @_;
|
my($man, $url, $toc, $htmllang) = @_;
|
||||||
|
|
||||||
my @systems = tuwf->dbAlli('
|
my @systems = tuwf->dbAlli('
|
||||||
SELECT DISTINCT p.system
|
SELECT DISTINCT p.system
|
||||||
|
|
@ -655,8 +703,8 @@ sub man_nav_ {
|
||||||
)->@*;
|
)->@*;
|
||||||
|
|
||||||
nav_ sub {
|
nav_ sub {
|
||||||
form_ action => "/sysredir/$man->{name}.$man->{section}", method => 'get',
|
form_ action => '/sysredir/'.$url->mansect(), method => 'get',
|
||||||
onsubmit => 'location.href="/man/"+system_select[system_select.selectedIndex].value+"/'.$man->{name}.'.'.$man->{section}.'";return false',
|
onsubmit => 'location.href="/man/"+system_select[system_select.selectedIndex].value+"/'.$url->mansect().'";return false',
|
||||||
sub {
|
sub {
|
||||||
my %names;
|
my %names;
|
||||||
push $names{$_->{name}}->@*, $_ for map sysbyid->{$_->{system}}, sort { $b->{system} <=> $a->{system} } @systems;
|
push $names{$_->{name}}->@*, $_ for map sysbyid->{$_->{system}}, sort { $b->{system} <=> $a->{system} } @systems;
|
||||||
|
|
@ -686,7 +734,7 @@ sub man_nav_ {
|
||||||
if($man->{section} eq $_) {
|
if($man->{section} eq $_) {
|
||||||
i_ $_;
|
i_ $_;
|
||||||
} else {
|
} else {
|
||||||
a_ href => "/$man->{name}.$_", $_;
|
a_ href => "/man/$man->{name}.$_", $_;
|
||||||
}
|
}
|
||||||
txt_ ' ';
|
txt_ ' ';
|
||||||
}
|
}
|
||||||
|
|
@ -701,7 +749,7 @@ sub man_nav_ {
|
||||||
if(($_||'') eq $cur) {
|
if(($_||'') eq $cur) {
|
||||||
i_ $_ || 'default';
|
i_ $_ || 'default';
|
||||||
} else {
|
} else {
|
||||||
a_ href => $_ ? "/lang/$_/$man->{name}.$man->{section}" : "/$man->{name}.$man->{section}", $_ || 'default';
|
a_ href => $_ ? "/man.$_/$man->{name}.$man->{section}" : "/man/$man->{name}.$man->{section}", $_ || 'default';
|
||||||
}
|
}
|
||||||
txt_ ' ';
|
txt_ ' ';
|
||||||
}
|
}
|
||||||
|
|
@ -746,10 +794,27 @@ sub soelim {
|
||||||
|
|
||||||
|
|
||||||
sub man_page {
|
sub man_page {
|
||||||
my($man) = @_;
|
my($man, $url) = @_;
|
||||||
|
tuwf->resLastMod($man->{released});
|
||||||
|
|
||||||
my $content = tuwf->dbRowi('SELECT encode(hash, \'hex\') AS hash, content FROM contents WHERE id =', \$man->{content});
|
my $content = tuwf->dbRowi('SELECT encode(hash, \'hex\') AS hash, content FROM contents WHERE id =', \$man->{content});
|
||||||
|
if($url->{fmt} eq 'raw') {
|
||||||
|
tuwf->resHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||||
|
tuwf->resHeader('Content-Disposition', sprintf 'filename="%s.%s"', $man->{name}, $man->{section});
|
||||||
|
lit $content->{content};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
my $fmt = ManUtils::html ManUtils::fmt_block soelim $man->{verid}, $content->{content};
|
my $fmt = ManUtils::html ManUtils::fmt_block soelim $man->{verid}, $content->{content};
|
||||||
|
if($url->{fmt} eq 'txt') {
|
||||||
|
# TODO: The 'txt' format is kind of broken right now as it includes our HTML formatting codes.
|
||||||
|
# This feature is a WIP and not advertised at the moment, anyway.
|
||||||
|
tuwf->resHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||||
|
tuwf->resHeader('Content-Disposition', sprintf 'filename="%s.%s.txt"', $man->{name}, $man->{section});
|
||||||
|
lit $fmt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
my @toc;
|
my @toc;
|
||||||
$fmt =~ s{\n<b>(.+?)<\/b>\n}{
|
$fmt =~ s{\n<b>(.+?)<\/b>\n}{
|
||||||
push @toc, $1;
|
push @toc, $1;
|
||||||
|
|
@ -769,9 +834,8 @@ sub man_page {
|
||||||
);
|
);
|
||||||
my @htmllang = $man->{locale} =~ /^([a-z]{2,3})(?:_([A-Z]{2}))?(?:$|@|\.)/ ? (lang => $1.($2?"-$2":'')) : ();
|
my @htmllang = $man->{locale} =~ /^([a-z]{2,3})(?:_([A-Z]{2}))?(?:$|@|\.)/ ? (lang => $1.($2?"-$2":'')) : ();
|
||||||
|
|
||||||
tuwf->resLastMod($man->{released});
|
|
||||||
framework_ title => $man->{name}, mainclass => 'manpage', sub {
|
framework_ title => $man->{name}, mainclass => 'manpage', sub {
|
||||||
man_nav_ $man, \@toc, \@htmllang;
|
man_nav_ $man, $url, \@toc, \@htmllang;
|
||||||
# TODO: Replace the 'versions' and 'locations' functionality with non-JS alternatives.
|
# TODO: Replace the 'versions' and 'locations' functionality with non-JS alternatives.
|
||||||
div_ id => 'manbuttons', sub {
|
div_ id => 'manbuttons', sub {
|
||||||
h1_ $man->{name};
|
h1_ $man->{name};
|
||||||
|
|
@ -781,8 +845,8 @@ sub man_page {
|
||||||
'data-locale' => $man->{locale}||'',
|
'data-locale' => $man->{locale}||'',
|
||||||
'data-hasversions' => $hasversions?1:0,
|
'data-hasversions' => $hasversions?1:0,
|
||||||
sub {
|
sub {
|
||||||
li_ sub { a_ href => "/$man->{name}/".shorthash_to_hex($man->{shorthash}).'/src', 'source' };
|
li_ sub { a_ href => $url->set(fmt => 'raw'), 'source' };
|
||||||
li_ sub { a_ href => "/$man->{name}/".shorthash_to_hex($man->{shorthash}), 'permalink' };
|
li_ sub { a_ href => $url->set(system => sysbyid->{$man->{system}}{short}, category => undef, shorthash => shorthash_to_hex $man->{shorthash}), 'permalink' };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
div_ id => 'manres', class => 'hidden', '';
|
div_ id => 'manres', class => 'hidden', '';
|
||||||
|
|
@ -791,55 +855,77 @@ sub man_page {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# /<name>[.section] - short and handy catch-all URL for man pages
|
||||||
|
# /<name>/<shorthash> - old permalink format
|
||||||
# This one has to go before the other mappings, to ensure that links work for
|
# This one has to go before the other mappings, to ensure that links work for
|
||||||
# man pages called 'pkg' or 'man'. This also means that we can't have a
|
# man pages called 'pkg' or 'man'.
|
||||||
# system named 8 hex digits, but at least that's easy to guarantee. :)
|
|
||||||
TUWF::get qr{/(?<name>[^/]+)(?:/(?<hash>[0-9a-f]{8}))?} => sub {
|
TUWF::get qr{/(?<name>[^/]+)(?:/(?<hash>[0-9a-f]{8}))?} => sub {
|
||||||
my $name = normalize_name tuwf->capture('name');
|
my $name = normalize_name tuwf->capture('name');
|
||||||
my $shorthash = tuwf->capture('hash');
|
my $shorthash = tuwf->capture('hash');
|
||||||
|
|
||||||
# Unfortunately, even in the permalink format with the hash, we don't know
|
my($man, $sect) = man_pref_name $name, $shorthash ? sql 'f.shorthash =', \shorthash_to_int $shorthash : 'true';
|
||||||
# from which system and package we're supposed to get the man page. This
|
|
||||||
# info is used in the UI and needed in order to do .so substitution, so we
|
|
||||||
# can substitute files from the same package as the requested man page. Use
|
|
||||||
# the man_pref logic here to deterministically select a good package.
|
|
||||||
my($man, undef) = $shorthash
|
|
||||||
? man_pref undef, sql 'm.name =', \$name, 'AND f.shorthash =', shorthash_to_int($shorthash)
|
|
||||||
: man_pref_name $name, 'true';
|
|
||||||
return tuwf->resNotFound() if !$man->{name};
|
return tuwf->resNotFound() if !$man->{name};
|
||||||
|
|
||||||
man_page $man;
|
man_page $man, ManUrl->new(
|
||||||
|
fmt => 'man',
|
||||||
|
man => length $sect ? $man->{name} : $name,
|
||||||
|
section => length $sect ? $sect : undef,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TUWF::get qr{/man/([^/]+)/(.+)} => sub {
|
# /<name>/<shorthash>/src - old URL format to get the raw man page
|
||||||
my($sys, $path) = tuwf->captures(1,2);
|
TUWF::get qr{/([^/]+)/([0-9a-f]{8})/src} => sub {
|
||||||
|
my $name = normalize_name tuwf->capture(1);
|
||||||
|
my $shorthash = tuwf->capture(2);
|
||||||
|
|
||||||
# Path can be:
|
my($man) = man_pref_name $name, sql 'f.shorthash =', \shorthash_to_int $shorthash;
|
||||||
# 1. <name>
|
return tuwf->resNotFound if !$man->{name};
|
||||||
# 2. <category>/<package>/<name>
|
man_page $man, ManUrl->new(fmt => 'raw', man => $name);
|
||||||
# 3. <category>/<package>/<version>/<name>
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TUWF::get qr{/(?<fmt>man|txt|raw)(?:\.(?<shorthash>[a-fA-F0-9]{8}))?(?:\.(?<lang>[^/]+))?/(?<path>.+)} => sub {
|
||||||
|
my($fmt, $shorthash, $lang, $path) = tuwf->captures(qw|fmt shorthash lang path|);
|
||||||
|
|
||||||
|
my @where;
|
||||||
|
my $name = normalize_name($path =~ s{/?([^/]+)$}{} && $1);
|
||||||
|
my $system = $path =~ s{^([^/]+)/?}{} && $1;
|
||||||
|
|
||||||
# $sys can be either a full system 'short' name, or a prefix (e.g. 'debian' meaning 'any debian-* version')
|
# $sys can be either a full system 'short' name, or a prefix (e.g. 'debian' meaning 'any debian-* version')
|
||||||
my $sysid = sysbyshort->{$sys};
|
if($system) {
|
||||||
$sysid = $sysid ? [$sysid->{id}] : [ map sysbyshort->{$_}{id}, grep /^\Q$sys\E-/, keys sysbyshort->%* ];
|
my $sysid = sysbyshort->{$system};
|
||||||
return tuwf->resNotFound if !@$sysid;
|
$sysid = $sysid ? [$sysid->{id}] : [ map sysbyshort->{$_}{id}, grep /^\Q$system\E-/, keys sysbyshort->%* ];
|
||||||
|
return tuwf->resNotFound if !@$sysid;
|
||||||
my $man;
|
push @where, sql 'system IN', $sysid;
|
||||||
if($path !~ m{/}) { # (1)
|
|
||||||
($man) = man_pref_name $path, sql 's.id IN', $sysid;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$path =~ s{/([^/]+)$}{};
|
|
||||||
my $name = $1;
|
|
||||||
|
|
||||||
my($pkg, $ver) = pkg_frompath sql('system IN', $sysid), $path; # Handles (2) and (3)
|
|
||||||
return tuwf->resNotFound if !$pkg;
|
|
||||||
|
|
||||||
($man) = man_pref_name $name, sql 's.id IN', $sysid, 'AND p.id =', \$pkg->{id}, $ver ? ('AND v.version =', \$ver) : ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# $path is now either:
|
||||||
|
# 1. $category/$package
|
||||||
|
# 2. $cagegory/$package/$version
|
||||||
|
my($pkg, $ver) = length $path ? pkg_frompath sql_and(@where), $path : (undef,undef);
|
||||||
|
return tuwf->resNotFound if length $path && !$pkg;
|
||||||
|
push @where, sql 'p.id =', \$pkg->{id} if $pkg;
|
||||||
|
push @where, sql 'v.version =', \$ver if length $ver;
|
||||||
|
|
||||||
|
push @where, sql 'f.shorthash =', \shorthash_to_int $shorthash if $shorthash;
|
||||||
|
push @where, sql 'l.locale ilike', \(escape_like($lang).'%') if $lang;
|
||||||
|
|
||||||
|
my($man, $section) = man_pref_name $name, sql_and @where;
|
||||||
return tuwf->resNotFound if !$man;
|
return tuwf->resNotFound if !$man;
|
||||||
man_page $man;
|
|
||||||
|
my $url = ManUrl->new(
|
||||||
|
fmt => $fmt,
|
||||||
|
shorthash => $shorthash,
|
||||||
|
lang => $lang,
|
||||||
|
system => length $system ? $system : undef,
|
||||||
|
category => $pkg ? $pkg->{category} : undef,
|
||||||
|
package => $pkg ? $pkg->{name} : undef,
|
||||||
|
version => length $ver ? $ver : undef,
|
||||||
|
man => length $section ? $man->{name} : $name,
|
||||||
|
section => length $section ? $section : undef,
|
||||||
|
);
|
||||||
|
man_page $man, $url;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -909,14 +995,23 @@ TUWF::get qr{/pkg/([^/]+)/(.+)} => sub {
|
||||||
my $p = tuwf->validate(get => p => { onerror => 1, uint => 1, range => [1,100] })->data;
|
my $p = tuwf->validate(get => p => { onerror => 1, uint => 1, range => [1,100] })->data;
|
||||||
|
|
||||||
my $count = tuwf->dbVali('SELECT count(*) FROM files WHERE pkgver =', \$sel->{id});
|
my $count = tuwf->dbVali('SELECT count(*) FROM files WHERE pkgver =', \$sel->{id});
|
||||||
my $mans = tuwf->dbPagei({ results => 200, page => $p },
|
my $mans = tuwf->dbPagei({ results => 200, page => $p }, '
|
||||||
"SELECT m.name, m.section, f.shorthash, f.filename, l.locale
|
WITH lst AS (
|
||||||
FROM files f
|
SELECT f.man, m.name, m.section, f.shorthash, f.filename, l.locale
|
||||||
JOIN locales l ON l.id = f.locale
|
FROM files f
|
||||||
JOIN mans m ON m.id = f.man
|
JOIN locales l ON l.id = f.locale
|
||||||
WHERE f.pkgver =", \$sel->{id}, '
|
JOIN mans m ON m.id = f.man
|
||||||
ORDER BY m.name, l.locale, f.filename'
|
WHERE f.pkgver =', \$sel->{id}, '
|
||||||
);
|
), needlang AS (
|
||||||
|
SELECT man FROM lst GROUP BY man HAVING count(*) > 1
|
||||||
|
), needhash AS (
|
||||||
|
SELECT man, locale FROM lst GROUP BY man, locale HAVING count(*) > 1
|
||||||
|
) SELECT name, section, shorthash, filename, locale
|
||||||
|
, EXISTS(SELECT 1 FROM needlang WHERE man = l.man) AS needlang
|
||||||
|
, EXISTS(SELECT 1 FROM needhash WHERE man = l.man AND locale = l.locale) AS needhash
|
||||||
|
FROM lst l
|
||||||
|
ORDER BY name, section, locale, filename
|
||||||
|
');
|
||||||
|
|
||||||
# Latest version of this package determines last modification date of the page.
|
# Latest version of this package determines last modification date of the page.
|
||||||
tuwf->resLastMod($vers->[0]{released});
|
tuwf->resLastMod($vers->[0]{released});
|
||||||
|
|
@ -946,9 +1041,9 @@ TUWF::get qr{/pkg/([^/]+)/(.+)} => sub {
|
||||||
paginate_ "/pkg/$pkgpath/$sel->{version}?p=", $count, 200, $p;
|
paginate_ "/pkg/$pkgpath/$sel->{version}?p=", $count, 200, $p;
|
||||||
ul_ sub {
|
ul_ sub {
|
||||||
li_ sub {
|
li_ sub {
|
||||||
# BUG: This URL should include the shorthash (or locale, at least),
|
# Only add the hash or locale to the URL if it's necessary to select the proper man page.
|
||||||
# because the same package may have multiple pages with the same name and section.
|
my $ext = $_->{needhash} ? '.'.shorthash_to_hex $_->{shorthash} : $_->{needlang} ? ".$_->{locale}" : '';
|
||||||
a_ href => "/man/$pkgpath/$sel->{version}/$_->{name}.$_->{section}", "$_->{name}($_->{section})";
|
a_ href => "/man$ext/$pkgpath/$sel->{version}/$_->{name}.$_->{section}", "$_->{name}($_->{section})";
|
||||||
b_ " $_->{locale}" if $_->{locale};
|
b_ " $_->{locale}" if $_->{locale};
|
||||||
small_ " $_->{filename}";
|
small_ " $_->{filename}";
|
||||||
} for(@$mans);
|
} for(@$mans);
|
||||||
|
|
@ -974,17 +1069,10 @@ TUWF::get qr{/browse/([^/]+)/([^/]+)(?:/([^/]+))?} => sub {
|
||||||
# Redirect for the system selection box, for visitors who have disabled JS.
|
# Redirect for the system selection box, for visitors who have disabled JS.
|
||||||
TUWF::get qr{/sysredir/([^/]+)} => sub { tuwf->resRedirect('/man/'.(tuwf->reqGet('system')//'arch').'/'.tuwf->capture(1), 'temp') };
|
TUWF::get qr{/sysredir/([^/]+)} => sub { tuwf->resRedirect('/man/'.(tuwf->reqGet('system')//'arch').'/'.tuwf->capture(1), 'temp') };
|
||||||
|
|
||||||
|
# Redirect for a specific language for a man page. I have no idea if anyone
|
||||||
# Redirect for a specific language for a man page.
|
# still uses this URL format, but it was supported at some point, so let's keep
|
||||||
# I'm not a fan of this solution; might drop it in the future.
|
# it around.
|
||||||
TUWF::get qr{/lang/([^/]+)/([^/]+)} => sub {
|
TUWF::get qr{/lang/([^/]+)/([^/]+)} => sub { tuwf->resRedirect('/man.'.tuwf->capture(1).'/'.tuwf->capture(2), 'temp') };
|
||||||
my $lang = tuwf->capture(1);
|
|
||||||
my $name = normalize_name tuwf->capture(2);
|
|
||||||
my($man, undef) = man_pref_name $name,
|
|
||||||
sql "substring(l.locale from '^[^.]+') ilike", \(escape_like($lang).'%');
|
|
||||||
return tuwf->resNotFound if !length $man->{name};
|
|
||||||
tuwf->resRedirect("/$man->{name}/".shorthash_to_hex($man->{shorthash}), 'temp');
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
TUWF::get '/json/tree.json' => sub {
|
TUWF::get '/json/tree.json' => sub {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue