Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to Path::Tiny #1264

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/Dancer2.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use Import::Into;
use Dancer2::Core;
use Dancer2::Core::App;
use Dancer2::Core::Runner;
use Dancer2::FileUtils;

our $AUTHORITY = 'SUKRIA';

Expand Down
48 changes: 26 additions & 22 deletions lib/Dancer2/CLI/Command/gen.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ use warnings;
use App::Cmd::Setup -command;

use HTTP::Tiny;
use Path::Tiny ();
use File::Find;
use File::Path 'mkpath';
use File::Spec::Functions;
use File::Share 'dist_dir';
use File::Basename qw/dirname basename/;
use Dancer2::Template::Simple;
use Module::Runtime 'require_module';
use Dancer2::Template::Simple;

my $SKEL_APP_FILE = 'lib/AppFile.pm';

Expand Down Expand Up @@ -45,12 +43,12 @@ sub validate_args {
);
}

my $path = $opt->{path};
-d $path or $self->usage_error("directory '$path' does not exist");
my $path = Path::Tiny::path( $opt->{path} );
$path->is_dir or $self->usage_error("directory '$path' does not exist");
-w $path or $self->usage_error("directory '$path' is not writeable");

if ( my $skel_path = $opt->{skel} ) {
-d $skel_path
Path::Tiny::path($skel_path)->is_dir
or $self->usage_error("skeleton directory '$skel_path' not found");
}
}
Expand All @@ -59,30 +57,35 @@ sub execute {
my ($self, $opt, $args) = @_;
$self->_version_check() unless $opt->{'no_check'};

my $dist_dir = dist_dir('Dancer2');
my $skel_dir = $opt->{skel} || catdir($dist_dir, 'skel');
-d $skel_dir or die "$skel_dir doesn't exist";
my @dirs =
$opt->{'skel'}
? ($opt->{'skel'})
: (dist_dir('Dancer2'), 'skel');

my $skel_dir = Path::Tiny::path(@dirs);
$skel_dir->is_dir
or die "Skeleton directory '$skel_dir' doesn't exist";

my $app_name = $opt->{application};
my $app_file = _get_app_file($app_name);
my $app_path = _get_app_path($opt->{path}, $app_name);

if( my $dir = $opt->{directory} ) {
$app_path = catdir( $opt->{path}, $dir );
$app_path = Path::Tiny::path( $opt->{path}, $dir );
}

my $files_to_copy = _build_file_list($skel_dir, $app_path);
foreach my $pair (@$files_to_copy) {
if ($pair->[0] =~ m/$SKEL_APP_FILE$/) {
$pair->[1] = catfile($app_path, $app_file);
$pair->[1] = Path::Tiny::path($app_path, $app_file);
last;
}
}

my $vars = {
appname => $app_name,
appfile => $app_file,
appdir => File::Spec->rel2abs($app_path),
appdir => Path::Tiny::path($app_path)->absolute,
perl_interpreter => _get_perl_interpreter(),
cleanfiles => _get_dashed_name($app_name),
dancer_version => $self->version(),
Expand Down Expand Up @@ -148,7 +151,7 @@ sub _build_file_list {
my $is_git = $file =~ m{^\.git(/|$)}
and return;

push @result, [ $_, catfile($to, $file) ];
push @result, [ $_, Path::Tiny::path($to, $file) ];
};

find({ wanted => $wanted, no_chdir => 1 }, $from);
Expand All @@ -167,15 +170,15 @@ sub _copy_templates {
next unless ($res eq 'y') or ($res eq 'a');
}

my $to_dir = dirname($to);
if (! -d $to_dir) {
my $to_dir = Path::Tiny::path($to)->parent;
if (! $to_dir->is_dir ) {
print "+ $to_dir\n";
mkpath $to_dir or die "could not mkpath $to_dir: $!";
$to_dir->mkpath or die "could not mkpath $to_dir: $!";
}

my $to_file = basename($to);
my $to_file = Path::Tiny::path($to)->parent->stringify;
my $ex = ($to_file =~ s/^\+//);
$to = catfile($to_dir, $to_file) if $ex;
$to = Path::Tiny::path($to_dir, $to_file)->stringify if $ex;

print "+ $to\n";
my $content;
Expand Down Expand Up @@ -210,7 +213,7 @@ sub _create_manifest {

foreach my $file (@{$files}) {
my $filename = substr $file->[1], length($dir) + 1;
my $basename = basename $filename;
my $basename = path($filename)->parent->stringify;
my $clean_basename = $basename;
$clean_basename =~ s/^\+//;
$filename =~ s/\Q$basename\E/$clean_basename/;
Expand Down Expand Up @@ -239,13 +242,14 @@ sub _process_template {

sub _get_app_path {
my ($path, $appname) = @_;
return catdir($path, _get_dashed_name($appname));
return Path::Tiny::path($path, _get_dashed_name($appname) );
}

sub _get_app_file {
my $appname = shift;

$appname =~ s{::}{/}g;
return catfile('lib', "$appname.pm");
return Path::Tiny::path( 'lib', "$appname.pm" );
}

sub _get_perl_interpreter {
Expand Down
12 changes: 6 additions & 6 deletions lib/Dancer2/Cookbook.pod
Original file line number Diff line number Diff line change
Expand Up @@ -903,13 +903,13 @@ API and then displays it dynamically in a web page.

Other than L<Dancer2> for defining routes, we will use L<HTTP::Tiny>
to make the weather API request, L<JSON> to decode it from JSON format,
and finally L<File::Spec> to provide a fully-qualified path to our
and finally L<Path::Tiny> to provide a fully-qualified path to our
template engine.

use JSON;
use Dancer2;
use HTTP::Tiny;
use File::Spec;
use Path::Tiny;

=head4 Configuration

Expand All @@ -919,16 +919,16 @@ to I<views> directory in our current directory. Since we want to put our
template in our current directory, we will configure that. However,
I<Template::Toolkit> does not want us to provide a relative path without
configuring it to allow it. This is a security issue. So, we're using
L<File::Spec> to create a full path to where we are.
L<Path::Tiny> to create a full path to where we are.

We also unset the default layout, so Dancer won't try to wrap our template
with another one. This is a feature in Dancer to allow you to wrap your
templates with a layout when your templating system doesn't support it. Since
we're not using a layout here, we don't need it.

set template => 'template_toolkit'; # set template engine
set layout => undef; # disable layout
set views => File::Spec->rel2abs('.'); # full path to views
set template => 'template_toolkit'; # set template engine
set layout => undef; # disable layout
set views => Path::Tiny->cwd->absolute; # full path to views

Now, we define our URL:

Expand Down
56 changes: 40 additions & 16 deletions lib/Dancer2/Core/App.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Scalar::Util 'blessed';
use Module::Runtime 'is_module_name';
use Safe::Isa;
use Sub::Quote;
use File::Spec;
use Path::Tiny ();
use Module::Runtime 'use_module';
use List::Util ();
use Ref::Util qw< is_ref is_globref is_scalarref >;
Expand All @@ -18,18 +18,16 @@ use Plack::Middleware::Head;
use Plack::Middleware::Conditional;
use Plack::Middleware::ConditionalGET;

use Dancer2::FileUtils 'path';
use Dancer2::Core;
use Dancer2::Core::Cookie;
use Dancer2::Core::HTTP;
use Dancer2::Core::Error;
use Dancer2::Core::Types;
use Dancer2::Core::Route;
use Dancer2::Core::Hook;
use Dancer2::Core::Request;
use Dancer2::Core::Factory;

use Dancer2::Handler::File;

our $EVAL_SHIM; $EVAL_SHIM ||= sub {
my $code = shift;
$code->(@_);
Expand Down Expand Up @@ -245,7 +243,7 @@ sub _build_session_engine {
# Note that engine options will replace the default session_dir (if provided).
return $self->_factory->create(
session => $value,
session_dir => path( $self->config->{appdir}, 'sessions' ),
session_dir => Path::Tiny::path( $self->config->{appdir}, 'sessions' )->stringify,
%{$engine_options},
postponed_hooks => $self->postponed_hooks,

Expand Down Expand Up @@ -681,13 +679,13 @@ around execute_hook => sub {
sub _build_default_config {
my $self = shift;

my $public = $ENV{DANCER_PUBLIC} || path( $self->location, 'public' );
my $public = $ENV{DANCER_PUBLIC} || Path::Tiny::path( $self->location, 'public' )->stringify;
return {
content_type => ( $ENV{DANCER_CONTENT_TYPE} || 'text/html' ),
charset => ( $ENV{DANCER_CHARSET} || '' ),
logger => ( $ENV{DANCER_LOGGER} || 'console' ),
views => ( $ENV{DANCER_VIEWS}
|| path( $self->location, 'views' ) ),
|| Path::Tiny::path( $self->location, 'views' )->stringify ),
environment => $self->environment,
appdir => $self->location,
public_dir => $public,
Expand Down Expand Up @@ -1030,30 +1028,41 @@ sub send_file {
}
# static file dir - either system root or public_dir
my $dir = $options{system_path}
? File::Spec->rootdir
? Path::Tiny->rootdir
: $ENV{DANCER_PUBLIC}
|| $self->config->{public_dir}
|| path( $self->location, 'public' );
|| Path::Tiny::path( $self->location, 'public' )->stringify;

$file_path = Dancer2::Handler::File->merge_paths( $path, $dir );
my $err_response = sub {
my $status = shift;
$self->response->status($status);
$self->response->header( 'Content-Type', 'text/plain' );
$self->response->content( Dancer2::Core::HTTP->status_message($status) );
$self->with_return->( $self->response );
};
$err_response->(403) if !defined $file_path;
$err_response->(404) if !-f $file_path;

# resolve relative paths (with '../') as much as possible
$file_path = Path::Tiny::path( $dir, $path )->realpath;

# We need to check whether they are trying to access
# a directory outside their scope
$err_response->(403) if !Path::Tiny::path($dir)->realpath->subsumes($file_path);

# other error checks
$err_response->(403) if !$file_path->exists;
$err_response->(404) if !$file_path->is_file;
$err_response->(403) if !-r $file_path;

# Read file content as bytes
$fh = Dancer2::FileUtils::open_file( "<", $file_path );
binmode $fh;
$fh = $file_path->openr_raw();

$content_type = Dancer2::runner()->mime_type->for_file($file_path) || 'text/plain';
if ( $content_type =~ m!^text/! ) {
$charset = $self->config->{charset} || "utf-8";
}

# cleanup for other functions not assuming on Path::Tiny
$file_path = $file_path->stringify;
}

# Now we are sure we can render the file...
Expand Down Expand Up @@ -1097,7 +1106,14 @@ sub send_file {
$response = $self->response;
# direct assignment to hash element, avoids around modifier
# trying to serialise this this content.
$response->{content} = Dancer2::FileUtils::read_glob_content($fh);

# optimized slurp
{
## no critic qw(Variables::RequireInitializationForLocalVars)
local $/;
$response->{'content'} = <$fh>;
}

$response->is_encoded(1); # bytes are already encoded
}

Expand Down Expand Up @@ -1402,7 +1418,15 @@ sub to_app {
# when the file exists. Otherwise the request passes into our app.
$psgi = Plack::Middleware::Conditional->wrap(
$psgi,
condition => sub { -f path( $self->config->{public_dir}, shift->{PATH_INFO} ) },
condition => sub {
my $env = shift;
Path::Tiny::path(
$self->config->{'public_dir'},
defined $env->{'PATH_INFO'} && length $env->{'PATH_INFO'}
? ($env->{'PATH_INFO'})
: (),
)->is_file;
},
builder => sub { Plack::Middleware::ConditionalGET->wrap( $static_app ) },
);
}
Expand Down
6 changes: 3 additions & 3 deletions lib/Dancer2/Core/DSL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ package Dancer2::Core::DSL;

use Moo;
use Carp;
use Path::Tiny ();
use Module::Runtime 'require_module';
use Ref::Util qw< is_arrayref >;
use Dancer2::Core::Hook;
use Dancer2::FileUtils;
use Dancer2::Core::Response::Delayed;

with 'Dancer2::Core::Role::DSL';
Expand Down Expand Up @@ -143,8 +143,8 @@ sub error { shift->app->log( error => @_ ) }
sub true {1}
sub false {0}

sub dirname { shift and Dancer2::FileUtils::dirname(@_) }
sub path { shift and Dancer2::FileUtils::path(@_) }
sub dirname { shift and Path::Tiny::path(@_)->parent->stringify }
sub path { shift and Path::Tiny::path(@_)->stringify }

sub config { shift->app->settings }

Expand Down
7 changes: 3 additions & 4 deletions lib/Dancer2/Core/Error.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use Carp;
use Dancer2::Core::Types;
use Dancer2::Core::HTTP;
use Data::Dumper;
use Dancer2::FileUtils qw/path open_file/;
use Path::Tiny ();
use Sub::Quote;
use Module::Runtime 'require_module';
use Ref::Util qw< is_hashref >;
Expand Down Expand Up @@ -343,9 +343,8 @@ sub backtrace {
return $html unless $file and $line;

# file and line are located, let's read the source Luke!
my $fh = eval { open_file('<', $file) } or return $html;
my @lines = <$fh>;
close $fh;
my @lines;
eval { @lines = Path::Tiny::path($file)->lines_utf8; 1; } or return $html;

$html .= qq|<div class="title">$file around line $line</div>|;

Expand Down
12 changes: 4 additions & 8 deletions lib/Dancer2/Core/Request/Upload.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ package Dancer2::Core::Request::Upload;
use Moo;

use Carp;
use File::Spec;
use Module::Runtime 'require_module';
use Path::Tiny ();
use File::Copy ();

use Dancer2::Core::Types;
use Dancer2::FileUtils qw(open_file);

has filename => (
is => 'ro',
Expand All @@ -33,13 +32,11 @@ has size => (
sub file_handle {
my ($self) = @_;
return $self->{_fh} if defined $self->{_fh};
my $fh = open_file( '<', $self->tempname );
$self->{_fh} = $fh;
$self->{_fh} = Path::Tiny::path( $self->tempname )->openr_raw;
}

sub copy_to {
my ( $self, $target ) = @_;
require_module('File::Copy');
File::Copy::copy( $self->tempname, $target );
}

Expand Down Expand Up @@ -69,8 +66,7 @@ sub content {

sub basename {
my ($self) = @_;
require_module('File::Basename');
File::Basename::basename( $self->filename );
return Path::Tiny::path( $self->filename )->basename;
}

sub type {
Expand Down
Loading