App-Fetchware
view release on metacpan or search on metacpan
lib/App/Fetchware.pm view on Meta::CPAN
EOA
sha1_url => <<EOA,
sha1_url specfies the url that fetchware uses to download sha1sum files of
this program. This url should be the program's main download site instead of a
mirror, because a hacked mirror could alter the sha1sum on that mirror.
EOA
md5_url => <<EOA,
md5_url specfies the url that fetchware uses to download md5sum files of
this program. This url should be the program's main download site instead of a
mirror, because a hacked mirror could alter the md5sum on that mirror.
EOA
verify_method => <<EOA,
verify_method specifes a specific method that fetchware should use to verify
your program. This method can be 'gpg', 'sha1', or 'md5'.
EOA
no_install => <<EOA,
no_install specifies that this software should not be installed. Instead, the
install step is skipped, and fetchware prints to STDOUT where it downloaded,
verified, and built your program. no_install must be a true or false value.
EOA
verify_failure_ok => <<EOA,
verify_failure_ok specifies that fetchware should not stop installing your
software and terminate with an error message if fetchware fails to verify your
software. You should never set this to true. Doing so could cause fetchware to
install software that may have been compromised, or had malware inserted into
it. Never use this option unless the author or maintainer of this program does
not gpg sign or checksum his software.
EOA
user_keyring => <<EOA,
users_keyring if enabled causes fetchware to use the user's own gpg keyring
instead of fetchware's own keyring.
EOA
mirror => <<EOA
The mirror configuration option provides fetchware with alternate servers to
try to download this program from. This option is used when the server
specified in the url options in this file is unavailable or times out.
EOA
}
);
###INSANEFEATUREENHANCEMENT### Prompt for name of program, and do a fuzzy
#search on CPAN for that program under
#App::Fetchware::FetchwarefileX::UpCasedProgName. Consider using the meta
#CPAN API. And if it exists ask user if they wanna use that one instead of
#autogening one.
#
#Perhaps create a 'fetchwarefile' command to download and look at
#fetchwarefiles from CPAN, and then install them, and/or perhaps upload
#them pausing to ask for the user's PAUSE credentials!!!!!!!!!
extension_name(__PACKAGE__);
my $opening_message = <<EOM;
Fetchware's new command is reasonably sophisticated, and is smart enough to
determine based on the lookup_url you provide if it can autogenerate a
Fetchwarefile for you. If Fetchware cannot, then it will ask you more
questions regarding the information it requires to be able to build a
installable fetchware package for you. After that, fetchware will ask you if
you would like to edit the Fetchwarefile, fetchware has created for you in an
editor. If you say yes, fetchware will open a editor for you, but if you say
no, fetchware will skip the custom editing. Next, fetchware will create a test
Fetchwarefile for you, and ask you if you would like to test it by trying to
install it now. If you say yes, fetchware will install it, and if you say no,
then fetchware will print the location of the Fetchwarefile it created for
you to later use to install your application.
EOM
opening_message($opening_message);
# Ask user for name of program unless the user provided one at command
# line such as fetchware new <programname>.
$program_name = fetchwarefile_name(program => $program_name);
vmsg "Determined name of your program to be [$program_name]";
$fetchwarefile->config_options(program => $program_name);
vmsg "Appended program [$program_name] configuration option to Fetchwarefile";
my $lookup_url = get_lookup_url($term);
vmsg "Asked user for lookup_url [$lookup_url] from user.";
$fetchwarefile->config_options(lookup_url => $lookup_url);
vmsg "Appended lookup_url [$lookup_url] configuration option to Fetchwarefile";
vmsg "Downloaded lookup_url [$lookup_url]";
my $filename_listing = download_lookup_url($term, $lookup_url);
vmsg "Downloaded lookup_url's directory listing";
vmsg Dumper($filename_listing);
my $mirrors_hashref = get_mirrors($term, $filename_listing);
vmsg "Added mirrors to your Fetchwarefile.";
vmsg Dumper($mirrors_hashref);
my $verify_hashref = get_verification($term, $filename_listing, $lookup_url);
vmsg "Added verification settings to Fetchwarefile.";
vmsg Dumper($verify_hashref);
my $filter_hashref = get_filter_option($term, $filename_listing);
vmsg "Added [$filter_hashref->{filter}] filter setting to Fetchwarefile.";
$fetchwarefile->config_options(
%$mirrors_hashref,
%$verify_hashref,
%$filter_hashref
);
###BUGALERT### Ask to parrallelize make with make_options???
###BUGALERT### Verify prefix is writable by current user, who will
#presumably be the user who will install the package now and later.
###BUGALERT### Ask user for a prefix if their running nonroot???
vmsg 'Prompting for other options that may be needed.';
my $other_options_hashref = prompt_for_other_options($term,
temp_dir => {
prompt => <<EOP,
What temp_dir configuration option would you like?
EOP
print_me => <<EOP
temp_dir is the directory where fetchware creates a temporary directory that
stores all of the temporary files it creates while it is building your software.
The default directory is /tmp on Unix systems and C:\\temp on Windows systems.
EOP
},
user => {
prompt => <<EOP,
lib/App/Fetchware.pm view on Meta::CPAN
} # Enclosing block for $"
# Ensure no files starting with an absolute path get extracted
# And determine $build_path.
my $build_path = check_archive_files($files);
vmsg "Unarchiving $format archive [$package_path].";
unarchive_package($format, $package_path);
msg "Determined build path to be [$build_path]";
return $build_path;
}
sub list_files {
my $package_path = shift;
# List files based on archive format.
my $files;
my $format;
if ($package_path =~ /\.(t(gz|bz|xz|Z))|(tar\.(gz|bz2|xz|Z))|.fpkg$/) {
$format = 'tar';
vmsg <<EOM;
Listing files in your tar format archive [$package_path].
EOM
$files = list_files_tar($package_path);
} elsif ($package_path =~ /\.zip$/) {
$format = 'zip';
vmsg <<EOM;
Listing files in your zip format archive [$package_path].
EOM
$files = list_files_zip($package_path);
} else {
die <<EOD;
App-Fetchware: Fetchware failed to determine what type of archive your
downloaded package is [$package_path]. Fetchware only supports zip and tar
format archives.
EOD
}
# unarchive_package() needs $format, so return that too.
return $format, $files;
}
sub list_files_tar {
my $path_to_tar_archive = shift;
my $tar_iter = Archive::Tar->iter($path_to_tar_archive, 1, );
die <<EOD unless defined $tar_iter;
App-Fetchware: fetchware failed to create a new Archive::Tar iterator. The
Archive::Tar error message was [@{[Archive::Tar->error()]}].
EOD
# Iterate over the the archive one file at a time to save memory on big
# archives suchs a say MariaDB or the Linux kernel.
my @files;
while (my $file = $tar_iter->() ) {
push @files, $file->full_path();
}
return \@files;
}
{ # Begin %zip_error_codes hash.
my %zip_error_codes = (
AZ_OK => 'Everything is fine.',
AZ_STREAM_END =>
'The read stream (or central directory) ended normally.',
AZ_ERROR => 'There was some generic kind of error.',
AZ_FORMAT_ERROR => 'There is a format error in a ZIP file being read.',
AZ_IO_ERROR => 'There was an IO error'
);
sub list_files_zip {
my $path_to_zip_archive = shift;
my $zip = Archive::Zip->new();
my $zip_error;
if(($zip_error = $zip->read($path_to_zip_archive)) ne AZ_OK) {
die <<EOD;
App-Fetchware: Fetchware failed to read in the zip file [$path_to_zip_archive].
The zip error message was [$zip_error_codes{$zip_error}].
EOD
}
# List the zip files "members," which are annoying classes not just a list
# of file names. I could use the memberNames() method, but that method
# returns their "internal" names, but I want their external names, what
# their names will be on your file system.
my @members = $zip->members();
my @external_filenames;
for my $member (@members) {
push @external_filenames, $member->fileName();
}
# Return list of "external" filenames.
return \@external_filenames;
}
sub unarchive_package {
my ($format, $package_path) = @_;
unarchive_tar($package_path) if $format eq 'tar';
unarchive_zip($package_path) if $format eq 'zip';
}
lib/App/Fetchware.pm view on Meta::CPAN
=item B<uninstall_commands> - Specifies a list of commands that fetchware will
use to I<uninstall> your program. You only need this option if your source code
distribution does not provide a C<make uninstall> target, which not every source
code distribution does.
=item B<no_install> - Specifies a boolean (true or false) value to turn off fetchware installing the software it has downloaded, verified, unarchvied, and built. If you specify a true argument (1 or 'True' or 'On'), then fetchware will C<not> install...
=back
Just copy and paste the example below replacing C<[new_directive]> with the name
of the new directive you would like to add, and fill in the space between the
single quotes C<'>.
[new_directive] '';
After pasting it should look like.
[new_directive] '~/wallpapers';
=back
=head1 USING YOUR App::Fetchware FETCHWAREFILE WITH FETCHWARE
After you have
L<created your Fetchwarefile|/"MANUALLY CREATING A App::Fetchware FETCHWAREFILE">
as shown above you need to actually use the fetchware command line program to
install, upgrade, or uninstall your App::Fetchware Fetchwarefile.
=over
=item B<install>
A C<fetchware install [path/to/Fetchwarefile]> while using a App::Fetchware
Fetchwarefile causes fetchware to install the program specified in your
fetchwarefile to your computer as you have specified any build or install
options.
=item B<upgrade>
A C<fetchware upgrade [installed program name]> while using a App::Fetchware
Fetchwarefile will simply run the same thing as install all over again, which
ill upgrade your program if a new version is available.
=item B<uninstall>
A C<fetchware uninstall [installed program name]> will cause fetchware to run
the command C<make uninstall>, or run the commands specified by the
C<uninstall_commands> configuration option. C<make uninstall> is only available
from some programs that use AutoTools such as ctags, but apache, for example,
also uses AutoTools, but does not provide a uninstall make target. Apache for
example, therefore, cannot be uninstalled by fetchware automatically.
=item B<upgrade-all>
A C<fetchware upgrade-all> will cause fetchware to run C<fetchware upgrade> for
all installed packages that fetchware is tracking in its internal fetchware
database. This command can be used to have fetchware upgrade all currently
installed programs that fetchware installed.
If you would like C<fetchware upgrade-all> to be run every night automatically
by cron, then just create a file say fetchware with the contents below in it,
and add it to /etc/cron.daily.
#!/bin/sh
# Update all already installed fetchware packages.
fetchware upgrade-all
And if you don't want to run it system wide as root, you can add it to your user
crontab by pasting the snippet below in to your crontab by executing C<crontab -e>.
# Check for updates using fetchware every night at 2:30AM.
# Minute Hour Day of Month Month Day of Week Command
# (0-59) (0-23) (1-31) (1-12 or Jan-Dec) (0-6 or Sun-Sat)
30 2 * * * fetchware upgrade-all
=back
=head1 App::Fetchware'S FETCHWAREFILE CONFIGURATION OPTIONS
App::Fetchware has many configuration options. Most were briefly described in
the section L<MANUALLY CREATING A App::Fetchware FETCHWAREFILE>. All of them are
detailed below.
=head2 program 'Program Name';
C<program> simply gives this Fetchwarefile a name. It is availabe to fetchware
after parsing your Fetchwarefile, and is used to name your Fetchwarefile when
using C<fetchware new>. It is required just like C<lookup_url>, C<mirror>,
perhaps C<filter>, and some method to verify downloads are.
=head2 filter 'perl regex here';
Specifies a Perl regular expression that fetchware uses when it determines what
the latest version of a program is. It simply compares each file in the
directory listing specified in your C<lookup_url> to this regular expression,
and only matching files are allowed to pass through to the next part of
fetchware that looks for source code archives to download.
See L<perlretut> for details on how to use and create Perl regular expressions;
however, actual regex know how is not really needed just paste verbatim text
between the single quotes C<'>. For example, C<filter 'httpd-2.2';> will cause
fetchware to only download Apache 2.2 instead of the version for Windows or
whatever is in the weird httpd-deps-* package.
=head2 temp_dir '/tmp';
C<temp_dir> tells fetchware where to store fetchware's temporary working
directory that it uses to download, verify, unarchive, build, and install your
software. By default it uses your system temp directory, which is whatever
directory L<File::Temp's> tempdir() decides to use, which is whatever
L<File::Spec>'s tmpdir() decides to use.
=head2 fetchware_db_path '~/.fetchwaredb';
C<fetchware_db_path> tells fetchware to use a different directory other
than its default directory to store the installed fetchware package for the
particular fetchware package that this option is specified in your
Fetchwarefile. Fetchware's default is C</var/log/fetchware> on Unix when run as
root, and something like C</home/[username]/.local/share/Perl/dist/fetchware/>
when run nonroot.
lib/App/Fetchware.pm view on Meta::CPAN
=over
=item All of them, because it calls bin/fetchware's cmd_install(),
which in turn calls all of the API subroutines that fetchware's install command
does.
=back
=back
Exists separate from new(), because new() drops privileges like most other
fetchware commands do. But the new command includes the ability to ask the user
if they want to install the associated program from their newly created
Fetchwarefile, which requires root privileges. Therefore, we must also have a
API subroutine that runs in the root privileged parent to that the install
commands will run with proper permissions when fetchware is run as root.
=over
=item drop_privs() NOTES
This section notes whatever problems you might come accross implementing and
debugging your Fetchware extension due to fetchware's drop_privs mechanism.
See L<Util's drop_privs() subroutine for more info|App::Fetchware::Util/drop_privs()>.
=over
=item *
When fetchware is run as root, new_install() is called in the parent process
with root permissions so that you can call the
ask_to_install_now_to_test_fetchwarefile() helper subroutine. I suppose you
could do something else in your extension if it makes sense, but that's what
this API sub is intended for. The ask_to_install_now_to_test_fetchwarefile()
helper subroutine needs root permissions (Unless the Fetchwarefile has been
setup so that the user running it has access.), because it will call fetchware's
cmd_install() to directly cause fetchware to go ahead and install the previoulsy
generated Fetchwarefile.
=back
=back
=head2 new_install() API REFERENCE
The subroutines below are used by new_install() to provide the new_install functionality
for fetchware. If you have overridden the new_install() handler, you may want to use
some of these subroutines so that you don't have to copy and paste anything from
new_install.
App::Fetchware is B<not> object-oriented; therefore, you B<can not> subclass
App::Fetchware to extend it!
=head3 ask_to_install_now_to_test_fetchwarefile()
my $fetchware_package_path = ask_to_install_now_to_test_fetchwarefile($term, \$fetchwarefile, $program_name);
my $fetchwarefile_filename = ask_to_install_now_to_test_fetchwarefile($term, \$fetchwarefile, $program_name);
This subroutine asks the user if they want to install the Fetchwarefile that
this subroutine has been called with. If they say yes, then the Fetchwarefile is
passed on to cmd_install() to do all of the installation stuff. If they say no,
then fetchware saves the file to C<"$program_name.Fetchwarefile"> or
ask_to_install_now_to_test_fetchwarefile() will ask the user where to save the
file until the user picks a filename that does not exist.
=over
NOTE: ask_to_install_now_to_test_fetchwarefile() has an infinite loop in it! It
asks the user forever until they provide a filename that doesn't exist. Should a
limit be placed on this? Should it only ask just once?
=back
If you answer yes to install your Fetchwarefile, then
ask_to_install_now_to_test_fetchwarefile() will return the full path to the
fetchware package that has been installed.
=head2 start()
my $temp_dir = start();
=over
=item Configuration subroutines used:
=over
=item temp_dir
=back
=back
Creates a temp directory using File::Temp, and sets that directory up so that it
will be deleted by File::Temp when fetchware closes.
Returns the $temp_file that start() creates, so everything else has access to
the directory they should use for storing file operations.
=over
=item EXTENSION OVERRIDE NOTES
start() calls L<App::Fetchware::Util>'s create_tempdir() subroutine that cleans
up the temporary directory. If your fetchware extension overrides start() or
end(), you must call create_tempdir() or name your temproary directories in a
manner that fetchware clean won't find them, so something that does not start
with C<fetchware-*>.
If you fail to do this, and you use some other method to create temporary
directories that begin with C<fetchware-*>, then fetchware clean may delete your
temporary directories out from under your feet. To fix this problem:
=over
=item *
Use L<App::Fetchware::Util>'s create_tempdir() in your start() and
cleanup_tempdir() in your end().
=item *
( run in 1.415 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )