Check the list of module installed in machine - perl

I have made a script to intimate the admin the list of module need to be installed on machine .
I am trying to check wheather the module installed by underbelow code. The odd thing is that it is showing even installed module in the machine as not installed
#!/usr/bin/perl -w
my #module_list =('Smart::Comments','HTML::Parse');
foreach (#module_list) {
eval { require "$_" };
if (!($#)) {
print "Module Not installed : $_\n";
}
}

You need to use the string form of eval because require needs a bareword argument to match against the double-colon-separated form of the module name (e.g. Scalar::Util). (If it's not a bareword, then it needs to be a relative path, e.g. 'Scalar/Util.pm')
#!/usr/bin/perl
use strict;
use warnings;
my #module_list = ('Scalar::Util', 'flibble');
foreach (#module_list) {
if (!eval "require $_") {
print "Module not installed: $_\n";
}
}

There's my App::Module::Lister, which I designed as a modulino that can run as a module, a command-line utility, or a CGI script. It's a simple thing I needed for a friend who only had FTP access to a web server.
It gives you the list of everything in Perl's module search path, which I usually find easier than checking for specific modules each time. Once I have the whole list, I just look at the list.
You could check that you can load the module, but I tend to not like that because I don't want to potentially run the module's code to see if it's installed. It's usually not a problem, though.

Related

How to run this simple Perl CGI script on Mac from terminal?

This simple .pl script is supposed to grab all of the images in a directory and output an HTML — that when opened in a browser — displays all of the images in that dir at their natural dimensions.
From the mac command line, I want to just say perl myscript.pl and have it run.
… It used to run on apache in /cgi-bin.
#!/usr/bin/perl -wT
# myscript.pl
use strict;
use CGI;
use Image::Size;
my $q = new CGI;
my $imageDir = "./";
my #images;
opendir DIR, "$imageDir" or die "Can't open $imageDir $!";
#images = grep { /\.(?:png|gif|jpg)$/i } readdir DIR;
closedir DIR;
print $q->header("text/html"),
$q->start_html("Images in $imageDir"),
$q->p("Here are all the images in $imageDir");
foreach my $image (#images) {
my ($width, $height) = imgsize("$image");
print $q->p(
$q->a({-href=>$image},
$q->img({-src=>$image,
-width=>$width,
-height=>$height})
)
);
}
print $q->end_html;
Perl used to include the CGI module in the Standard Library, but it was removed in v5.22 (see The Long Death of CGI.pm). Lots of older code assumed that it would always be there, but now you have to install it yourself:
$ cpan CGI
Perl used to include the CGI module in the Standard Library, but it was removed in v5.22. Lots of older code assumed that it would always be there, but now you have to install it yourself.
The corelist program that comes with Perl is handy for checking these things:
$ corelist CGI
Data for 2020-03-07
CGI was first released with perl 5.004, deprecated (will be CPAN-only) in v5.19.7 and removed from v5.21.0
I handle this sort of thing by using the extract_modules program from my Module::Extract::Use module. Otherwise, I end up installing one module, then run again and discover another one to install, and so on:
$ extract_modules some_script.pl | xargs cpan
There's another interesting point for module writers. For a long time, we'd only list the external prerequisites in Makefile.PL. You should list even the internal ones now that Perl has a precedent for kicking modules out of the Standard Library. Along with that, specify a dependency for any module you actually use rather than relying it being in a particular distribution.
And, I was moving legacy programs around so much that I wrote a small tool, scriptdist to wrap the module infrastructure around single-file programs so I could install them as modules. The big win there is that cpan and similar tools install the prereqs for you. I haven't used it in a long time since I now just start programs as regular Perl distributions.

Check and report Perl module missing

Is there any way to report the missing modules used in the Perl file beforehand instead of getting as an error.
I have something like use Digest::MD5, use File::DosGlob modules in my Perl program. Whenever the users run the script they are getting an error if there is no specific module installed in their system. They could not understand the default error message given by #INC. So I would like to clearly tell them that these modules need to be installed to run the script.
You could build your own verification by using a BEGIN block. Those are run at compile time, just like use is. Keep in mind that use Foo is essentially nothing else as this:
BEGIN {
require Foo;
Foo->import;
}
The following code will replace all use statements with a single BEGIN and place them inside an eval. That's essentially like a try/catch mechanism.
We need the string eval (which is considered evil around here) because require only converts from package names with colons :: to paths if the argument is a bareword. But because we have the name in $module, it's a string, so we need to place it into an eval according to require's docs.
If that string eval fails, we die. That's caught by the outer eval block and $# is set. We can then check if it contains our module name, in which case we naively assume the failure was because that module is not installed. This check could be a bit more elaborate.
We keep track of any failures in $fails, and if there were any, we stop.
#!/usr/bin/perl
use strict;
use warnings;
# all our use statements go here
BEGIN {
my $fails;
foreach my $module ( qw/Digest::MD5 File::DosGlob ASDF/ ) {
eval {
eval "require $module" or die; # because $module is not a bareword
$module->import;
};
if ($# && $# =~ /$module/) {
warn "You need to install the $module module";
$fails++;
}
}
exit if $fails;
}
# ...
Above I included ASDF, which I don't have, so when run it will say
You need to install the ASDF module at /home/code/scratch.pl line 1335.
You might want to make that message a bit more verbose. If your users are not able to understand the default error message that Perl gives when it cannot find a module, it might be wise to include a guide on how to install stuff right there.
Note that both modules you listed have been included with Perl for a while (read: since March 2002). So why would you want to do this for those modules?
$ corelist Digest::MD5
Data for 2014-09-14
Digest::MD5 was first released with perl v5.7.3
$ corelist File::DosGlob
Data for 2014-09-14
File::DosGlob was first released with perl 5.00405
A better way would be ship your program as a distribution that can be installed, and include a Makefile or a cpanfile or something similar that lists dependencies. There is a guide in perlnewmod on how to start a new module. You'd not want to upload to CPAN obviously, but the basics are the same.
With this, your users would get all dependencies installed automatically.
You could use Devel::Modlist, it will list all the required module for your program.
perl -d:Modlist test.pl
There's another module Module::ScanDeps which comes with a utility scandeps.pl which you can use on your script as:
scandeps.pl test.pl
Note that sanity checking your Perl code using perl -c is dangerous, so use it carefully.
Your question isn't really clear about what "beforehand" means. To check if a Perl program's syntax is correct and directly included modules are resolvable, use
perl -c <perl-program.pl>
This checks the syntax of your file and ensures that any modules used by your code exist. However, it does not transitively check the entire dependency tree, only those mentioned in perl-program.pl.

How can I use the Environment Modules system in Perl?

How can one use the Environment Modules system* in Perl?
Running
system("load module <module>");
does not work, presumably because it forks to another environment.
* Not to be confused with Perl modules. According to the Wikipedia entry:
The Environment Modules system is a tool to help users manage their Unix or Linux shell environment, by allowing groups of related environment-variable settings to be made or removed dynamically.
It looks like the Perl module Env::Modulecmd will do what you want. From the documentation:
Env::Modulecmd provides an automated interface to modulecmd from Perl. The most straightforward use of Env::Modulecmd is for loading and unloading modules at compile time, although many other uses are provided.
Example usage:
use Env::Modulecmd { load => 'foo/1.0' };
Alternately, to do it less perl-namespace like and more environment module shell-like, you can source the Environment Modules initialization perl code like the other shells:
do( '/usr/share/Modules/init/perl');
module('load use.own');
print module('list');
For a one-line example:
perl -e "do ('/usr/share/Modules/init/perl');print module('list');"
(This problem, "source perl environment module" uses such generic words, that it is almost un-searchable.)
system("load module foo ; foo bar");
or, if that doesn't work, then
system("load module foo\nfoo bar");
I'm guessing it makes changes to the environment variables. To change Perl's environment variables, it would have to be executed within the Perl process. That's not going to work since it was surely only designed to be integrated into the shell. (It might not be too hard to port it, though.)
If you are ok with restarting the script after loading the module, you can use the following workaround:
use String::ShellQuote qw( shell_quote );
BEGIN {
if (!#ARGV || $ARGV[0] ne '!!foo_loaded!!') {
my $perl_cmd = shell_quote($^X, '--', $0, '!!foo_loaded!!', #ARGV);
exec("load module foo ; $perl_cmd")
or die $!;
}
shift(#ARGV);
}

How can I tell if a Perl module is core or part of the standard install?

How can I check if a Perl module is part of the core - i.e. it is part of the standard installation?
I'm looking for:
a command-line command:
a Perl subroutine/function to check within code
Perhaps the question should be: How can I tell what modules were originally provided with the specific Perl installation on a machine? (Actually, it is now asked as How can I tell what modules were originally provided with the specific Perl installation on a machine?.)
Given that there now appears to not to be an overall Perl standard installation, at least the answer to this new question will tell me what I originally had in the installation when it was first installed.
With that knowledge and if I keep the original installer image/package OR know how to get the exact thing again online, then I have a repeatable Perl installation for several machines with the knowledge of what modules will be present and what modules will not.
To clarify further: I am looking at what came with the installation originally, what modules were provided as part of that installation, and what was built-in. NOT what has been installed since then.
And I want to be able to do this on the machine that has the installation. So for this I would be relying upon the installation to have a record in some form as to what it has originally.
I asked spin-off question:
How can I tell what modules were originally provided with the specific Perl installation on a machine? (How can I tell what modules were originally provided with the specific Perl installation on a machine?)
The corelist command from the Module::CoreList module will determine if a module is Core or not.
> corelist Carp
Carp was first release with perl 5
> corelist XML::Twig
XML::Twig was not in CORE (or so I think)
Here is one way to use it in a script. The Module::CoreList POD is too terse -- you have to go hunting through the source code to find what methods to call:
use strict;
use warnings;
use Module::CoreList;
my $mod = 'Carp';
#my $mod = 'XML::Twig';
my #ms = Module::CoreList->find_modules(qr/^$mod$/);
if (#ms) {
print "$mod in core\n";
}
else {
print "$mod not in core\n";
}
__END__
Carp in core
You could check perlmodlib in a sub:
my %_stdmod;
sub is_standard_module {
my($module) = #_;
unless (keys %_stdmod) {
chomp(my $perlmodlib = `perldoc -l perlmodlib`);
die "cannot locate perlmodlib\n" unless $perlmodlib;
open my $fh, "<", $perlmodlib
or die "$0: open $perlmodlib: $!\n";
while (<$fh>) {
next unless /^=head\d\s+Pragmatic\s+Modules/ ..
/^=head\d\s+CPAN/;
if (/^=item\s+(\w+(::\w+)*)/) {
++$_stdmod{ lc $1 };
}
}
}
exists $_stdmod{ lc $module } ? $module : ();
}
Example usage:
die "Usage: $0 module..\n" unless #ARGV;
foreach my $mod (#ARGV) {
my $stdmod = is_standard_module $mod;
print "$0: $mod is ", ($stdmod ? "" : "not "), "standard\n";
}
Output:
$ ./isstdmod threads::shared AnyDBM_File CGI LWP::Simple
./isstdmod: threads::shared is standard
./isstdmod: AnyDBM_File is standard
./isstdmod: CGI is standard
./isstdmod: LWP::Simple is not standard
perldoc is most definitely part of the Perl's true core and standard installation. The source distribution for perl-5.10.1, for example, contains
perldoc.PL, generates perldoc as part of the standard installation
perlmodlib.PL, generates perlmodlib.pod as part of the standard installation
This is not a new addition. Perl-5.6.0, about ten years old, had perlmodlib as part of its true-core, standard installation.
Installations that do not contain these items are non-standard. Yes, I appreciate that it may seem academic from your perspective, but your vendor's packaging permitted a non-standard installation that breaks otherwise working programs.
With Debian's package manager, you can get the standard Perl installation with
$ apt-get --install-recommends install perl
There really is no such thing as "core" any more. There used to be a standard Perl distribution, but a lot of people don't have a standard Perl distribution. Operating system distributions modify it by either adding or removing modules, changing modules, and so on. You can't rely on the standard distribution being actually standard. Some Linux distributions don't even include the Perl documentation as part of the base Perl installation.
You mention that you can't use Module::CoreList because it isn't core, but if you can create files, you can install the module. You can even pretend that you wrote it yourself.
For the really lazy, there's the Core Modules list on the perldoc.perl.org website.
You can use (for example, search for Net::FTP):
perl -MNet::FTP -e 1
If it doesn't have output, then it's installed.
Other resources
perldoc perlmodlib
perldoc perllocal
A node from perlmonks
In a response to a comment of Gbacon's, you say that you want the answer to be platform neutral. I don't know of such a solution, but I wonder if it's even the right way to go.
If your goal is to find out on specific machines, I would use the tools that come with the platform. On Debian, that would include dpkg (pre-installed on any Debian system) or apt-file (not pre-installed necessarily) or other APT tools.
As an example, take a look at the output of this:
dpkg-query -L perl | less
You would obviously need to parse the output, but it strikes me as a start precisely because it is specific to the machine in question.
From the command-line:
Let's say that you want to know
whether module Tie::Hash is
installed.
To find out, execute
the following from the command line:
perl -MTie::Hash -e 1
If you don't get any output from the above command then the module is installed; if you get an error, it's not installed.
For making this check from within the script you can make use of Module::Load::Conditional.

How can I determine CPAN dependencies before I deploy a Perl project?

Does anyone have any suggestions for a good approach to finding all the CPAN dependencies that might have arisen in a bespoke development project. As tends to be the case your local development environment rarely matches your live one and as you build more and more projects you tend to build up a local library of installed modules. These then lead to you not necessarily noticing that your latest project has a requirement on a non-core module. As there is generally a requirement to package the entire project up for deployment to another group (in our case our operations team), it is important to know what modules should be included in the package.
Does anyone have any insights into the problem.
Thanks
Peter
I've had this problem myself. Devel::Modlist (as suggested by this answer) takes a dynamic approach. It reports the modules that were actually loaded during a particular run of your script. This catches modules that are loaded by any means, but it may not catch conditional requirements. That is, if you have code like this:
if ($some_condition) { require Some::Module }
and $some_condition happens to be false, Devel::Modlist will not list Some::Module as a requirement.
I decided to use Module::ExtractUse instead. It does a static analysis, which means that it will always catch Some::Module in the above example. On the other hand, it can't do anything about code like:
my $module = "Other::Module";
eval "use $module;";
Of course, you could use both approaches and then combine the two lists.
Anyway, here's the solution I came up with:
#! /usr/bin/perl
#---------------------------------------------------------------------
# Copyright 2008 Christopher J. Madsen <perl at cjmweb.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
# GNU General Public License or the Artistic License for more details.
#
# Recursively collect dependencies of Perl scripts
#---------------------------------------------------------------------
use strict;
use warnings;
use File::Spec ();
use Module::CoreList ();
use Module::ExtractUse ();
my %need;
my $core = $Module::CoreList::version{'5.008'};
# These modules have lots of dependencies. I don't need to see them now.
my %noRecurse = map { $_ => 1 } qw(
Log::Log4perl
XML::Twig
);
foreach my $file (#ARGV) {
findDeps($file);
}
foreach my $module (sort keys %need) {
print " $module\n";
}
#---------------------------------------------------------------------
sub findDeps
{
my ($file) = #_;
my $p = Module::ExtractUse->new;
$p->extract_use($file);
foreach my $module ($p->array) {
next if exists $core->{$module};
next if $module =~ /^5[._\d]+/; # Ignore "use MIN-PERL-VERSION"
next if $module =~ /\$/; # Run-time specified module
if (++$need{$module} == 1 and not $noRecurse{$module}) {
my $path = findModule($module);
if ($path) { findDeps($path) }
else { warn "WARNING: Can't find $module\n" }
} # end if first use of $module
} # end foreach $module used
} # end findDeps
#---------------------------------------------------------------------
sub findModule
{
my ($module) = #_;
$module =~ s!::|\'!/!g;
$module .= '.pm';
foreach my $dir (#INC) {
my $path = File::Spec->catfile($dir, $module);
return $path if -f $path;
}
return;
} # end findModule
You'd run this like:
perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl
It prints a list of all non-core modules necessary to run the scripts listed. (Unless they do fancy tricks with module loading that prevent Module::ExtractUse from seeing them.)
You can use online web-service at deps.cpantesters.org that will provide you many useful dependency data. All modules on CPAN already have the link to the dependency site (on the right side of the module page).
In the past I have used Devel::Modlist which is reasonably good allowing you to go
perl -d:Modlist script.pl
To get a list of the required modules.
I have a Make-based build system for all my C/C++ applications (both PC-based and for various embedded projects), and while I love being able to do a top-level build on a fresh machine and verify all dependencies are in place (I check my toolchains in to revision control :D), I've been frustrated at not doing the same for interpreted languages that currently have no makefile in my build system.
I'm tempted to write a script that:
searches my revision control repository for files with the .pl or .pm extension
runs perl -d:Modlist on them (thanks Vagnerr!)
concatenating it to the list of required modules
and finally comparing it to the list of installed modules.
I'd then execute that script as part of my top-level build, so that anyone building anything will know if they have everything they need to run every perl script they got from revision control. If there is some perl script they never run and don't want to CPAN install what's required to run it, they'd have to remove the unwanted script from their harddrive, so the dependency checker can't find them. I know how to modify a perforce client to leave out certain subdirectories when you do a 'sync', I'll have to figure that out for subversion...
I'd suggest making the dependency checker a single script that searches for pl files, as opposed to an individual makefile to check dependencies for each script, or based on a hard-coded list of script names. If you choose a method that requires user action to have a script checked for dependencies, people will forget to perform that action, since they will be able to run the script even if they don't do the dependency check.
Like I said, I haven't implemented the above yet, but this question has prompted me to try to do so. I'll post back with my experience after I'm done.
The 'obvious' way - painful but moderately effective - is to install a brand new build of base Perl in some out of the way location (you aren't going to use this in production), and then try to install your module using this 'virgin' version of Perl. You will find all the missing dependencies. The first time, this could be painful. After the first time, you'll already have the majority of the dependencies covered, and it will be vastly less painful.
Consider running your own local repository of CPAN modules - so that you won't always have to download the code. Also consider how you clean up the out of date modules.
use Acme::Magic::Pony;
Seriously. It will auto-install Perl modules if they turn up missing. See the Acme::Magic::Pony page in CPAN.
Its a "horse that's bolted" answer but I've got into the habit of creating a Bundle file with all my dependencies. Thus when I go to a new environment I just copy it over and install it.
For eg. I have a Baz.pm
package Bundle::Baz;
$VERSION = '0.1';
1;
__END__
=head1 NAME
Bundle::Baz
=head1 SYNOPSIS
perl -MCPAN -e 'install Bundle::Baz'
=head1 CONTENTS
# Baz's modules
XML::Twig
XML::Writer
Perl6::Say
Moose
Put this in ~/.cpan/Bundle/ (or wherever your .cpan lives) and then install 'Bundle::Baz' like a normal CPAN module. This then installs all the modules listed under "=head1 CONTENTS".
Here is a quickie bash function (using the excellent ack):
# find-perl-module-use <directory> (lib/ by default)
function find-perl-module-use() {
dir=${1:-lib}
ack '^\s*use\s+.*;\s*$' $dir | awk '{ print $2 }' | sed 's/();\?$\|;$//' | sort | uniq
ack '^\s*use\s+base\s+.*;\s*$' $dir | awk '{ print $3 }' | sed 's/();\?$\|;$//' | sort | uniq
}