view release on metacpan or search on metacpan
bin/fetchware view on Meta::CPAN
# Must parse the Fetchwarefile in the parent, so that the parent has access
# to the imported subroutines and modified fetchware configuration (%CONFIG)
# just as the child does.
parse_fetchwarefile($fetchwarefile);
vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
# start() runs as root before the fork, because it uses
# App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
# subroutine uses a variable to store an open filehandle to a
# "fetchware.sem" semaphore file. This filehandle must stay open and locked
# using flock, because otherwise a "fetchware clean" run could delete the
# temporary directory out from under fetchware. Therefore, the parent must
# open this semaphore, because the child if it runs start() will close this
# file handle when it exits causing cleanup_tempdir() to freak out when
# end() is called.
my $temp_dir = start();
# Drop privs, so only install() and end() are called with root perms
$output = drop_privs(
sub {
bin/fetchware view on Meta::CPAN
# Must parse the Fetchwarefile in the parent, so that the parent has access
# to the imported subroutines and modified fetchware configuration (%CONFIG)
# just as the child does.
parse_fetchwarefile($fetchwarefile);
vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
# start() runs as root before the fork, because it uses
# App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
# subroutine uses a variable to store an open filehandle to a
# "fetchware.sem" semaphore file. This filehandle must stay open and locked
# using flock, because otherwise a "fetchware clean" run could delete the
# temporary directory out from under fetchware. Therefore, the parent must
# open this semaphore, because the child if it runs start() will close this
# file handle when it exits causing cleanup_tempdir() to freak out when
# end() is called.
my $temp_dir = start();
# "Download" the package using File::Copy's cp().
my $package_path;
if (cp($fetchware_package_path, $temp_dir)) {
bin/fetchware view on Meta::CPAN
# Must parse the Fetchwarefile in the parent, so that the parent has access
# to the imported subroutines and modified fetchware configuration (%CONFIG)
# just as the child does.
parse_fetchwarefile($fetchwarefile);
vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
# start() runs as root before the fork, because it uses
# App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
# subroutine uses a variable to store an open filehandle to a
# "fetchware.sem" semaphore file. This filehandle must stay open and locked
# using flock, because otherwise a "fetchware clean" run could delete the
# temporary directory out from under fetchware. Therefore, the parent must
# open this semaphore, because the child if it runs start() will close this
# file handle when it exits causing cleanup_tempdir() to freak out when
# end() is called.
my $temp_dir = start();
# Drop privs, so only install() is called with root permissions
my $output = drop_privs(
sub {
bin/fetchware view on Meta::CPAN
# Must parse the Fetchwarefile in the parent, so that the parent has access
# to the imported subroutines and modified fetchware configuration (%CONFIG)
# just as the child does.
parse_fetchwarefile($fetchwarefile);
vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
# start() runs as root before the fork, because it uses
# App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
# subroutine uses a variable to store an open filehandle to a
# "fetchware.sem" semaphore file. This filehandle must stay open and locked
# using flock, because otherwise a "fetchware clean" run could delete the
# temporary directory out from under fetchware. Therefore, the parent must
# open this semaphore, because the child if it runs start() will close this
# file handle when it exits causing cleanup_tempdir() to freak out when
# end() is called.
#
# Call start() with an option to have it keep the temp dir, and not
# have File::Temp clean it up with an END handler.
my $temp_dir = start(KeepTempDir => 1);
bin/fetchware view on Meta::CPAN
msg "fetchware clean found no fetchware temporary directories to clean"
if @globbed_fetchware_temp_dirs < 1;
# Holds the number of directories that had errors when they were
# deleted.
my $num_remove_tree_errors = 0;
# Number of directories remove_tree removed successfully.
my $num_remove_tree_successes = 0;
# Loop over fetchware temp dirs, and delete the ones that are not locked.
for my $temp_dir (@globbed_fetchware_temp_dirs) {
# Try to lock the 'fetchware.sem' semaphore lock file
# I annoying must open the file before I can see if I can lock it or
# not.
my $sem_lock_file = catfile($temp_dir, 'fetchware.sem');
my $fh_sem;
if (open $fh_sem, '>', $sem_lock_file) {
vmsg "Successfully created [fetchware.sem] semaphore lock file.";
} else {
bin/fetchware view on Meta::CPAN
}
# Now flock 'fetchware.sem.' This should
# Use LOCK_NB so flock won't stupidly wait forever and ever until
# he lock becomes available.
# If flock fails, don't die! Instead, just skip deleting this
# fetchware temporary directory, and go on to the next one.
unless (flock $fh_sem, LOCK_EX | LOCK_NB) {
# Flock failed, something else has the lock, print message, and skip
# this directory, and go on to the next one.
msg <<EOM;
[$temp_dir] locked by another fetchware process. Skipping.
EOM
next;
}
# Delete the whole $tempdir. Use error and result for File::Path's
# experimental error handling, and set safe to true to avoid borking the
# filesystem. This might be run as root, so it really could screw up
# your filesystem big time! So set safe to true to avoid doing so.
remove_tree($temp_dir, {
error => \my $err,
lib/App/Fetchware/Util.pm view on Meta::CPAN
# cleanup_tempdir() closes clearing the lock. This is used to support
# fetchware clean. The filehandle needs to be declared outside
# create_tempdir()'s scope, because when this filehandle goes out of scope
# the file is closed, and the lock is released, but fetchware needs to keep
# hold of this lock for the life of fetchware to ensure that any fetchware
# clean won't delete this fetchware temporary directory.
my $fh_sem;
###BUGALERT### Add support for the -f/--force option to force deleting fetchware
#temp dirs even if locked.
sub create_tempdir {
my %opts = @_;
msg 'Creating temp dir to use to install your package.';
# Ask for better security.
File::Temp->safe_level( File::Temp::HIGH );
# Create the temp dir in the portable locations as returned by
# File::Spec->tempdir() using the specified template (the weird $$ is this
lib/App/Fetchware/Util.pm view on Meta::CPAN
vmsg "Successfully created [fetchware.sem] semaphore lock file.";
# Now flock 'fetchware.sem.' This should
# Use LOCK_NB so flock won't stupidly wait forever and ever until the lock
# becomes available.
flock $fh_sem, LOCK_EX | LOCK_NB or die <<EOD;
App-Fetchware-Util: Failed to flock [fetchware.sem] semaphore lock file! This
should not happen, because this is being done in a brand new temporary directory
that only this instance of fetchware cares about. This just shouldn't happen. OS
error [$!].
EOD
vmsg "Successfully locked [fetchware.sem] semaphore lock file using flock.";
msg "Temporary directory created [$temp_dir]";
return $temp_dir;
}
sub original_cwd {
return $original_cwd;
lib/App/Fetchware/Util.pm view on Meta::CPAN
Uses HTTP::Tiny to download the specified HTTP URL.
Supports adding extra arguments to HTTP::Tiny's new() constructor. These
arguments are B<not> checked for correctness; instead, they are simply forwarded
to HTTP::Tiny, which does not check them for correctness either. HTTP::Tiny
simply loops over its internal listing of what is arguments should be, and then
accesses the arguments if they exist.
This was really only implemented to allow App::FetchwareX::HTMLPageSync to change
its user agent string to avoid being blocked or freaking out Web developers that
they're being screen scraped by some obnoxious bot as HTMLPageSync is wimpy and
harmless, and only downloads one page.
You would add an argument like this:
download_http_url($http_url, agent => 'Firefox');
See HTTP::Tiny's documentation for what these options are.
=head2 download_file_url()
lib/App/Fetchware/Util.pm view on Meta::CPAN
whatever File::Spec's tmpdir() says to use.
The C<NoChown =E<gt> 1> option causes create_tempdir() to B<not> chown to
config('user').
=head3 Locking Fetchware's temp directories with a semaphore file.
In order to support C<fetchware clean>, create_tempdir() creates a semaphore
file. The file is used by C<fetchware clean> (via bin/fetchware's cmd_clean())
to determine if another fetchware process out there is currently using this
temporary directory, and if it is not, the file is not currently locked with
flock, then the entire directory is deleted using File::Path's remove_path()
function. If the file is there and locked, then the directory is skipped by
cmd_clean().
cleanup_tempdir() is responsible for unlocking the semaphore file that
create_tempdir() creates. However, the coolest part of using flock is that if
fetchware is killed in any manner whether its C<END> block or File::Temp's
C<END>block run, the OS will still unlock the file, so no edge cases need
handling, because the OS will do them for us!
=head2 original_cwd()
lib/Test/Fetchware.pm view on Meta::CPAN
matches the same element of C<@{$sorted_export}>. You do not have to pre sort
these array refs, because export_ok() will copy them, and sort that copy of
them. Uses Test::More's pass() or fail() for each element in the arrays.
=head2 end_ok()
Because end() no longer uses File::Temp's cleanup() to delete B<all> temporary
File::Temp managed temporary directories when end() is called, you can no longer
test end() we a simple C<ok(not -e $temp_dir, $test_name);>; instead, you should
use this testing subroutine. It tests if the specified $temp_dir still has a
locked C<'fetchware.sem'> fetchware semaphore file. If the file is not locked,
then end_ok() reports success, but if it cannot obtain a lock, end_ok reports
failure simply using ok().
=head2 add_prefix_if_nonroot()
my $prefix = add_prefix_if_nonroot();
my $callbacks_return_value = add_prefix_if_nonroot(sub { a callback });
fetchware is designed to be run as root, and to install system software in
t/bin-fetchware-clean.t view on Meta::CPAN
subtest 'test cmd_clean() success' => sub {
# Some CPAN Testers smokers have lax umask causing File::Temp's and
# fetchware's own safe_open() security checking to fail. Overcome this
# limiation by testing cmd_clean()'s cleanup code inside a temporary
# directory instead of cwd().
my $testing_tempdir = tempdir("fetchware-$$-XXXXXXXXXX", TMPDIR => 1,
CLEANUP => 1);
ok( -e $testing_tempdir, 'checked creating testing tempdir.');
# Use create_tempdir(), which creates a semaphore and print_ok to test if
# cmd_clean skips locked temp dirs.
# Use a localized TempDir, so that most likely only the current user has
# access to it, and so that I can test cmd_clean() under controlled
# circumstances so that a directory owned by root, for example, does not
# mess up what the error message is supposed to be causing the test to fail.
my $tempdir = create_tempdir(TempDir => $testing_tempdir);
ok(-e $tempdir, 'checked creating a temporary directory.');
print_ok(sub {cmd_clean($testing_tempdir)},
qr/.*?] locked by another fetchware process\. Skipping\./,
'checked cmd_clean skipping locked fetchware directories.');
ok(chdir(original_cwd()), 'chdir() out of tempdir, so we can delete it');
# Create one fetchware temporary directory to test cmd_clean()'s ability to
# delete it.
$tempdir = tempdir("fetchware-$$-XXXXXXXXXXXXX", DIR => $testing_tempdir,
CLEANUP => 1);
ok(-e $tempdir, 'checked creating a temporary directory.');
# Delete the newly created tempdir.