mourningdove/cgi-bin/Plack/Middleware/DW/Dev.pm

81 lines
2.2 KiB
Perl
Raw Permalink Normal View History

2026-05-24 01:03:05 +00:00
#!/usr/bin/perl
#
# Plack::Middleware::DW::Dev
#
# Middleware that is used by development servers to do things like reload PM files
# that have changed, etc. Must not be included in production.
#
# Authors:
# Mark Smith <mark@dreamwidth.org>
#
# Copyright (c) 2021 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself. For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#
package Plack::Middleware::DW::Dev;
use strict;
use v5.10;
use Log::Log4perl;
my $log = Log::Log4perl->get_logger(__PACKAGE__);
use parent qw/ Plack::Middleware /;
our %LIB_MOD_TIME;
sub call {
my ( $self, $env ) = @_;
$log->logcroak('Unable to run: not dev server!') unless $LJ::IS_DEV_SERVER;
# Refresh modtimes in case we don't have one (if a file got loaded later
# in another request, we should still be able to reload it)
while ( my ( $k, $file ) = each %INC ) {
next unless defined $file; # Happens if require caused a runtime error
next if $LIB_MOD_TIME{$file};
next unless $file =~ m!^\Q$LJ::HOME\E!;
my $mod = ( stat($file) )[9];
$LIB_MOD_TIME{$file} = $mod;
}
# Now determine what to reload
my %to_reload;
while ( my ( $file, $mod ) = each %LIB_MOD_TIME ) {
my $cur_mod = ( stat($file) )[9];
next if $cur_mod == $mod;
$to_reload{$file} = 1;
}
foreach my $key ( keys %INC ) {
my $file = $INC{$key};
delete $INC{$key} if $to_reload{$file};
}
# And now reload it
foreach my $file ( keys %to_reload ) {
$log->info( 'Reloading file: ', $file );
my %reloaded;
local $SIG{__WARN__} = sub {
if ( $_[0] =~ m/^Subroutine (\S+) redefined at / ) {
warn @_ if ( $reloaded{$1}++ );
}
else {
warn(@_);
}
};
my $good = do $file;
if ($good) {
$LIB_MOD_TIME{$file} = ( stat($file) )[9];
}
else {
$log->logcroak( 'Failed to reload module [', $file, '] due to error: ', $@ );
}
}
return $self->app->($env);
}
1;