Skip to content

Commit

Permalink
added experimental self-restarting Morbo development web server and r…
Browse files Browse the repository at this point in the history
…emoved old "--reload" support since there have been too many negative side effects
  • Loading branch information
kraih committed Jun 17, 2011
1 parent 4552589 commit 5af1133
Show file tree
Hide file tree
Showing 22 changed files with 305 additions and 257 deletions.
5 changes: 5 additions & 0 deletions Changes
@@ -1,14 +1,19 @@
This file documents the revision history for Perl extension Mojolicious.

1.44 2011-06-13 00:00:00
- Added EXPERIMENTAL self-restarting Morbo development web server and
removed old "--reload" support since there have been too many
negative side effects.
- Added EXPERIMENTAL application mount plugin.
- Updated prettify.js to version 1-Jun-2011.
- Updated WebSocket diagnostics test in Mojo::HelloWorld for latest
Firefox Aurora.
- Improved inline template and static file performance.
- Improved documentation.
- Improved tests.
- Fixed a few application embedding bugs.
- Fixed link generation bug in Mojolicious::Plugin::PodRenderer.
- Fixed small embedding bug in Mojolicious::Plugin::RequestTimer.

1.43 2011-06-13 00:00:00
- Improved after_dispatch hook by allowing it to change session data.
Expand Down
22 changes: 6 additions & 16 deletions lib/Mojo/Command.pm
Expand Up @@ -103,18 +103,12 @@ sub get_all_data {
my ($self, $class) = @_;
$class ||= ref $self;

# Handle
# Refresh or use cached data
my $d = do { no strict 'refs'; \*{"$class\::DATA"} };

# Refresh
if (fileno $d) {
seek $d, 0, 0;
$CACHE->{$class} = join '', <$d>;
close $d;
}

# Content
return unless defined(my $content = $CACHE->{$class});
return $CACHE->{$class} unless fileno $d;
seek $d, 0, 0;
my $content = join '', <$d>;
close $d;

# Ignore everything before __DATA__ (windows will seek to start of file)
$content =~ s/^.*\n__DATA__\r?\n/\n/s;
Expand All @@ -127,7 +121,7 @@ sub get_all_data {
shift @data;
# Find data
my $all = {};
my $all = $CACHE->{$class} = {};
while (@data) {
my ($name, $content) = splice @data, 0, 2;
b64_decode $content if $name =~ s/\s*\(\s*base64\s*\)$//;
Expand Down Expand Up @@ -294,10 +288,6 @@ sub run {
sub start {
my $self = shift;

# Don't run commands if we are reloading
return $self if $ENV{MOJO_COMMANDS_DONE};
$ENV{MOJO_COMMANDS_DONE} ||= 1;

# Executable
$ENV{MOJO_EXE} ||= (caller)[1] if $ENV{MOJO_APP};

Expand Down
99 changes: 6 additions & 93 deletions lib/Mojo/Loader.pm
@@ -1,37 +1,24 @@
package Mojo::Loader;
use Mojo::Base -base;

# "Don't let Krusty's death get you down, boy.
# People die all the time, just like that.
# Why, you could wake up dead tomorrow! Well, good night."
use Carp 'carp';
use File::Basename;
use File::Spec;
use Mojo::Command;
use Mojo::Exception;

use constant DEBUG => $ENV{MOJO_LOADER_DEBUG} || 0;

# Cache stats
my $STATS = {};

# Debugger sub tracking
BEGIN { $^P |= 0x10 }

# "Homer no function beer well without."
sub load {
my ($self, $module) = @_;

# Check module name
return 1 if !$module || $module !~ /^[\w\:\']+$/;

# Forced reload
if ($ENV{MOJO_RELOAD}) {
my $key = $module;
$key =~ s/\:\:/\//g;
$key .= '.pm';
_unload($key);
}

# Already loaded
else { return if $module->can('new') }
return if $module->can('new');

# Load
unless (eval "require $module; 1") {
Expand All @@ -47,37 +34,8 @@ sub load {
return;
}

# "Don't let Krusty's death get you down, boy.
# People die all the time, just like that.
# Why, you could wake up dead tomorrow! Well, good night."
sub reload {

# Cleanup script and "main" namespace
delete $INC{$0};
$STATS->{$0} = 1;
_purge(grep { index($_, 'main::') == 0 } keys %DB::sub);

# Reload
while (my ($key, $file) = each %INC) {

# Modified time
next unless $file;
my $mtime = (stat $file)[9];

# Startup time as default
$STATS->{$file} = $^T unless defined $STATS->{$file};

# Modified
if ($mtime > $STATS->{$file}) {
if (my $e = _reload($key)) { return $e }
$STATS->{$file} = $mtime;
}
}

# Force script reloading
return _reload($0);
}

# "This is the worst thing you've ever done.
# You say that so often that it lost its meaning."
sub search {
my ($self, $namespace) = @_;

Expand Down Expand Up @@ -109,35 +67,6 @@ sub search {
return $modules;
}

# "This is the worst thing you've ever done.
# You say that so often that it lost its meaning."
sub _purge {
for my $sub (@_) {
warn "PURGE $sub\n" if DEBUG;
carp "Can't unload sub '$sub': $@" unless eval { undef &$sub; 1 };
delete $DB::sub{$sub};
no strict 'refs';
$sub =~ /^(.*::)(.*?)$/ and delete *{$1}->{$2};
}
}

sub _reload {
my $key = shift;
return if $key eq 'Mojo/Loader.pm';
warn "CLEANING $key\n" if DEBUG;
_unload($key);
warn "RELOADING $key\n" if DEBUG;
return Mojo::Exception->new($@)
unless eval { package main; require $key; 1 };
return;
}

sub _unload {
my $key = shift;
return unless my $file = delete $INC{$key};
_purge(grep { index($DB::sub{$_}, "$file:") == 0 } keys %DB::sub);
}

1;
__END__
Expand All @@ -153,9 +82,6 @@ Mojo::Loader - Loader
my $modules = $loader->search('Some::Namespace');
$loader->load($modules->[0]);
# Reload
Mojo::Loader->reload;
=head1 DESCRIPTION
L<Mojo::Loader> is a class loader and plugin framework.
Expand All @@ -172,25 +98,12 @@ following new ones.
Load a class, note that classes are checked for a C<new> method to see if
they are already loaded.
=head2 C<reload>
my $e = Mojo::Loader->reload;
Reload all Perl files with changes.
=head2 C<search>
my $modules = $loader->search('MyApp::Namespace');
Search modules in a namespace.
=head1 DEBUGGING
You can set the C<MOJO_LOADER_DEBUG> environment variable to get some
advanced diagnostics information printed to C<STDERR>.
MOJO_LOADER_DEBUG=1
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
Expand Down
27 changes: 4 additions & 23 deletions lib/Mojo/Message.pm
Expand Up @@ -4,7 +4,8 @@ use Mojo::Base -base;
use Carp 'croak';
use Mojo::Asset::Memory;
use Mojo::Content::Single;
use Mojo::Loader;
use Mojo::DOM;
use Mojo::JSON;
use Mojo::Parameters;
use Mojo::Upload;
use Mojo::Util qw/decode url_unescape/;
Expand Down Expand Up @@ -191,21 +192,13 @@ sub dom {
# Multipart
return if $self->is_multipart;

# Load DOM class
my $class = $self->dom_class;
if (my $e = Mojo::Loader->load($class)) {
croak ref $e
? qq/Can't load DOM class "$class": $e/
: qq/DOM class "$class" doesn't exist./;
}

# Charset
my $charset;
($self->headers->content_type || '') =~ /charset=\"?([^\"\s;]+)\"?/
and $charset = $1;

# Parse
my $dom = $class->new(charset => $charset)->parse($self->body);
my $dom = $self->dom_class->new(charset => $charset)->parse($self->body);

# Find right away
return $dom->find(@_) if @_;
Expand Down Expand Up @@ -327,20 +320,8 @@ sub is_multipart { shift->content->is_multipart }

sub json {
my $self = shift;

# Multipart
return if $self->is_multipart;

# Load JSON class
my $class = $self->json_class;
if (my $e = Mojo::Loader->load($class)) {
croak ref $e
? qq/Can't load JSON class "$class": $e/
: qq/JSON class "$class" doesn't exist./;
}

# Decode
return $class->new->decode($self->body);
return $self->json_class->new->decode($self->body);
}

sub leftovers { shift->content->leftovers }
Expand Down
30 changes: 8 additions & 22 deletions lib/Mojo/Server.pm
Expand Up @@ -31,13 +31,6 @@ has on_request => sub {
has on_transaction => sub {
sub {
my $self = shift;

# Reload
if ($self->reload) {
if (my $e = Mojo::Loader->reload) { warn $e }
delete $self->{app};
}

$self->app->on_transaction->($self->app);
};
};
Expand All @@ -47,7 +40,6 @@ has on_websocket => sub {
$self->app->on_websocket->($self->app, @_)->server_handshake;
};
};
has reload => sub { $ENV{MOJO_RELOAD} || 0 };

sub load_app {
my ($self, $file) = @_;
Expand All @@ -56,17 +48,18 @@ sub load_app {
local $ENV{MOJO_APP_LOADER} = 1;
local $ENV{MOJO_APP};
local $ENV{MOJO_EXE};
local $ENV{MOJO_COMMANDS_DONE};

# Try to load application from script
my $class = 'Mojo::Server::_' . md5_sum($file . $$);
# Try to load application from script into sandbox
my $class = 'Mojo::Server::SandBox::' . md5_sum($file . $$);
my $app;
die $@ unless eval <<EOF;
package $class;
unless (\$app = do \$file) {
die qq/Can't load application "\$file": \$@/ if \$@;
die qq/Can't load application "\$file": \$!/ unless defined \$app;
die qq/Can't load application' "\$file".\n/ unless \$app;
{
unless (\$app = do \$file) {
die qq/Can't load application "\$file": \$@/ if \$@;
die qq/Can't load application "\$file": \$!/ unless defined \$app;
die qq/Can't load application' "\$file".\n/ unless \$app;
}
}
1;
EOF
Expand Down Expand Up @@ -158,13 +151,6 @@ Callback to be invoked when a new transaction is needed.
Callback to be invoked for WebSocket handshakes.
=head2 C<reload>
my $reload = $server->reload;
$server = $server->reload(1);
Activate automatic reloading.
=head1 METHODS
L<Mojo::Server> inherits all methods from L<Mojo::Base> and implements the
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/Server/Daemon.pm
Expand Up @@ -289,9 +289,10 @@ sub _listen {
}

# Friendly message
return if $self->silent;
$self->app->log->info("Server listening ($listen)");
$listen =~ s/^(https?\:\/\/)\*/${1}127.0.0.1/i;
print "Server available at $listen.\n" unless $self->silent;
print "Server available at $listen.\n";
}

sub _read {
Expand Down
11 changes: 1 addition & 10 deletions lib/Mojo/Server/Hypnotoad.pm
Expand Up @@ -14,9 +14,7 @@ use POSIX qw/setsid WNOHANG/;
use Scalar::Util 'weaken';

# Preload
use Mojo::DOM;
use Mojo::UserAgent;
use Mojolicious::Controller;

use constant DEBUG => $ENV{HYPNOTOAD_DEBUG} || 0;

Expand Down Expand Up @@ -65,10 +63,6 @@ sub run {
$ENV{HYPNOTOAD_EXE} ||= $0;
$0 = $ENV{HYPNOTOAD_APP};

# Cleanup
delete $ENV{MOJO_COMMANDS_DONE};
delete $ENV{MOJO_RELOAD};

# Clean start
exec $ENV{HYPNOTOAD_EXE} unless $ENV{HYPNOTOAD_REV}++;

Expand Down Expand Up @@ -396,9 +390,6 @@ Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD!
use Mojo::Server::Hypnotoad;
my $toad = Mojo::Server::Hypnotoad->new;
$toad->run('myapp.pl', 'hypnotoad.conf');
=head1 DESCRIPTION
L<Mojo::Server::Hypnotoad> is a full featured UNIX optimized preforking async
Expand Down Expand Up @@ -610,7 +601,7 @@ Start server.
You can set the C<HYPNOTOAD_DEBUG> environment variable to get some advanced
diagnostics information printed to C<STDERR>.
MOJO_HYPNOTOAD_DEBUG=1
HYPNOTOAD_DEBUG=1
=head1 SEE ALSO
Expand Down

0 comments on commit 5af1133

Please sign in to comment.