App-Fetchware
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();
# "Download" the package using File::Copy's cp().
my $package_path;
if (cp($fetchware_package_path, $temp_dir)) {
# Determine the output file that cp() used.
###BUGALERT### Open the file for cp(), and provide cp() with a
#filehandle to write the data to to ensure the filename is exactly
#what it needs to be.
$package_path = catfile($temp_dir,
file($fetchware_package_path)->basename());
} else {
die <<EOD;
fetchware: Fetchware failed to copy the file [$fetchware_package_path] to the
destination directory [$temp_dir]. OS error [$!].
EOD
}
vmsg "Copied installed package to temporary directory at [$package_path]";
my $build_path = unarchive($package_path);
uninstall($build_path);
end();
vmsg 'Uninstalling fetchware package from fetchware database.';
uninstall_fetchware_package_from_database($fetchware_package_path);
msg "Uninstalled fetchware package [$uninstall_package_path].";
# Return the name of the uninstalled package's full path fetchware's
# database.
return $fetchware_package_path;
}
###BUGALERT### Move cmd_new() before install()?????
###BUGALERT### Print out fetchware's assumptions it makes about what FTP & hTTP
#lookup_url's look like, versionstring's assumptions, timestamp's assumptions,
#verify's assumptions, and so on. If not here in new() at least do it in the
#POD documentation.
###BUGALERT### Support ~/.Fetchwarefile, or whatever File::HomeDir wants it to
#be. Test if ~/.Fetchwarefile exists, if it does do nothing, but if it does not
#exist then prompt the user to fill one out!!!
############BUGALERT########################BUGALERT##################
############BUGALERT########################BUGALERT##################
###BUGALERT### Modify analyze_lookup_listing() to print the directory listing
#for the user to peruse, and have the user choose what program they want to
#install from the listing. Then use that as the basis for the filter option.
#httpd-2.4.1.tar.bz2 would simply be m/(\w+?)[.-_\d]+?/ And $1 is the filter
#option. If the match fails to the existing manual crap.
############BUGALERT########################BUGALERT##################
############BUGALERT########################BUGALERT##################
###BUGALERT### Add a command line option to fetchware new that allows users to
#only edit a blank file (Have helpful comments about what options are must
#haves), and then have fetchware ask the user if they would like to then install
#that new Fetchwarefile.
###BUGALERT### Rename lookup_url to main_mirror or master_mirror or author_mirror
#or something to better implicitly explain what it is.
###BUGALERT### Add the check to see if there is a MIRRORS file or some similar
#regex, and if so parse it, and auto add it to the list of mirrors? Is this
#really feasible?
sub cmd_new {
# These are the variables that the child must share back with the parent.
my $program_name = shift; # The child might change or define it again.
my $term = Term::ReadLine->new('Fetchware new');
# Must ask user what App::Fetchware extension they are going to create a
# Fetchwarefile for, so I can load that extension's new() and new_install()
# API subroutines, because *no* API subroutines are available until
# parse_fetchwarefile() is called in cmd_install(), and I can't call
# parse_fetchwarefile() before the user has answered the questons to
# actually create a Fetchwarefile.
my $fetchware_extension = $term->get_reply(
print_me => <<EOP,
Unless you're using a Fetchware extension, press enter to continue along in the
creation of your new Fetchwarefile. If you are using a Fetchware extension,
please enter its name without the 'App::FetchwareX::' prefix.
EOP
prompt => q{Unless you're using a Fetchware extension press enter to use default?},
default => 'App::Fetchware',
);
###Security Note### Whatever string the user supplies will be given
#to Module::Load's load() subroutine, and then forwarded on to
#Perl's require() function, which parses and executes it as far as
#loading it goes, and then whatever new() and new_install()
#subroutines will be imported in the current package, and later one
#executed below new() with dropped privs, and new_install() as root
#if fun as root. You may consider this a security hole as it is
#never a good idea to execute user specified code, but considering
#later on cmd_new() via new() will ask the user if they want to edit
#the Fetchwarefile, where they can put whatever Perl code in it they
#want to, and then ask_to_install_now_to_test_fetchwarefile() will
#actually then run that Fetchwarefile, so that is also a security
#hole. However none of this really is a security hole, because the
#user could create a Perl program that does whatever bad stuff that
#they could use this to mess with Fetchware for.
###Do basic security checking anyway.
die <<EOD if $fetchware_extension =~ m!\.\./|/|.pl|.pm!;
fetchware: The Fetchware extension you provided has characters that are not
allowed in fetchware extensions such as [../ , / , .pl , or .pm]. Please remove
these characters, and try again.
EOD
if (grep { $fetchware_extension eq $_ }
qw(App::Fetchware Fetchware fetchware default Default)
) {
load 'App::Fetchware', qw(new new_install);
} else {
# Prepend the App::FetchwareX:: prefix for all fetchware
# extensions.
$fetchware_extension = "App::FetchwareX::$fetchware_extension";
load $fetchware_extension, qw(new new_install);
}
# Drop privs, so only install() is called with root permissions
my $output = drop_privs( sub {
my $write_pipe = shift;
my @pipe_args = new($term, $program_name);
# Tell the parent, root, process the values of the variables the
# child calculated in this coderef, and write them across this pipe
# back to the parent
write_dropprivs_pipe($write_pipe, @pipe_args);
}, config('user'),
# cmd_new() does not want or need the directory that drop_privs() creates
# for the child so that the child can write files inside the parent's
# temporary directory that was created with start().
SkipTempDirCreation => 1
); # End drop_privs() back to root now!
# Read from the pipe the child, the drop_privs()ed process, writes to to
# read the necessary values that correspond to the variables that the
# child must communicate back to the parent, so the parent can continue
bin/fetchware view on Meta::CPAN
if ($> == 0) {
# Fetchware is modeled slightly after Slackware's package manager,
# which keeps its package database under /var/log/packages.
$fetchware_database_path = '/var/log/fetchware';
# else use a "user" directory.
} else {
$fetchware_database_path
=
File::HomeDir->my_dist_data('fetchware', { create => 1 });
}
} elsif ($^O eq "MSWin32") {
# Load main Windows module to use to see if we're Administrator or not.
BEGIN {
if ($^O eq "MSWin32")
{
require Win32;
Win32->import(); # assuming you would not be passing arguments to "use Module"
}
}
if (Win32::IsAdminUser()) {
# Is this an appropriate default?
$fetchware_database_path = 'C:\Fetchware';
} else {
$fetchware_database_path
=
File::HomeDir->my_dist_data('fetchware' , { create => 1 });
}
# Fall back on File::HomeDir's recommendation if not "Unix" or windows.
###BUGALERT### Is this appropriate for Mac OSX???? /Fetchware perhaps?????
} else {
$fetchware_database_path
=
File::HomeDir->my_dist_data('fetchware', { create => 1 });
}
vmsg <<EOM;
Determined fetchware database path to be: [$fetchware_database_path]
EOM
return $fetchware_database_path;
}
sub determine_fetchware_package_path {
my $fetchware_package = shift;
my ($package, $filename, $line) = caller;
my $fetchware_db_glob = catfile(fetchware_database_path(), '*');
my @fetchware_package_filenames
=
grep /$fetchware_package/, glob $fetchware_db_glob;
die <<EOD if @fetchware_package_filenames == 0;
fetchware: Fetchware failed to determine the fetchware package that is
associated with the argument that you provided to fetchware
[$fetchware_package]. In this case, fetchware only allows arguments for
fetchware packages that have already been installed. Please run fetchware list
to obtain a list of installed packages to choose from.
EOD
###BUGALERT### Use Term::UI, and output a numbered list for the user to
#choose from using a prompt, and then rerun upgrade with that argument.
if (@fetchware_package_filenames > 1) {
# Print beginning of message to STDERR.
warn <<EOW;
fetchware: Too many installed packages match the argument you provided to the
upgrade command. Your argument was [$fetchware_package], and the multiple
results it returned were:
EOW
# Print modified array values to STDERR.
for (@fetchware_package_filenames) {
warn file($_)->basename(), "\n";
}
# Print closing of message to STDERR.
die <<EOD;
Choose which package from the list above you want to upgrade, and rerun
fetchware upgrade using it as the argument for the package you want to upgrade.
EOD
}
# Return the first and only result.
return $fetchware_package_filenames[0];
}
sub extract_fetchwarefile {
my ($fetchware_package_path) = @_;
# safe_open() the fetchware package path, which ends with .fpkg, but it
# actually a .tar.gz.
my $fh = safe_open($fetchware_package_path, <<EOD);
fetchware: run-time error. fetchware failed to open the Fetchwarefile you
specified on the command line [$fetchware_package_path]. Please check
permissions and try again. See perldoc App::Fetchware. OS error [$!].
EOD
# Create a temporary file to write the ungzipped file to.
my ($output_fh, $gunzipped_path) = tempfile("fetchware-$$-XXXXXXXXXXX",
TMPDIR => 1, UNLINK => 1);
gunzip($fh => $output_fh) or die <<EOD;
fetchware: IO::Uncompress::Gunzip::gunzip failed to un gzip
[$fetchware_package_path]. Gunzip's error [$GunzipError].
EOD
my $tar = Archive::Tar->new();
# seek the $output_fh back to its beginning, so tar can reuse it.
seek $output_fh, 0, SEEK_SET;
# read in the same output filehandle that gunzip() wrote the uncompressed tar
# file to. This prevents any race conditions, and other users from messing
# with our version of the open file.
$tar->read($output_fh) or die <<EOD;
fetchware: Archive::Tar failed to read in the gunziped file [$gunzipped_path]
that was previously gziped as [$fetchware_package_path].
Archive::Tar error [@{[Archive::Tar->error()]}].
EOD
( run in 0.983 second using v1.01-cache-2.11-cpan-6aa56a78535 )