[Bps-public-commit] r14435 - in Pushmi/trunk: . Pushmi-Admin/etc Pushmi-Admin/lib/Pushmi/Admin Pushmi-Admin/lib/Pushmi/Admin/Event Pushmi-Admin/lib/Pushmi/Admin/Model Pushmi-Admin/share/web/static/css
alexmv at bestpractical.com
alexmv at bestpractical.com
Wed Jul 23 13:27:10 EDT 2008
Author: alexmv
Date: Wed Jul 23 13:27:10 2008
New Revision: 14435
Added:
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Event/
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Event/ReplicaStatus.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Watcher.pm
Modified:
Pushmi/trunk/ (props changed)
Pushmi/trunk/Pushmi-Admin/etc/config.yml
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm
Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css
Log:
r34565 at kohr-ah: chmrr | 2008-07-23 13:26:58 -0400
* PubSub is almost working
Modified: Pushmi/trunk/Pushmi-Admin/etc/config.yml
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/etc/config.yml (original)
+++ Pushmi/trunk/Pushmi-Admin/etc/config.yml Wed Jul 23 13:27:10 2008
@@ -12,7 +12,7 @@
Driver: SQLite
Host: localhost
Password: ''
- RecordBaseClass: Jifty::DBI::Record::Cachable
+ RecordBaseClass: Jifty::DBI::Record::Memcached
User: ''
Version: 0.0.1
DevelMode: 1
@@ -31,7 +31,7 @@
- AdminUI: {}
PubSub:
Backend: Memcached
- Enable: ~
+ Enable: 1
SkipAccessControl: 0
TemplateClass: Pushmi::Admin::View
View:
@@ -51,6 +51,7 @@
error_mode: fatal
Port: 8888
ServeStaticFiles: 1
+ ServerClass: Jifty::Server::Fork
StaticRoot: share/web/static
TemplateRoot: share/web/templates
application:
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin.pm Wed Jul 23 13:27:10 2008
@@ -0,0 +1,60 @@
+use warnings;
+use strict;
+
+package Pushmi::Admin;
+
+sub svn_info_for {
+ my $class = shift;
+ my ($url) = @_;
+
+ my $memcached = $Jifty::DBI::Record::Memcached::MEMCACHED;
+ my $props = $memcached->get( $url );
+ return $props if defined $props;
+
+ my $client = SVN::Client->new(
+ auth => [
+ SVN::Client::get_simple_provider(),
+ SVN::Client::get_username_provider(),
+ ]
+ );
+
+ my $start = Time::HiRes::time;
+ local $SIG{ALRM} = sub { die "Timeout!" };
+ alarm 10;
+ eval {
+ $client->info(
+ $url, undef, "HEAD",
+ sub {
+ $props->{rev} = $_[1]->rev;
+ $props->{date} = $_[1]->last_changed_date;
+ },
+ 0
+ );
+ };
+ warn "$@" if $@;
+ alarm 0;
+
+ my $for;
+ if ($props) {
+ $props->{latency} = Time::HiRes::time - $start;
+ $for = $props->{latency} * 5;
+ $for = 2 if $for < 2;
+ } else {
+ $props = '';
+ $for = 5;
+ }
+ $for *= 60 unless $url =~ /^file:/;
+ $memcached->set( $url => $props, $for );
+
+ return $props;
+}
+
+sub clear_svn_info_for {
+ my $class = shift;
+ my ($url) = @_;
+
+ my $memcached = $Jifty::DBI::Record::Memcached::MEMCACHED;
+ $memcached->delete( $url );
+}
+
+1;
Modified: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm (original)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm Wed Jul 23 13:27:10 2008
@@ -5,7 +5,6 @@
use Jifty::Dispatcher -base;
on '/create' => run {
- warn YAML::Dump( Jifty->web->response );
if ( Jifty->web->response->result("create")
and Jifty->web->response->result("create")->success )
{
@@ -33,9 +32,4 @@
show '/advanced';
};
-after '*' => run {
- return if already_run;
- Pushmi::Admin::Model::Replica->clear_cache;
-};
-
1;
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Event/ReplicaStatus.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Event/ReplicaStatus.pm Wed Jul 23 13:27:10 2008
@@ -0,0 +1,18 @@
+package Pushmi::Admin::Event::ReplicaStatus;
+use strict;
+use warnings;
+use base 'Pushmi::Admin::Event';
+
+sub match {
+ my $self = shift;
+ my $query = shift;
+
+ return $self->data->{id} == $query->{id} if $query->{id};
+ return 1;
+}
+
+sub render_arguments {
+ %{$_[0]->data};
+}
+
+1;
Modified: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm (original)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm Wed Jul 23 13:27:10 2008
@@ -92,11 +92,16 @@
sub pushmi {
my $self = shift;
- return Pushmi::Mirror->new( path => $self->svn_root );
+ return $self->{pushmi} if $self->{pushmi};
+ my $p = Pushmi::Mirror->new( path => $self->svn_root );
+ eval { $p->repos } or return;
+ return $self->{pushmi} = $p;
}
sub delete {
my $self = shift;
+ $self->stop_watcher;
+ $self->clear_cache;
my $http = Pushmi::Admin::Model::HttpRootCollection->new;
$http->limit( column => "replica_id", value => $self->id );
$_->delete while $_ = $http->next;
@@ -114,113 +119,92 @@
sub sync {
my $self = shift;
- return if $self->pushmi->locked;
+ return if $self->pushmi and $self->pushmi->locked;
unless (fork) {
+ close STDOUT; # XXX This doesn't work?
exec( $^X, Jifty->config->app("pushmi_bin"), "sync",
$self->svn_root );
}
+ $self->clear_cache;
}
-sub svn_info_for {
+sub svn_root {
+ my $self = shift;
+ my @parts = File::Spec->splitpath( Jifty->config->app('svn_root') );
+ return File::Spec->catfile( @parts, $self->clean_name );
+}
+
+sub cache {
my $self = shift;
- my ($url) = @_;
+ return $self->{cache} if $self->{cache};
+ return {} unless $self->id;
- my $client = SVN::Client->new(
- auth => [
- SVN::Client::get_simple_provider(),
- SVN::Client::get_username_provider(),
- ]
- );
+ my $c = {};
+ my $local = Pushmi::Admin->svn_info_for( "file://" . $self->svn_root );
+ my $remote = Pushmi::Admin->svn_info_for( $self->url );
+ if ( not $local or not $self->pushmi ) {
+ $self->set_status("failed");
+ } elsif ( not $remote ) {
+ $c->{local_revision} = $local->{rev};
+ $c->{local_date} = $local->{date};
+ $self->set_status("offline");
+ } else {
+ $c->{remote_revision} = $remote->{rev};
+ $c->{remote_date} = $remote->{date};
+ $c->{latency} = $remote->{latency};
+ $c->{local_revision} = $local->{rev};
+ $c->{local_date} = $local->{date};
+ if ( $self->pushmi->locked ) {
+ $self->set_status("loading");
+ } elsif ( $local->{rev} < $remote->{rev} ) {
+ $self->set_status("behind");
+ } else {
+ $self->set_status("ok");
+ }
+ }
+ $c->{status} = $self->_value("status");
+ return $self->{cache} = $c;
+}
- my $start = Time::HiRes::time;
- my $props;
- local $SIG{ALRM} = sub { die "Timeout!" };
- alarm 10;
- eval {
- $client->info(
- $url, undef, "HEAD",
- sub {
- $props->{rev} = $_[1]->rev;
- $props->{date} = $_[1]->last_changed_date;
- },
- 0
- );
- };
- warn "$@" if $@;
- alarm 0;
- $props->{latency} = Time::HiRes::time - $start if $props;
- return $props;
+sub clear_cache {
+ my $self = shift;
+ delete $self->{cache};
+ Pushmi::Admin->clear_svn_info_for( "file://" . $self->svn_root );
+ Pushmi::Admin->clear_svn_info_for( $self->url );
}
sub remote_revision {
my $self = shift;
- $self->status;
- return $CACHE{ $self->id }{remote_revision};
+ return $self->cache->{remote_revision};
}
sub latency {
my $self = shift;
- $self->status;
- return sprintf( "%.2f seconds", $CACHE{ $self->id }{latency} );
+ return sprintf( "%.2f seconds", $self->cache->{latency} );
}
sub last_remote {
my $self = shift;
- $self->status;
return Time::Duration::duration(
- time - $CACHE{ $self->id }{remote_date} / 1e6 )
+ time - $self->cache->{remote_date} / 1e6 )
. " ago";
}
sub local_revision {
my $self = shift;
- $self->status;
- return $CACHE{ $self->id }{local_revision};
+ return $self->cache->{local_revision};
}
sub last_local {
my $self = shift;
- $self->status;
- return Time::Duration::duration(
- time - $CACHE{ $self->id }{local_date} / 1e6 )
+ return Time::Duration::duration( time - $self->cache->{local_date} / 1e6 )
. " ago";
}
-sub svn_root {
- my $self = shift;
- my @parts = File::Spec->splitpath( Jifty->config->app('svn_root') );
- return File::Spec->catfile( @parts, $self->clean_name );
-}
-
sub status {
my $self = shift;
- if ( $self->id and not $CACHE{ $self->id } ) {
- my $c = $CACHE{ $self->id } = {};
- my $local = $self->svn_info_for( "file://" . $self->svn_root );
- my $remote = $self->svn_info_for( $self->url );
- if ( not $local ) {
- $self->set_status("failed");
- } elsif ( not $remote ) {
- $c->{local_revision} = $local->{rev};
- $c->{local_date} = $local->{date};
- $self->set_status("offline");
- } else {
- $c->{remote_revision} = $remote->{rev};
- $c->{remote_date} = $remote->{date};
- $c->{latency} = $remote->{latency};
- $c->{local_revision} = $local->{rev};
- $c->{local_date} = $local->{date};
- if ( $self->pushmi->locked ) {
- $self->set_status("loading");
- } elsif ( $local->{rev} < $remote->{rev} ) {
- $self->set_status("behind");
- } else {
- $self->set_status("ok");
- }
- }
- }
- return $self->_value("status");
+ return $self->cache->{status};
}
sub long_status {
@@ -251,12 +235,42 @@
}
}
-sub current_user_can {
- return 1;
+sub start_watcher {
+ my $self = shift;
+ $SIG{CHLD} = sub { print STDERR "sigchld: $!" while wait > 0; };
+ Jifty->bus->modify(
+ watchers => sub {
+ return
+ if $_->{ $self->clean_name }
+ and kill 0, $_->{ $self->clean_name }{pid};
+ if ( my $pid = fork ) {
+ $_->{ $self->clean_name } = { pid => $pid };
+ } else {
+ my $id = $self->id;
+ exec( $^X => "-Ilib",
+ "-MPushmi::Admin::Watcher",
+ "-e" => "Pushmi::Admin::Watcher->new($id)"
+ );
+ }
+ }
+ );
}
-sub clear_cache {
- %CACHE = ();
+sub stop_watcher {
+ my $self = shift;
+ my $pid;
+ Jifty->bus->modify(
+ watchers => sub {
+ return unless $_->{ $self->clean_name };
+ $pid = $_->{ $self->clean_name }{pid};
+ delete $_->{ $self->clean_name };
+ }
+ );
+ kill 2, $pid if $pid;
+}
+
+sub current_user_can {
+ return 1;
}
1;
Modified: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm (original)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm Wed Jul 23 13:27:10 2008
@@ -1,5 +1,8 @@
package Pushmi::Admin::View;
+use strict;
+use warnings;
+
use Jifty::View::Declare -base;
use YAML;
@@ -13,20 +16,11 @@
{ id is 'replica_list', class is 'roundbox' };
h2 {"Current replicas"};
while ( my $replica = $replicas->next ) {
- div {
- { class is 'replica status-light ' . $replica->status };
- h3 {
- hyperlink(
- url => "/replica/" . $replica->clean_name,
- label => $replica->name
- );
- };
- hyperlink( url => $replica->url, label => $replica->url );
- div {
- { class is 'status' }
- $replica->long_status;
- }
- }
+ render_region(
+ name => "summary-" . $replica->id,
+ path => "/fragments/summary",
+ arguments => { id => $replica->id }
+ );
}
};
@@ -96,26 +90,46 @@
}
}
+template 'fragments/summary' => sub {
+ my $id = get('id');
+ my $replica = Pushmi::Admin::Model::Replica->load($id);
+ div {
+ { class is 'replica status-light ' . $replica->status };
+ h3 {
+ hyperlink(
+ url => "/replica/" . $replica->clean_name,
+ label => $replica->name
+ );
+ };
+ hyperlink( url => $replica->url, label => $replica->url );
+ div {
+ { class is 'status' }
+ $replica->long_status;
+ }
+ };
+
+ # Add a PubSub watcher, if need be
+ Jifty->subs->add(
+ class => 'ReplicaStatus',
+ queries => [{ id => $id }],
+ mode => 'Replace',
+ region => Jifty->web->qualified_region,
+ render_with => '/fragments/summary',
+ );
+ $replica->start_watcher;
+};
+
template 'replica' => page { title => "About " . get("replica")->name }
content {
my $replica = get 'replica';
div {
{ class is 'roundbox' };
- h2 {"Replica status"}
- div {
- { class is 'replica status-light ' . $replica->status };
- h3 {
- hyperlink(
- url => "/replica/" . $replica->clean_name,
- label => $replica->name
- );
- };
- hyperlink( url => $replica->url, label => $replica->url );
- div {
- { class is 'status' }
- $replica->long_status;
- }
- }
+ h2 {"Replica status"};
+ render_region(
+ name => "summary-" . $replica->id,
+ path => "/fragments/summary",
+ arguments => { id => $replica->id }
+ );
};
div {
@@ -164,6 +178,7 @@
h2 {"Local replica failure"};
}
};
+
div {
{ id is 'advanced' }
hyperlink(
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Watcher.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Watcher.pm Wed Jul 23 13:27:10 2008
@@ -0,0 +1,44 @@
+package Pushmi::Admin::Watcher;
+
+use Jifty;
+
+use strict;
+use warnings;
+
+BEGIN {
+ # We must close STDOUT, or our parent request may never return to the client
+ close STDOUT;
+ Jifty->new;
+}
+
+
+sub new {
+ my ($class, $id) = @_;
+ my $previous = "";
+
+ my $replica = Pushmi::Admin::Model::Replica->load($id);
+ exit unless $replica->id;
+
+ Jifty->bus->modify(
+ watchers => sub {
+ $_->{ $replica->clean_name }{pid} = $$;
+ }
+ );
+ while (1) {
+ $replica = Pushmi::Admin::Model::Replica->load($id);
+ last unless $replica->id;
+ if ($replica->long_status ne $previous) {
+ print STDERR "@{[$replica->clean_name]}: NEW STATUS: @{[$replica->long_status]}\n";
+ Pushmi::Admin::Event::ReplicaStatus->new(
+ { id => $id }
+ )->publish;
+ }
+ $previous = $replica->long_status;
+ sleep 1;
+ }
+
+ print STDERR "@{[$id]} exiting\n";
+ exit;
+}
+
+1;
Modified: Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css (original)
+++ Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css Wed Jul 23 13:27:10 2008
@@ -82,6 +82,7 @@
font-weight: normal;
}
+
/* Rounded boxes and titles */
.roundbox {
@@ -108,15 +109,21 @@
clear: left;
}
-/* Customizations */
+
+/* Replica summaries, lists, and status lights */
+
#replica_status {
- width: 450px;
background: #223;
}
+.replica + .replica {
+ border-top: 1px solid #334;
+}
+
.replica {
clear: left;
padding-left: 60px;
+ margin: 1em 0;
}
.replica.status-light {
@@ -130,6 +137,9 @@
.status-light.offline { background-image: url(/static/images/status/red.png); }
.status-light.failed { background-image: url(/static/images/status/red.png); }
+
+/* The "advanced" button and page */
+
#advanced {
margin: 1em 0;
padding: 1em;
@@ -142,12 +152,15 @@
padding: 1em;
}
-.delete_replica input, .remirror_replica input {
+input.button {
border: 1px solid #334;
background: #223;
color: #ddd;
-moz-border-radius: 5px; -webkit-border-radius: 5px;
padding: 0.5em;
+}
+
+.delete_replica input, .remirror_replica input {
padding-left: 2.5em;
background-repeat: no-repeat;
background-position: 10px 7px;
@@ -164,4 +177,7 @@
.delete_replica {
border-bottom: 1px solid #334;
-}
\ No newline at end of file
+}
+
+
+/* */
\ No newline at end of file
More information about the Bps-public-commit
mailing list