Catalyst-Plugin-Static-Simple-0.36/0000755000175000017500000000000013252455554016464 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/MANIFEST0000644000175000017500000000325213252455456017620 0ustar ilmariilmari.travis.yml Changes inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AuthorRequires.pm inc/Module/Install/AuthorTests.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Catalyst/Plugin/Static/Simple.pm Makefile.PL MANIFEST This list of files META.yml t/01use.t t/04static.t t/05dirs.t t/06include_path.t t/07mime_types.t t/08subreq.t t/09ignore_ext.t t/10ignore_dirs.t t/11serve_static.t t/12check_error_scope.t t/13no_include_path.t t/14deprecated.t t/20debug.t t/author/02pod.t t/author/03podcoverage.t t/author/notabs.t t/lib/IncTestApp.pm t/lib/IncTestApp/Controller/Root.pm t/lib/IncTestApp/root/images/bad.gif t/lib/IncTestApp/root/overlay/overlay.jpg t/lib/TestApp.pm t/lib/TestApp/Controller/Root.pm t/lib/TestApp/root/always-static/test t/lib/TestApp/root/always-static/test.html t/lib/TestApp/root/css/static.css t/lib/TestApp/root/files/bad.gif t/lib/TestApp/root/files/empty.txt t/lib/TestApp/root/files/err.unknown t/lib/TestApp/root/files/static.css t/lib/TestApp/root/ignored/bad.gif t/lib/TestApp/root/ignored/index.html t/lib/TestApp/root/ignored/static.css t/lib/TestApp/root/ignored/tmpl.tt t/lib/TestApp/root/images/bad.gif t/lib/TestApp/root/images/catalyst.png t/lib/TestApp/root/incpath/incpath.css t/lib/TestApp/root/overlay/o-ignored/bad.gif t/lib/TestApp/root/overlay/o-ignored/index.html t/lib/TestApp/root/overlay/o-ignored/static.css t/lib/TestApp/root/overlay/o-ignored/tmpl.tt t/lib/TestApp/root/overlay/overlay.jpg t/lib/TestLog.pm Catalyst-Plugin-Static-Simple-0.36/Makefile.PL0000644000175000017500000000226413252232153020426 0ustar ilmariilmariuse strict; use warnings; BEGIN { push @INC, '.' unless $INC[-1] eq '.'; } use inc::Module::Install 0.91; use Module::Install::AuthorRequires; use Module::Install::AuthorTests; name 'Catalyst-Plugin-Static-Simple'; all_from 'lib/Catalyst/Plugin/Static/Simple.pm'; requires 'Catalyst::Runtime' => '5.80008'; requires 'MIME::Types' => '2.03'; requires 'Test::More'; requires 'Moose'; requires 'MooseX::Types'; requires 'namespace::autoclean'; test_requires 'Test::More'; author_requires 'Test::NoTabs'; author_requires 'Test::Pod' => '1.14'; author_requires 'Test::Pod::Coverage' => '1.04'; author_tests 't/author'; if( can_use 'Catalyst::Plugin::SubRequest' ) { unless( can_use 'Catalyst::Plugin::SubRequest' => '0.08' ) { print "** WARNING **\n" . "You appear to have a version of Catalyst::Plugin::SubRequest " . "older than 0.08.\n" . "You must upgrade to SubRequest 0.08 or later if you use it " . "in any applications with Static::Simple.\n"; requires 'Catalyst::Plugin::SubRequest' => '0.08'; } } auto_install; resources repository => 'git://git.shadowcat.co.uk/catagits/Catalyst-Plugin-Static-Simple.git'; WriteAll; Catalyst-Plugin-Static-Simple-0.36/.travis.yml0000644000175000017500000000052113252232153020557 0ustar ilmariilmarilanguage: perl perl: - "5.26" - "5.24" - "5.22" - "5.20" - "5.18" - "5.16" - "5.14" - "5.12" - "5.10" - "5.8" sudo: false before_install: - eval $(curl https://travis-perl.github.io/init) --auto install: - $HELPERS_ROOT/bin/cpan-config - cpan-install --deps Test::NoTabs Test::Pod Test::Pod::Coverage Catalyst-Plugin-Static-Simple-0.36/META.yml0000644000175000017500000000137613252455455017744 0ustar ilmariilmari--- abstract: 'Make serving static pages painless.' author: - 'Andy Grundman, ' build_requires: ExtUtils::MakeMaker: 6.36 Test::More: 0 configure_requires: ExtUtils::MakeMaker: 6.36 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.18' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Catalyst-Plugin-Static-Simple no_index: directory: - inc - t requires: Catalyst::Runtime: '5.80008' MIME::Types: '2.03' Moose: 0 MooseX::Types: 0 Test::More: 0 namespace::autoclean: 0 resources: license: http://dev.perl.org/licenses/ repository: git://git.shadowcat.co.uk/catagits/Catalyst-Plugin-Static-Simple.git version: '0.36' Catalyst-Plugin-Static-Simple-0.36/inc/0000755000175000017500000000000013252455554017235 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/inc/Module/0000755000175000017500000000000013252455554020462 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/inc/Module/Install.pm0000644000175000017500000002714513252455454022436 0ustar ilmariilmari#line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.18'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $base_path = VMS::Filespec::unixify($base_path) if $^O eq 'VMS'; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( {no_chdir => 1, wanted => sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($File::Find::name); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }}, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/0000755000175000017500000000000013252455554022070 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Can.pm0000644000175000017500000000640513252455454023133 0ustar ilmariilmari#line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; if ($^O eq 'VMS') { require ExtUtils::CBuilder; my $builder = ExtUtils::CBuilder->new( quiet => 1, ); return $builder->have_compiler; } my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 245 Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Metadata.pm0000644000175000017500000004330213252455454024147 0ustar ilmariilmari#line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Base.pm0000644000175000017500000000214713252455454023303 0ustar ilmariilmari#line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.18'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Include.pm0000644000175000017500000000101513252455454024005 0ustar ilmariilmari#line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Makefile.pm0000644000175000017500000002743713252455454024157 0ustar ilmariilmari#line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/WriteAll.pm0000644000175000017500000000237613252455454024160 0ustar ilmariilmari#line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/AuthorTests.pm0000644000175000017500000000221513252455454024712 0ustar ilmariilmari#line 1 package Module::Install::AuthorTests; use 5.005; use strict; use Module::Install::Base; use Carp (); #line 16 use vars qw{$VERSION $ISCORE @ISA}; BEGIN { $VERSION = '0.002'; $ISCORE = 1; @ISA = qw{Module::Install::Base}; } #line 42 sub author_tests { my ($self, @dirs) = @_; _add_author_tests($self, \@dirs, 0); } #line 56 sub recursive_author_tests { my ($self, @dirs) = @_; _add_author_tests($self, \@dirs, 1); } sub _wanted { my $href = shift; sub { /\.t$/ and -f $_ and $href->{$File::Find::dir} = 1 } } sub _add_author_tests { my ($self, $dirs, $recurse) = @_; return unless $Module::Install::AUTHOR; my @tests = $self->tests ? (split / /, $self->tests) : 't/*.t'; # XXX: pick a default, later -- rjbs, 2008-02-24 my @dirs = @$dirs ? @$dirs : Carp::confess "no dirs given to author_tests"; @dirs = grep { -d } @dirs; if ($recurse) { require File::Find; my %test_dir; File::Find::find(_wanted(\%test_dir), @dirs); $self->tests( join ' ', @tests, map { "$_/*.t" } sort keys %test_dir ); } else { $self->tests( join ' ', @tests, map { "$_/*.t" } sort @dirs ); } } #line 107 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Fetch.pm0000644000175000017500000000462713252455454023467 0ustar ilmariilmari#line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/Win32.pm0000644000175000017500000000340313252455454023327 0ustar ilmariilmari#line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/AuthorRequires.pm0000644000175000017500000000113113252455454025403 0ustar ilmariilmari#line 1 use strict; use warnings; package Module::Install::AuthorRequires; use base 'Module::Install::Base'; # cargo cult BEGIN { our $VERSION = '0.02'; our $ISCORE = 1; } sub author_requires { my $self = shift; return $self->{values}->{author_requires} unless @_; my @added; while (@_) { my $mod = shift or last; my $version = shift || 0; push @added, [$mod => $version]; } push @{ $self->{values}->{author_requires} }, @added; $self->admin->author_requires(@added); return map { @$_ } @added; } 1; __END__ #line 92 Catalyst-Plugin-Static-Simple-0.36/inc/Module/Install/AutoInstall.pm0000644000175000017500000000416213252455454024667 0ustar ilmariilmari#line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.18'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); my %seen; my @requires = map @$_, map @$_, grep ref, $self->requires; while (my ($mod, $ver) = splice(@requires, 0, 2)) { $seen{$mod}{$ver}++; } my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @deduped; while (my ($mod, $ver) = splice(@features_require, 0, 2)) { push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; } $self->requires(@deduped); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub installdeps_target { my ($self, @args) = @_; $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall::_installdeps_target(1); $self->auto_install(@args); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Catalyst-Plugin-Static-Simple-0.36/inc/Module/AutoInstall.pm0000644000175000017500000006231113252455454023261 0ustar ilmariilmari#line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.18'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::getcwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward compatibility while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed, @modules_to_upgrade ); while (my ($pkg, $ver) = splice(@_, 0, 2)) { # grep out those already installed if (_version_cmp(_version_of($pkg), $ver) >= 0) { push @installed, $pkg; if ($UpgradeDeps) { push @modules_to_upgrade, $pkg, $ver; } } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @modules_to_upgrade; @installed = (); @modules_to_upgrade = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $opt eq 'urllist' ? [$arg] : $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::getcwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1197 Catalyst-Plugin-Static-Simple-0.36/t/0000755000175000017500000000000013252455554016727 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/04static.t0000644000175000017500000000246313252213526020543 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; # Module::Build craps out on files with spaces so it's not included in the dist my $has_space_file = -e "$FindBin::Bin/lib/TestApp/root/files/space file.txt"; use Test::More; plan tests => ($has_space_file) ? 12 : 9; use Catalyst::Test 'TestApp'; # test getting a css file ok( my $res = request('http://localhost/files/static.css'), 'request ok' ); is( $res->content_type, 'text/css', 'content-type text/css ok' ); like( $res->content, qr/background/, 'content of css ok' ); # test a file with spaces if ( $has_space_file ) { ok( $res = request('http://localhost/files/space file.txt'), 'request ok' ); is( $res->content_type, 'text/plain', 'content-type text/plain ok' ); like( $res->content, qr/background/, 'content of space file ok' ); } # test a non-existent file ok( $res = request('http://localhost/files/404.txt'), 'request ok' ); is( $res->content, 'default', 'default handler for non-existent content ok' ); # test unknown extension ok( $res = request('http://localhost/files/err.unknown'), 'request ok' ); is( $res->content_type, 'text/plain', 'unknown extension as text/plain ok' ); ok( $res = request('http://localhost/files/empty.txt'), 'request ok' ); is( $res->content, '', 'empty files result in an empty response' ); Catalyst-Plugin-Static-Simple-0.36/t/12check_error_scope.t0000644000175000017500000000122713252205174022727 0ustar ilmariilmari#!perl use strict; use warnings; no strict 'refs'; no warnings 'redefine'; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 3; BEGIN { use Catalyst::Plugin::Static::Simple; Catalyst::Plugin::Static::Simple->meta->add_before_method_modifier( 'prepare_action', sub { my ($c) = @_; eval { die("FOO"); }; ok( $@, '$@ has a value.' ); } ); } use Catalyst::Test 'TestApp'; TestApp->config->{'Plugin::Static::Simple'}->{dirs} = [qr{stuff/}]; ok( my $res = request("http://localhost/"), 'request ok' ); ok( $res->code == 200, q{Previous error doesn't crash static::simple} ); Catalyst-Plugin-Static-Simple-0.36/t/author/0000755000175000017500000000000013252455554020231 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/author/02pod.t0000644000175000017500000000012413252205174021326 0ustar ilmariilmariuse strict; use warnings; use Test::More; use Test::Pod 1.14; all_pod_files_ok(); Catalyst-Plugin-Static-Simple-0.36/t/author/03podcoverage.t0000644000175000017500000000010713252205174023044 0ustar ilmariilmariuse Test::More; use Test::Pod::Coverage 1.04; all_pod_coverage_ok(); Catalyst-Plugin-Static-Simple-0.36/t/author/notabs.t0000644000175000017500000000013213252205174021667 0ustar ilmariilmariuse strict; use warnings; use Test::More; use Test::NoTabs; all_perl_files_ok(qw/lib/); Catalyst-Plugin-Static-Simple-0.36/t/05dirs.t0000644000175000017500000000256113252450747020225 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 13; use Catalyst::Test 'TestApp'; # test defined static dirs TestApp->config->{'Plugin::Static::Simple'}->{dirs} = [ 'always-static', qr/^images/, 'qr/^css/', ]; # a file with no extension will return text/plain ok( my $res = request('http://localhost/always-static/test'), 'request ok' ); is( $res->content_type, 'text/plain', 'text/plain ok' ); # a file with an extension in ignore_extensions still gets served ok( $res = request('http://localhost/always-static/test.html'), 'request ok' ); is( $res->code, 200, 'html file in dirs get served' ); # a missing file in a defined static dir will return 404 and text/html ok( $res = request('http://localhost/always-static/404.txt'), 'request ok' ); is( $res->code, 404, '404 ok' ); is( $res->content_type, 'text/html', '404 is text/html' ); # qr regex test ok( $res = request('http://localhost/images/catalyst.png'), 'request ok' ); like( $res->content_type, qr{\Aimage/.*png\z}, 'qr regex path ok' ); # eval regex test ok( $res = request('http://localhost/css/static.css'), 'request ok' ); like( $res->content, qr/background/, 'eval regex path ok' ); # A static dir with no trailing slash is handled by Cat ok( $res = request('http://localhost/always-static'), 'request ok' ); is( $res->content, 'default', 'content ok' ); Catalyst-Plugin-Static-Simple-0.36/t/14deprecated.t0000644000175000017500000000110313252205174021343 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 5; use Catalyst::Test 'IncTestApp'; is( $TestLog::logged, "Deprecated 'static' config key used, please use the key 'Plugin::Static::Simple' instead", "Got warning" ); # test overlay dir ok( my $res = request('http://localhost/overlay.jpg'), 'request ok' ); is( $res->content_type, 'image/jpeg', 'overlay path ok' ); # test passthrough to root ok( $res = request('http://localhost/images/bad.gif'), 'request ok' ); is( $res->content_type, 'image/gif', 'root path ok' ); Catalyst-Plugin-Static-Simple-0.36/t/07mime_types.t0000644000175000017500000000112313252213526021422 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 4; use Catalyst::Test 'TestApp'; # test custom MIME types TestApp->config->{'Plugin::Static::Simple'}->{mime_types} = { unknown => 'holy/crap', gif => 'patents/are-evil', }; ok( my $res = request('http://localhost/files/err.unknown'), 'request ok' ); is( $res->content_type, 'holy/crap', 'custom MIME type ok' ); ok( $res = request('http://localhost/files/bad.gif'), 'request ok' ); is( $res->content_type, 'patents/are-evil', 'custom MIME type overlay ok' ); Catalyst-Plugin-Static-Simple-0.36/t/01use.t0000644000175000017500000000013413252205174020036 0ustar ilmariilmariuse Test::More tests => 2; use_ok('Catalyst'); use_ok('Catalyst::Plugin::Static::Simple'); Catalyst-Plugin-Static-Simple-0.36/t/13no_include_path.t0000644000175000017500000000100613252205174022377 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 4; use Catalyst::Test 'TestApp'; # test passthrough to root ok( my $res = request('http://localhost/images/bad.gif'), 'request ok' ); is( $res->content_type, 'image/gif', 'root path ok' ); is( scalar @{ TestApp->config->{'Plugin::Static::Simple'}->{include_path} }, 1, 'One include path used'); is( TestApp->config->{'Plugin::Static::Simple'}->{include_path}->[0], TestApp->config->{root}, "It's the root path" ); Catalyst-Plugin-Static-Simple-0.36/t/06include_path.t0000644000175000017500000000143013252205174021706 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 6; use Catalyst::Test 'TestApp'; # test altenate root dirs TestApp->config->{'Plugin::Static::Simple'}->{include_path} = [ TestApp->config->{root} . '/overlay', \&TestApp::incpath_generator, TestApp->config->{root}, ]; # test overlay dir ok( my $res = request('http://localhost/overlay.jpg'), 'request ok' ); is( $res->content_type, 'image/jpeg', 'overlay path ok' ); # test incpath_generator ok( $res = request('http://localhost/incpath.css'), 'request ok' ); is( $res->content_type, 'text/css', 'incpath coderef ok' ); # test passthrough to root ok( $res = request('http://localhost/images/bad.gif'), 'request ok' ); is( $res->content_type, 'image/gif', 'root path ok' ); Catalyst-Plugin-Static-Simple-0.36/t/11serve_static.t0000644000175000017500000000122513252205174021740 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 6; use Catalyst::Test 'TestApp'; # test getting a file via serve_static_file ok( my $res = request('http://localhost/serve_static'), 'request ok' ); is( $res->code, 200, '200 ok' ); # .pm can be both application/x-pagemaker or text/x-perl, so only check for a slash like( $res->content_type, qr{/}, 'content-type ok' ); like( $res->content, qr/package TestApp/, 'content of serve_static ok' ); # test getting a non-existant file via serve_static_file ok( $res = request('http://localhost/serve_static_404'), 'request ok' ); is( $res->code, 404, '404 ok' ); Catalyst-Plugin-Static-Simple-0.36/t/09ignore_ext.t0000644000175000017500000000071613252205174021423 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 4; use Catalyst::Test 'TestApp'; # test ignoring extensions # default is tt/html/xhtml ok( my $res = request('http://localhost/ignored/tmpl.tt'), 'request ok' ); is( $res->content, 'default', 'ignored extension tt ok' ); ok( $res = request('http://localhost/ignored/index.html'), 'request ok' ); is( $res->content, 'default', 'ignored extension html ok' ); Catalyst-Plugin-Static-Simple-0.36/t/08subreq.t0000644000175000017500000000107013252205174020552 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 2; use Catalyst::Test 'TestApp'; SKIP: { unless ( TestApp->isa('Catalyst::Plugin::SubRequest') ) { skip "Install Catalyst::Plugin::SubRequest >= 0.15 for these tests", 2; } unless ( $Catalyst::Plugin::SubRequest::VERSION >= 0.15 ) { skip "Need Catalyst::Plugin::SubRequest >= 0.15 for these tests", 2; } ok( my $res = request('http://localhost/subtest'), 'Request' ); is( $res->content, 'subtest2 ok', 'SubRequest ok' ); } Catalyst-Plugin-Static-Simple-0.36/t/10ignore_dirs.t0000644000175000017500000000151213252205174021547 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 6; use Catalyst::Test 'TestApp'; # test ignoring directories TestApp->config->{'Plugin::Static::Simple'}->{ignore_dirs} = [ qw/ignored o-ignored files/ ]; # test altenate root dirs TestApp->config->{'Plugin::Static::Simple'}->{include_path} = [ TestApp->config->{root} . '/overlay', TestApp->config->{root}, ]; ok( my $res = request('http://localhost/ignored/bad.gif'), 'request ok' ); is( $res->content, 'default', 'ignored directory `ignored` ok' ); ok( $res = request('http://localhost/files/static.css'), 'request ok' ); is( $res->content, 'default', 'ignored directory `files` ok' ); ok( $res = request('http://localhost/o-ignored/bad.gif'), 'request ok' ); is( $res->content, 'default', 'ignored overlay directory ok' ); Catalyst-Plugin-Static-Simple-0.36/t/lib/0000755000175000017500000000000013252455554017475 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/0000755000175000017500000000000013252455554021507 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/Controller/0000755000175000017500000000000013252455554023632 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/Controller/Root.pm0000644000175000017500000000026613252205174025106 0ustar ilmariilmaripackage IncTestApp::Controller::Root; use strict; use warnings; use File::Spec::Functions; use base qw/Catalyst::Controller/; __PACKAGE__->config(namespace => ''); 1; Catalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/root/0000755000175000017500000000000013252455554022472 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/root/overlay/0000755000175000017500000000000013252455554024153 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/root/overlay/overlay.jpg0000644000175000017500000000003713252205174026325 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/root/images/0000755000175000017500000000000013252455554023737 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp/root/images/bad.gif0000644000175000017500000000003713252205174025143 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp.pm0000644000175000017500000000103513252205174021401 0ustar ilmariilmaripackage TestApp; use strict; use Catalyst; use FindBin; our $VERSION = '0.01'; TestApp->config( name => 'TestApp', debug => 1, ); my @plugins = qw/Static::Simple/; # load the SubRequest plugin if available eval { require Catalyst::Plugin::SubRequest; die unless Catalyst::Plugin::SubRequest->VERSION ge '0.08'; }; push @plugins, 'SubRequest' unless ($@); TestApp->setup( @plugins ); sub incpath_generator { my $c = shift; return [ $c->config->{root} . '/incpath' ]; } 1; Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/0000755000175000017500000000000013252455554021055 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/Controller/0000755000175000017500000000000013252455554023200 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/Controller/Root.pm0000644000175000017500000000150113252205174024445 0ustar ilmariilmaripackage TestApp::Controller::Root; use strict; use warnings; use File::Spec::Functions; use base qw/Catalyst::Controller/; __PACKAGE__->config(namespace => ''); sub default : Private { my ( $self, $c ) = @_; $c->res->output( 'default' ); } sub subtest : Local { my ( $self, $c ) = @_; $c->res->output( $c->subreq('/subtest2') ); } sub subtest2 : Local { my ( $self, $c ) = @_; $c->res->output( 'subtest2 ok' ); } sub serve_static : Local { my ( $self, $c ) = @_; my $file = catfile( $FindBin::Bin, 'lib', 'TestApp.pm' ); $c->serve_static_file( $file ); } sub serve_static_404 : Local { my ( $self, $c ) = @_; my $file = catfile( $FindBin::Bin, 'lib', 'foo.pm' ); $c->serve_static_file( $file ); } 1; Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/0000755000175000017500000000000013252455554022040 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/always-static/0000755000175000017500000000000013252455554024625 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/always-static/test.html0000644000175000017500000000014113252205174026455 0ustar ilmariilmari test
test
Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/always-static/test0000644000175000017500000000002213252205174025510 0ustar ilmariilmariI am a text file! Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/ignored/0000755000175000017500000000000013252455554023467 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/ignored/index.html0000644000175000017500000000003713252205174025453 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/ignored/bad.gif0000644000175000017500000000003713252205174024673 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/ignored/tmpl.tt0000644000175000017500000000003713252205174025003 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/ignored/static.css0000644000175000017500000000003713252205174025457 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/css/0000755000175000017500000000000013252455554022630 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/css/static.css0000644000175000017500000000003713252205174024620 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/0000755000175000017500000000000013252455554023521 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/o-ignored/0000755000175000017500000000000013252455554025404 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/o-ignored/index.html0000644000175000017500000000003713252205174027370 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/o-ignored/bad.gif0000644000175000017500000000003713252205174026610 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/o-ignored/tmpl.tt0000644000175000017500000000003713252205174026720 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/o-ignored/static.css0000644000175000017500000000003713252205174027374 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/overlay/overlay.jpg0000644000175000017500000000003713252205174025673 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/files/0000755000175000017500000000000013252455554023142 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/files/err.unknown0000644000175000017500000000003713252213526025342 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/files/empty.txt0000644000175000017500000000000013252205174025016 0ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/files/bad.gif0000644000175000017500000000003713252205174024346 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/files/static.css0000644000175000017500000000003713252205174025132 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/images/0000755000175000017500000000000013252455554023305 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/images/bad.gif0000644000175000017500000000003713252205174024511 0ustar ilmariilmaribody { background: #fff; } Catalyst-Plugin-Static-Simple-0.36/t/lib/TestApp/root/images/catalyst.png0000644000175000017500000000437713252205174025641 0ustar ilmariilmariPNG  IHDRXTgAMAOX2tEXtSoftwareAdobe ImageReadyqe<PLTEOOggzzٔKKrrr((㳲嬬 80)fffSSS|||ZZZZZƇ..ك簾掊vqlttݺꥥII6.'ܐooo||E=7RKEhb]옘\\,,ł}yIB;{vqc]XԮ}lfaMF@ǻKKKjjj FFFԜ\\\铐^WQΟZSM}xsίPIC̝_YS66ح??mmlݷٰ rr諬գթߢaaa%IDATxڬ PWEA}FxUD9Y9[xP<"$,`r"ePZiZCE{M[Ŏmm{?;>"' IXoJcM p՞x+[n/-iVoJJʩ0+8Noo0ةx:{!n\8`:HScB#$ ރDb' XS&]7ި/H,oY"Ɋ):%Gdh`fIvZY3E;~e'asr#UfE8 sPobreh;6p4ø1TQ/ORNF0_BZdqLp6ar/'Nsxn1׃XRuBQ 6i1WsJ$=I ACqM[VӕmxWW׫?2Δa usՔ^ /v] a"U}N3k3 .ΰرR?}YʞZG`acݙN?W7_Z[ Z{d Ȉg˰ن Gí֠V''=lZH5-::>|rBѨ~כ67+V { SShBQ!GG phT(*|6ϙtFAvlJ;Id 28˝KsN2}U*nGM'In8 &ܤ^F ùs;붘(ʝ6z& rۗ)D<JP(f0yXAEQ(堥a •p!?`_,Z4;ۆj!?Qr<`94!hk,:jڈ0\w8QL$E$~!c;[P{.N#]eVYcpގ.gAȂZBڗDMSZZHmZmH7̘L.ݭJB^$'!JPˊ(V Y"ټZ.6Kf%1Am xϯDQqnnCg  S-\vU Pe!HP e*QJu I* sub { my $self = shift; $logged = shift; }; 1; Catalyst-Plugin-Static-Simple-0.36/t/lib/IncTestApp.pm0000644000175000017500000000163213252213526022036 0ustar ilmariilmaripackage IncTestApp; # FIXME: I have to do this because TestApp runs setup at compile time # Perhaps it would be better to let the tests run setup? use strict; use Catalyst; use FindBin; use TestLog; our $VERSION = '0.01'; IncTestApp->config( name => 'TestApp', debug => 1, static => { include_path => [ IncTestApp->config->{root}, ] }, 'Plugin::Static::Simple' => { include_path => [ IncTestApp->config->{root} . '/overlay', ] }, ); IncTestApp->log( TestLog->new ); my @plugins = qw/Static::Simple/; # load the SubRequest plugin if available eval { require Catalyst::Plugin::SubRequest; die unless Catalyst::Plugin::SubRequest->VERSION ge '0.08'; }; push @plugins, 'SubRequest' unless ($@); IncTestApp->setup( @plugins ); sub incpath_generator { my $c = shift; return [ $c->config->{root} . '/incpath' ]; } 1; Catalyst-Plugin-Static-Simple-0.36/t/20debug.t0000644000175000017500000000154413252205174020337 0ustar ilmariilmari#!perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Test::More tests => 5; use Catalyst::Test 'TestApp'; # test defined static dirs TestApp->config->{'Plugin::Static::Simple'}->{dirs} = [ 'always-static', ]; TestApp->config->{'Plugin::Static::Simple'}->{debug} = 1; use Catalyst::Log; local *Catalyst::Log::_send_to_log; local our @MESSAGES; { no warnings 'redefine'; *Catalyst::Log::_send_to_log = sub { my $self = shift; push @MESSAGES, @_; }; } # a missing file in a defined static dir will return 404 and text/html ok( my $res = request('http://localhost/always-static/404.txt'), 'request ok' ); is( $res->code, 404, '404 ok' ); is( $res->content_type, 'text/html', '404 is text/html' ); ok(defined $MESSAGES[0], 'debug message set'); like( $MESSAGES[0], qr/404/, 'debug message contains 404'); Catalyst-Plugin-Static-Simple-0.36/Changes0000644000175000017500000001767513252455417017775 0ustar ilmariilmariRevision history for Perl extension Catalyst::Plugin::Static::Simple 0.36 2018-03-15 11:37 GMT - Relax PNG content type check in t/05dirs.t 0.35 2018-03-14 12:07 GMT - Use less-likely extension for unknown file type (RT#124211) 0.34 2017-08-02 09:56 Los Angeles - Remove MYMETA.* (RT#108814) - Fix installing on 5.26.0+ (RT#121861) - Fix security vulnerability, when serving static files with dots in the names (RT#120558) - Fix typo in POD (RT#87098) 0.33 2014-09-26 17:00 BST - In the case where someone is trying to merge configurations and some config sets use the depracated 'static' keyword, the configs will be properly merged. 0.32 2014-06-04 17:00 EDT - Sets 'autoflush' in the Catalyst Log object to false if available. This is a new API being added in Catalyst as of version 5.90065 0.31 2013-09-09 16:30:00 - Updated docs to reflect config key change from 'static' to 'Plugin::Static::Simple' (RT#77709) - Migrated repository from subversion to git - Fixed MIME::Types 2.xx compatibility be removing call to an undocumented method - Bumped the MIME::Types requirement to 2.03 to ensure its improvements make it into Catalyst environments 0.30 2012-05-04 17:05:00 - Add Cache-Control:public header - Optionally provide Expires header - Change configuration key to 'Plugin::Static::Simple' by default. The old 'static' key is still supported, but issues a warning. 0.29 2010-02-01 18:45:00 - Switch from override to around, because really, wtf 0.28 2010-01-04 13:15:00 - Fix issues in debug mode. (RT#53338) 0.27 2010-01-03 14:49:00 - Switch to being a Moose role, removing dependencies on Class::Data::Inheritable and Class::Accessor (Andrey Kostenko in RT#51089) - Make Pod tests mandatory for authors but never run otherwise - Switch to Test::NoTabs to ensure no tabs, rather than Test::Perl::Critic 0.26 2009-12-06 12:30:00 - Fix Pod to show less nasty method of assigning config by calling the config method with parameters, rather than poking around inside the hash. - Require newer (>= 0.15) Catalyst::Plugin::SubRequest for subrequest tests as old versions don't work with new Catalyst (>= 5.80014) 0.25 2009-10-22 21:40:00 BST - Fix bug where old unrelated $@ values would result in an error. 0.24 2009-10-18 19:10:00 BST - Fixup copyright information 0.23 2009-10-06 17:40:39 - Move actions out of TestApp into a Root controller as this is now deprecated. 0.22 2009-08-21 18:14:59 - Add tests for delivering empty files. - Fix those tests by depending on Catalyst-Runtime 5.80008. - Throw away compatibility code for older catalyst versions. - Fix docs to not include plugins in call to ->setup() (t0m) 0.21 2009-03-29 20:31:49 - Documentation improvements (jester) - Change from NEXT to MRO::Compat - RT#40628, RT#44553 (ilmari) - Bump prereq to MIME::Types to 1.25 to correctly send files commonly used to graft support for transparent PNGs into MSIE6 - RT#41314 (Florian Ragwitz) 0.20 2007-09-24 10:00:00 - Fixed issue where the static dir regex did not add a trailing slash so URLs such as /static1 were served as static when they should be handled by Catalyst. (Will Hawes) - Added text/html Content-Type to 404 responses. (Will Hawes) 0.19 2007-07-02 17:00:00 - Fixed test failure on some systems in 11serve_static.t due to multiple MIME types defined for the extension '.pm'. 0.18 2007-07-01 00:15:00 - Logging may now be enabled with the less confusing MyApp->config->{static}->{logging} = 1; 0.17 2007-05-11 11:00:00 - Added serve_static_file, to serve a given file as static. (groditi) 0.16 2007-04-30 15:00:00 - Allow all files in directories defined by the config option 'dirs' to be served as static even if the file matches ignore_dirs or ignore_extensions. - Fixed bug where 204 or 304 status codes would result in a 500 error under mod_perl. - Switch to Module::Install. 0.15 2006-12-08 22:30:00 - Quote metacharacters used in $c->config->{dirs} (Vlad Dan Dascalescu) - store Mime::Types object in config hash instead of as classdata - cleanup code a bit 0.14 2006-03-24 11:15:00 - Unescape the URI path before looking for the file. This fixes issues with files that have spaces. 0.13 2005-12-15 10:00:00 - Fixed bug in ignore_dirs under win32. - Doc rewriting 0.12 (released only with Catalyst) - Made prepare_action play nice with other plugins by not short- circuiting. - Added tmpl to the ignored extensions. - Fixed security problem if req->path contained '..'. 0.11 2005-11-13 16:25:00 - Removed the code that set the 304 Not Modified header. This caused problems with IE under Apache. - Changed 5.50 writing method to pass an IO::File object directly to $c->res->body. - This version is included with Catalyst 5.50. 0.10 2005-10-19 17:20:00 - Added tt2 to the list of ignored extensions. - For Catalyst 5.5+, replaced File::Slurp with a buffered read/write process. This will improve memory usage and performance on larger static files. - Removed Apache integration feature. It is slower than serving through Catalyst and as far as I know no one is using it. If you need the best performance, use a separate Location block for static content. 0.09 2005-10-07 13:40:00 - Added new configuration options to improve security: ignore_extensions - keep certain extensions from being static - This option defaults to tt, html, and xhtml to prevent template files from being accessible. ignore_dirs - keep certain dirs from being static - include_path is no longer experimental. - Added support for hiding log output, depends on Cat 5.50. (Marcus Ramberg) 0.08 2005-09-07 18:50:00 - Added tests for everything except Apache support. 0.07 2005-09-05 21:05:00 - POD fixes. (Thomas L. Shinnick) 0.06 2005-09-05 15:40:00 - Moved initial file check into prepare_action so processing can bypass other plugins. - Added error-checking to static dir regexes. - Cleaned up various code as per Best Practices. 0.05 2005-08-26 12:00:00 - Added use_apache option to enable the Apache DECLINED support. Default is disabled as it appears Catalyst is faster at serving the files! - Added a check that Apache's DocumentRoot matches Catalyst's root before serving DECLINED. - Preload MIME::Types index during setup() so it's not built on the first request. - Added a note on performance of Apache vs. Catalyst. 0.04 2005-08-22 12:00:00 - Fixed bug where static files were searched for on every request even without a file extension. - Fixed bug where files without extensions in defined static dirs were not served with text/plain. - Consolidated the debug log messages. 0.03 2005-08-21 23:50:00 - Added config option for include_path to allow for multiple directories with static files. This option should be considered experimental! - Documentation cleanups. 0.02 2005-08-16 18:00:00 - Return DECLINED when running under mod_perl to allow Apache to serve the static file. This is not done when any custom MIME types have been specified, however. 0.01 2005-08-11 22:00:00 - Initial release. Catalyst-Plugin-Static-Simple-0.36/lib/0000755000175000017500000000000013252455554017232 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/lib/Catalyst/0000755000175000017500000000000013252455554021016 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/lib/Catalyst/Plugin/0000755000175000017500000000000013252455554022254 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/lib/Catalyst/Plugin/Static/0000755000175000017500000000000013252455554023503 5ustar ilmariilmariCatalyst-Plugin-Static-Simple-0.36/lib/Catalyst/Plugin/Static/Simple.pm0000755000175000017500000005035413252455377025307 0ustar ilmariilmaripackage Catalyst::Plugin::Static::Simple; use Moose::Role; use File::stat; use File::Spec (); use IO::File (); use MIME::Types (); use MooseX::Types::Moose qw/ArrayRef Str/; use Catalyst::Utils; use namespace::autoclean; our $VERSION = '0.36'; has _static_file => ( is => 'rw' ); has _static_debug_message => ( is => 'rw', isa => ArrayRef[Str] ); after setup_finalize => sub { my $c = shift; # New: Turn off new 'autoflush' flag in logger (see Catalyst::Log). # This is needed to surpress output of debug log messages for # static requests: $c->log->autoflush(0) if $c->log->can('autoflush'); }; before prepare_action => sub { my $c = shift; my $path = $c->req->path; my $config = $c->config->{'Plugin::Static::Simple'}; $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; # is the URI in a static-defined path? foreach my $dir ( @{ $config->{dirs} } ) { my $dir_re = quotemeta $dir; # strip trailing slashes, they'll be added in our regex $dir_re =~ s{/$}{}; my $re; if ( $dir =~ m{^qr/}xms ) { $re = eval $dir; if ($@) { $c->error( "Error compiling static dir regex '$dir': $@" ); } } else { $re = qr{^${dir_re}/}; } if ( $path =~ $re ) { if ( $c->_locate_static_file( $path, 1 ) ) { $c->_debug_msg( 'from static directory' ) if $config->{debug}; } else { $c->_debug_msg( "404: file not found: $path" ) if $config->{debug}; $c->res->status( 404 ); $c->res->content_type( 'text/html' ); } } } # Does the path have an extension? if ( $path =~ /\.([^\/\\]+)$/m ) { # and does it exist? $c->_locate_static_file( $path ); } }; around dispatch => sub { my $orig = shift; my $c = shift; return if ( $c->res->status != 200 ); if ( $c->_static_file ) { if ( $c->config->{'Plugin::Static::Simple'}->{no_logs} && $c->log->can('abort') ) { $c->log->abort( 1 ); } return $c->_serve_static; } else { return $c->$orig(@_); } }; before finalize => sub { my $c = shift; # display all log messages if ( $c->config->{'Plugin::Static::Simple'}->{debug} && scalar @{$c->_debug_msg} ) { $c->log->debug( 'Static::Simple: ' . join q{ }, @{$c->_debug_msg} ); } }; before setup_finalize => sub { my $c = shift; $c->log->warn("Deprecated 'static' config key used, please use the key 'Plugin::Static::Simple' instead") if exists $c->config->{static}; if (exists $c->config->{static}->{include_path}) { $c->config->{'Plugin::Static::Simple'}->{include_path} = [ @{$c->config->{'Plugin::Static::Simple'}->{include_path} || []}, @{delete $c->config->{static}->{include_path} || []} ]; } my $config = $c->config->{'Plugin::Static::Simple'} = $c->config->{'static'} = Catalyst::Utils::merge_hashes( $c->config->{'Plugin::Static::Simple'} || {}, $c->config->{static} || {} ); $config->{dirs} ||= []; $config->{include_path} ||= [ $c->config->{root} ]; $config->{mime_types} ||= {}; $config->{ignore_extensions} ||= [ qw/tmpl tt tt2 html xhtml/ ]; $config->{ignore_dirs} ||= []; $config->{debug} ||= $c->debug; $config->{no_logs} = 1 unless defined $config->{no_logs}; $config->{no_logs} = 0 if $config->{logging}; # load up a MIME::Types object, only loading types with # at least 1 file extension $config->{mime_types_obj} = MIME::Types->new( only_complete => 1 ); }; # Search through all included directories for the static file # Based on Template Toolkit INCLUDE_PATH code sub _locate_static_file { my ( $c, $path, $in_static_dir ) = @_; $path = File::Spec->catdir( File::Spec->no_upwards( File::Spec->splitdir( $path ) ) ); my $config = $c->config->{'Plugin::Static::Simple'}; my @ipaths = @{ $config->{include_path} }; my $dpaths; my $count = 64; # maximum number of directories to search DIR_CHECK: while ( @ipaths && --$count) { my $dir = shift @ipaths || next DIR_CHECK; if ( ref $dir eq 'CODE' ) { eval { $dpaths = &$dir( $c ) }; if ($@) { $c->log->error( 'Static::Simple: include_path error: ' . $@ ); } else { unshift @ipaths, @$dpaths; next DIR_CHECK; } } else { $dir =~ s/(\/|\\)$//xms; if ( -d $dir && -f $dir . '/' . $path ) { # Don't ignore any files in static dirs defined with 'dirs' unless ( $in_static_dir ) { # do we need to ignore the file? for my $ignore ( @{ $config->{ignore_dirs} } ) { $ignore =~ s{(/|\\)$}{}; if ( $path =~ /^$ignore(\/|\\)/ ) { $c->_debug_msg( "Ignoring directory `$ignore`" ) if $config->{debug}; next DIR_CHECK; } } # do we need to ignore based on extension? for my $ignore_ext ( @{ $config->{ignore_extensions} } ) { if ( $path =~ /.*\.${ignore_ext}$/ixms ) { $c->_debug_msg( "Ignoring extension `$ignore_ext`" ) if $config->{debug}; next DIR_CHECK; } } } $c->_debug_msg( 'Serving ' . $dir . '/' . $path ) if $config->{debug}; return $c->_static_file( $dir . '/' . $path ); } } } return; } sub _serve_static { my $c = shift; my $config = $c->config->{'Plugin::Static::Simple'}; my $full_path = shift || $c->_static_file; my $type = $c->_ext_to_type( $full_path ); my $stat = stat $full_path; $c->res->headers->content_type( $type ); $c->res->headers->content_length( $stat->size ); $c->res->headers->last_modified( $stat->mtime ); # Tell Firefox & friends its OK to cache, even over SSL: $c->res->headers->header('Cache-control' => 'public'); # Optionally, set a fixed expiry time: if ($config->{expires}) { $c->res->headers->expires(time() + $config->{expires}); } my $fh = IO::File->new( $full_path, 'r' ); if ( defined $fh ) { binmode $fh; $c->res->body( $fh ); } else { Catalyst::Exception->throw( message => "Unable to open $full_path for reading" ); } return 1; } sub serve_static_file { my ( $c, $full_path ) = @_; my $config = $c->config->{'Plugin::Static::Simple'}; if ( -e $full_path ) { $c->_debug_msg( "Serving static file: $full_path" ) if $config->{debug}; } else { $c->_debug_msg( "404: file not found: $full_path" ) if $config->{debug}; $c->res->status( 404 ); $c->res->content_type( 'text/html' ); return; } $c->_serve_static( $full_path ); } # looks up the correct MIME type for the current file extension sub _ext_to_type { my ( $c, $full_path ) = @_; my $config = $c->config->{'Plugin::Static::Simple'}; if ( $full_path =~ /.*\.(\S{1,})$/xms ) { my $ext = $1; my $type = $config->{mime_types}{$ext} || $config->{mime_types_obj}->mimeTypeOf( $ext ); if ( $type ) { $c->_debug_msg( "as $type" ) if $config->{debug}; return ( ref $type ) ? $type->type : $type; } else { $c->_debug_msg( "as text/plain (unknown extension $ext)" ) if $config->{debug}; return 'text/plain'; } } else { $c->_debug_msg( 'as text/plain (no extension)' ) if $config->{debug}; return 'text/plain'; } } sub _debug_msg { my ( $c, $msg ) = @_; if ( !defined $c->_static_debug_message ) { $c->_static_debug_message( [] ); } if ( $msg ) { push @{ $c->_static_debug_message }, $msg; } return $c->_static_debug_message; } 1; __END__ =head1 NAME Catalyst::Plugin::Static::Simple - Make serving static pages painless. =head1 SYNOPSIS package MyApp; use Catalyst qw/ Static::Simple /; MyApp->setup; # that's it; static content is automatically served by Catalyst # from the application's root directory, though you can configure # things or bypass Catalyst entirely in a production environment # # one caveat: the files must be served from an absolute path # (i.e. /images/foo.png) =head1 DESCRIPTION The Static::Simple plugin is designed to make serving static content in your application during development quick and easy, without requiring a single line of code from you. This plugin detects static files by looking at the file extension in the URL (such as B<.css> or B<.png> or B<.js>). The plugin uses the lightweight L module to map file extensions to IANA-registered MIME types, and will serve your static files with the correct MIME type directly to the browser, without being processed through Catalyst. Note that actions mapped to paths using periods (.) will still operate properly. If the plugin can not find the file, the request is dispatched to your application instead. This means you are responsible for generating a C<404> error if your application can not process the request: # handled by static::simple, not dispatched to your application /images/exists.png # static::simple will not find the file and let your application # handle the request. You are responsible for generating a file # or returning a 404 error /images/does_not_exist.png Though Static::Simple is designed to work out-of-the-box, you can tweak the operation by adding various configuration options. In a production environment, you will probably want to use your webserver to deliver static content; for an example see L, below. =head1 DEFAULT BEHAVIOUR By default, Static::Simple will deliver all files having extensions (that is, bits of text following a period (C<.>)), I files having the extensions C, C, C, C, and C. These files, and all files without extensions, will be processed through Catalyst. If L doesn't recognize an extension, it will be served as C. To restate: files having the extensions C, C, C, C, and C I be served statically by default, they will be processed by Catalyst. Thus if you want to use C<.html> files from within a Catalyst app as static files, you need to change the configuration of Static::Simple. Note also that files having any other extension I be served statically, so if you're using any other extension for template files, you should also change the configuration. Logging of static files is turned off by default. =head1 ADVANCED CONFIGURATION Configuration is completely optional and is specified within Cconfig-E{Plugin::Static::Simple}>. If you use any of these options, this module will probably feel less "simple" to you! =head2 Enabling request logging Since Catalyst 5.50, logging of static requests is turned off by default; static requests tend to clutter the log output and rarely reveal anything useful. However, if you want to enable logging of static requests, you can do so by setting Cconfig-E{Plugin::Static::Simple}-E{logging}> to 1. =head2 Forcing directories into static mode Define a list of top-level directories beneath your 'root' directory that should always be served in static mode. Regular expressions may be specified using C. MyApp->config( 'Plugin::Static::Simple' => { dirs => [ 'static', qr/^(images|css)/, ], } ); =head2 Including additional directories You may specify a list of directories in which to search for your static files. The directories will be searched in order and will return the first file found. Note that your root directory is B automatically added to the search path when you specify an C. You should use Cconfig-E{root}> to add it. MyApp->config( 'Plugin::Static::Simple' => { include_path => [ '/path/to/overlay', \&incpath_generator, MyApp->config->{root}, ], }, ); With the above setting, a request for the file C will search for the following files, returning the first one found: /path/to/overlay/images/logo.jpg /dynamic/path/images/logo.jpg /your/app/home/root/images/logo.jpg The include path can contain a subroutine reference to dynamically return a list of available directories. This method will receive the C<$c> object as a parameter and should return a reference to a list of directories. Errors can be reported using C. This method will be called every time a file is requested that appears to be a static file (i.e. it has an extension). For example: sub incpath_generator { my $c = shift; if ( $c->session->{customer_dir} ) { return [ $c->session->{customer_dir} ]; } else { die "No customer dir defined."; } } =head2 Ignoring certain types of files There are some file types you may not wish to serve as static files. Most important in this category are your raw template files. By default, files with the extensions C, C, C, C, and C will be ignored by Static::Simple in the interest of security. If you wish to define your own extensions to ignore, use the C option: MyApp->config( 'Plugin::Static::Simple' => { ignore_extensions => [ qw/html asp php/ ], }, ); =head2 Ignoring entire directories To prevent an entire directory from being served statically, you can use the C option. This option contains a list of relative directory paths to ignore. If using C, the path will be checked against every included path. MyApp->config( 'Plugin::Static::Simple' => { ignore_dirs => [ qw/tmpl css/ ], }, ); For example, if combined with the above C setting, this C value will ignore the following directories if they exist: /path/to/overlay/tmpl /path/to/overlay/css /dynamic/path/tmpl /dynamic/path/css /your/app/home/root/tmpl /your/app/home/root/css =head2 Custom MIME types To override or add to the default MIME types set by the L module, you may enter your own extension to MIME type mapping. MyApp->config( 'Plugin::Static::Simple' => { mime_types => { jpg => 'image/jpg', png => 'image/png', }, }, ); =head2 Controlling caching with Expires header The files served by Static::Simple will have a Last-Modified header set, which allows some browsers to cache them for a while. However if you want to explicitly set an Expires header, such as to allow proxies to cache your static content, then you can do so by setting the "expires" config option. The value indicates the number of seconds after access time to allow caching. So a value of zero really means "don't cache at all", and any higher values will keep the file around for that long. MyApp->config( 'Plugin::Static::Simple' => { expires => 3600, # Caching allowed for one hour. }, ); =head2 Compatibility with other plugins Since version 0.12, Static::Simple plays nice with other plugins. It no longer short-circuits the C stage as it was causing too many compatibility issues with other plugins. =head2 Debugging information Enable additional debugging information printed in the Catalyst log. This is automatically enabled when running Catalyst in -Debug mode. MyApp->config( 'Plugin::Static::Simple' => { debug => 1, }, ); =head1 USING WITH APACHE While Static::Simple will work just fine serving files through Catalyst in mod_perl, for increased performance you may wish to have Apache handle the serving of your static files directly. To do this, simply use a dedicated directory for your static files and configure an Apache Location block for that directory This approach is recommended for production installations. SetHandler default-handler Using this approach Apache will bypass any handling of these directories through Catalyst. You can leave Static::Simple as part of your application, and it will continue to function on a development server, or using Catalyst's built-in server. In practice, your Catalyst application is probably (i.e. should be) structured in the recommended way (i.e., that generated by bootstrapping the application with the C script, with a main directory under which is a C directory for module files and a C directory for templates and static files). Thus, unless you break up this structure when deploying your app by moving the static files to a different location in your filesystem, you will need to use an Alias directive in Apache to point to the right place. You will then need to add a Directory block to give permission for Apache to serve these files. The final configuration will look something like this: Alias /myapp/static /filesystem/path/to/MyApp/root/static allow from all SetHandler default-handler If you are running in a VirtualHost, you can just set the DocumentRoot location to the location of your root directory; see L. =head1 PUBLIC METHODS =head2 serve_static_file $file_path Will serve the file located in $file_path statically. This is useful when you need to autogenerate them if they don't exist, or they are stored in a model. package MyApp::Controller::User; sub curr_user_thumb : PathPart("my_thumbnail.png") { my ( $self, $c ) = @_; my $file_path = $c->user->picture_thumbnail_path; $c->serve_static_file($file_path); } =head1 INTERNAL EXTENDED METHODS Static::Simple extends the following steps in the Catalyst process. =head2 prepare_action C is used to first check if the request path is a static file. If so, we skip all other C steps to improve performance. =head2 dispatch C takes the file found during C and writes it to the output. =head2 finalize C serves up final header information and displays any log messages. =head2 setup C initializes all default values. =head1 DEPRECATIONS The old style of configuration using the C<'static'> config key was deprecated in version 0.30. A warning will be issued if this is used, and the contents of the config at this key will be merged with the newer C<'Plugin::Static::Simple'> key. Be aware that if the C<'include_path'> key under C<'static'> exists at all, it will be merged with any content of the same key under C<'Plugin::Static::Simple'>. Be careful not to set this to a non-arrayref, therefore. =head1 SEE ALSO L, L, L =head1 AUTHOR Andy Grundman, =head1 CONTRIBUTORS Marcus Ramberg, Jesse Sheidlower, Guillermo Roditi, Florian Ragwitz, Tomas Doran, Justin Wheeler (dnm) Matt S Trout, Toby Corkindale, =head1 THANKS The authors of Catalyst::Plugin::Static: Sebastian Riedel Christian Hansen Marcus Ramberg For the include_path code from Template Toolkit: Andy Wardley =head1 COPYRIGHT Copyright (c) 2005 - 2011 the Catalyst::Plugin::Static::Simple L and L as listed above. =head1 LICENSE This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut