App-hopen
view release on metacpan or search on metacpan
lib/App/hopen.pm view on Meta::CPAN
}
# Process other arguments. The first two non-option arguments are dest
# dir and project dir, if --from and --to were not given.
$hrOptsOut->{DEST_DIR} //= $params{from}->[0] if @{$params{from}};
$hrOptsOut->{PROJ_DIR} //= $params{from}->[1] if @{$params{from}}>1;
# Sanity check VERBOSE2, and give it a default of 0
my $v2 = $hrOptsOut->{VERBOSE2} // 0;
$v2 = 1 if $v2 eq ''; # --verbose without value === --verbose=1
die "--verbose requires a positive numeric argument"
if (defined $v2) && ( !looks_like_number($v2) || (int($v2) < 0) );
$hrOptsOut->{VERBOSE2} = int($v2 // 0);
} #_parse_command_line() }}}2
# }}}1
# === Main worker code ================================================== {{{1
sub _execute_hopen_file { # Load and run a single hopen file {{{2
=head2 _execute_hopen_file
Execute a single hopen file, but B<do not> run the DAG. Usage:
_execute_hopen_file($filename[, options...])
This function takes input from L</$_hrData> unless a C<< DATA=>{...} >> option
is given. This function updates L</$_hrData> based on the results.
Options are:
=over
=item phase
If given, force the phase to be the one specified.
=item quiet
If truthy, suppress extra output.
=item libs
If given, it must be an arrayref of directories. Each of those will be
turned into a C<use lib> statement (see L<lib>) in the generated source.
=back
=cut
my $fn = shift or croak 'Need a file to run';
my %opts = @_;
$Phase = $opts{phase} if $opts{phase};
my $merger = Hash::Merge->new('RETAINMENT_PRECEDENT');
# == Set up code pieces related to phase control ==
my ($set_phase, $cannot_set_phase, $cannot_set_phase_warn);
my $setting_phase_allowed = false;
# Note: all phase-setting functions succeed if there was nothing
# for them to do!
$set_phase = q(
sub can_set_phase { true }
sub set_phase {
my $new_phase = shift or croak 'Need a phase';
return if $App::hopen::BuildSystemGlobals::Phase eq $new_phase;
croak "Phase $new_phase is not one of the ones I know about (" .
join(', ', @PHASES) . ')'
unless defined phase_idx($new_phase);
$App::hopen::BuildSystemGlobals::Phase = $new_phase;
$App::hopen::_did_set_phase = true;
) .
($opts{quiet} ? '' : 'say "Running $new_phase phase";') . "}\n";
$cannot_set_phase = q(
sub can_set_phase { false }
sub set_phase {
my $new_phase = shift // '';
return if $App::hopen::BuildSystemGlobals::Phase eq $new_phase;
croak "I'm sorry, but this file (``$FILENAME'') is not allowed to set the phase"
}
);
$cannot_set_phase_warn = q(
sub can_set_phase { false }
sub set_phase {
my $new_phase = shift // '';
return if $App::hopen::BuildSystemGlobals::Phase eq $new_phase;
) .
($opts{quiet} ? '' :
q(
warn "``$FILENAME'': Ignoring attempt to set phase";
)
) . "}\n";
my $lib_dirs = '';
if($opts{libs}) {
$lib_dirs .= "use lib '" . (dir($_)->absolute =~ s/'/\\'/gr) . "';\n"
foreach @{$opts{libs}};
}
# == Make the hopen file into a package we can eval ==
my ($friendly_name, $pkg_name, $file_text, $phase_text);
$phase_text = q(
use App::hopen::Phases ':all';
);
# -- Load the file
if(ref $fn eq 'HASH') { # it's a -e
hlog { 'Processing', $fn->{name} };
$file_text = $fn->{text};
$friendly_name = $fn->{name};
$pkg_name = 'CmdLineE' . $fn->{num} . '_' . $_hf_pkg_idx++;
$phase_text .= defined($opts{phase}) ? $cannot_set_phase : $set_phase;
# -e's can set phase unless --phase was specified
} else {
hlog { 'Processing', $fn };
$file_text = file($fn)->slurp;
$pkg_name = ($fn =~ s/[^a-zA-Z0-9]/_/gr) . '_' . $_hf_pkg_idx++;
$friendly_name = $fn;
if( isMYH($fn) and !defined($opts{phase}) ) {
# MY.hopen.pl files can set $Phase unless --phase was given.
$phase_text .= $set_phase;
$setting_phase_allowed = true;
} else {
# For MY.hopen.pl, when --phase is set, set_phase doesn't croak.
# If this were not the case, every second or subsequent run
# of hopen(1) would croak if --phase were specified!
$phase_text .= isMYH($fn) ? $cannot_set_phase_warn : $cannot_set_phase;
# TODO? permit regular hopen files to set the the phase if
# neither MYH nor the command line did, and we're at the first
# phase. This is so the hopen file can say `set_phase 'Gen';`
# if there's nothing to do during Check.
}
} #endif -e else
$friendly_name =~ s{"}{-}g;
# as far as I can tell, #line can't handle embedded quotes.
# -- Build the package
# TODO move phase-setting to App::hopen::MYhopen
# TODO set $App::hopen::MYhopen::IsMYH to indicate whether or not this
# file is MY.hopen.pl.
my $src = line_mark_string <<EOT ;
{
package __Rpkg_$pkg_name;
use App::hopen::HopenFileKit "\Q$friendly_name\E";
# \\Q and \\E since, on Windows, \$friendly_name is likely to
# include backslashes.
# Other lib dirs
$lib_dirs
# /Other lib dirs
# Other phase text
$phase_text
# /Other phase text
EOT
# Now shadow $Phase so the hopen file can't change it without
# really trying! Note that we actually interpolate the current
# phase in as a literal so that it's read-only (see perlmod).
unless($setting_phase_allowed) {
$src .= line_mark_string <<EOT;
our \$Phase;
local *Phase = \\"$Phase";
EOT
}
# Run the code given in the hopen file. Wrap it in a named BLOCK so that
# Phases::on() will work, but don't rely on the return value of that
# BLOCK (per perlsyn).
$src .= line_mark_string <<EOT;
sub __Rsub_$pkg_name {
my \$__R_retval;
__R_DO: {
\$__R_retval = do { # return statements in here will exit the Rsub
#line 1 "$friendly_name"
$file_text
}; # do{}
} #__R_DO
EOT
# If the file_text did not expressly return(), control will reach the
# following block, where we get the correct return value. If the file_text
( run in 1.941 second using v1.01-cache-2.11-cpan-302cb4679cc )