Skip to content
This repository
tree: f59683817e
Fetching contributors…

Cannot retrieve contributors at this time

executable file 230 lines (169 sloc) 5.738 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
#!/usr/bin/perl
use strict;
use lib "lib";
use Cwd;
use File::Basename;
use Getopt::Long;
use Plack::Loader;
use Plack::Util;
use Pod::Usage;
use Try::Tiny;

my $psgi;
my $eval;
my $host;
my $port = 5000;
my $env = "development";
my $help = 0;
my $backend;
my @reload;
my $reload;
my @includes;
my @modules;

# delay the build process for reloader
sub build(&;$) {
    my $block = shift;
    my $app = shift || sub { };
    return sub { $block->($app->()) };
}

# From 'prove': Allow cuddling the paths with -I and -M
@ARGV = map { /^(-[IM])(.+)/ ? ($1,$2) : $_ } @ARGV;

Getopt::Long::Configure("no_ignore_case", "pass_through");
GetOptions(
    "a|app=s" => \$psgi,
    "o|host=s" => \$host,
    "p|port=i" => \$port,
    "s|server=s" => \$backend,
    "i|impl=s" => sub { warn "-i is deprecated. Use -s instead\n"; $backend = $_[1] },
    "E|env=s" => \$env,
    "e=s" => \$eval,
    'I=s@' => \@includes,
    'M=s@' => \@modules,
    'r|reload' => sub { $reload = 1 },
    'R|Reload=s' => sub { push @reload, split ",", $_[1] },
    "h|help", => \$help,
);

pod2usage(0) if $help;
lib->import(@includes) if @includes;

if ($eval) {
    push @modules, 'Plack::Builder';
}

for (@modules) {
    my($module, @import) = split /[=,]/;
    eval "require $module" or die $@;
    $module->import(@import);
}

my(@options, @argv);
while (defined($_ = shift @ARGV)) {
    if (s/^--//) {
        my @v = split '=', $_, 2;
        $v[0] =~ tr/-/_/;
        if (@v == 2) {
            push @options, @v;
        } else {
            push @options, @v, shift @ARGV;
        }
    } else {
        push @argv, $_;
    }
}

push @options, host => $host, port => $port;

$psgi ||= $argv[0] || "app.psgi";
my $handler = $eval ? build { eval $eval or die $@ } : build { Plack::Util::load_psgi $psgi };

if ($env eq 'development') {
    require Plack::Middleware::StackTrace;
    require Plack::Middleware::AccessLog;
    $handler = build { Plack::Middleware::StackTrace->wrap($_[0]) } $handler;
    $handler = build { Plack::Middleware::AccessLog->wrap($_[0], logger => sub { print STDERR @_ }) } $handler;
}

my($loader, $app);

if ($reload or @reload) {
    if ($reload) {
        push @reload, $eval ? "lib" : ( File::Basename::dirname($psgi) . "/lib", $psgi );
    }
    warn "plackup: Watching ", join(", ", @reload), " for changes\n";
    require Plack::Loader::Reloadable;
    $loader = Plack::Loader::Reloadable->new(\@reload);
    $app = $handler;
} else {
    $loader = 'Plack::Loader';
    $app = $handler->();
}

my $server = $backend ? $loader->load($backend, @options) : $loader->auto(@options);
$server->run($app);

__END__

=head1 NAME

plackup - Run PSGI application with Plack servers

=head1 SYNOPSIS

# read your app from app.psgi file
plackup

# can be passed as an ARGV[0] (or with -a option)
plackup hello.psgi

# Switch server implementation with --server (or -s)
plackup --server Coro --port 9090 --host 127.0.0.1 test.psgi

=head1 DESCRIPTION

plackup is a command line utility to run PSGI application from the command line.

plackup automatically figures out the environment it is run in, and
runs your application in that environment. FastCGI, CGI, AnyEvent and
others can all be detected. See L<Plack::Loader> for the authorative
list.

C<plackup> assumes you have an C<app.psgi> script in your current
directory, that would look like:

#!/usr/bin/perl
use MyApp;
my $app = MyApp->new;
my $handler = sub { $app->run_psgi(@_) };

The last statement of C<app.psgi> should be a code reference that is a
PSGI application.

=head1 ARGUMENTS

=over 4

=item .psgi

plackup --host 127.0.0.1 --port 9090 /path/to/app.psgi

The first non-option argument is used as a C<.psgi> file path. You can
also set this path with C<-a> or C<--app> option. If omitted, the
default file path is C<app.psgi> in the current directory.

=back

=head1 OPTIONS

=over 4

=item -a, --app

C<--app> option allows you to locate a C<.psgi> script with a
different name in a different path. This can also be set as a
non-option argument. (See above)

=item -e

Evaluate the given perl code as a PSGI app, much like perl's C<-e>
option.

=item -o, --host

The interface a TCP based server daemon binds to. Defauts to undef,
which lets most server backends bind the any (*) interface. This
opeion doesn't mean anything if the server is not TCP based.

=item -p, --port

The port number a TCP based server daemon listens on. Defaults to
5000. This option doesn't mean anything if the server is not TCP
based.

=item -s, --server

Select a specific implementation to run on using the C<PLACK_SERVER>
environment variable or use the C<-s> or C<--server> flag which will
be prefered over the environment variable if present.

=item -I

Specify perl library include path, like C<perl>'s -I option.

=item -M

Specify modules to load before loading the app code.

=item -E, --env

Specify the environment option (default is C<development>). If it's
set to C<development>, following middleware is enabled by default:
L<CommonLogger>, L<StackTrace>.

=item -r, --reload

Make plackup to watch updates from your development directory and
restarts the server whenever a file is updated. This option by default
watches the current directory. Use C<-R> if you want to watch other
directories.

=item -R, --Reload

C<-R> option allows you to specify the path to watch file updates
separated by comma (C<,>).

plackup -R /path/to/project/lib,/path/to/project/templates

=back

Other options that starts with C<--> are passed through to the backend
server. See each Plack::Server backend documentations to see which
options are available.

=head1 SEE ALSO

L<Plack::Loader>

=cut
Something went wrong with that request. Please try again.