package Beam::Runner::Util;
our $VERSION = '0.016';
# ABSTRACT: Utilities for Beam::Runner command classes
#pod =head1 SYNOPSIS
#pod
#pod use Beam::Runner::Util qw( find_container_path );
#pod
#pod my $path = find_container_path( $container_name );
#pod
#pod =head1 DESCRIPTION
#pod
#pod This module has some shared utility functions for creating
#pod L<Beam::Runner::Command> classes.
#pod
#pod =head1 SEE ALSO
#pod
#pod L<Beam::Runner>, L<beam>, L<Exporter>
#pod
#pod =cut
use strict;
use warnings;
use Exporter 'import';
use Path::Tiny qw( path );
our @EXPORT_OK = qw( find_container_path find_containers );
# File extensions to try to find, starting with no extension (which is
# to say the extension is given by the user's input)
our @EXTS = ( "", qw( .yml .yaml .json .xml .pl ) );
# A regex to use to remove the container's name
my $EXT_RE = qr/(?:@{[ join '|', @EXTS ]})$/;
# The "BEAM_PATH" separator value. Windows uses ';' to separate
# PATH-like variables, everything else uses ':'
our $PATHS_SEP = $^O eq 'MSWin32' ? ';' : ':';
#pod =sub find_containers
#pod
#pod my %container = find_containers();
#pod
#pod Returns a list of C<name> and C<path> pairs pointing to all the containers
#pod in the C<BEAM_PATH> paths.
#pod
#pod =cut
sub find_containers {
my %containers;
for my $dir ( split /$PATHS_SEP/, $ENV{BEAM_PATH} // '' ) {
my $p = path( $dir );
my $i = $p->iterator( { recurse => 1, follow_symlinks => 1 } );
while ( my $file = $i->() ) {
next unless $file->is_file;
next unless $file =~ $EXT_RE;
my $name = $file->relative( $p );
$name =~ s/$EXT_RE//;
$containers{ $name } ||= $file;
}
}
return %containers;
}
#pod =sub find_container_path
#pod
#pod my $path = find_container_path( $container_name );
#pod
#pod Find the path to the given container. If the given container is already
#pod an absolute path, it is simply returned. Otherwise, the container is
#pod searched for in the directories defined by the C<BEAM_PATH> environment
#pod variable.
#pod
#pod If the container cannot be found, throws an exception with a user-friendly
#pod error message.
#pod
#pod =cut
sub find_container_path {
my ( $container ) = @_;
my $path;
if ( path( $container )->is_file ) {
return path( $container );
}
my @dirs = ( "." );
if ( $ENV{BEAM_PATH} ) {
push @dirs, split /$PATHS_SEP/, $ENV{BEAM_PATH};
}
DIR: for my $dir ( @dirs ) {
my $d = path( $dir );
for my $ext ( @EXTS ) {
my $f = $d->child( $container . $ext );
if ( $f->exists ) {
$path = $f;
last DIR;
}
}
}
die sprintf qq{Could not find container "%s" in directories: %s\n},
$container, join( $PATHS_SEP, @dirs )
unless $path;
return $path;
}
1;
__END__
=pod
=head1 NAME
Beam::Runner::Util - Utilities for Beam::Runner command classes
=head1 VERSION
version 0.016
=head1 SYNOPSIS
use Beam::Runner::Util qw( find_container_path );
my $path = find_container_path( $container_name );
=head1 DESCRIPTION
This module has some shared utility functions for creating
L<Beam::Runner::Command> classes.
=head1 SUBROUTINES
=head2 find_containers
my %container = find_containers();
Returns a list of C<name> and C<path> pairs pointing to all the containers
in the C<BEAM_PATH> paths.
=head2 find_container_path
my $path = find_container_path( $container_name );
Find the path to the given container. If the given container is already
an absolute path, it is simply returned. Otherwise, the container is
searched for in the directories defined by the C<BEAM_PATH> environment
variable.
If the container cannot be found, throws an exception with a user-friendly
error message.
=head1 SEE ALSO
L<Beam::Runner>, L<beam>, L<Exporter>
=head1 AUTHOR
Doug Bell <preaction@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by Doug Bell.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut