$should_update_db = 1 if $db_mtime < $archive_mtime;
}
- unlink $db_file if -e $db_file and $should_update_db;
-
$self->schema( BackPAN::Index::Schema->connect("dbi:SQLite:dbname=$db_file") );
return unless $should_update_db;
)
SQL
);
+ my %delete_for = (
+ files => 'DELETE FROM files',
+ releases => 'DELETE FROM releases',
+ dists => 'DELETE FROM dists',
+ );
my $dbh = $self->_dbh;
- for my $sql (values %create_for) {
- $dbh->do($sql);
+ for my $table_name (keys %create_for) {
+ $dbh->do($create_for{$table_name});
+ $dbh->do($delete_for{$table_name});
}
$self->schema->rescan;
dispatch {
subdispatch sub () {
$self->_build_request_obj_from($_[+PSGI_ENV]);
+ my $base_title = 'BackPAN.org';
[
sub (/) {
$self->html_response({ body => $self->index_page_content });
my $release_rs = $self->releases($_[1]);
if ( $release_rs->count ) {
my $body = $self->releases_page_content($release_rs)
- ->select('#nav-releases')->add_to_attribute(class => 'active');
+ ->select('#nav-releases')->add_to_attribute(class => 'active')
+ ->select('title')->replace_content(join q{ - }, 'Releases', $base_title);
return $self->html_response({ body => $body });
}
else {
my $dist_rs = $self->dists($_[1]);
if ( $dist_rs->count ) {
my $body = $self->dists_page_content($dist_rs)
- ->select('#nav-dists')->add_to_attribute(class => 'active');
+ ->select('#nav-dists')->add_to_attribute(class => 'active')
+ ->select('title')->replace_content(join q{ - }, 'Distributions', $base_title);
return $self->html_response({ body => $body });
}
else {
sub ( /distribution/*|/distribution/*/ + ?* ) {
if ( my $dist = $self->get_dist($_[1]) ) {
- my $body = $self->dist_info_page_content($dist, $_[2]);
+ my $body = $self->dist_info_page_content($dist, $_[2])
+ ->select('title')->replace_content(join q{ - }, $self->format_dist_name($dist->name), $base_title);
return $self->html_response({ body => $body });
}
else {
sub ( /authors|/authors/ + ?* ) {
if ( my $authors = $self->authors($_[1]) ) {
my $body = $self->authors_page_content($authors)
- ->select('#nav-authors')->add_to_attribute(class => 'active');
+ ->select('#nav-authors')->add_to_attribute(class => 'active')
+ ->select('title')->replace_content(join q{ - }, 'Authors', $base_title);
return $self->html_response({ body => $body });
}
else {
my $body = $self->dists_page_content($dist_rs)
->select('#q')->add_to_attribute(
value => $query_str
- );
+ )
+ ->select('title')->replace_content(join q{ - }, 'Search', $base_title);
return $self->html_response({ body => $body });
}
else {
404 => 'root/html/error_404.html';
enable 'HTTPExceptions';
enable 'Head';
- enable 'AccessLog',
- format => 'combined',
- logger => sub { get_logger('accesslog')->info(@_) };
- enable 'Log4perl', conf => 'log/log.conf';
+ #enable 'AccessLog',
+ # format => 'combined',
+ # logger => sub { get_logger('accesslog')->info(@_) };
+ #enable 'Log4perl', conf => 'log/log.conf';
$app;
};
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>BackPAN</title>
+ <title>About - BackPAN.org</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/main.css" type="text/css" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>BackPAN</title>
+ <title>Not found - BackPAN.org</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/main.css" type="text/css" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>BackPAN</title>
+ <title>Ooooops! - BackPAN.org</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/main.css" type="text/css" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>BackPAN</title>
+ <title>BackPAN.org</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/static/main.css" type="text/css" />
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>BackPAN</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <link rel="stylesheet" href="/static/main.css" type="text/css" />
+ </head>
+<body>
+<div class="container">
+ <div id="search">
+ <form action="/search" method="GET">
+ <input type="text" id="q" name="q" />
+ <input type="submit" id="searchbtn" value="Search" />
+ </form>
+ </div>
+ <div id="logo">
+ <a href="/"><h1>BackPAN.org</h1><a>
+ </div>
+ <div id="menu">
+ <div class="nav">
+ <ul>
+ <li><a id="nav-releases" href="/releases">Releases</a></li>
+ <li><a id="nav-dists" href="/dists">Distributions</a></li>
+ <li><a id="nav-authors" href="/authors">Authors</a></li>
+ <li><a id="nav-about" class="active" href="/about">About</a></li>
+ </ul>
+ </div>
+ </div>
+ <div id="header">
+ <p>A Complete History of CPAN.</p>
+ </div>
+ <div id="content">
+ <div id="plain-text">
+ <p>The <a href="http://cpan.org" target="_blank">Comprehensive Perl Archive Network (CPAN)</a> is a very useful
+ collection of Perl code. However, authors of modules can delete older versions of modules to only
+ let CPAN have the latest version of a module and BackPAN is where these deleted modules are backed up.</p>
+ <p>BackPAN.org is a project created by <a href="http://search.cpan.org/~wreis/" target="_blank">Wallace Reis</a>
+ using <a href="http://search.cpan.org/perldoc?Web::Simple" target="_blank">Web::Simple</a> and
+ <a href="http://search.cpan.org/perldoc?HTML::Zoom" target="_blank">HTML::Zoom</a>. Kindly hosted by
+ <a href="http://shadowcat.co.uk" target="_blank">Shadowcat Systems</a>. Website design developed by
+ <a href="http://paulovitor.com" target="_blank">Paulo Vitor</a>.</p>
+ <p>Please send any corrections, suggestions or comments to wreis at cpan.org.</p>
+ <p>You can check out the source code from: git://git.shadowcat.co.uk/catagits/BackPAN-Web.git</p>
+ <p>IRC channel: irc.perl.org #backpan-web</p>
+ </div>
+ </div>
+</div>
+<div id="footer">
+ <p>Created by <a href="http://search.cpan.org/~wreis/" target="_blank">Wallace Reis</a></p>
+ <p>Hosted by <a href="http://shadowcat.co.uk" target="_blank">Shadowcat Systems</a></p>
+</div>
+</body>
+</html>
--- /dev/null
+<div id="content">
+ <div id="dist">
+ <span>Name: [% name %]</span><br />
+ <span>Number of releases: [% num_releases %]</span><br />
+ <span>Maintainers:</span><br />
+ <ul class="maintainer-list">
+ <li><a>Name</a></li>
+ </ul><br />
+ <span>First release: <a class="f_rel_link">[% f_release_label %]</a></span><br />
+ <span>Latest release: <a class="l_rel_link">[% l_release_label %]</a></span><br />
+ </div>
+ <div id="list">
+ <span>Releases:</span><br />
+ <ul class="main-list">
+ <li><a>Name</a></li>
+ </ul>
+ <div id="paging">
+ <div id="pages">
+ <span><a>Page Number</a></span>
+ </div>
+ <span class="paging-desc" />
+ <span class="entries" />
+ </div>
+ </div>
+</div>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>BackPAN</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <link rel="stylesheet" href="/static/main.css" type="text/css" />
+ </head>
+<body>
+<div class="container">
+ <div id="search">
+ <form action="/search" method="GET">
+ <input type="text" id="q" name="q" />
+ <input type="submit" id="searchbtn" value="Search" />
+ </form>
+ </div>
+ <div id="logo">
+ <a href="/"><h1>BackPAN.org</h1><a>
+ </div>
+ <div id="menu">
+ <div class="nav">
+ <ul>
+ <li><a id="nav-releases" href="/releases">Releases</a></li>
+ <li><a id="nav-dists" href="/dists">Distributions</a></li>
+ <li><a id="nav-authors" href="/authors">Authors</a></li>
+ <li><a id="nav-about" href="/about">About</a></li>
+ </ul>
+ </div>
+ </div>
+ <div id="header">
+ <p>A Complete History of CPAN.</p>
+ </div>
+ <div id="content">
+ <div id="plain-text">
+ <p>Sorry, not found!</p>
+ <p>Whatever it was you were looking for, it's not here.</p>
+ <p>Please send any corrections, suggestions or comments to wreis at cpan.org.</p>
+ </div>
+ </div>
+</div>
+<div id="footer">
+ <p>Created by <a href="http://search.cpan.org/~wreis/" target="_blank">Wallace Reis</a></p>
+ <p>Hosted by <a href="http://shadowcat.co.uk" target="_blank">Shadowcat Systems</a></p>
+</div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>BackPAN</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <link rel="stylesheet" href="/static/main.css" type="text/css" />
+ </head>
+<body>
+<div class="container">
+ <div id="search">
+ <form action="/search" method="GET">
+ <input type="text" id="q" name="q" />
+ <input type="submit" id="searchbtn" value="Search" />
+ </form>
+ </div>
+ <div id="logo">
+ <a href="/"><h1>BackPAN.org</h1><a>
+ </div>
+ <div id="menu">
+ <div class="nav">
+ <ul>
+ <li><a id="nav-releases" href="/releases">Releases</a></li>
+ <li><a id="nav-dists" href="/dists">Distributions</a></li>
+ <li><a id="nav-authors" href="/authors">Authors</a></li>
+ <li><a id="nav-about" href="/about">About</a></li>
+ </ul>
+ </div>
+ </div>
+ <div id="header">
+ <p>A Complete History of CPAN.</p>
+ </div>
+ <div id="content">
+ <div id="plain-text"><p>Ooooops! Sorry, we couldn't process your request.</p></div>
+ </div>
+</div>
+<div id="footer">
+ <p>Created by <a href="http://search.cpan.org/~wreis/" target="_blank">Wallace Reis</a></p>
+ <p>Hosted by <a href="http://shadowcat.co.uk" target="_blank">Shadowcat Systems</a></p>
+</div>
+</body>
+</html>
--- /dev/null
+<div id="content">
+ <span>New releases</p>
+ <div id="list">
+ <ul class="main-list">
+ <li><a>Name</a></li>
+ </ul>
+ </div>
+</div>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>BackPAN</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <link rel="stylesheet" href="/static/main.css" type="text/css" />
+ </head>
+<body>
+<div class="container">
+ <div id="search">
+ <form action="/search" method="GET">
+ <input type="text" id="q" name="q" />
+ <input type="submit" id="searchbtn" value="Search" />
+ </form>
+ </div>
+ <div id="logo">
+ <a href="/"><h1>BackPAN.org</h1><a>
+ </div>
+ <div id="menu">
+ <div class="nav">
+ <ul>
+ <li><a id="nav-releases" href="/releases">Releases</a></li>
+ <li><a id="nav-dists" href="/dists">Distributions</a></li>
+ <li><a id="nav-authors" href="/authors">Authors</a></li>
+ <li><a id="nav-about" href="/about">About</a></li>
+ </ul>
+ </div>
+ </div>
+ <div id="header">
+ <p>A Complete History of CPAN.</p>
+ </div>
+ <div id="content">
+ </div>
+</div>
+<div id="footer">
+ <p>Created by <a href="http://search.cpan.org/~wreis/" target="_blank">Wallace Reis</a></p>
+ <p>Hosted by <a href="http://shadowcat.co.uk" target="_blank">Shadowcat Systems</a></p>
+</div>
+</body>
+</html>
--- /dev/null
+<div id="content">
+ <div id="page-size">
+ <span>Page Size:</span>
+ <div class="page-size-options">
+ <span><a>Page Size</a></span>
+ </div>
+ </div>
+ <div id="ordering">
+ <span>Sort by:</span>
+ <div class="ordering-options">
+ <span><a>Name</a></span>
+ </div>
+ </div>
+ <div id="list">
+ <ul class="main-list">
+ <li><a>Name</a></li>
+ </ul>
+ </div>
+ <div id="paging">
+ <div id="pages">
+ <span><a>Page Number</a></span>
+ </div>
+ <span class="paging-desc" />
+ <span class="entries" />
+ </div>
+</div>
--- /dev/null
+* {
+margin:0;
+padding:0;
+list-style: none;
+}
+
+body {
+text-align: center;
+font-family: Arial, sans-serif;
+color: #333;
+}
+
+a { color:#004065; }
+
+.container {
+margin: 20px auto 40px auto;
+text-align: left;
+width: 900px;
+}
+
+#ordering, #header, #paging, #list { float: left; }
+#menu, #page-size, #search { float: right; }
+
+#search input#q {
+float: right;
+border: 1px solid #004065;
+padding: 1px 25px 1px 5px;
+font-size: 14px;
+background: url(searchbtn.png) no-repeat right;
+}
+
+#header {
+font-size: 12px;
+color: #999;
+}
+
+.nav ul li {
+display: inline;
+}
+
+.nav ul li a {
+font-size: 14px;
+padding: 0 15px;
+text-decoration: none;
+color: #004065;
+height: 30px;
+line-height: 30px;
+display: block;
+float: left;
+}
+
+.nav ul li a:hover {
+background: #004065;
+color: #FFF;
+text-shadow: 1px 1px 1px #333;
+}
+
+#content, #list, #footer { width: 100%; overflow: auto; }
+
+#content {
+margin-top: 30px;
+border-top: 5px solid #004065;
+}
+
+#page-size, #ordering { width: 245px; }
+#page-size span, #ordering span {
+float: left;
+font-size: 14px;
+padding-top: 6px;
+}
+
+.page-size-options span a, .ordering-options span a {
+text-decoration: none;
+margin-left: 2px;
+padding: 0 4px;
+margin-top: -6px;
+display: block;
+height: 28px;
+line-height: 28px;
+float: left;
+}
+.page-size-options span a:hover, .ordering-options span a:hover {
+background: url(arrow-down.gif) no-repeat center top;
+}
+
+a.active {
+background: url(arrow-up.gif) no-repeat center bottom;
+}
+
+.main-list {
+border-top: 1px solid #004065;
+border-bottom: 1px solid #004065;
+margin-top: 5px;
+}
+/* IExpression to the horror */
+.main-list li {
+display: table;
+width: 900px;
+}
+/* I Love IExplorer! */
+
+.main-list li a {
+display: block;
+font-size: 15px;
+color: #333;
+text-decoration: none;
+padding: 5px 30px;
+}
+.main-list li a:hover {
+color: #FFF;
+background: #004065;
+}
+.main-list li.even a { background: #eaeaea; }
+.main-list li.even a:hover {
+color: #FFF;
+background: #004065;
+}
+
+#paging span {
+font-size: 12px;
+}
+#pages span a {
+margin-left: 2px;
+padding: 2px;
+color: #004065;
+font-size: 14px;
+text-decoration: none;
+}
+
+#plain-text {
+min-height: 518px;
+}
+#plain-text a { text-decoration: none }
+#plain-text a:hover { text-decoration: underline }
+#plain-text p {
+padding: 20px 20px 5px 20px;
+}
+
+#footer {
+min-height: 40px;
+background: #004065;
+color: #fff;
+}
+#footer a {
+text-decoration: none;
+text-shadow: 1px 1px 1px #333;
+color: #FFF;
+}
+#footer a:hover { text-decoration: underline }
--- /dev/null
+use strict;
+use warnings;
+use lib 'lib';
+use BackPAN::Web;
+use Plack::Test;
+use HTTP::Request::Common;
+use Test::More;
+use Devel::Cycle;
+use Data::Dumper;
+use Devel::Events::Handler::ObjectTracker;
+use Devel::Events::Filter::RemoveFields;
+use Devel::Events::Generator::Objects;
+
+my $tracker = Devel::Events::Handler::ObjectTracker->new();
+
+my $gen = Devel::Events::Generator::Objects->new(
+ handler => Devel::Events::Filter::RemoveFields->new(
+ fields => [qw/generator/], # don't need to have a ref to $gen in each event
+ handler => $tracker,
+),
+);
+
+
+my $app = BackPAN::Web->as_psgi_app;
+
+my $run = sub {
+ $gen->enable(); # start generating events
+ test_psgi app => $app,
+ client => sub {
+ my $cb = shift;
+ foreach my $path (qw{/ /releases /dists /authors /about}) {
+ for (1..1000) {
+ my $res = $cb->(GET $path);
+ ok($res->code == 200) or diag($res->code);
+ }
+ }
+ };
+ $gen->disable();
+};
+$run->();
+
+# live_objects is a Tie::RefHash::Weak hash
+
+my @leaked_objects = keys %{ $tracker->live_objects };
+
+print "leaked ", scalar(@leaked_objects), " objects\n";
+
+foreach my $object ( @leaked_objects ) {
+ print "Leaked object: $object\n";
+
+ # the event that generated it
+ #print Dumper( $object, $tracker->live_objects->{$object} );
+
+ find_cycle( $object );
+}
+
+done_testing();